Skip to content

feat(im): add +chat-list and --exclude-muted to filter muted chats#820

Open
shifengjuan-dev wants to merge 1 commit intolarksuite:mainfrom
shifengjuan-dev:feat/im-chats-filter-muted
Open

feat(im): add +chat-list and --exclude-muted to filter muted chats#820
shifengjuan-dev wants to merge 1 commit intolarksuite:mainfrom
shifengjuan-dev:feat/im-chats-filter-muted

Conversation

@shifengjuan-dev
Copy link
Copy Markdown
Contributor

@shifengjuan-dev shifengjuan-dev commented May 11, 2026

Summary

  • Add im +chat-list shortcut wrapping GET /open-apis/im/v1/chats (previously not exposed via lark-cli).
  • Add --exclude-muted to both +chat-search and +chat-list: client-side filter that calls POST /open-apis/im/v1/chat_user_setting/batch_get_mute_status after each page and drops is_muted=true chats.
  • Introduce shortcuts/im/mute_filter.go with pure helpers and an orchestrator (MaybeApplyMuteFilter) shared by both shortcuts.

Design highlights

  • Pure A (transparent reporting, no top-up). Filtered pages may be smaller than --page-size; the JSON output adds a filter sub-object with applied/skipped/fetched_count/returned_count/filtered_count/hint so AI/scripts can chain page_token.
  • Invariant: fetched_count == returned_count + filtered_count always holds.
  • Bot identity (--as bot): batch_get_mute_status is UAT-only, so the filter is skipped with filter.skipped=true, skip_reason="bot_identity_no_mute_data". All chats returned unfiltered.
  • --search-types public_not_joined alone: pre-skipped with skip_reason="all_non_member_search_types" (the batch call would 100% return not_a_member).
  • Non-member chats (e.g. default query containing public_not_joined results): silently retained, not counted in filtered_count; surfaced in the hint text only.
  • No request-body pollution: --exclude-muted never injects search_types or any other field into the search/list request. Verified via dry-run tests.
  • No client-side metrics: server-side BatchGetChatMuteStatus already has metrics (mute_status.go:60-62). CLI does not duplicate.

Output schema (only when --exclude-muted is set)

{
  "chats": [...],
  "filter": {
    "applied": "exclude_muted",
    "skipped": false,
    "fetched_count": 20,
    "returned_count": 19,
    "filtered_count": 1,
    "hint": "Filtered out 1 muted chat(s) on this page (19 remaining, including 2 non-member public group(s)); use --page-token to fetch more."
  }
}

Hint is shown in --format json (field) and --format pretty (line below summary). Not shown in --format table/ndjson/csv — consistent with the existing pagination hint behavior.

Test plan

  • go test ./shortcuts/im/... — passes
  • go build ./... — clean
  • go vet ./... — clean
  • +chat-list --dry-run — endpoint + params correct
  • +chat-search --query foo --exclude-muted --dry-run — request body unchanged, no search_types injection
  • +chat-search --search-types public_not_joined --exclude-muted --dry-runsearch_types present as user requested, no auto-injection
  • +chat-list --help exposes --exclude-muted with correct description
  • Live UAT call against tenant once batch_get_mute_status is GA (currently UAT-only)
  • Live --as bot call confirms filter.skipped=true with bot_identity_no_mute_data

Risks

  • batch_get_mute_status is currently UAT-only (TAT/bot rejected at the API gateway). The CLI handles this gracefully (bot identity skips the filter), but the API itself must be GA before this feature is broadly usable.
  • im:chat:read scope is assumed to cover chat_user_setting reads. If the gateway requires a separate scope, users will see 99991679/99991672 and we will need a follow-up to add the right scope.
  • Coupling to v2 search response shape: implementation reads meta_data.chat_id from each item; if the v2 search response schema changes the wrapping, the filter helper needs updating.

Spec docs

  • Design: docs/specs/2026-05-09-im-chats-filter-muted-design.md
  • Plan: docs/specs/2026-05-09-im-chats-filter-muted-plan.md

