Skip to content

Make Feishu group listening, contact lookup, and replies reliable - #996

Draft
Y1fe1Zh0u wants to merge 5 commits into
dataelement:v1.11.4from
Y1fe1Zh0u:agent/feishu-passive-listening-v1114
Draft

Make Feishu group listening, contact lookup, and replies reliable#996
Y1fe1Zh0u wants to merge 5 commits into
dataelement:v1.11.4from
Y1fe1Zh0u:agent/feishu-passive-listening-v1114

Conversation

@Y1fe1Zh0u

@Y1fe1Zh0u Y1fe1Zh0u commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

What changed

  • Accept ordinary messages from Feishu groups while preserving provider sender identity and the external-group Session contract.
  • Suppress only exact NO_REPLY completions before external delivery.
  • Keep normal replies bound to the originating Session and require explicit confirmation for cross-Session sends.
  • Keep external-group conversations visible without treating their placeholder user_id as Direct-session ownership.
  • Add a provider-native GLANCE acknowledgement only after a completed reply passes NO_REPLY suppression.
  • Search the configured Feishu app's live Contact v3 scope when the tenant Directory has no matching person; calendar attendee resolution privately reuses exact-name open_id matches.
  • Prevent public external-group Runs from entering waiting_user; clarification is returned publicly and the shared Session lane is released for the next message.

Why

Feishu group Agents need to listen passively without noisy replies, acknowledge only messages they deliberately answer, resolve colleagues from the Bot-visible Feishu directory, and avoid letting one participant's clarification wait block the shared public lane.

Two production failures exposed missing cross-contract coverage:

  1. feishu_user_search projected only pre-synced Clawith OrgMember rows, so correctly configured Bot credentials could create calendar events while valid Feishu colleagues still returned zero matches.
  2. An external-group Run could enter waiting_user, but channel resume validation expected a Direct/Web Chat thread shape. The Run held external_group_thread:* indefinitely and blocked later messages.

Delivery and safety behavior

  • Exact NO_REPLY, Direct Chat, and non-terminal deliveries do not add the reaction.
  • Reaction failures are cosmetic and cannot block or duplicate durable text delivery.
  • Synced Directory contacts remain authoritative; live Feishu fallback is bounded by the configured Bot's directly granted users and visible departments.
  • Provider open_id values remain private to calendar execution and are not exposed in model-visible search results.
  • External Feishu groups remain session_type=group, group_id=NULL, and do not gain native Clawith Group handoff tools.
  • Public group clarification completes the current Run; only Direct Chat retains waiting_user semantics.
  • Existing Feishu apps must approve im:message.group_msg and im:message.reactions:write_only, then publish a new app version.

Validation

  • Final clean PR head: 148 scoped Backend tests passed across Feishu Contact search, typed Feishu outcomes, Runtime model steps, Chat intake, Channel intake, and Feishu channel Runtime.
  • Scoped Ruff passed for the modified Runtime, Contact-search, and test files.
  • git diff --check passed.
  • Frontend: 112 tests passed and production build passed for the visibility/reaction commits.
  • Live 3010 E2E passed after narrow deployment:
    • a new external-group Session was created without old checkpoint state;
    • Contact v3 queried directly visible users, departments, and department members;
    • calendar event clawith场景讨论 was created for 15:00-16:00;
    • 周逸飞、覃睿、曾征、张健 were all resolved and four invitations were confirmed;
    • the Run completed, released its lane, and delivered the final reply to the originating Feishu group.

Not tested

  • Full Backend test suite on the final five-commit PR head.
  • Multi-worker load and high-volume concurrent external-group traffic.
  • Live rendering of the GLANCE reaction after the new permission is approved.

Feishu group bots can now accept ordinary user messages, freeze each input on a stable external-group lane, retain provider sender identity, and suppress exact NO_REPLY completions before creating an external outbox. Current-conversation replies stay bound to the originating Session, while explicit cross-Session sends require an execution-time confirmation flag.

Constraint: Existing Feishu apps require manual im:message.group_msg approval and publication.

Rejected: Let models choose a reply group through send_channel_message | directory guesses can send to the wrong Session.

Confidence: high

Scope-risk: moderate

Directive: Keep ordinary replies on the Run delivery target; cross-Session channel sends must remain explicit and validated.

