summaryrefslogtreecommitdiffhomepage
path: root/packages/kernel/src/runtime/run-turn.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-22 13:52:42 +0900
committerAdam Malczewski <[email protected]>2026-06-22 13:52:42 +0900
commit519b79999d49156bbfaecc91a2d882fba2475fef (patch)
tree35fb9a7e0a7b1b1f4377b83ca89282bdb78f3398 /packages/kernel/src/runtime/run-turn.ts
parent20db60b0705ab65b6ade67ff614d347e13dc9803 (diff)
downloaddispatch-519b79999d49156bbfaecc91a2d882fba2475fef.tar.gz
dispatch-519b79999d49156bbfaecc91a2d882fba2475fef.zip
feat: incremental seq assignment during generation (CR-6)
The backend now persists chunks at step boundaries during generation, not only at turn-seal. This enables the FE to syncTail mid-turn and pick up committed, seq'd chunks (eliminating the provisional state). Changes: - RunTurnInput: add onStepComplete callback (kernel contract) - runTurn: call onStepComplete after each step's messages are finalized - Orchestrator: persist userMsg at turn start + each step's messages via onStepComplete. Falls back to batch persist if callback isn't called (backward compatible with test fakes). The user message gets seq numbers before the first step generates. Each step's assistant + tool messages get seq numbers as they complete. The FE's existing syncTail (?sinceSeq=N) picks them up during generation. Also adds backend-to-fe-handoff.md with CR-6 response + full endpoint list.
Diffstat (limited to 'packages/kernel/src/runtime/run-turn.ts')
-rw-r--r--packages/kernel/src/runtime/run-turn.ts17
1 files changed, 17 insertions, 0 deletions
diff --git a/packages/kernel/src/runtime/run-turn.ts b/packages/kernel/src/runtime/run-turn.ts
index 228ef8a..4a12e28 100644
--- a/packages/kernel/src/runtime/run-turn.ts
+++ b/packages/kernel/src/runtime/run-turn.ts
@@ -526,6 +526,23 @@ export async function runTurn(input: RunTurnInput): Promise<RunTurnResult> {
resultMessages.push(msg);
}
+ // Incremental persistence: notify the caller that this step's
+ // messages are finalized. The caller can persist them immediately
+ // (assigning seq numbers during generation). The messages are the
+ // SAME objects in resultMessages — the caller must NOT double-persist.
+ if (input.onStepComplete !== undefined) {
+ const stepMessages: ChatMessage[] = [];
+ if (stepResult.assistantMessage !== undefined) {
+ stepMessages.push(stepResult.assistantMessage);
+ }
+ for (const msg of stepResult.toolMessages) {
+ stepMessages.push(msg);
+ }
+ if (stepMessages.length > 0) {
+ await input.onStepComplete(stepMessages);
+ }
+ }
+
if (signal.aborted) {
finishReason = "aborted";
break;