Skip to content

feat: add text content card to display agent output in threads - #110

Merged
lishuceo merged 1 commit into
mainfrom
feat/text-content-card
Mar 4, 2026
Merged

feat: add text content card to display agent output in threads#110
lishuceo merged 1 commit into
mainfrom
feat/text-content-card

Conversation

@lishuceo

@lishuceo lishuceo commented Mar 4, 2026

Copy link
Copy Markdown
Owner

Summary

  • 新增文本内容卡片(buildTextContentCard),在话题模式下持续追加显示 agent 的文本输出,解决中间 turn 文本丢失问题
  • 使用 UTF-8 字节级截断(28KB 上限),保留尾部最新内容,最大化利用飞书卡片容量
  • 顺手修复 pre-existing bug:正常完成路径的进度卡片遗漏最后一轮 tool calls

Test plan

  • npm run typecheck 通过
  • npx vitest run 相关测试全部通过(52 + 42 = 94 tests)
  • Codex CLI review APPROVED
  • 在飞书中发送多轮工具调用任务,验证文本卡片持续追加、完成后切换状态

🤖 Generated with Claude Code

Previously in thread mode, only the last turn's text was shown in the
result card. Intermediate turns' text content was accumulated in memory
but never sent to Feishu, causing users to miss detailed conclusions.

Add a continuously-updated text content card between the progress card
(tool calls) and the result card (status). Also fix pre-existing bug
where the normal completion path dropped the last turn's tool calls
from the progress card.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Mar 4, 2026

Copy link
Copy Markdown

Claude finished @lishuceo's task in 1m 43s —— View job


Code Review for PR #110

  • Check for previous review comments — none found
  • Read full source files and understand context
  • Review changes in src/feishu/message-builder.ts
  • Review changes in src/feishu/event-handler.ts
  • Review changes in src/feishu/__tests__/message-builder.test.ts
  • Post review summary

✅ Approved

Clean, well-structured PR that follows existing patterns and fixes a real bug. No issues found with confidence ≥ 75.

What was reviewed

1. buildTextContentCard + truncateToByteLimit (message-builder.ts:556-622)

  • UTF-8 byte-level truncation is correctly implemented: finds the buffer offset, skips continuation bytes (0x80-0xBF) to land on a valid character boundary, preserves the tail (latest content).
  • CARD_TEXT_MAX_BYTES = 28000 with ~2KB headroom for JSON structure overhead is reasonable for Feishu's ~30KB card limit.
  • The truncation prefix _(前部分内容已省略)_ adds minimal overhead (~40 bytes) — won't push past the limit.
  • Card structure follows the exact same pattern as buildToolProgressCard (header template toggling, footer parts, elements layout). Consistent.

2. Text card lifecycle in event-handler.ts (lines 1137-1186, 1349-1350, 1406-1418, 1444-1445)

  • appendText / flushTextCard closure design cleanly separates accumulation from card I/O.
  • flushTextCard correctly handles create-or-update: first call creates via replyCardInThread, subsequent calls update via updateCard. The textCardFailed flag prevents retrying a permanently failed card — good defensive pattern, consistent with progressCardFailed.
  • All three exit paths (restart, normal completion, error) properly call flushTextCard(pendingTurn?.textContent, true) to flush the last buffered turn and mark the card as completed.
  • The ?? undefined on replyCardInThread return (line 1155) safely normalizes a potential null runtime return.
  • Guard if (!threadReplyMsgId) in flushTextCard (line 1149) correctly limits text cards to thread mode only.

3. Bug fix: missing last-turn tool calls on normal completion (lines 1407-1414)

This is a legitimate fix. The onTurn callback flushes the previous turn's tool calls into accumulatedToolCalls, so the final pendingTurn is never flushed by onTurn. Before this PR, the normal completion path used accumulatedToolCalls alone, missing the last turn's calls. The restart path (line 1339) and error path (line 1436) already had this fix — this PR makes the normal path consistent. Correct.

4. Tests (message-builder.test.ts:506-551)

Good coverage of the key scenarios:

  • In-progress vs completed header state
  • Short text (no truncation)
  • Long text (truncation keeping tail, verifying total serialized size < 30720 bytes)
  • Empty text placeholder

Minor observations (not blocking)

  • The onTurn callback appends pendingTurn.textContent via appendText() (line 1174) and also calls flushTextCard() without extraText (line 1186). This is correct — the separation is intentional — but a brief inline comment clarifying "text already appended above, just flush" could help future readers. Not a blocker.

Overall: well-written, follows existing patterns, good test coverage, and the pre-existing bug fix is a nice bonus.

@lishuceo
lishuceo merged commit 73d20a4 into main Mar 4, 2026
1 check passed
@lishuceo
lishuceo deleted the feat/text-content-card branch March 4, 2026 06:39
lishuceo added a commit that referenced this pull request Mar 4, 2026
Previously in thread mode, only the last turn's text was shown in the
result card. Intermediate turns' text content was accumulated in memory
but never sent to Feishu, causing users to miss detailed conclusions.

Add a continuously-updated text content card between the progress card
(tool calls) and the result card (status). Also fix pre-existing bug
where the normal completion path dropped the last turn's tool calls
from the progress card.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
lishuceo added a commit that referenced this pull request Mar 4, 2026
* ci: 增加 CI 测试门禁 + 文档变更跳过部署

- deploy.yml: 加 paths-ignore 跳过 docs/md 等纯文档变更
- deploy.yml: 新增 test job (ubuntu-latest) 作为部署前门禁,typecheck + 单元测试
- 新建 ci.yml: PR 级别测试 (typecheck + lint + unit tests)
- 测试排除 quality.test.ts 和 integration.test.ts (外部 API 依赖)
- 新增 docs/ci-improvements.md 改进方案文档

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add text content card to display agent output in threads (#110)

Previously in thread mode, only the last turn's text was shown in the
result card. Intermediate turns' text content was accumulated in memory
but never sent to Feishu, causing users to miss detailed conclusions.

Add a continuously-updated text content card between the progress card
(tool calls) and the result card (status). Also fix pre-existing bug
where the normal completion path dropped the last turn's tool calls
from the progress card.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: CI 移除 lint 步骤 — ESLint v10 缺少 flat config

ESLint v10 要求 eslint.config.js (flat config),项目尚未配置,
本地和 CI 均无法运行 npm run lint。先移除 CI lint 步骤,
待后续 PR 单独修复 ESLint 配置。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
lishuceo added a commit that referenced this pull request Apr 8, 2026
Previously in thread mode, only the last turn's text was shown in the
result card. Intermediate turns' text content was accumulated in memory
but never sent to Feishu, causing users to miss detailed conclusions.

Add a continuously-updated text content card between the progress card
(tool calls) and the result card (status). Also fix pre-existing bug
where the normal completion path dropped the last turn's tool calls
from the progress card.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
lishuceo added a commit that referenced this pull request Apr 8, 2026
* ci: 增加 CI 测试门禁 + 文档变更跳过部署

- deploy.yml: 加 paths-ignore 跳过 docs/md 等纯文档变更
- deploy.yml: 新增 test job (ubuntu-latest) 作为部署前门禁,typecheck + 单元测试
- 新建 ci.yml: PR 级别测试 (typecheck + lint + unit tests)
- 测试排除 quality.test.ts 和 integration.test.ts (外部 API 依赖)
- 新增 docs/ci-improvements.md 改进方案文档

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add text content card to display agent output in threads (#110)

Previously in thread mode, only the last turn's text was shown in the
result card. Intermediate turns' text content was accumulated in memory
but never sent to Feishu, causing users to miss detailed conclusions.

Add a continuously-updated text content card between the progress card
(tool calls) and the result card (status). Also fix pre-existing bug
where the normal completion path dropped the last turn's tool calls
from the progress card.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: CI 移除 lint 步骤 — ESLint v10 缺少 flat config

ESLint v10 要求 eslint.config.js (flat config),项目尚未配置,
本地和 CI 均无法运行 npm run lint。先移除 CI lint 步骤,
待后续 PR 单独修复 ESLint 配置。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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