Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: StreamingCard debounce, SessionPoisoned recovery, thinkingDelay removal#72

Merged
NeverMore93 merged 6 commits into
mainfrom
029-prompt-redesign
Apr 29, 2026
Merged

feat: StreamingCard debounce, SessionPoisoned recovery, thinkingDelay removal#72
NeverMore93 merged 6 commits into
mainfrom
029-prompt-redesign

Conversation

@NeverMore93

Copy link
Copy Markdown
Owner

Summary

  • StreamingCard debounce: 200ms debounce on conclusion render, reducing CardKit API calls from 30-100/sec to ~5/sec during streaming
  • SessionPoisoned L1 recovery: v2 client deleteMessage to surgically remove poisoned message before falling back to session invalidation
  • thinkingDelay removal: Send "正在思考..." placeholder immediately when CardKit unavailable (structurally eliminates race condition)
  • Error reclassification: tool-choice-type moved from SessionPoisoned to ModelUnavailable (provider config mismatch, not history corruption)
  • Gateway catch-all: Error notifications for chatType resolution and async processing failures
  • Prompt redesign: Migrate skills/ to prompts/, update docs to remove thinkingDelay references

Test plan

  • Send message → verify StreamingCard renders smoothly without CardKit API throttling
  • Send YAML/TS file → verify AI reads content (no UnsupportedFunctionalityError)
  • Verify SessionPoisoned recovery: deleteMessage called before session invalidation
  • Verify "正在思考..." appears immediately on fallback path (no 2.5s delay)
  • npm run typecheck passes
  • npm run build passes

🤖 Generated with Claude Code

wentaoyuan added 3 commits April 29, 2026 21:41
… removal

- StreamingCard: 200ms debounce on conclusion render, reducing CardKit API
  calls from 30-100/sec to ~5/sec during streaming
- cardkit: remove updateElement retry loop (debounce is root cause fix)
- chat.ts: SessionPoisoned L1 recovery via v2 client deleteMessage before
  falling back to session invalidation
- chat.ts: remove thinkingDelay, send "正在思考..." placeholder immediately
  when CardKit unavailable (structurally eliminates race condition)
- errors.ts: reclassify tool-choice-type from SessionPoisoned to ModelUnavailable
- gateway.ts: catch-all error notifications for chatType resolution and
  async processing failures
- types.ts: remove thinkingDelay config field, nudge default to English
- send-card.ts: enhance tool description with constraints
- index.ts: migrate prompt path from skills/ to prompts/
- Delete skills/ directory (migrated to prompts/)
- Update CLAUDE.md, BEHAVIOR.md, README.md, AGENTS.md to remove
  thinkingDelay references
- Update prompts/feishu-card-interaction/prompt.md with latest changes
@NeverMore93

Copy link
Copy Markdown
Owner Author

/gemini review

@NeverMore93

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions

github-actions Bot commented Apr 29, 2026

Copy link
Copy Markdown

Qodana for JVM

It seems all right 👌

No new problems were found according to the checks applied

View the detailed Qodana report

To be able to view the detailed Qodana report, you can either:

To get *.log files or any other Qodana artifacts, run the action with upload-result option set to true,
so that the action will upload the files as the job artifacts:

      - name: 'Qodana Scan'
        uses: JetBrains/[email protected]
        with:
          upload-result: true
Contact Qodana team

Contact us at [email protected]

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the project to version 1.9.0, introducing a dedicated BEHAVIOR.md for product logic and migrating the skills directory to prompts. Key functional changes include removing the thinkingDelay configuration, implementing a 200ms debounce for streaming card updates to reduce API load, and adding a session recovery mechanism that deletes poisoned messages. Review feedback suggests retaining the retry logic for card updates to ensure robustness against network jitters and optimizing the poisoned message search by scanning session history in reverse order.

Comment thread src/feishu/cardkit.ts
Comment thread src/handler/chat.ts Outdated
@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@NeverMore93 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 44 minutes and 15 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 549740c2-7cde-48f3-8a3e-fbb784068293

📥 Commits

Reviewing files that changed from the base of the PR and between a52be07 and eaaeca8.

📒 Files selected for processing (22)
  • .specify/memory/constitution.md
  • AGENTS.md
  • BEHAVIOR.md
  • CLAUDE.md
  • README.md
  • package.json
  • prompts/CLAUDE.md
  • prompts/feishu-card-interaction/prompt.md
  • skills/CLAUDE.md
  • skills/feishu-card-interaction/SKILL.md
  • skills/feishu-card-interaction/prompt.md
  • src/feishu/cardkit.ts
  • src/feishu/content-extractor.ts
  • src/feishu/gateway.ts
  • src/feishu/streaming-card.ts
  • src/handler/CLAUDE.md
  • src/handler/chat.ts
  • src/handler/errors.ts
  • src/handler/event.ts
  • src/index.ts
  • src/tools/send-card.ts
  • src/types.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 029-prompt-redesign

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
Review rate limit: 0/1 reviews remaining, refill in 44 minutes and 15 seconds.

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

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the project to version 1.9.0, introducing a new BEHAVIOR.md file to define product behavior and responsibilities. Key changes include renaming the skills directory to prompts, refining prompt layering principles, and removing the thinkingDelay configuration. On the technical side, it implements a debouncing mechanism for card rendering to optimize API usage and introduces a session poisoning recovery flow that attempts to delete specific problematic messages. Feedback focuses on improving type safety for message parts and refactoring duplicated logic for placeholder messages.

