fix(feishu): stream CardKit text deltas#82419
Conversation
|
Codex review: needs real behavior proof before merge. Summary Reproducibility: no. high-confidence live Feishu reproduction is available here. Source inspection does show current main sends accumulated CardKit content, and the PR source shows a remaining non-prefix streaming rewrite path that can still append the whole rewritten body. Real behavior proof Next step before merge Security Review findings
Review detailsBest possible solution: Update the Feishu streaming path to replace non-prefix streaming rewrites as well as final rewrites, add regression coverage for that mid-stream case, and require redacted live Feishu/CardKit proof before merge. Do we have a high-confidence way to reproduce the issue? No high-confidence live Feishu reproduction is available here. Source inspection does show current main sends accumulated CardKit content, and the PR source shows a remaining non-prefix streaming rewrite path that can still append the whole rewritten body. Is this the best way to solve the issue? No, not yet. The prefix-growth delta path is narrow, but the streaming update path should use the same replacement branch as final closeout when the next visible body no longer starts with Full review comments:
Overall correctness: patch is incorrect Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against f78434985af9. |
|
Pushed a follow-up fix for the failed-delta case. @codex review |
|
Codex Review: Didn't find any major issues. Delightful! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
Pushed a second follow-up for non-prefix final closeout rewrites. @codex review |
|
Pushed follow-up c33f2c0 for the non-prefix CardKit closeout rewrite case. Local verification:
No live Feishu/CardKit credentialed proof is available from my environment, so that part still needs contributor/maintainer evidence. @clawsweeper re-review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c33f2c0e8d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| auditContext: "feishu.streaming-card.update", | ||
| }); | ||
| await release(); | ||
| return true; |
There was a problem hiding this comment.
Treat non-OK content updates as failed sends
updateCardContent returns true for any resolved fetch, even when Feishu responds with HTTP errors (for example 429/5xx), because it never checks response.ok before marking success. With the new sentText bookkeeping, that causes the session to advance its sent baseline and future delta payloads to omit text that was never actually accepted by CardKit, so users can permanently lose chunks after transient API failures.
Useful? React with 👍 / 👎.
| auditContext: "feishu.streaming-card.replace", | ||
| }); | ||
| await release(); | ||
| return true; |
There was a problem hiding this comment.
Mark replace failures when final rewrite gets non-OK response
replaceCardContent has the same success-path issue: it returns true without validating the HTTP status, so a non-OK final rewrite response is treated as delivered. In non-prefix closeout rewrites this can leave the card showing stale streamed content while internal state assumes the replacement succeeded, preventing a correct retry path.
Useful? React with 👍 / 👎.
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@codex review |
|
Addressed the Codex P1 findings in d99beb6. Both CardKit append and replacement updates now treat non-OK HTTP responses as failed sends before advancing the delivered baseline, with regression coverage for 429 append retry and 500 final replacement failure. Verification:
@codex review |
|
Codex Review: Didn't find any major issues. What shall we delve into next? ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Fixes openclaw#82417. Co-authored-by: hclsys <7755017+hclsys@users.noreply.github.com>
Fixes openclaw#82417. Co-authored-by: hclsys <7755017+hclsys@users.noreply.github.com>
Fixes openclaw#82417. Co-authored-by: hclsys <7755017+hclsys@users.noreply.github.com>
Fixes openclaw#82417. Co-authored-by: hclsys <7755017+hclsys@users.noreply.github.com>
Fixes openclaw#82417. Co-authored-by: hclsys <7755017+hclsys@users.noreply.github.com>
Fixes openclaw#82417. Co-authored-by: hclsys <7755017+hclsys@users.noreply.github.com>
Fixes openclaw#82417. Co-authored-by: hclsys <7755017+hclsys@users.noreply.github.com>
Fixes openclaw#82417. Co-authored-by: hclsys <7755017+hclsys@users.noreply.github.com>
Real behavior proof
/elements/content/contentPUT. On clients where that endpoint appends streamed content, updates likeA,AB,ABCrender asAABABC. Fixes [Bug]: Feishu CardKit streaming card appends full accumulated text on each update instead of replacing #82417.a7c06bcfc11a5c9b993b5c716c237eab3fcbfffa, Node/Vitest through the repo toolchain, exercisingFeishuStreamingSession.update()and the exact CardKit content-update request body emitted byextensions/feishu/src/streaming-card.tswith the network guard mocked at the Feishu HTTP boundary.pnpm exec oxfmt --check --threads=1 extensions/feishu/src/streaming-card.ts extensions/feishu/src/streaming-card.test.ts node scripts/run-vitest.mjs extensions/feishu/src/streaming-card.test.ts node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.json extensions/feishu/src/streaming-card.ts extensions/feishu/src/streaming-card.test.ts git diff --checkFocused assertions now verify the emitted CardKit update payloads send only the appended suffix:
{"content":" small","sequence":2,"uuid":"s_card_1_2"} {"content":"!","sequence":2,"uuid":"s_card_2_2"}Thinking...placeholder.fetchWithSsrFGuardsends the CardKit update.Implementation notes
extensions/feishu/src/streaming-card.tsstate.currentTextas the full logical accumulated text./cardkit/v1/cards/{card_id}/elements/content/content.Thinking..., avoiding a stale placeholder prefix in append-mode clients.extensions/feishu/src/streaming-card.test.tsPre-implement audits
mergeStreamingTextfor full logical text and added a private suffix resolver for the CardKit append payload.updateCardContentis private toFeishuStreamingSession; publicupdate()/close()contracts are preserved.