Tested: Backend focused pytest suites (113, 90, 66, and 61 passed); scoped Ruff on modified focused files; frontend npm run build; scripts/arch-guard.sh; live 3010 Feishu ordinary-message, NO_REPLY, origin-Session delivery, and calendar E2E.

Not-tested: Multi-worker load and high-volume long-running compaction under production traffic.
External group Sessions store the Agent creator as a placeholder user, so user-id-only filtering hid them from the admin-facing Other sessions list. Classify group and Agent sessions by their explicit session metadata before applying direct-session ownership filtering.

Constraint: External Feishu groups must remain group_id=NULL and keep the existing placeholder user contract.

Rejected: Move external groups into My sessions | that surface is intentionally restricted to writable Direct sessions.

Confidence: high

Scope-risk: narrow

Directive: Do not use ChatSession.user_id to classify external group ownership.

Tested: frontend npm test (112 passed); frontend npm run build

Not-tested: 3010 deployment and live Feishu group visibility
Preserve the provider message identity through the durable delivery route and add the GLANCE reaction only after a completed terminal response has passed exact NO_REPLY suppression. Reaction failures remain cosmetic so they cannot block or duplicate the durable text reply. The Feishu permission templates now request the matching write-only reaction scope.

Constraint: The reaction must not run on intake, waiting states, direct chats, or exact NO_REPLY completions.

Rejected: Add the reaction in the webhook handler | that runs before the Agent NO_REPLY decision.

Rejected: Call Feishu from the Runtime delivery transaction | external side effects must stay behind the durable channel outbox.

Confidence: high

Scope-risk: narrow

Directive: Keep source_message_id provider-native and gate future acknowledgement reactions on terminal completed delivery.

Tested: 68 scoped backend tests; 112 frontend tests; frontend production build; scoped Ruff; git diff check; architecture guard

Not-tested: Live Feishu group reaction rendering and newly approved application scope
The Feishu user-search tool previously projected only pre-synced Clawith OrgMember rows, so a correctly configured bot could create calendar events while every attendee lookup returned zero. The tool now keeps the tenant-scoped projection as its first choice, then performs a bounded app-identity Contact v3 lookup across directly granted users and visible departments. Calendar attendee resolution privately reuses exact-name matches without exposing provider IDs to the model.

Constraint: Provider open_id values must remain private to calendar execution

Constraint: Local Tenant-scoped directory results remain authoritative when available

Constraint: Bot authentication uses tenant_access_token; Feishu search/v1/user requires user_access_token

Rejected: Treat empty local OrgMember results as missing Feishu permission | 3010 proved a valid token and one directly visible user

Rejected: Persist live contacts from a read tool | introduces hidden cross-system writes and sync ownership

Confidence: high

Scope-risk: moderate

Directive: Keep direct-user scope support even if department-based contact sync is expanded

Tested: 140 scoped Feishu and Directory tests; focused Ruff; git diff --check; live 3010 read-only Contact API probe found 周逸飞

Not-tested: Deployed 3010 Agent Run and calendar invitation after this patch
External Feishu groups share one public Session lane, so a waiting_user checkpoint can block unrelated group traffic and cannot be resumed by the Direct Chat scope contract. Mark the immutable Chat session type in Run input and repair user waits into public clarification replies without enabling native Group handoff tools.

Constraint: External Feishu groups use session_type=group with group_id=NULL and must not gain native Clawith Group tools.

Rejected: Resume external-group waiting_user Runs | one participant's wait would hold the shared public lane and consume unrelated messages.

Confidence: high

Scope-risk: narrow

Directive: Public group Runs ask clarifying questions in their final reply and release the lane; only Direct Chat may retain waiting_user.

Tested: 94 scoped Runtime, Chat intake, Channel, and Feishu tests; scoped Ruff; live 3010 new-Session calendar E2E.

Not-tested: Full backend test suite and high-volume concurrent external-group traffic.
@Y1fe1Zh0u Y1fe1Zh0u changed the title Let Feishu group Agents listen without noisy replies Let Feishu group Agents listen and acknowledge chosen replies Aug 19, 2026
@Y1fe1Zh0u Y1fe1Zh0u changed the title Let Feishu group Agents listen and acknowledge chosen replies Make Feishu group listening, contact lookup, and replies reliable Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant