summaryrefslogtreecommitdiffhomepage
path: root/packages/kernel/src/contracts/runtime.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-27 01:09:39 +0900
committerAdam Malczewski <[email protected]>2026-06-27 01:09:39 +0900
commit61e45e60d699ed1ca46f94a8f181c92a940317c6 (patch)
tree2892d9773c5a8e367e1e58cdb1e88d9c6ad3fe6d /packages/kernel/src/contracts/runtime.ts
parent63c7e64532e85e0bbdd6d9ac6825d8f86be98e7a (diff)
parent727c98c9dae516a2070eb950410314380a20c974 (diff)
downloaddispatch-61e45e60d699ed1ca46f94a8f181c92a940317c6.tar.gz
dispatch-61e45e60d699ed1ca46f94a8f181c92a940317c6.zip
Merge branch 'feature/indent-change' into dev
Diffstat (limited to 'packages/kernel/src/contracts/runtime.ts')
-rw-r--r--packages/kernel/src/contracts/runtime.ts282
1 files changed, 141 insertions, 141 deletions
diff --git a/packages/kernel/src/contracts/runtime.ts b/packages/kernel/src/contracts/runtime.ts
index dc74c84..71d2211 100644
--- a/packages/kernel/src/contracts/runtime.ts
+++ b/packages/kernel/src/contracts/runtime.ts
@@ -26,14 +26,14 @@ export type EventEmitter = (event: AgentEvent) => void;
* passed through verbatim without losing autocomplete on the known values.
*/
export type FinishReason =
- | "stop"
- | "tool-calls"
- | "length"
- | "content-filter"
- | "max-steps"
- | "error"
- | "aborted"
- | (string & {});
+ | "stop"
+ | "tool-calls"
+ | "length"
+ | "content-filter"
+ | "max-steps"
+ | "error"
+ | "aborted"
+ | (string & {});
/**
* Input to `runTurn` — everything the kernel needs to execute one turn.
@@ -41,121 +41,121 @@ export type FinishReason =
* the kernel never reads config or resolves providers/tools itself.
*/
export interface RunTurnInput {
- /** The resolved provider to stream from. */
- readonly provider: ProviderContract;
-
- /** The conversation history (including system prompt as first message). */
- readonly messages: readonly ChatMessage[];
-
- /** The tool set available for this turn (may be empty). */
- readonly tools: readonly ToolContract[];
-
- /** How to dispatch tool calls within each step. */
- readonly dispatch: ToolDispatchPolicy;
-
- /** 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/conversation identity
- * and passes them in, so events are traceable to their conversation.
- */
- readonly conversationId: 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;
-
- /**
- * Working directory for this turn's tool execution. The kernel does NOT
- * interpret it — it forwards the value verbatim to each `ToolExecuteContext.cwd`
- * so tools resolve/contain paths against it. It never enters the model prompt,
- * so it does not affect prompt caching. When omitted, tools fall back to their
- * own configured/default workdir.
- */
- readonly cwd?: string;
-
- /**
- * The computer to execute this turn's tools on (SSH support). Omitted/undefined
- * = LOCAL (today's behavior). When set, it is an SSH config alias; the kernel
- * does NOT interpret it — it forwards the value verbatim to each
- * `ToolExecuteContext.computerId`, exactly like `cwd`. It never enters the
- * model prompt, so it does not affect prompt caching. Tools resolve their
- * execution backend (local vs. remote) from this; see
- * `notes/ssh-support-plan.md`.
- */
- readonly computerId?: string;
-
- /**
- * Optional logger for structured span instrumentation. The runtime opens
- * turn/step/tool-call spans using this logger. If omitted, no spans are
- * emitted (backward-compatible with callers that don't yet pass a logger).
- */
- readonly logger?: Logger;
-
- /**
- * Optional monotonic-ish clock (milliseconds) for emitting wall-clock timing
- * on outward events: per-step `step-complete` (ttft/decode/genTotal), tool
- * execution `durationMs` on `tool-result`, and turn `durationMs` on `done`.
- * Injected (not ambient) so the runtime stays pure and deterministic in tests.
- * If omitted, the runtime emits no such timing (the optional fields stay
- * absent) — backward-compatible with callers that don't provide a clock.
- */
- readonly now?: () => number;
-
- /**
- * Optional. Called by the runtime at the tool-result boundary — after a
- * step whose tool calls have all executed, before the next step begins —
- * to drain messages to inject alongside the tool results. Whatever it
- * returns is appended as user-role messages to the next step's input, so
- * a caller can inject mid-turn guidance the model sees with the tool
- * results. When omitted or returning an empty array, no injection happens
- * (the runtime is unchanged).
- *
- * Injected (not ambient) so the kernel stays pure: it owns no queue and
- * names no feature — it just calls the callback and appends what it gets.
- * Only invoked when a step PRODUCED tool calls (the tool-result boundary);
- * a step that ends without tool calls does not drain (the caller decides
- * what to do with any pending messages after the turn ends).
- */
- readonly drainSteering?: () => readonly ChatMessage[];
-
- /**
- * Optional. Called by the runtime after each step's messages are finalized
- * (the assistant message + tool-result messages are built). The caller can
- * use this to persist step messages incrementally — assigning seq numbers
- * during generation so consumers can `GET /conversations/:id?sinceSeq=N`
- * mid-turn. When omitted, the caller must persist all messages at turn end
- * (via `RunTurnResult.messages`). The messages passed to this callback are
- * the SAME objects in `RunTurnResult.messages` — the caller must NOT
- * double-persist them.
- */
- readonly onStepComplete?: (messages: readonly ChatMessage[]) => Promise<void> | void;
-
- /**
- * Optional injected retry strategy for retryable provider errors (e.g. HTTP
- * 429 / 5xx "overloaded"). When omitted, a retryable error ends the step
- * exactly as before (backward-compatible). When provided, the runtime wraps
- * `provider.stream()` consumption in a retry loop: on a retryable error
- * (an emitted `error` ProviderEvent with `retryable === true`, OR a thrown
- * error) — ONLY when no content was emitted yet this step (the safety
- * invariant — never duplicate partial output) — it asks `retry.delayFor`
- * for a delay, emits a transient `provider-retry` AgentEvent, sleeps via the
- * injected `retry.sleep` (abortable), and re-calls `provider.stream()`.
- *
- * Injected (not ambient): the kernel imports no timer and owns no schedule.
- * Mirrors the `now`/`logger` injection pattern — optional + backward-compatible.
- */
- readonly retry?: RetryStrategy;
+ /** The resolved provider to stream from. */
+ readonly provider: ProviderContract;
+
+ /** The conversation history (including system prompt as first message). */
+ readonly messages: readonly ChatMessage[];
+
+ /** The tool set available for this turn (may be empty). */
+ readonly tools: readonly ToolContract[];
+
+ /** How to dispatch tool calls within each step. */
+ readonly dispatch: ToolDispatchPolicy;
+
+ /** 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/conversation identity
+ * and passes them in, so events are traceable to their conversation.
+ */
+ readonly conversationId: 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;
+
+ /**
+ * Working directory for this turn's tool execution. The kernel does NOT
+ * interpret it — it forwards the value verbatim to each `ToolExecuteContext.cwd`
+ * so tools resolve/contain paths against it. It never enters the model prompt,
+ * so it does not affect prompt caching. When omitted, tools fall back to their
+ * own configured/default workdir.
+ */
+ readonly cwd?: string;
+
+ /**
+ * The computer to execute this turn's tools on (SSH support). Omitted/undefined
+ * = LOCAL (today's behavior). When set, it is an SSH config alias; the kernel
+ * does NOT interpret it — it forwards the value verbatim to each
+ * `ToolExecuteContext.computerId`, exactly like `cwd`. It never enters the
+ * model prompt, so it does not affect prompt caching. Tools resolve their
+ * execution backend (local vs. remote) from this; see
+ * `notes/ssh-support-plan.md`.
+ */
+ readonly computerId?: string;
+
+ /**
+ * Optional logger for structured span instrumentation. The runtime opens
+ * turn/step/tool-call spans using this logger. If omitted, no spans are
+ * emitted (backward-compatible with callers that don't yet pass a logger).
+ */
+ readonly logger?: Logger;
+
+ /**
+ * Optional monotonic-ish clock (milliseconds) for emitting wall-clock timing
+ * on outward events: per-step `step-complete` (ttft/decode/genTotal), tool
+ * execution `durationMs` on `tool-result`, and turn `durationMs` on `done`.
+ * Injected (not ambient) so the runtime stays pure and deterministic in tests.
+ * If omitted, the runtime emits no such timing (the optional fields stay
+ * absent) — backward-compatible with callers that don't provide a clock.
+ */
+ readonly now?: () => number;
+
+ /**
+ * Optional. Called by the runtime at the tool-result boundary — after a
+ * step whose tool calls have all executed, before the next step begins —
+ * to drain messages to inject alongside the tool results. Whatever it
+ * returns is appended as user-role messages to the next step's input, so
+ * a caller can inject mid-turn guidance the model sees with the tool
+ * results. When omitted or returning an empty array, no injection happens
+ * (the runtime is unchanged).
+ *
+ * Injected (not ambient) so the kernel stays pure: it owns no queue and
+ * names no feature — it just calls the callback and appends what it gets.
+ * Only invoked when a step PRODUCED tool calls (the tool-result boundary);
+ * a step that ends without tool calls does not drain (the caller decides
+ * what to do with any pending messages after the turn ends).
+ */
+ readonly drainSteering?: () => readonly ChatMessage[];
+
+ /**
+ * Optional. Called by the runtime after each step's messages are finalized
+ * (the assistant message + tool-result messages are built). The caller can
+ * use this to persist step messages incrementally — assigning seq numbers
+ * during generation so consumers can `GET /conversations/:id?sinceSeq=N`
+ * mid-turn. When omitted, the caller must persist all messages at turn end
+ * (via `RunTurnResult.messages`). The messages passed to this callback are
+ * the SAME objects in `RunTurnResult.messages` — the caller must NOT
+ * double-persist them.
+ */
+ readonly onStepComplete?: (messages: readonly ChatMessage[]) => Promise<void> | void;
+
+ /**
+ * Optional injected retry strategy for retryable provider errors (e.g. HTTP
+ * 429 / 5xx "overloaded"). When omitted, a retryable error ends the step
+ * exactly as before (backward-compatible). When provided, the runtime wraps
+ * `provider.stream()` consumption in a retry loop: on a retryable error
+ * (an emitted `error` ProviderEvent with `retryable === true`, OR a thrown
+ * error) — ONLY when no content was emitted yet this step (the safety
+ * invariant — never duplicate partial output) — it asks `retry.delayFor`
+ * for a delay, emits a transient `provider-retry` AgentEvent, sleeps via the
+ * injected `retry.sleep` (abortable), and re-calls `provider.stream()`.
+ *
+ * Injected (not ambient): the kernel imports no timer and owns no schedule.
+ * Mirrors the `now`/`logger` injection pattern — optional + backward-compatible.
+ */
+ readonly retry?: RetryStrategy;
}
/**
@@ -163,14 +163,14 @@ export interface RunTurnInput {
* persist the new messages and report usage.
*/
export interface RunTurnResult {
- /** The assistant messages produced by this turn (appended to history). */
- readonly messages: readonly ChatMessage[];
+ /** The assistant messages produced by this turn (appended to history). */
+ readonly messages: readonly ChatMessage[];
- /** Aggregated token usage across all steps in the turn. */
- readonly usage: Usage;
+ /** Aggregated token usage across all steps in the turn. */
+ readonly usage: Usage;
- /** Why the turn ended. */
- readonly finishReason: FinishReason;
+ /** Why the turn ended. */
+ readonly finishReason: FinishReason;
}
/**
@@ -187,16 +187,16 @@ export interface RunTurnResult {
* the step exactly as before).
*/
export interface RetryStrategy {
- /**
- * Pure, deterministic decision: given the 0-based attempt index, return the
- * delay in ms to sleep before the next retry, or `undefined` to stop (budget
- * exhausted). No I/O, no clock — fully testable.
- */
- readonly delayFor: (attempt: number) => number | undefined;
- /**
- * Injected effect: actually sleep for the given ms. Must honor the abort
- * signal — reject when aborted so the turn seals `aborted`. The kernel
- * imports no timer; the shell provides a `setTimeout`-based implementation.
- */
- readonly sleep: (ms: number, signal: AbortSignal) => Promise<void>;
+ /**
+ * Pure, deterministic decision: given the 0-based attempt index, return the
+ * delay in ms to sleep before the next retry, or `undefined` to stop (budget
+ * exhausted). No I/O, no clock — fully testable.
+ */
+ readonly delayFor: (attempt: number) => number | undefined;
+ /**
+ * Injected effect: actually sleep for the given ms. Must honor the abort
+ * signal — reject when aborted so the turn seals `aborted`. The kernel
+ * imports no timer; the shell provides a `setTimeout`-based implementation.
+ */
+ readonly sleep: (ms: number, signal: AbortSignal) => Promise<void>;
}