summaryrefslogtreecommitdiffhomepage
path: root/packages/kernel/src/runtime/run-turn.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-06 21:29:52 +0900
committerAdam Malczewski <[email protected]>2026-06-06 21:29:52 +0900
commit2c5bc242a8a99e3b863c247f70b26f5883333677 (patch)
treece938fbef47d8dab44bfe5cce68ebfac7a91ca8a /packages/kernel/src/runtime/run-turn.ts
parentfedf9c2695476e9ee6f95776b0244acfc37f022f (diff)
downloaddispatch-2c5bc242a8a99e3b863c247f70b26f5883333677.tar.gz
dispatch-2c5bc242a8a99e3b863c247f70b26f5883333677.zip
feat(kernel-runtime,session-orchestrator): emit turn lifecycle events
Close a gap found live: neither transport emitted turn-start/done/turn-sealed (the wire defined them; nothing fired them). turn-sealed is the FE's cache-commit signal (frontend-design §6.3); done ends the stream. - kernel-runtime: runTurn emits turn-start first and done (with finishReason) last, on every exit path (stop/tool-calls/max-steps/error/aborted). - session-orchestrator: emits turn-sealed after conversationStore.append succeeds (the kernel touches no DB, so the post-persist seal is the orchestrator's). Not emitted if append throws. No contract change (all three wire types already existed). Verified live: HTTP /chat and WS chat both stream turn-start … done turn-sealed. typecheck clean, 494 vitest + 80 bun, biome clean.
Diffstat (limited to 'packages/kernel/src/runtime/run-turn.ts')
-rw-r--r--packages/kernel/src/runtime/run-turn.ts6
1 files changed, 6 insertions, 0 deletions
diff --git a/packages/kernel/src/runtime/run-turn.ts b/packages/kernel/src/runtime/run-turn.ts
index 6b07e24..1e98351 100644
--- a/packages/kernel/src/runtime/run-turn.ts
+++ b/packages/kernel/src/runtime/run-turn.ts
@@ -5,11 +5,13 @@ import type { EventEmitter, RunTurnInput, RunTurnResult } from "../contracts/run
import type { ToolCall, ToolContract } from "../contracts/tool.js";
import { createStepDispatcher, type StepDispatcher } from "./dispatch.js";
import {
+ doneEvent,
errorEvent,
reasoningDeltaEvent,
textDeltaEvent,
toolCallEvent,
toolResultEvent,
+ turnStartEvent,
usageEvent,
} from "./events.js";
@@ -346,6 +348,8 @@ export async function runTurn(input: RunTurnInput): Promise<RunTurnResult> {
// Track open tool-call spans across steps so we can close them on abort
const toolSpans = new Map<string, Span>();
+ input.emit(turnStartEvent(conversationId, turnId));
+
try {
for (let step = 0; step < MAX_STEPS; step++) {
if (signal.aborted) {
@@ -422,6 +426,8 @@ export async function runTurn(input: RunTurnInput): Promise<RunTurnResult> {
}
}
+ input.emit(doneEvent(conversationId, turnId, finishReason));
+
return { messages: resultMessages, usage: totalUsage, finishReason };
}