summaryrefslogtreecommitdiffhomepage
path: root/packages/session-orchestrator/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/session-orchestrator/src')
-rw-r--r--packages/session-orchestrator/src/orchestrator.test.ts2
-rw-r--r--packages/session-orchestrator/src/orchestrator.ts25
2 files changed, 23 insertions, 4 deletions
diff --git a/packages/session-orchestrator/src/orchestrator.test.ts b/packages/session-orchestrator/src/orchestrator.test.ts
index d5585c2..012ac5c 100644
--- a/packages/session-orchestrator/src/orchestrator.test.ts
+++ b/packages/session-orchestrator/src/orchestrator.test.ts
@@ -574,7 +574,7 @@ describe("turn-sealed event", () => {
},
});
- expect(ordering).toEqual(["append", "appendMetrics", "turn-sealed"]);
+ expect(ordering).toEqual(["append", "append", "appendMetrics", "turn-sealed"]);
});
it("does not emit turn-sealed when append throws — emits error event instead", async () => {
diff --git a/packages/session-orchestrator/src/orchestrator.ts b/packages/session-orchestrator/src/orchestrator.ts
index bc9e78b..22a5c11 100644
--- a/packages/session-orchestrator/src/orchestrator.ts
+++ b/packages/session-orchestrator/src/orchestrator.ts
@@ -457,10 +457,29 @@ export function createSessionOrchestrator(
...(drainSteering !== undefined ? { drainSteering } : {}),
};
- const result = await deps.runTurn(opts);
+ // Persist the user message at turn start so it has a seq
+ // number before the first step generates. This enables the
+ // FE to syncTail during generation (CR-6).
+ await deps.conversationStore.append(conversationId, [userMsg]);
+
+ let stepsPersisted = false;
+ const result = await deps.runTurn({
+ ...opts,
+ // Incremental persistence: persist each step's messages
+ // as they are finalized. Seq numbers are assigned during
+ // generation, so the FE can GET /conversations/:id?sinceSeq=N
+ // mid-turn and pick up committed chunks (CR-6).
+ onStepComplete: async (stepMessages) => {
+ await deps.conversationStore.append(conversationId, stepMessages);
+ stepsPersisted = true;
+ },
+ });
- const toPersist: ChatMessage[] = [userMsg, ...result.messages];
- await deps.conversationStore.append(conversationId, toPersist);
+ // Fallback: if onStepComplete was never called (e.g., a fake
+ // runTurn in tests), persist all result messages as a batch.
+ if (!stepsPersisted && result.messages.length > 0) {
+ await deps.conversationStore.append(conversationId, result.messages);
+ }
const turnMetrics = metrics.build(turnId);
await deps.conversationStore.appendMetrics(conversationId, turnMetrics);