These reference the earlier exploration at docs/specs/2026-04-28-search-filter-muted-chats-design.md — this PR is the CLI-side variant (option D — pure transparent reporting) that does not block on the search-team-side option B.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added +chat-list to list your group chats with sorting, pagination, and formatted output.
    • Added --exclude-muted to +chat-list and +chat-search to omit muted/DND chats (applies to user identity; bot results remain unfiltered). Filter metadata appears in supported output formats.
  • Documentation

    • Added user guides for chat-list usage, pagination examples, and mute-filter behavior/hints.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7d2a7360-7267-4a99-891c-761a64e62dff

📥 Commits

Reviewing files that changed from the base of the PR and between 689ac26 and 4c0ed06.

📒 Files selected for processing (12)
  • CHANGELOG.md
  • shortcuts/im/builders_test.go
  • shortcuts/im/helpers_test.go
  • shortcuts/im/im_chat_list.go
  • shortcuts/im/im_chat_list_test.go
  • shortcuts/im/im_chat_search.go
  • shortcuts/im/mute_filter.go
  • shortcuts/im/mute_filter_test.go
  • shortcuts/im/shortcuts.go
  • skills/lark-im/SKILL.md
  • skills/lark-im/references/lark-im-chat-list.md
  • skills/lark-im/references/lark-im-chat-search.md
✅ Files skipped from review due to trivial changes (5)
  • CHANGELOG.md
  • skills/lark-im/SKILL.md
  • skills/lark-im/references/lark-im-chat-list.md
  • shortcuts/im/im_chat_list_test.go
  • shortcuts/im/mute_filter_test.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • shortcuts/im/shortcuts.go
  • shortcuts/im/helpers_test.go
  • skills/lark-im/references/lark-im-chat-search.md
  • shortcuts/im/mute_filter.go
  • shortcuts/im/im_chat_list.go
  • shortcuts/im/im_chat_search.go
  • shortcuts/im/builders_test.go

📝 Walkthrough

Walkthrough

This PR adds a new +chat-list shortcut and an --exclude-muted flag for +chat-list and +chat-search that client-side filters muted chats via a mute-status batch API and reports filter metadata/hints.

Changes

IM Mute Filtering and Chat List

