diff options
| author | Adam Malczewski <[email protected]> | 2026-06-05 01:35:50 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-05 01:35:50 +0900 |
| commit | 94dd5334b0277f3cf3b0588150a6615af86a32b3 (patch) | |
| tree | 53b1b327790ae43bd3b7cbabe555b832f3e27248 /packages/kernel/src/runtime | |
| parent | 977ca522736bba53172e010494de5ac59fdb2a4a (diff) | |
| download | dispatch-94dd5334b0277f3cf3b0588150a6615af86a32b3.tar.gz dispatch-94dd5334b0277f3cf3b0588150a6615af86a32b3.zip | |
refactor(kernel): rename tabId → conversationId across contracts + consumers (218 tests)
Step 4 of the post-MVP backlog: resolve the last vocab drift. The canonical
term for a thread of turns is `conversationId` (GLOSSARY), but `AgentEvent`
variants and `RunTurnInput` still used the legacy `tabId` from the old frontend
"tab" concept, with session-orchestrator bridging `conversationId → tabId`.
Atomic, type-driven rename across the full 10-file consumer set:
- contracts/events.ts: all 11 AgentEvent variants tabId → conversationId
- contracts/runtime.ts: RunTurnInput.tabId → conversationId
- runtime/{events,run-turn,dispatch}.ts: factory params, ctx field, locals
- session-orchestrator: drop the redundant `tabId: conversationId` bridge line
- transport-http: emit wiring; external /chat field + X-Conversation-Id header
unchanged (already canonical) — only the emitted NDJSON event field flips
- tests (run-turn, app, logic): inputs + assertions now use conversationId
Pure rename, zero behavior change: typecheck clean, 218 tests pass (unchanged
count), biome clean, `grep tabId packages/` → zero matches. Verified live:
multi-turn curl emits conversationId-keyed NDJSON and threads history correctly.
GLOSSARY drift note removed. Closes the post-MVP backlog (Steps 1–4).
Diffstat (limited to 'packages/kernel/src/runtime')
| -rw-r--r-- | packages/kernel/src/runtime/dispatch.ts | 15 | ||||
| -rw-r--r-- | packages/kernel/src/runtime/events.ts | 34 | ||||
| -rw-r--r-- | packages/kernel/src/runtime/run-turn.test.ts | 38 | ||||
| -rw-r--r-- | packages/kernel/src/runtime/run-turn.ts | 39 |
4 files changed, 77 insertions, 49 deletions
diff --git a/packages/kernel/src/runtime/dispatch.ts b/packages/kernel/src/runtime/dispatch.ts index c6c5f8e..626b333 100644 --- a/packages/kernel/src/runtime/dispatch.ts +++ b/packages/kernel/src/runtime/dispatch.ts @@ -13,7 +13,7 @@ export async function executeToolCall( tool: ToolContract | undefined, signal: AbortSignal, emit: EventEmitter, - tabId: string, + conversationId: string, turnId: string, ): Promise<ToolResult> { if (tool === undefined) { @@ -26,7 +26,7 @@ export async function executeToolCall( toolCallId: call.id, signal, onOutput: (data, stream) => { - emit(toolOutputEvent(tabId, turnId, call.id, data, stream)); + emit(toolOutputEvent(conversationId, turnId, call.id, data, stream)); }, }; try { @@ -48,7 +48,7 @@ export function createStepDispatcher( policy: ToolDispatchPolicy, signal: AbortSignal, emit: EventEmitter, - tabId: string, + conversationId: string, turnId: string, ): StepDispatcher { let activeCount = 0; @@ -78,7 +78,14 @@ export function createStepDispatcher( } async function runAndResolve(entry: QueueEntry): Promise<void> { - const result = await executeToolCall(entry.call, entry.tool, signal, emit, tabId, turnId); + const result = await executeToolCall( + entry.call, + entry.tool, + signal, + emit, + conversationId, + turnId, + ); activeCount--; if (entry.tool?.concurrencySafe === false) unsafeRunning = false; entry.resolve(result); diff --git a/packages/kernel/src/runtime/events.ts b/packages/kernel/src/runtime/events.ts index 62218be..2a92008 100644 --- a/packages/kernel/src/runtime/events.ts +++ b/packages/kernel/src/runtime/events.ts @@ -1,57 +1,61 @@ import type { AgentEvent } from "../contracts/events.js"; import type { Usage } from "../contracts/provider.js"; -export function textDeltaEvent(tabId: string, turnId: string, delta: string): AgentEvent { - return { type: "text-delta", tabId, turnId, delta }; +export function textDeltaEvent(conversationId: string, turnId: string, delta: string): AgentEvent { + return { type: "text-delta", conversationId, turnId, delta }; } -export function reasoningDeltaEvent(tabId: string, turnId: string, delta: string): AgentEvent { - return { type: "reasoning-delta", tabId, turnId, delta }; +export function reasoningDeltaEvent( + conversationId: string, + turnId: string, + delta: string, +): AgentEvent { + return { type: "reasoning-delta", conversationId, turnId, delta }; } export function toolCallEvent( - tabId: string, + conversationId: string, turnId: string, toolCallId: string, toolName: string, input: unknown, ): AgentEvent { - return { type: "tool-call", tabId, turnId, toolCallId, toolName, input }; + return { type: "tool-call", conversationId, turnId, toolCallId, toolName, input }; } export function toolResultEvent( - tabId: string, + conversationId: string, turnId: string, toolCallId: string, toolName: string, content: string, isError: boolean, ): AgentEvent { - return { type: "tool-result", tabId, turnId, toolCallId, toolName, content, isError }; + return { type: "tool-result", conversationId, turnId, toolCallId, toolName, content, isError }; } export function toolOutputEvent( - tabId: string, + conversationId: string, turnId: string, toolCallId: string, data: string, stream: "stdout" | "stderr", ): AgentEvent { - return { type: "tool-output", tabId, turnId, toolCallId, data, stream }; + return { type: "tool-output", conversationId, turnId, toolCallId, data, stream }; } -export function usageEvent(tabId: string, turnId: string, usage: Usage): AgentEvent { - return { type: "usage", tabId, turnId, usage }; +export function usageEvent(conversationId: string, turnId: string, usage: Usage): AgentEvent { + return { type: "usage", conversationId, turnId, usage }; } export function errorEvent( - tabId: string, + conversationId: string, turnId: string, message: string, code?: string, ): AgentEvent { if (code !== undefined) { - return { type: "error", tabId, turnId, message, code }; + return { type: "error", conversationId, turnId, message, code }; } - return { type: "error", tabId, turnId, message }; + return { type: "error", conversationId, turnId, message }; } diff --git a/packages/kernel/src/runtime/run-turn.test.ts b/packages/kernel/src/runtime/run-turn.test.ts index 1ea6406..696a385 100644 --- a/packages/kernel/src/runtime/run-turn.test.ts +++ b/packages/kernel/src/runtime/run-turn.test.ts @@ -52,7 +52,7 @@ const userMessage: ChatMessage = { }; describe("runTurn", () => { - it("emits events with the tabId and turnId from input", async () => { + it("emits events with the conversationId and turnId from input", async () => { const provider = createFakeProvider([ [ { type: "text-delta", delta: "hi" }, @@ -68,14 +68,14 @@ describe("runTurn", () => { messages: [userMessage], tools: [], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "conv-42", + conversationId: "conv-42", turnId: "turn-99", emit, }); expect(events.length).toBeGreaterThan(0); for (const event of events) { - expect(event.tabId).toBe("conv-42"); + expect(event.conversationId).toBe("conv-42"); if (event.type !== "status") { expect(event.turnId).toBe("turn-99"); } @@ -100,7 +100,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit, }); @@ -143,7 +143,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [tool], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit, }); @@ -201,7 +201,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [tool], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit: () => {}, }); @@ -250,7 +250,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [toolA, toolB], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit: () => {}, }); @@ -294,7 +294,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [toolA, toolB], dispatch: { maxConcurrent: 2, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit: () => {}, }); @@ -352,7 +352,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [toolA, toolB, toolC], dispatch: { maxConcurrent: 0, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit: () => {}, }); @@ -413,7 +413,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [tool], dispatch: { maxConcurrent: 1, eager: true }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit: () => {}, }); @@ -464,7 +464,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [tool], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit: () => {}, }); @@ -513,7 +513,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [tool], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit, signal: ac.signal, @@ -545,7 +545,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit: () => {}, signal: ac.signal, @@ -583,7 +583,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [tool], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit, }); @@ -657,7 +657,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [unsafeTool, safeTool], dispatch: { maxConcurrent: 5, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit: () => {}, }); @@ -691,7 +691,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit, }); @@ -724,7 +724,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit, }); @@ -759,7 +759,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [tool], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit: () => {}, }); @@ -797,7 +797,7 @@ describe("runTurn", () => { messages: [userMessage], tools: [tool], dispatch: { maxConcurrent: 1, eager: false }, - tabId: "tab-test", + conversationId: "tab-test", turnId: "turn-test", emit, }); diff --git a/packages/kernel/src/runtime/run-turn.ts b/packages/kernel/src/runtime/run-turn.ts index 919491a..9421d86 100644 --- a/packages/kernel/src/runtime/run-turn.ts +++ b/packages/kernel/src/runtime/run-turn.ts @@ -74,7 +74,7 @@ interface StepContext { readonly dispatch: RunTurnInput["dispatch"]; readonly emit: EventEmitter; readonly signal: AbortSignal; - readonly tabId: string; + readonly conversationId: string; readonly turnId: string; } @@ -96,11 +96,11 @@ function processEvent( switch (event.type) { case "text-delta": appendTextDelta(chunks, event.delta); - ctx.emit(textDeltaEvent(ctx.tabId, ctx.turnId, event.delta)); + ctx.emit(textDeltaEvent(ctx.conversationId, ctx.turnId, event.delta)); break; case "reasoning-delta": appendThinkingDelta(chunks, event.delta); - ctx.emit(reasoningDeltaEvent(ctx.tabId, ctx.turnId, event.delta)); + ctx.emit(reasoningDeltaEvent(ctx.conversationId, ctx.turnId, event.delta)); break; case "tool-call": { const call: ToolCall = { @@ -115,14 +115,22 @@ function processEvent( toolName: event.toolName, input: event.input, }); - ctx.emit(toolCallEvent(ctx.tabId, ctx.turnId, event.toolCallId, event.toolName, event.input)); + ctx.emit( + toolCallEvent( + ctx.conversationId, + ctx.turnId, + event.toolCallId, + event.toolName, + event.input, + ), + ); if (ctx.dispatch.eager) { dispatcher.submit(call); } break; } case "usage": - ctx.emit(usageEvent(ctx.tabId, ctx.turnId, event.usage)); + ctx.emit(usageEvent(ctx.conversationId, ctx.turnId, event.usage)); break; case "finish": break; @@ -132,7 +140,7 @@ function processEvent( } else { chunks.push({ type: "error", message: event.message }); } - ctx.emit(errorEvent(ctx.tabId, ctx.turnId, event.message, event.code)); + ctx.emit(errorEvent(ctx.conversationId, ctx.turnId, event.message, event.code)); break; } } @@ -148,7 +156,7 @@ async function executeStep(ctx: StepContext): Promise<StepResult> { ctx.dispatch, ctx.signal, ctx.emit, - ctx.tabId, + ctx.conversationId, ctx.turnId, ); @@ -167,7 +175,7 @@ async function executeStep(ctx: StepContext): Promise<StepResult> { } catch (err) { const message = err instanceof Error ? err.message : String(err); chunks.push({ type: "error", message }); - ctx.emit(errorEvent(ctx.tabId, ctx.turnId, message)); + ctx.emit(errorEvent(ctx.conversationId, ctx.turnId, message)); finishReason = "error"; } @@ -184,7 +192,16 @@ async function executeStep(ctx: StepContext): Promise<StepResult> { const result = results.get(call.id); if (result !== undefined) { const isError = result.isError ?? false; - ctx.emit(toolResultEvent(ctx.tabId, ctx.turnId, call.id, call.name, result.content, isError)); + ctx.emit( + toolResultEvent( + ctx.conversationId, + ctx.turnId, + call.id, + call.name, + result.content, + isError, + ), + ); toolMessages.push({ role: "tool", chunks: [ @@ -217,7 +234,7 @@ export async function runTurn(input: RunTurnInput): Promise<RunTurnResult> { toolMap.set(tool.name, tool); } - const tabId = input.tabId; + const conversationId = input.conversationId; const turnId = input.turnId; const signal = input.signal ?? new AbortController().signal; @@ -235,7 +252,7 @@ export async function runTurn(input: RunTurnInput): Promise<RunTurnResult> { dispatch: input.dispatch, emit: input.emit, signal, - tabId, + conversationId, turnId, }); |
