Replace text-only PatchableTextStream with a unified StreamingAgentCard that
renders the full agent run lifecycle in a single Feishu interactive card:
- Tool-use panel: collapsible, shows each tool call with status (running/
success/error), input summary, and result/error in code blocks
- Reasoning panel: collapsible, streams thinking text inline then collapses
on completion
- Answer text: rendered via native Feishu markdown component (no post-row
round-trip)
Runner now captures previously-discarded SDK events:
- thinking_delta → reasoning stream
- tool_use id + input on content_block_start / assistant message
- tool_result from user messages (was entirely unhandled)
New files:
- card/trace-store.ts: per-run in-memory tool-use trace with secret redaction
- card/builder.ts: Feishu card JSON builder (tool panel + reasoning + text)
- card/streaming-card.ts: StreamingAgentCard controller (400ms throttled)
client.ts: add sendCard/patchCard raw JSON primitives
Two bugs were introduced when sendTextMessage was changed to auto-detect
message format (text/post/interactive):
1. Message type mismatch: sendTextMessage could create a text or post
message, but patchTextMessage only works on interactive cards.
Fix: add sendInteractiveCardMessage for streaming create (always
interactive, always patchable).
2. flushTextToSink state corruption: the text management after flush
had a flawed appendedDuringFlush heuristic that could lose text or
duplicate it. Fix: properly track sent vs unsent text by removing
the sent prefix length, keeping only the last chunk for future patches.
Also fix finish() to flush pending text regardless of currentMessageId.
- parsePostMessage: full Feishu post payload parser with locale fallback,
supports text/a/at/img/media/file/code_block/br/hr/emotion elements
- Trigger accepts post messages, extracts text + downloads attachments
- Post messages with attachments bypass batching, text-only posts batch
- Add unit tests (10) for all element types and edge cases
- Increase max message length from 4000 to 8000 chars
- Add splitAtBoundary: paragraph > newline > space priority, never split
inside fenced code blocks (move split to before opening fence)
- Add sendLongText: sends multi-chunk long messages sequentially
- Update PatchableTextStream.flush to use splitAtBoundary
- Add unit tests (6) for splitting edge cases
- sendApprovalCard: interactive card with configurable buttons
- resolveCard: patch card to show resolution state (green/red)
- ApprovalManager: register/resolve lifecycle with 5min timeout
- request_approval MCP tool: agent can ask user for confirmation
- Wire onCardAction in trigger handler and server startup
- Add unit tests (5) for card JSON, manager, and routing
- Add buildOutboundPayload: detect markdown format, isolate code blocks,
force plain text for tables, fallback from post to text on API rejection
- Add addReaction/removeReaction for processing status lifecycle
- Replace THUMBSUP with Typing→(remove on success | CrossMark on failure)
- Add unit tests for markdown rendering (15) and reactions (6)