diff options
| author | Adam Malczewski <[email protected]> | 2026-06-27 01:12:40 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-27 01:12:40 +0900 |
| commit | 98b0638838a8e754927d8c030ce8bded18d63e7d (patch) | |
| tree | 0d4e21c3d4792fcd77e1040373b260e38efa34ce /packages/kernel/src/contracts/runtime.ts | |
| parent | d92a4af6191d7d20acf861adf605ad0227b6b287 (diff) | |
| parent | 61e45e60d699ed1ca46f94a8f181c92a940317c6 (diff) | |
| download | dispatch-98b0638838a8e754927d8c030ce8bded18d63e7d.tar.gz dispatch-98b0638838a8e754927d8c030ce8bded18d63e7d.zip | |
Merge branch 'dev' into feature/heartbeat
# Conflicts:
# packages/host-bin/package.json
# packages/host-bin/src/main.ts
# packages/session-orchestrator/src/orchestrator.ts
# packages/system-prompt/src/service.test.ts
# packages/system-prompt/src/service.ts
# packages/system-prompt/src/types.ts
# packages/transport-contract/package.json
# packages/transport-http/package.json
# packages/transport-http/src/app.test.ts
# packages/transport-http/src/app.ts
# packages/transport-http/src/extension.ts
# packages/transport-http/tsconfig.json
# tsconfig.json
Diffstat (limited to 'packages/kernel/src/contracts/runtime.ts')
| -rw-r--r-- | packages/kernel/src/contracts/runtime.ts | 282 |
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>; } |
