Skip to content

fix(web): make mid-turn delta offsets step-relative#1609

Merged
wbxl2000 merged 2 commits into
mainfrom
fix/web-resync-step-blob
Jul 13, 2026
Merged

fix(web): make mid-turn delta offsets step-relative#1609
wbxl2000 merged 2 commits into
mainfrom
fix/web-resync-step-blob

Conversation

@wbxl2000

@wbxl2000 wbxl2000 commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Related Issue

No linked issue — the problem is explained below.

Problem

In kimi-web, when a snapshot resync happens while a multi-step turn is still running (page refresh, WebSocket reconnect on tab focus, or a server-requested resync), the turn re-renders incorrectly: earlier steps' body text is re-appended as a trailing blob of duplicated Markdown after the structured history, and thinking blocks / tool cards stop separating properly. Long turns (30+ steps, thinking enabled) make it most visible.

Root cause on the v2 (kap-server) sync path: the server's in-flight turn tracker accumulated assistant_text / thinking_text for the WHOLE turn instead of the currently-streaming step. Completed steps are already present in the snapshot transcript as structured messages, so when a reconnecting client seeded a partially-streamed assistant message from in_flight_turn, it carried a second copy of every earlier step's text.

What changed

  • kap-server: reset the in-flight assistant/thinking text accumulation at each turn.step.started (running tool calls are intentionally kept — a call without a result yet is not in the transcript and must still be seeded). The pre-append offset stamped on volatile delta frames becomes step-relative as a consequence.
  • kimi-web event projector: reset the client-side delta alignment counters at each turn.step.started to match the step-relative offsets. Without this, every delta from step 2 onward misaligns (silently skipped as a duplicate, or misread as a gap). A lost head-of-step delta now surfaces as a recoverable gap → resync instead of a permanent silent stall.
  • kimi-web transcript rendering: the dedup that drops a resync-seeded copy of an already-persisted step now signs messages by normalized content (concatenated stream text + sorted tool-call ids, subset-covered) instead of exact JSON. The exact-JSON signature was defeated whenever the two copies differed by a provider thinking signature, tool progress outputLines, part boundaries, or the tool set (a finished parallel tool leaves running_tools, so the seed's id set is a strict subset). Before dropping the seed, its tool progress is merged into the existing card so a mid-tool refresh keeps the latest output (and never overwrites a settled tool result).
  • protocol: document in_flight_turn.assistant_text / thinking_text as current-step accumulation (reset at turn.step.started; earlier steps are in messages).
  • Tests: kap-server tracker unit tests (step-boundary reset, step-relative offsets, tools kept across steps, mismatched turn ignored); kimi-web projector tests (gap detection after a step boundary, step-2 deltas append to the fresh step message, seed contains only the current step and live deltas align against the seeded length); kimi-web turn-rendering tests (resync-seed dedup across signature/progress/part-boundary differences, progress preservation, no overwrite of settled results, parallel-tool subset seeds, no over-dedup of distinct steps).

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

Reset in-flight text and client stream alignment at step boundaries so
resync seeds only the current step instead of duplicating prior steps.
@changeset-bot

changeset-bot Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 51db588

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 86be5e384e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +733 to +734
s.turnTextLen = 0;
s.turnThinkLen = 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep offset semantics compatible with the v1 backend

When the web app is connected to the v1 backend, this unconditional reset makes every later-step delta look like a gap: packages/server/src/services/gateway/inFlightTurnTracker.ts still has no turn.step.started reset and stamps offset from the whole-turn assistantText.length / thinkingText.length, while the client now resets its local length to 0 at each step. In a v1 multi-step turn, the first step-2 delta therefore arrives with a cumulative offset greater than the local length, causing historyCompacted resyncs or stalled streaming instead of appending the delta; either v1 needs the same server-side offset change or the client reset needs to be gated to step-relative backends.

Useful? React with 👍 / 👎.

@pkg-pr-new

pkg-pr-new Bot commented Jul 13, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@51db588
npx https://pkg.pr.new/@moonshot-ai/kimi-code@51db588

commit: 51db588

The exact-JSON content signature missed duplicates when the two copies
differed by thinking signature, tool progress, part boundaries, or the
tool set (finished parallel tools leave running_tools). Reduce content
to concatenated stream text plus sorted tool-call ids and treat a
covered subset as the duplicate, merging the seed's tool progress into
the existing cards before dropping it.
@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 51db588b98

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +733 to +734
s.turnTextLen = 0;
s.turnThinkLen = 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep step offsets compatible with the v1 backend

When kimi-web is connected to the v1 server, this reset makes the first delta after every turn.step.started look like a gap because packages/server/src/services/gateway/inFlightTurnTracker.ts still stamps offset from the whole-turn assistantText/thinkingText and was not updated to reset at step boundaries. I checked that tracker: it has no turn.step.started case, so on step 2 it sends an offset greater than the freshly reset local length here, causing alignDelta() to emit delta_gap and force a resync for normal multi-step turns on the supported v1 backend.

Useful? React with 👍 / 👎.

@wbxl2000 wbxl2000 merged commit e223549 into main Jul 13, 2026
11 checks passed
@wbxl2000 wbxl2000 deleted the fix/web-resync-step-blob branch July 13, 2026 12:47
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