Layer / File(s) Summary
Mute Filter Data Model
shortcuts/im/mute_filter.go
MuteFilterMeta type tracks filtering metadata and constants define batch-size limits and skip reasons.
Mute Filter Helpers
shortcuts/im/mute_filter.go
BuildMuteFilterHint, BuildBatchGetMuteStatusBody, ParseBatchGetMuteStatusResponse, ExtractChatIDs, MuteFilterMetaToMap.
Core Filter Logic & Orchestration
shortcuts/im/mute_filter.go
ApplyMuteFilter drops muted rows and updates counters; FetchMuteStatus calls the mute-status API; MaybeApplyMuteFilter orchestrates conditional fetch, filtering, and hint/meta computation.
Mute Filter Tests
shortcuts/im/mute_filter_test.go
Unit tests for hint generation, batch request/response parsing, ApplyMuteFilter semantics, ID extraction, meta mapping, orchestrator branches, and FetchMuteStatus edge cases.
Chat List Command
shortcuts/im/im_chat_list.go
ImChatList shortcut with flags (--user-id-type, --sort-type, --page-size, --page-token, --exclude-muted), page-size validation (1–100), param builder, Execute flow, optional mute filtering, and output rendering.
Chat List Tests
shortcuts/im/im_chat_list_test.go
Tests for buildChatListParams defaults/overrides, ImChatList.Validate page-size bounds, and ImChatList.DryRun endpoint/fields.
Chat Search Enhancement
shortcuts/im/im_chat_search.go
Adds --exclude-muted flag, computes pre-skip for --search-types like public_not_joined, applies mute filtering, includes filter metadata, and prints filter hints.
Shortcut Dry-Run & Builders Tests
shortcuts/im/builders_test.go
Dry-run assertions for ImChatSearch/ImChatList and TestDetectAllNonMemberPreSkip.
Command Registration & Helpers Test
shortcuts/im/shortcuts.go, shortcuts/im/helpers_test.go
Registers ImChatList in Shortcuts() and updates TestShortcuts expected ordering.
Documentation
CHANGELOG.md, skills/lark-im/SKILL.md, skills/lark-im/references/*.md
Adds changelog entry and reference docs for +chat-list and --exclude-muted, explains filter metadata structure, counts invariant, bot-identity behavior, and output format compatibility for hints.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • larksuite/cli#770: Also updates IM shortcuts and TestShortcuts ordering; related to command registration and tests.

Suggested reviewers

  • YangJunzhou-01
  • sammi-bytedance

Poem

🐰 A new shortcut hops into the list,
With muted chats politely missed,
Search and list now filter and show,
Counts and hints tell what we know,
Hop on, friends — the output is bliss!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: adding +chat-list shortcut and --exclude-muted flag for filtering muted chats.
Description check ✅ Passed The description comprehensively covers summary, changes, design highlights, output schema, test plan with checkmarks, risks, and spec docs. All template sections are well-populated with detailed information.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added domain/im PR touches the im domain size/L Large or sensitive change across domains or core paths labels May 11, 2026
Adds a new im +chat-list shortcut (wraps GET /open-apis/im/v1/chats)
and a --exclude-muted flag on both +chat-list and the existing
+chat-search to drop chats the current user has muted.

Native chat search/list APIs do not return mute status, so the filter
is applied client-side after each page: extract chat_ids, call
POST /open-apis/im/v1/chat_user_setting/batch_get_mute_status, drop
is_muted=true rows. Output adds a "filter" sub-object only when
--exclude-muted is set (backward compatible). Pretty output appends a
single hint line below the table summary; json keeps it under
filter.hint. table/ndjson/csv do not surface it, consistent with the
existing pagination hint behavior.

Behavior:
- Bot identity (--as bot): mute API is UAT-only, so the filter is
  skipped with filter.skipped=true and skip_reason "bot_identity_no_mute_data".
- --search-types public_not_joined alone: all results are non-member
  public groups; batch call is pre-skipped with skip_reason
  "all_non_member_search_types".
- Empty page: short-circuits to avoid the upstream "chat_ids is empty"
  InvalidParam, returns counts=0.
- Non-member chats (invalid_id_list from default queries containing
  public_not_joined): silently retained, not counted in filtered_count;
  surfaced in the hint when filtered_count > 0.
- Invariant: fetched_count == returned_count + filtered_count always
  holds. No top-up loop -- callers continue via page_token if needed.

Filter is purely client-side: request body and search_types are
unchanged regardless of --exclude-muted. No new scopes required;
reuses im:chat:read.

Introduces shortcuts/im/mute_filter.go with pure helpers
(BuildMuteFilterHint covering all 8 hint states,
BuildBatchGetMuteStatusBody, ParseBatchGetMuteStatusResponse,
ApplyMuteFilter, ExtractChatIDs, MuteFilterMetaToMap) plus the
FetchMuteStatus API wrapper and MaybeApplyMuteFilter orchestrator.
~27 unit tests cover all hint states, orchestrator branches
(bot-skip / pre-skip / empty / default), codec round-trip, page-size
bounds, and dry-run non-pollution.

Change-Id: Ia98980a8dbf8fc34d5614573201fb81eecd60a75
Spec: docs/specs/2026-05-09-im-chats-filter-muted-design.md
Plan: docs/specs/2026-05-09-im-chats-filter-muted-plan.md
@shifengjuan-dev shifengjuan-dev force-pushed the feat/im-chats-filter-muted branch from 689ac26 to 4c0ed06 Compare May 11, 2026 13:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain/im PR touches the im domain size/L Large or sensitive change across domains or core paths

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant