summaryrefslogtreecommitdiffhomepage
path: root/packages/kernel
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-04 22:59:57 +0900
committerAdam Malczewski <[email protected]>2026-06-04 22:59:57 +0900
commit974ce6f46c25a522a42c6bd04fd62ce2d031aad5 (patch)
tree79564a1e5c4265c07e0a313a12ee385155635b1a /packages/kernel
parentae22da591474d4be7daf16be552ad7437ef1828b (diff)
downloaddispatch-974ce6f46c25a522a42c6bd04fd62ce2d031aad5.tar.gz
dispatch-974ce6f46c25a522a42c6bd04fd62ce2d031aad5.zip
feat(contracts): RunTurnInput gains tabId/turnId/providerOpts; FinishReason union (resolves runtime CR-1/2/3)
Diffstat (limited to 'packages/kernel')
-rw-r--r--packages/kernel/src/contracts/index.ts1
-rw-r--r--packages/kernel/src/contracts/runtime.ts37
-rw-r--r--packages/kernel/src/runtime/run-turn.test.ts32
3 files changed, 67 insertions, 3 deletions
diff --git a/packages/kernel/src/contracts/index.ts b/packages/kernel/src/contracts/index.ts
index 1c3393f..0b578cb 100644
--- a/packages/kernel/src/contracts/index.ts
+++ b/packages/kernel/src/contracts/index.ts
@@ -82,6 +82,7 @@ export type {
} from "./provider.js";
export type {
EventEmitter,
+ FinishReason,
RunTurnInput,
RunTurnResult,
} from "./runtime.js";
diff --git a/packages/kernel/src/contracts/runtime.ts b/packages/kernel/src/contracts/runtime.ts
index 15f4869..ff994af 100644
--- a/packages/kernel/src/contracts/runtime.ts
+++ b/packages/kernel/src/contracts/runtime.ts
@@ -10,7 +10,7 @@
import type { ChatMessage } from "./conversation.js";
import type { ToolDispatchPolicy } from "./dispatch.js";
import type { AgentEvent } from "./events.js";
-import type { ProviderContract, Usage } from "./provider.js";
+import type { ProviderContract, ProviderStreamOptions, Usage } from "./provider.js";
import type { ToolContract } from "./tool.js";
/**
@@ -20,6 +20,21 @@ import type { ToolContract } from "./tool.js";
export type EventEmitter = (event: AgentEvent) => void;
/**
+ * Why a turn ended. Known kernel/provider reasons are enumerated for ergonomics;
+ * the trailing `(string & {})` keeps the type open for provider-specific reasons
+ * passed through verbatim without losing autocomplete on the known values.
+ */
+export type FinishReason =
+ | "stop"
+ | "tool-calls"
+ | "length"
+ | "content-filter"
+ | "max-steps"
+ | "error"
+ | "aborted"
+ | (string & {});
+
+/**
* Input to `runTurn` — everything the kernel needs to execute one turn.
* All fields are resolved by the session-orchestrator before calling;
* the kernel never reads config or resolves providers/tools itself.
@@ -40,6 +55,22 @@ export interface RunTurnInput {
/** The emitter the kernel calls for each outward event. */
readonly emit: EventEmitter;
+ /**
+ * Identifiers used to attribute every emitted `AgentEvent`. The kernel does
+ * not generate these — the session-orchestrator owns turn/tab identity and
+ * passes them in, so events are traceable to their conversation.
+ */
+ readonly tabId: string;
+ readonly turnId: string;
+
+ /**
+ * Optional per-turn provider options (model, temperature, maxTokens,
+ * systemPrompt). The orchestrator resolves these; the kernel forwards them
+ * verbatim to `provider.stream` and never interprets them. A provider may
+ * also be pre-configured at construction and ignore these.
+ */
+ readonly providerOpts?: ProviderStreamOptions;
+
/** Cancellation signal for the entire turn. */
readonly signal?: AbortSignal;
}
@@ -55,6 +86,6 @@ export interface RunTurnResult {
/** Aggregated token usage across all steps in the turn. */
readonly usage: Usage;
- /** Why the turn ended (e.g. "stop", "max-steps", "error", "aborted"). */
- readonly finishReason: string;
+ /** Why the turn ended. */
+ readonly finishReason: FinishReason;
}
diff --git a/packages/kernel/src/runtime/run-turn.test.ts b/packages/kernel/src/runtime/run-turn.test.ts
index eba05e6..f63a0a8 100644
--- a/packages/kernel/src/runtime/run-turn.test.ts
+++ b/packages/kernel/src/runtime/run-turn.test.ts
@@ -70,6 +70,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [],
dispatch: { maxConcurrent: 1, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit,
});
@@ -111,6 +113,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [tool],
dispatch: { maxConcurrent: 1, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit,
});
@@ -167,6 +171,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [tool],
dispatch: { maxConcurrent: 1, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit: () => {},
});
@@ -214,6 +220,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [toolA, toolB],
dispatch: { maxConcurrent: 1, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit: () => {},
});
@@ -256,6 +264,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [toolA, toolB],
dispatch: { maxConcurrent: 2, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit: () => {},
});
@@ -312,6 +322,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [toolA, toolB, toolC],
dispatch: { maxConcurrent: 0, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit: () => {},
});
@@ -371,6 +383,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [tool],
dispatch: { maxConcurrent: 1, eager: true },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit: () => {},
});
@@ -420,6 +434,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [tool],
dispatch: { maxConcurrent: 1, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit: () => {},
});
@@ -467,6 +483,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [tool],
dispatch: { maxConcurrent: 1, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit,
signal: ac.signal,
});
@@ -497,6 +515,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [],
dispatch: { maxConcurrent: 1, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit: () => {},
signal: ac.signal,
});
@@ -533,6 +553,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [tool],
dispatch: { maxConcurrent: 1, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit,
});
@@ -605,6 +627,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [unsafeTool, safeTool],
dispatch: { maxConcurrent: 5, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit: () => {},
});
@@ -637,6 +661,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [],
dispatch: { maxConcurrent: 1, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit,
});
@@ -668,6 +694,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [],
dispatch: { maxConcurrent: 1, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit,
});
@@ -701,6 +729,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [tool],
dispatch: { maxConcurrent: 1, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit: () => {},
});
@@ -737,6 +767,8 @@ describe("runTurn", () => {
messages: [userMessage],
tools: [tool],
dispatch: { maxConcurrent: 1, eager: false },
+ tabId: "tab-test",
+ turnId: "turn-test",
emit,
});