Comment thread src/handler/chat.ts
Comment thread src/handler/chat.ts
Scan messages from newest to oldest — the poisoned message is typically
the most recent one, so reverse iteration finds it faster in long sessions.

Addresses Gemini review feedback.
@NeverMore93

Copy link
Copy Markdown
Owner Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the plugin to version 1.9.0, primarily restructuring prompt management by moving from skills/ to prompts/ and introducing BEHAVIOR.md to document product behavior. Key functional changes include the removal of the thinkingDelay setting, the implementation of debounce logic for card rendering to reduce API overhead, and a new recovery mechanism for poisoned sessions that attempts to delete specific messages. Reviewers noted that removing retry logic for card updates might decrease robustness against network issues and that the lack of fallback logic when loading prompts could lead to startup crashes if files are missing.

Comment thread src/feishu/cardkit.ts
Comment thread src/index.ts
@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown

Caution

Review failed

An error occurred during the review process. Please try again later.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 029-prompt-redesign

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.

Prevents cryptic ENOENT crash if prompts/ is missing due to broken
installation. Returns minimal fallback prompt instead.

Addresses Gemini review feedback.
@NeverMore93

Copy link
Copy Markdown
Owner Author

/gemini review

Per user decision: if prompt.md is missing, the installation is broken
and should crash at startup, not silently degrade.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the version to 1.9.0 and introduces a new product behavior specification in BEHAVIOR.md. Key changes include renaming the skills/ directory to prompts/, removing the thinkingDelay configuration, and implementing a session recovery mechanism to delete 'poisoned' messages. StreamingCard now uses a 200ms debounce for conclusion rendering. Feedback suggests restoring retry logic for card updates, refactoring duplicated recovery logic, and handling AbortError during recovery to prevent unnecessary session resets.

Comment thread src/feishu/cardkit.ts
Comment on lines +103 to 122
const res = await this.larkClient.cardkit.v1.cardElement.content({
data: {
content,
sequence,
},
path: {
card_id: cardId,
element_id: elementId,
},
})

if (res?.code !== 0) {
lastErr = new Error(`CardKit updateElement 失败: ${res?.msg ?? "unknown"} (code: ${res?.code})`)
this.log?.("warn", `CardKit updateElement 尝试 ${attempt}/${MAX_ATTEMPTS} 业务失败`, {
cardId,
elementId,
code: res?.code,
msg: res?.msg,
})
} else {
return
}
} catch (err) {
lastErr = err
this.log?.("warn", `CardKit updateElement 尝试 ${attempt}/${MAX_ATTEMPTS} transport 异常`, {
cardId,
elementId,
error: err instanceof Error ? err.message : String(err),
})
}
if (attempt < MAX_ATTEMPTS) {
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS))
}
if (res?.code !== 0) {
this.log?.("error", "CardKit updateElement 失败", {
cardId,
elementId,
code: res?.code,
msg: res?.msg,
})
throw new Error(`CardKit updateElement 失败: ${res?.msg ?? "unknown"} (code: ${res?.code})`)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

移除了 updateElement 的重试逻辑。虽然引入了 StreamingCard 的 debounce 机制减少了调用频率,但 updateElement 仍然是流式输出中最频繁的网络调用。单次网络抖动或瞬时频率限制(Rate Limit)仍可能导致调用失败。在当前实现中,一旦失败就会触发 StreamingCard 降级(degraded),导致流式体验中断。建议保留轻量级的重试机制(如之前的 1 次重试)以增强系统的健壮性。

Comment thread src/handler/chat.ts
Comment on lines +663 to +685
await client.session.promptAsync({
path: { id: session.id },
query,
body: { ...baseBody, messageID: recoveryRequestMessageId },
})

const finalText = await poll(client, session.id, {
timeout, pollInterval, stablePolls, query,
signal: mergeAbortSignals([signal, getRunAbortSignal(run.runId)]),
})

const actualModel = await fetchActualModel(client, session.id, requestMessageIds, log, query)
const terminalState = timedOut ? "timed_out" : "completed"
completeReplyRun(run.runId, terminalState)
if (streamingCard) {
await streamingCard.setRunState(terminalState, terminalState)
}
await finalizeReply({
streamingCard, feishuClient, chatId, placeholderId, log,
actualModel, title: replyTitle, state: terminalState,
conclusion: finalText || latestSnapshot.text || (timedOut ? "⚠️ 响应超时" : undefined),
detailsPhases: detailPhases.values(),
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

SessionPoisoned 恢复路径中的逻辑与主流程(第 559-605 行)高度重复,包括 promptAsyncpollfetchActualModelfinalizeReply 的调用。这种重复不仅增加了维护成本,还容易导致逻辑不一致(例如主流程的改进未同步到恢复流程)。建议将这部分核心对话逻辑抽象为私有函数或复用现有逻辑。

Comment thread src/handler/chat.ts
Comment on lines +690 to +695
} catch (recoveryErr) {
log("error", "删除中毒消息后重发 prompt 失败,降级到新建 session", {
sessionKey, rule: e.rule,
error: recoveryErr instanceof Error ? recoveryErr.message : String(recoveryErr),
})
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

SessionPoisoned 恢复路径的 catch 块中,未针对 AbortError 进行特殊处理。如果用户在恢复重试期间点击了“中断”按钮,poll 会抛出 AbortError,当前代码会将其视为普通错误并记录日志,随后进入 L2 逻辑导致会话被重置(invalidateSession)。这不符合预期,中断操作不应导致会话失效。建议在此处捕获并正确处理 AbortError

@NeverMore93 NeverMore93 merged commit 3a18779 into main Apr 29, 2026
8 checks passed
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