diff options
| author | Adam Malczewski <[email protected]> | 2026-06-10 09:51:00 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-10 09:51:00 +0900 |
| commit | 5ff460688519e48fd0bfab893ebaed4258dee789 (patch) | |
| tree | 8c5bcdfb04122b178c5e9bc8654afd563872a8a0 | |
| parent | a980aba97aed34692dd655e716747c4ff53fb186 (diff) | |
| download | dispatch-5ff460688519e48fd0bfab893ebaed4258dee789.tar.gz dispatch-5ff460688519e48fd0bfab893ebaed4258dee789.zip | |
kernel/run-turn: thread providerOpts (model) into provider.stream
executeStep built the stream opts with only the logger, so providerOpts.model
(the selected model) never reached any provider — each fell back to its own
default. Carry providerOpts through StepContext into the per-step stream opts,
plus a regression test asserting the model is forwarded.
| -rw-r--r-- | packages/kernel/src/runtime/run-turn.test.ts | 29 | ||||
| -rw-r--r-- | packages/kernel/src/runtime/run-turn.ts | 13 |
2 files changed, 40 insertions, 2 deletions
diff --git a/packages/kernel/src/runtime/run-turn.test.ts b/packages/kernel/src/runtime/run-turn.test.ts index 6db6645..fa2aba4 100644 --- a/packages/kernel/src/runtime/run-turn.test.ts +++ b/packages/kernel/src/runtime/run-turn.test.ts @@ -1523,6 +1523,35 @@ describe("runTurn", () => { expect(capturedOpts).toBeDefined(); expect(capturedOpts?.logger).toBeUndefined(); }); + + it("threads providerOpts.model through to provider.stream opts", async () => { + let capturedOpts: Record<string, unknown> | undefined; + + const provider: ProviderContract = { + id: "fake", + stream(_messages, _tools, opts) { + capturedOpts = opts !== undefined ? { ...opts } : undefined; + return (async function* () { + yield { type: "text-delta", delta: "hi" } as ProviderEvent; + yield { type: "usage", usage: { inputTokens: 1, outputTokens: 1 } } as ProviderEvent; + yield { type: "finish", reason: "stop" } as ProviderEvent; + })(); + }, + }; + + await runTurn({ + provider, + messages: [userMessage], + tools: [], + dispatch: { maxConcurrent: 1, eager: false }, + conversationId: "conv-1", + turnId: "turn-1", + emit: () => {}, + providerOpts: { model: "some-model-id" }, + }); + + expect(capturedOpts?.model).toBe("some-model-id"); + }); }); describe("span tree nesting", () => { diff --git a/packages/kernel/src/runtime/run-turn.ts b/packages/kernel/src/runtime/run-turn.ts index d5db1bf..b50e8ee 100644 --- a/packages/kernel/src/runtime/run-turn.ts +++ b/packages/kernel/src/runtime/run-turn.ts @@ -1,6 +1,11 @@ import type { ChatMessage, Chunk, StepId } from "../contracts/conversation.js"; import type { Logger, Span } from "../contracts/logging.js"; -import type { ProviderContract, ProviderEvent, Usage } from "../contracts/provider.js"; +import type { + ProviderContract, + ProviderEvent, + ProviderStreamOptions, + Usage, +} from "../contracts/provider.js"; import type { EventEmitter, RunTurnInput, RunTurnResult } from "../contracts/runtime.js"; import type { ToolCall, ToolContract } from "../contracts/tool.js"; import { createStepDispatcher, type StepDispatcher } from "./dispatch.js"; @@ -100,6 +105,8 @@ interface StepContext { readonly toolSpans: Map<string, Span>; readonly cwd: string | undefined; readonly now: (() => number) | undefined; + /** Per-turn provider options (model, systemPrompt, …) threaded to stream(). */ + readonly providerOpts: ProviderStreamOptions | undefined; } interface TimingState { @@ -295,7 +302,8 @@ async function executeStep(ctx: StepContext): Promise<StepResult> { } try { - const opts = { + const opts: ProviderStreamOptions = { + ...ctx.providerOpts, ...(ctx.turnSpan !== undefined && stepSpan !== undefined ? { logger: stepSpan.log } : {}), }; const stream = ctx.provider.stream(ctx.messages, ctx.tools, opts); @@ -501,6 +509,7 @@ export async function runTurn(input: RunTurnInput): Promise<RunTurnResult> { toolSpans, cwd: input.cwd, now, + providerOpts: input.providerOpts, }); totalUsage = addUsage(totalUsage, stepResult.usage); |
