summaryrefslogtreecommitdiffhomepage
path: root/packages/kernel/src/contracts/runtime.ts
blob: 891770975304bbe5a344cbdb9a672f7dce50d176 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/**
 * Runtime contracts — the input/output types for `runTurn`.
 *
 * The kernel's turn loop is a pure function of these inputs. It takes
 * messages as a plain input, returns result messages, and touches no DB.
 * The implementation lives in the kernel runtime module; these types are
 * the contract the session-orchestrator (core) programs against.
 */

import type { ChatMessage } from "./conversation.js";
import type { ToolDispatchPolicy } from "./dispatch.js";
import type { AgentEvent } from "./events.js";
import type { Logger } from "./logging.js";
import type { ProviderContract, ProviderStreamOptions, Usage } from "./provider.js";
import type { ToolContract } from "./tool.js";

/**
 * The emitter function the kernel calls to push events outward.
 * The session-orchestrator provides this, wiring it to transport + persistence.
 */
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.
 */
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;

	/**
	 * 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;
}

/**
 * The result of a completed turn. The session-orchestrator uses this to
 * persist the new messages and report usage.
 */
export interface RunTurnResult {
	/** 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;

	/** Why the turn ended. */
	readonly finishReason: FinishReason;
}