@workerdeck/core 0.22.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.d.mts +92 -1181
- package/build/index.mjs +406 -1976
- package/build/index.mjs.map +1 -1
- package/package.json +3 -3
package/build/index.d.mts
CHANGED
|
@@ -5,50 +5,17 @@ import { SandboxEngine, SandboxVfs } from "@workerdeck/sandbox";
|
|
|
5
5
|
import { Readable, Writable } from "node:stream";
|
|
6
6
|
|
|
7
7
|
//#region src/lib/attachments.d.ts
|
|
8
|
-
/**
|
|
9
|
-
* An attachment plus its bytes — what the host hands a runner at send time.
|
|
10
|
-
*
|
|
11
|
-
* The split matters: `data` goes into the message the engine sends and nowhere
|
|
12
|
-
* else. What the runner emits into the seq-numbered event log is the
|
|
13
|
-
* {@link MessageAttachment} half, so replay and parking stay cheap (see the
|
|
14
|
-
* protocol's note on why the bytes are not on the wire).
|
|
15
|
-
*/
|
|
16
8
|
type AttachmentInput = MessageAttachment & {
|
|
17
|
-
|
|
9
|
+
data: string;
|
|
18
10
|
};
|
|
19
|
-
/**
|
|
20
|
-
* How an attachment reaches the model. Not every file can be handed to a model
|
|
21
|
-
* as itself: images and PDFs have native block types, anything textual can be
|
|
22
|
-
* inlined, and the rest has no representation at all — so uploads of it are
|
|
23
|
-
* refused at the door rather than silently dropped from the message.
|
|
24
|
-
*/
|
|
25
11
|
type AttachmentKind = 'image' | 'document' | 'text';
|
|
26
|
-
/** Strips any `; charset=…` parameter and lowercases. */
|
|
27
12
|
declare function normalizeMediaType(mediaType: string): string;
|
|
28
|
-
/** How this media type can be sent, or null if it can't be. */
|
|
29
13
|
declare function attachmentKind(mediaType: string): AttachmentKind | null;
|
|
30
|
-
/** Human-readable list for the 415 an unsupported upload gets. */
|
|
31
14
|
declare const SUPPORTED_ATTACHMENT_TYPES: string;
|
|
32
|
-
/**
|
|
33
|
-
* Anthropic content blocks for a set of attachments, in the given order.
|
|
34
|
-
*
|
|
35
|
-
* Blocks lead the message and the user's text follows: the model reads the
|
|
36
|
-
* picture, then the instruction about it. Text files are inlined in a named
|
|
37
|
-
* envelope rather than as a bare block, so "here is my config" doesn't read as
|
|
38
|
-
* something the user typed.
|
|
39
|
-
*
|
|
40
|
-
* Structurally typed — `packages/core` models Anthropic content the way
|
|
41
|
-
* `packages/protocol` does, and the caller casts into the SDK's own param type.
|
|
42
|
-
*/
|
|
43
15
|
declare function attachmentContentBlocks(attachments: readonly AttachmentInput[]): Array<Record<string, unknown>>;
|
|
44
|
-
/** Strip the bytes: the log-safe half of an attachment. */
|
|
45
16
|
declare function attachmentRef(attachment: AttachmentInput): MessageAttachment;
|
|
46
17
|
//#endregion
|
|
47
18
|
//#region src/executors/tool-executor.d.ts
|
|
48
|
-
/**
|
|
49
|
-
* Result of one tool execution, whenever it arrives. `failed` is a normal
|
|
50
|
-
* outcome the agent loop adapts to — not an exception.
|
|
51
|
-
*/
|
|
52
19
|
type ToolExecutionResult = {
|
|
53
20
|
status: 'ok';
|
|
54
21
|
output: unknown;
|
|
@@ -60,10 +27,10 @@ type ToolExecutionResult = {
|
|
|
60
27
|
logs?: string[];
|
|
61
28
|
};
|
|
62
29
|
type ToolExecutionCall = {
|
|
63
|
-
|
|
64
|
-
sessionId: string;
|
|
65
|
-
tool: string;
|
|
66
|
-
input: unknown;
|
|
30
|
+
executionId: string;
|
|
31
|
+
sessionId: string;
|
|
32
|
+
tool: string;
|
|
33
|
+
input: unknown;
|
|
67
34
|
vfs?: SandboxVfs;
|
|
68
35
|
limits?: {
|
|
69
36
|
timeoutMs?: number;
|
|
@@ -71,11 +38,6 @@ type ToolExecutionCall = {
|
|
|
71
38
|
};
|
|
72
39
|
signal?: AbortSignal;
|
|
73
40
|
};
|
|
74
|
-
/**
|
|
75
|
-
* Dispatch outcome. `settled` carries the result inline; `pending` means it
|
|
76
|
-
* arrives out-of-band later, keyed by executionId — the shape that lets a
|
|
77
|
-
* deferred or remote executor drop in without touching the runner or protocol.
|
|
78
|
-
*/
|
|
79
41
|
type ToolExecutionDispatch = {
|
|
80
42
|
executionId: string;
|
|
81
43
|
status: 'settled';
|
|
@@ -84,70 +46,31 @@ type ToolExecutionDispatch = {
|
|
|
84
46
|
executionId: string;
|
|
85
47
|
status: 'pending';
|
|
86
48
|
};
|
|
87
|
-
/**
|
|
88
|
-
* The seam between the agent loop and wherever code actually runs — in-process
|
|
89
|
-
* QuickJS, a browser tab over the WS bridge, or a managed sandbox. Backends are
|
|
90
|
-
* interchangeable and selected by context.
|
|
91
|
-
*/
|
|
92
|
-
/**
|
|
93
|
-
* How an executor will handle one specific call, asked before dispatch so the
|
|
94
|
-
* runner can announce it on `execution_dispatched` (which is emitted before the
|
|
95
|
-
* call goes out, so a bridged request never precedes its own record).
|
|
96
|
-
*
|
|
97
|
-
* Per **call**, not per executor: an executor that routes by tool name can send
|
|
98
|
-
* `eval_script` to the in-process sandbox and a long-running tool to a remote
|
|
99
|
-
* worker, and only the latter should park the session.
|
|
100
|
-
*/
|
|
101
49
|
type ToolExecutionProfile = {
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* True when this execution may outlive not just the turn but the live runner:
|
|
105
|
-
* the session parks (state persisted, runner torn down) and the result arrives
|
|
106
|
-
* out of band, keyed by `executionId`.
|
|
107
|
-
*/
|
|
50
|
+
backend?: ToolExecutionBackend;
|
|
108
51
|
deferred?: boolean;
|
|
109
|
-
/** Advisory deadline, published as `expiresAt`. For a deferred execution the
|
|
110
|
-
* timer itself belongs to the host — the runner may be gone when it fires. */
|
|
111
52
|
timeoutMs?: number;
|
|
112
53
|
};
|
|
113
54
|
interface ToolExecutor {
|
|
114
|
-
/** Describe what this call will be: backend, deferredness, deadline. Omitted =
|
|
115
|
-
* an in-band execution on the runner's configured backend. */
|
|
116
55
|
describe?(call: ToolExecutionCall): ToolExecutionProfile;
|
|
117
56
|
dispatch(call: ToolExecutionCall): Promise<ToolExecutionDispatch>;
|
|
118
57
|
}
|
|
119
58
|
//#endregion
|
|
120
59
|
//#region src/runner-interface.d.ts
|
|
121
60
|
type SessionEventListener = (event: SessionEvent) => void;
|
|
122
|
-
/** One deferred execution a parked session is waiting on. */
|
|
123
61
|
type ParkedExecution = {
|
|
124
62
|
executionId: string;
|
|
125
|
-
toolName: string;
|
|
63
|
+
toolName: string;
|
|
126
64
|
expiresAt?: number;
|
|
127
65
|
};
|
|
128
|
-
/**
|
|
129
|
-
* Everything needed to rebuild a torn-down session under the same id — the durable
|
|
130
|
-
* half of deferred execution. The engine-neutral fields are what the host persists,
|
|
131
|
-
* indexes, and replays; `state` is the engine's own continuation state (for the
|
|
132
|
-
* provider engine, its ModelMessage history) and is **opaque** outside it. Keeping
|
|
133
|
-
* it opaque is what lets `packages/server` persist a provider session without ever
|
|
134
|
-
* importing a model SDK.
|
|
135
|
-
*
|
|
136
|
-
* Must stay JSON-serializable end to end: a durable store round-trips it verbatim.
|
|
137
|
-
* "Serializable" here means round-trips *unchanged* — a Date, a Map, or a typed
|
|
138
|
-
* array inside `state` survives `JSON.stringify` as something else and rehydrates
|
|
139
|
-
* wrong. Only the in-memory store hides that, by never serializing at all.
|
|
140
|
-
*/
|
|
141
66
|
type RunnerSnapshot = {
|
|
142
|
-
|
|
67
|
+
engine: ProfileEngine;
|
|
143
68
|
id: string;
|
|
144
69
|
createdAt: number;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
vfs?: Record<string, string>; /** The deferred executions this session parked on. */
|
|
150
|
-
parked: ParkedExecution[]; /** Engine-private continuation state. Never inspected by the host. */
|
|
70
|
+
seq: number;
|
|
71
|
+
events: SessionEvent[];
|
|
72
|
+
vfs?: Record<string, string>;
|
|
73
|
+
parked: ParkedExecution[];
|
|
151
74
|
state: unknown;
|
|
152
75
|
};
|
|
153
76
|
type PermissionDecision = {
|
|
@@ -158,156 +81,36 @@ type PermissionDecision = {
|
|
|
158
81
|
message?: string;
|
|
159
82
|
interrupt?: boolean;
|
|
160
83
|
};
|
|
161
|
-
/**
|
|
162
|
-
* Engine-independent runner surface — exactly what the server and queue consume.
|
|
163
|
-
* `SessionRunner` (Claude / Agent SDK) implements it today; additional engines
|
|
164
|
-
* implement the same contract and are selected behind it. Engine-specific
|
|
165
|
-
* machinery (SDK options, approval callbacks, input-queue shapes) stays inside
|
|
166
|
-
* the implementations.
|
|
167
|
-
*/
|
|
168
84
|
interface Runner {
|
|
169
85
|
readonly id: string;
|
|
170
86
|
readonly pendingApprovals: PermissionRequest[];
|
|
171
|
-
/** The session's scratch filesystem, when its engine has one. The server's
|
|
172
|
-
* file routes (GET /sessions/:id/files[...]) read it to serve deliverables;
|
|
173
|
-
* engines without a VFS (the Claude CLI engine) simply don't expose it. */
|
|
174
87
|
readonly vfs?: SandboxVfs;
|
|
175
|
-
/** Begin the session. Idempotent; returns the run promise (resolves when the run ends). */
|
|
176
88
|
start(): Promise<void>;
|
|
177
89
|
info(): SessionInfo;
|
|
178
|
-
/** Replay buffered events with seq > afterSeq, then deliver live events. Returns unsubscribe.
|
|
179
|
-
*
|
|
180
|
-
* `coalesceReplay` drops state readings superseded later in the same replay —
|
|
181
|
-
* the fifty stale context/rate-limit polls a long session accumulates, which
|
|
182
|
-
* a client otherwise applies one by one and *renders*, counting its usage
|
|
183
|
-
* meters up through the session's history on every attach. Opt-in, and the
|
|
184
|
-
* default must stay off: it is only sound for a consumer whose handling of
|
|
185
|
-
* those events is last-write-wins, and `parking.ts` — which subscribes from
|
|
186
|
-
* seq 0 — branches on `status_changed` instead. Live events are never
|
|
187
|
-
* affected; this touches the buffered replay alone.
|
|
188
|
-
*
|
|
189
|
-
* `truncateResults` delivers an oversized `tool_result` block as its head plus
|
|
190
|
-
* the markers that say so (protocol's {@link TOOL_RESULT_HEAD_CHARS}), leaving
|
|
191
|
-
* the whole thing one fetch away. Measured, that is 68% of a long session's
|
|
192
|
-
* attach in three frames. Opt-in for the same reason and with one extra
|
|
193
|
-
* condition: **the opt-in must be issued by the unit that renders**, because
|
|
194
|
-
* `client` and `react` are separate packages an embedder can skew, and a
|
|
195
|
-
* client that asked for heads without knowing how to fetch the rest would show
|
|
196
|
-
* one as though it were the whole result. Live events are untouched — a result
|
|
197
|
-
* arriving while you watch is already on screen — and so is the stored log,
|
|
198
|
-
* which parking snapshots and the fetch route both read.
|
|
199
|
-
*
|
|
200
|
-
* `imageRefs` replaces a `tool_result`'s base64 image parts with `image_ref`
|
|
201
|
-
* addresses (protocol's {@link ImageRefPart}), their bytes one REST fetch
|
|
202
|
-
* away. Opt-in under the same rule — issued by the unit that renders — but
|
|
203
|
-
* unlike the other two it applies to **live events as well as the replay**,
|
|
204
|
-
* because the client's one render path is ref-then-fetch and bytes on a live
|
|
205
|
-
* event would only be discarded or pinned. Measured, this is 91% of all
|
|
206
|
-
* tool-result payload and 0% of what any client draws. The stored log keeps
|
|
207
|
-
* every byte, which is what the fetch route serves back. */
|
|
208
90
|
subscribe(listener: SessionEventListener, afterSeq?: number, options?: {
|
|
209
91
|
coalesceReplay?: boolean;
|
|
210
92
|
truncateResults?: boolean;
|
|
211
93
|
imageRefs?: boolean;
|
|
212
94
|
}): () => void;
|
|
213
|
-
/** One buffered event by seq, or undefined — the read side of the log the
|
|
214
|
-
* replay already walks.
|
|
215
|
-
*
|
|
216
|
-
* Optional, like every member added after `Runner` became public API: an
|
|
217
|
-
* out-of-tree runner that declines it declines only the on-demand tool result
|
|
218
|
-
* with it (the route 404s), which is exactly the degradation a runner with no
|
|
219
|
-
* `truncateResults` support wants anyway.
|
|
220
|
-
*
|
|
221
|
-
* Deliberately **not** a "give me the whole log" accessor. The one caller
|
|
222
|
-
* needs a single event by a seq a client is holding, and a method that handed
|
|
223
|
-
* out the array would invite a second copy of the bytes this feature exists
|
|
224
|
-
* to stop shipping. */
|
|
225
95
|
eventAt?(seq: number): SessionEvent | undefined;
|
|
226
|
-
/** Queue a user message for the session (starts the next turn when idle).
|
|
227
|
-
* `attachments` carry their bytes to the engine and their reference to the
|
|
228
|
-
* event log (see {@link AttachmentInput}). */
|
|
229
96
|
sendMessage(text: string, attachments?: readonly AttachmentInput[]): void;
|
|
230
|
-
/** Live MCP server status. Resolves undefined when the engine cannot answer
|
|
231
|
-
* (no MCP surface, or a fake query in tests); omitted entirely by engines that
|
|
232
|
-
* have no MCP at all. */
|
|
233
97
|
mcpServers?(): Promise<McpServerStatusInfo[] | undefined>;
|
|
234
|
-
/** Reconnect one MCP server by name. Throws if it fails. */
|
|
235
98
|
reconnectMcpServer?(name: string): Promise<void>;
|
|
236
|
-
/** Enable or disable one MCP server by name. Throws if it fails. */
|
|
237
99
|
setMcpServerEnabled?(name: string, enabled: boolean): Promise<void>;
|
|
238
|
-
/** Set (or clear, with undefined) the host's display title — `meta.title`, which
|
|
239
|
-
* `info().title` prefers over the derived one. A host-facing edit only: nothing
|
|
240
|
-
* is sent to the engine. */
|
|
241
100
|
setTitle(title: string | undefined): void;
|
|
242
|
-
/** Resolve a pending permission request. Returns false if the id is unknown (e.g. timed out). */
|
|
243
101
|
resolvePermission(requestId: string, decision: PermissionDecision): boolean;
|
|
244
102
|
interrupt(): Promise<void>;
|
|
245
|
-
/**
|
|
246
|
-
* Reset the conversation in place: the session keeps its id, its watermarks
|
|
247
|
-
* and its place in the list, and the engine starts over with an empty
|
|
248
|
-
* context. Announced with a `conversation_reset` event, whose replay rules
|
|
249
|
-
* (see `transcriptContent` in `@workerdeck/protocol`) are what stop an
|
|
250
|
-
* attaching client from resurrecting the cleared rows.
|
|
251
|
-
*
|
|
252
|
-
* Optional, like every member added after `Runner` became public API: an
|
|
253
|
-
* out-of-tree runner that declines it declines the `clear_context` command
|
|
254
|
-
* with it, which is exactly what `EngineCapabilities.clearContext: false`
|
|
255
|
-
* tells clients to expect.
|
|
256
|
-
*
|
|
257
|
-
* **Queues behind in-flight work rather than racing it** — resolving when the
|
|
258
|
-
* clear has actually happened, not when it was accepted. A clear that landed
|
|
259
|
-
* in the middle of the turn it was clearing would be neither, and the engines
|
|
260
|
-
* differ in how they wait (claude hands `/clear` to a CLI that queues its own
|
|
261
|
-
* streamed input; codex and the provider put it on their turn chain), so the
|
|
262
|
-
* one thing callers may rely on is the resolution, not the mechanism.
|
|
263
|
-
*/
|
|
264
103
|
clearContext?(): Promise<void>;
|
|
265
104
|
setPermissionMode(mode: PermissionMode): Promise<void>;
|
|
266
|
-
/** Switch the model for subsequent responses; undefined = back to the default. */
|
|
267
105
|
setModel(model?: string): Promise<void>;
|
|
268
|
-
/** Deliver the terminal result of an out-of-band tool execution (e.g. a bridged
|
|
269
|
-
* call answered by a browser client). Optional: engines that never execute
|
|
270
|
-
* out-of-band simply don't expose it. Idempotent by executionId — unknown or
|
|
271
|
-
* already-settled ids return false. */
|
|
272
106
|
settleExecution?(executionId: string, result: ToolExecutionResult): boolean;
|
|
273
|
-
/**
|
|
274
|
-
* Park: capture durable state, release engine resources, and go inert — without
|
|
275
|
-
* ending the session (no `session_closed`; the status becomes `parked`). The host
|
|
276
|
-
* persists the snapshot, drops the runner, and rebuilds it under the same id when
|
|
277
|
-
* a deferred execution's result arrives.
|
|
278
|
-
*
|
|
279
|
-
* Returns undefined when parking is not possible right now — a turn is in flight,
|
|
280
|
-
* nothing is actually parked, or the engine doesn't support it (the Claude engine
|
|
281
|
-
* doesn't: the CLI owns its own process state).
|
|
282
|
-
*/
|
|
283
107
|
park?(): RunnerSnapshot | undefined;
|
|
284
|
-
/**
|
|
285
|
-
* The same snapshot, taken **without ending anything** — the runner stays live,
|
|
286
|
-
* attached and warm.
|
|
287
|
-
*
|
|
288
|
-
* Park and snapshot are two operations that happen to produce the same value,
|
|
289
|
-
* and separating them is what makes restart-survival possible for an engine
|
|
290
|
-
* that has no on-disk session of its own. A park is for a session with nothing
|
|
291
|
-
* to do for possibly days; this is for one whose user is mid-conversation and
|
|
292
|
-
* whose process might be redeployed out from under it. The host writes it
|
|
293
|
-
* through after each turn — never on a shutdown hook, because a `kill -9` runs
|
|
294
|
-
* no hook and that is precisely the case worth surviving — and rebuilds from
|
|
295
|
-
* the last write through the ordinary `restore` path.
|
|
296
|
-
*
|
|
297
|
-
* Returns undefined when a snapshot would capture a half-happened turn: one in
|
|
298
|
-
* flight, or pending in-process executions whose results die with the process.
|
|
299
|
-
* Optional for the same reason `park()` is — claude and codex run behind a
|
|
300
|
-
* binary that owns its process state, and have engine-side resume instead.
|
|
301
|
-
*/
|
|
302
108
|
snapshot?(): RunnerSnapshot | undefined;
|
|
303
|
-
/** Emit a session_error and terminate. For host-enforced policy (e.g. requireApiKey). */
|
|
304
109
|
fail(message: string): void;
|
|
305
|
-
/** Terminate the session and any underlying engine process. */
|
|
306
110
|
close(reason?: 'client' | 'server' | 'error'): void;
|
|
307
111
|
}
|
|
308
112
|
//#endregion
|
|
309
113
|
//#region src/lib/subscribers.d.ts
|
|
310
|
-
/** What a subscriber asked for. Absent fields mean the untransformed stream. */
|
|
311
114
|
type SubscribeOptions = {
|
|
312
115
|
coalesceReplay?: boolean;
|
|
313
116
|
truncateResults?: boolean;
|
|
@@ -326,25 +129,15 @@ type SessionInfoFn = (sdkSessionId: string, options: {
|
|
|
326
129
|
dir?: string;
|
|
327
130
|
}) => Promise<SDKSessionInfo | undefined>;
|
|
328
131
|
type SessionRunnerConfig = CreateSessionRequest & {
|
|
329
|
-
|
|
132
|
+
queryFn?: QueryFn;
|
|
330
133
|
env?: Record<string, string | undefined>;
|
|
331
|
-
pathToClaudeCodeExecutable?: string;
|
|
332
|
-
extraOptions?: Partial<Options>;
|
|
134
|
+
pathToClaudeCodeExecutable?: string;
|
|
135
|
+
extraOptions?: Partial<Options>;
|
|
333
136
|
defaultApprovalTimeoutMs?: number;
|
|
334
|
-
|
|
335
|
-
* starts, so late-attaching clients get a full transcript. Default true. */
|
|
336
|
-
backfillHistory?: boolean; /** Injectable history reader (tests). Defaults to the SDK's getSessionMessages. */
|
|
137
|
+
backfillHistory?: boolean;
|
|
337
138
|
historyFn?: HistoryFn;
|
|
338
|
-
/** Injectable session-metadata reader (tests). Defaults to the SDK's
|
|
339
|
-
* getSessionInfo — the only place the CLI's own session title is readable
|
|
340
|
-
* from, since no message on the stream carries it. */
|
|
341
139
|
sessionInfoFn?: SessionInfoFn;
|
|
342
140
|
};
|
|
343
|
-
/**
|
|
344
|
-
* One live Agent SDK session: owns the query() call, the streaming input queue, the
|
|
345
|
-
* pending-approval table, and a seq-numbered event log that subscribers can replay.
|
|
346
|
-
* No transport — the server (or any host) subscribes and bridges to the wire.
|
|
347
|
-
*/
|
|
348
141
|
declare class SessionRunner implements Runner {
|
|
349
142
|
#private;
|
|
350
143
|
readonly id: string;
|
|
@@ -353,116 +146,27 @@ declare class SessionRunner implements Runner {
|
|
|
353
146
|
get status(): SessionStatus;
|
|
354
147
|
get sdkSessionId(): string | undefined;
|
|
355
148
|
get lastSeq(): number;
|
|
356
|
-
/** 'oauth' = claude.ai subscription credentials; other values are API-key provenance. */
|
|
357
149
|
get apiKeySource(): string | undefined;
|
|
358
150
|
get pendingApprovals(): PermissionRequest[];
|
|
359
151
|
info(): SessionInfo;
|
|
360
|
-
/** Host-facing rename: writes `meta.title`, which `#title()` prefers. Clearing
|
|
361
|
-
* it (undefined) restores the derived title. The engine is never told. */
|
|
362
152
|
setTitle(title: string | undefined): void;
|
|
363
|
-
/** Begin the session. Idempotent; returns the run promise (resolves when the query ends). */
|
|
364
153
|
start(): Promise<void>;
|
|
365
|
-
/** Queue a user message for the session (starts the next turn when idle).
|
|
366
|
-
*
|
|
367
|
-
* `attachments` carry their own bytes; they reach the CLI as content blocks and
|
|
368
|
-
* are logged as references. A message may be attachments alone — an empty text
|
|
369
|
-
* block is not valid API input, so the text is only added when there is some. */
|
|
370
154
|
sendMessage(text: string, attachments?: readonly AttachmentInput[]): void;
|
|
371
|
-
/** Live MCP server status, straight from the CLI. Undefined when the engine
|
|
372
|
-
* can't answer (an injected fake query in tests) — the caller 501s rather than
|
|
373
|
-
* pretending the session has no servers. */
|
|
374
155
|
mcpServers(): Promise<McpServerStatusInfo[] | undefined>;
|
|
375
156
|
reconnectMcpServer(name: string): Promise<void>;
|
|
376
157
|
setMcpServerEnabled(name: string, enabled: boolean): Promise<void>;
|
|
377
|
-
/** Resolve a pending permission request. Returns false if the id is unknown (e.g. timed out). */
|
|
378
158
|
resolvePermission(requestId: string, decision: PermissionDecision): boolean;
|
|
379
159
|
interrupt(): Promise<void>;
|
|
380
|
-
/**
|
|
381
|
-
* Reset the conversation by sending the `/clear` the CLI already honors.
|
|
382
|
-
*
|
|
383
|
-
* Deliberately not a second mechanism: this engine's reset arrives *from the
|
|
384
|
-
* SDK*, and `normalizeSdkMessage` turns the CLI's report of it into the
|
|
385
|
-
* `conversation_reset` event (adopting the new conversation id and re-polling
|
|
386
|
-
* context usage on the way through). Reimplementing the clear here would give
|
|
387
|
-
* one engine two ways to reach the same state, and only one of them would get
|
|
388
|
-
* the id adoption right. So the command and the composer's `/clear` are one
|
|
389
|
-
* behaviour, and this method is the thin end of it.
|
|
390
|
-
*
|
|
391
|
-
* The one place it differs from the other two engines: this resolves when the
|
|
392
|
-
* `/clear` has been **handed to the CLI**, not when the reset has happened —
|
|
393
|
-
* the CLI queues its own streamed input, so waiting is its job, and there is
|
|
394
|
-
* no chain here to ride. The observable contract is the same (a clear sent
|
|
395
|
-
* mid-turn queues rather than cutting the turn short); only the moment the
|
|
396
|
-
* promise settles is weaker, and no caller depends on it.
|
|
397
|
-
*/
|
|
398
160
|
clearContext(): Promise<void>;
|
|
399
161
|
setPermissionMode(mode: PermissionMode): Promise<void>;
|
|
400
|
-
/** Switch the model for subsequent responses; undefined = back to the default. */
|
|
401
162
|
setModel(model?: string): Promise<void>;
|
|
402
|
-
/** Emit a session_error and terminate. For host-enforced policy (e.g. requireApiKey). */
|
|
403
163
|
fail(message: string): void;
|
|
404
|
-
/** Terminate the session and the underlying CLI subprocess. */
|
|
405
164
|
close(reason?: 'client' | 'server' | 'error'): void;
|
|
406
|
-
/** See `Runner.eventAt`. A linear scan: the one caller is a reader pressing
|
|
407
|
-
* "show everything" on one row, so a per-runner seq index would be a map
|
|
408
|
-
* maintained on every emit to save a walk nobody makes twice a minute. */
|
|
409
165
|
eventAt(seq: number): SessionEvent | undefined;
|
|
410
|
-
/**
|
|
411
|
-
* Replay buffered events with seq > afterSeq, then deliver live events.
|
|
412
|
-
* Returns an unsubscribe function.
|
|
413
|
-
*
|
|
414
|
-
* Replay honours the reset watermark: transcript content below the latest
|
|
415
|
-
* `conversation_reset` is skipped (the reducer would clear it again anyway,
|
|
416
|
-
* and a pre-reset client that never learned the reducer's case would render
|
|
417
|
-
* a conversation the engine has discarded), while state-bearing events —
|
|
418
|
-
* which are emitted once and never again — always replay. The reset event
|
|
419
|
-
* itself replays (the skip is strictly-below), which is what clears a
|
|
420
|
-
* reconnecting client still holding pre-reset rows; superseded resets are
|
|
421
|
-
* content below the newer one and are skipped with what they cleared.
|
|
422
|
-
*/
|
|
423
166
|
subscribe(listener: SessionEventListener, afterSeq?: number, options?: SubscribeOptions): () => void;
|
|
424
167
|
}
|
|
425
168
|
//#endregion
|
|
426
169
|
//#region src/lib/replay.d.ts
|
|
427
|
-
/**
|
|
428
|
-
* The one replay body, and what a socket receives from it.
|
|
429
|
-
*
|
|
430
|
-
* Every runner had a byte-identical copy of this loop — three spellings of four
|
|
431
|
-
* rules, one of which ("never drop the highest-seq event, whatever the rule
|
|
432
|
-
* says") is load-bearing and was three copies of a comment. Not a base class:
|
|
433
|
-
* the runners share nothing else, and a base class would have to own `#emit`,
|
|
434
|
-
* the most engine-specific method each of them has.
|
|
435
|
-
*
|
|
436
|
-
* The rules, in the order they are applied:
|
|
437
|
-
*
|
|
438
|
-
* 1. `afterSeq` — the caller already holds everything at or below it.
|
|
439
|
-
* 2. `resetSeq` — transcript *content* strictly below the latest
|
|
440
|
-
* `conversation_reset` is skipped, so a re-attach cannot resurrect a cleared
|
|
441
|
-
* conversation while state events still replay. **Every engine that can emit
|
|
442
|
-
* a reset must track it and pass it** — this was Claude's alone only for as
|
|
443
|
-
* long as Claude's was the only engine that could produce the event, and the
|
|
444
|
-
* failure when a runner forgets is quiet: the end state is right for a
|
|
445
|
-
* current reducer, so nothing looks broken while every attach re-sends the
|
|
446
|
-
* whole cleared conversation for the process's lifetime.
|
|
447
|
-
* 3. `coalesceReplay` — last-write-wins state readings superseded later in the
|
|
448
|
-
* same replay (`staleReplaySeqs`), plus everything `replayRetains` says the
|
|
449
|
-
* reducer reads and discards. Opt-in, and only sound for a consumer whose
|
|
450
|
-
* handling of those events is last-write-wins.
|
|
451
|
-
* 4. `imageRefs` — a base64 image part is delivered as an `image_ref` address
|
|
452
|
-
* (protocol's {@link imagePartRef}), its bytes one REST fetch away. Applied
|
|
453
|
-
* **before** rule 5, because it stamps indices from the stored part array
|
|
454
|
-
* which rule 5 then reshapes. Unlike rule 5 this also applies to the live
|
|
455
|
-
* path (see `SubscriberSet`), which is the one place these two rules differ.
|
|
456
|
-
* 5. `truncateResults` — a huge `tool_result` block is delivered as its head
|
|
457
|
-
* plus the markers that say so. **Never mutates the stored event**: the live
|
|
458
|
-
* path, the parking snapshot and the fetch route all need the whole thing,
|
|
459
|
-
* so this builds a copy and the log stays the log.
|
|
460
|
-
*
|
|
461
|
-
* The highest-seq event is delivered whatever rules 2 and 3 say — a client's
|
|
462
|
-
* replay hold waits for `state.lastSeq` to reach the attach's and would
|
|
463
|
-
* otherwise hang forever — but it is still *truncated* when rule 4 applies. A
|
|
464
|
-
* session that ends on a `find /` puts its 641 KB frame exactly there.
|
|
465
|
-
*/
|
|
466
170
|
declare function replaySlice(events: readonly SessionEvent[], options: {
|
|
467
171
|
afterSeq: number;
|
|
468
172
|
resetSeq?: number;
|
|
@@ -470,88 +174,43 @@ declare function replaySlice(events: readonly SessionEvent[], options: {
|
|
|
470
174
|
truncateResults?: boolean;
|
|
471
175
|
imageRefs?: boolean;
|
|
472
176
|
}): SessionEvent[];
|
|
473
|
-
/**
|
|
474
|
-
* A copy of `event` whose oversized `tool_result` blocks carry their head and
|
|
475
|
-
* say so — or `event` itself, unchanged and un-copied, when nothing is over the
|
|
476
|
-
* budget. That identity matters: an attach is mostly small events, and a fresh
|
|
477
|
-
* object for every one of them would cost more than the feature saves.
|
|
478
|
-
*
|
|
479
|
-
* Blocks are measured and cut **individually**. A message answering three calls
|
|
480
|
-
* where one is a `find /` keeps the two small results whole, which is what makes
|
|
481
|
-
* the per-block marker (rather than a per-event one) honest.
|
|
482
|
-
*/
|
|
483
177
|
declare function truncateResultBlocks(event: SessionEvent): SessionEvent;
|
|
484
178
|
//#endregion
|
|
485
179
|
//#region src/engines/provider/runner.d.ts
|
|
486
|
-
/** `cwd` is optional for this engine: the loop has no host-filesystem coupling
|
|
487
|
-
* (tools get scoped VFS handles instead). Defaults to process.cwd() for display. */
|
|
488
180
|
type AiSdkRunnerConfig = Omit<CreateSessionRequest, 'cwd'> & {
|
|
489
181
|
cwd?: string;
|
|
490
|
-
/** AI SDK language model instance (or gateway model id string). Provider
|
|
491
|
-
* resolution from profiles happens host-side; core takes the resolved model. */
|
|
492
182
|
languageModel: LanguageModel$1;
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
* `resolveToolCall()`, which re-enters the loop by message-state replay. */
|
|
496
|
-
tools?: ToolSet$1; /** System prompt (AI SDK v7 `instructions`). */
|
|
497
|
-
instructions?: string; /** Max loop steps per turn. Default 20. */
|
|
183
|
+
tools?: ToolSet$1;
|
|
184
|
+
instructions?: string;
|
|
498
185
|
maxSteps?: number;
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
* dispatch on park, apply the result, re-enter. Without one, parked calls
|
|
503
|
-
* stay on {@link pendingToolCalls} for the host to answer via
|
|
504
|
-
* {@link resolveToolCall}.
|
|
505
|
-
*/
|
|
506
|
-
executor?: ToolExecutor; /** Names the executor handles. Others stay pending for the host. */
|
|
507
|
-
executableTools?: string[]; /** Scratch filesystem handed to sandboxed executions. */
|
|
508
|
-
vfs?: SandboxVfs; /** Per-execution limits passed to the executor. */
|
|
186
|
+
executor?: ToolExecutor;
|
|
187
|
+
executableTools?: string[];
|
|
188
|
+
vfs?: SandboxVfs;
|
|
509
189
|
executionLimits?: {
|
|
510
190
|
timeoutMs?: number;
|
|
511
191
|
memoryLimitBytes?: number;
|
|
512
|
-
};
|
|
513
|
-
executionBackend?: ToolExecutionBackend;
|
|
192
|
+
};
|
|
193
|
+
executionBackend?: ToolExecutionBackend;
|
|
194
|
+
shouldApprove?: (call: {
|
|
195
|
+
toolName: string;
|
|
196
|
+
input: unknown;
|
|
197
|
+
}) => boolean;
|
|
198
|
+
approvalTimeoutMs?: number;
|
|
514
199
|
resolveModel?: (modelId: string | undefined) => LanguageModel$1;
|
|
515
|
-
/**
|
|
516
|
-
* Live MCP status for this session, when the host wired MCP at all. Unlike
|
|
517
|
-
* the CLI engines — which ask their binary — this engine's MCP is entirely
|
|
518
|
-
* host-assembled, so the host is the only party that can answer. Unset means
|
|
519
|
-
* "no MCP here", which reads as an empty list rather than an error: a session
|
|
520
|
-
* with no servers is a fact, not a missing feature.
|
|
521
|
-
*
|
|
522
|
-
* Named apart from the inherited `mcpServers` request field on purpose —
|
|
523
|
-
* that one is the *wire configuration* a client asked for, this one is what
|
|
524
|
-
* the host actually connected.
|
|
525
|
-
*/
|
|
526
200
|
reportMcpServers?: () => Promise<McpServerStatusInfo[] | undefined>;
|
|
527
|
-
/** Called once when the session closes — release per-session resources the
|
|
528
|
-
* host attached (an MCP connection, a watcher). Errors are swallowed. Also
|
|
529
|
-
* runs when the session parks: parking releases the same resources. */
|
|
530
201
|
onClose?: () => void | Promise<void>;
|
|
531
|
-
/**
|
|
532
|
-
* Rebuild a parked session from {@link AiSdkRunner.park}'s snapshot instead of
|
|
533
|
-
* starting a fresh one: the id, event log, seq counter, message history, and
|
|
534
|
-
* the executions it parked on are all adopted. The rest of the config is the
|
|
535
|
-
* live wiring (model, tools, executor, VFS) and is taken as given — a
|
|
536
|
-
* rehydrated session may legitimately come up against a re-created tool set.
|
|
537
|
-
*/
|
|
538
202
|
restore?: RunnerSnapshot;
|
|
539
203
|
};
|
|
540
|
-
/** An external (execute-less) tool call the loop is parked on. */
|
|
541
204
|
type PendingToolCall = {
|
|
542
205
|
toolCallId: string;
|
|
543
206
|
toolName: string;
|
|
544
207
|
input: unknown;
|
|
545
|
-
|
|
546
|
-
* park on it, and only a host-delivered result can settle it. */
|
|
547
|
-
deferred?: boolean; /** Epoch ms the host's execution watchdog should fire at. */
|
|
208
|
+
deferred?: boolean;
|
|
548
209
|
expiresAt?: number;
|
|
549
210
|
};
|
|
550
|
-
/** The provider engine's half of a {@link RunnerSnapshot} — its continuation
|
|
551
|
-
* state. Opaque to the host; only this class reads it. */
|
|
552
211
|
type AiSdkSessionState = {
|
|
553
212
|
messages: ModelMessage[];
|
|
554
|
-
pendingToolCalls: PendingToolCall[];
|
|
213
|
+
pendingToolCalls: PendingToolCall[];
|
|
555
214
|
dispatched: string[];
|
|
556
215
|
numTurns: number;
|
|
557
216
|
totalUsage: {
|
|
@@ -560,8 +219,6 @@ type AiSdkSessionState = {
|
|
|
560
219
|
cacheWrite: number;
|
|
561
220
|
cacheRead: number;
|
|
562
221
|
};
|
|
563
|
-
/** The in-progress turn's accumulator: a parked turn's earlier legs still owe
|
|
564
|
-
* their tokens and elapsed time to the turn_result that eventually lands. */
|
|
565
222
|
turnAccum?: {
|
|
566
223
|
startedAt: number;
|
|
567
224
|
input: number;
|
|
@@ -570,12 +227,8 @@ type AiSdkSessionState = {
|
|
|
570
227
|
cacheRead: number;
|
|
571
228
|
};
|
|
572
229
|
permissionMode: PermissionMode;
|
|
573
|
-
/** Model alias last requested (config.model or a set_model), NOT the resolved
|
|
574
|
-
* provider model id — re-resolution goes back through `resolveModel`. */
|
|
575
230
|
model?: string;
|
|
576
231
|
lastActivityAt?: number;
|
|
577
|
-
/** When the snapshot was taken, so a rehydrated turn can discount the time it
|
|
578
|
-
* spent parked instead of billing it as elapsed turn duration. */
|
|
579
232
|
parkedAt?: number;
|
|
580
233
|
};
|
|
581
234
|
type ToolCallOutput = {
|
|
@@ -585,16 +238,6 @@ type ToolCallOutput = {
|
|
|
585
238
|
type: 'json';
|
|
586
239
|
value: unknown;
|
|
587
240
|
};
|
|
588
|
-
/**
|
|
589
|
-
* Model-agnostic runner over the AI SDK v7 ToolLoopAgent. The session's durable
|
|
590
|
-
* state is its ModelMessage history: every turn — including continuation after an
|
|
591
|
-
* externally-executed tool call — is a fresh streamed call over that history
|
|
592
|
-
* (message-state replay; the loop cannot be suspended). Output is emitted as it
|
|
593
|
-
* happens: `stream_delta` per token (unless includePartialMessages is false) and
|
|
594
|
-
* assistant/tool messages per step. Emits the same seq-numbered SessionEvent log
|
|
595
|
-
* as SessionRunner; engine-specific CLI telemetry (system_init, capabilities,
|
|
596
|
-
* rate_limit, ...) is simply never emitted.
|
|
597
|
-
*/
|
|
598
241
|
declare class AiSdkRunner implements Runner {
|
|
599
242
|
#private;
|
|
600
243
|
readonly id: string;
|
|
@@ -602,200 +245,66 @@ declare class AiSdkRunner implements Runner {
|
|
|
602
245
|
constructor(config: AiSdkRunnerConfig, id?: string);
|
|
603
246
|
get status(): SessionStatus;
|
|
604
247
|
get lastSeq(): number;
|
|
605
|
-
/** The session's durable state — persist to park, replay to rehydrate. */
|
|
606
248
|
get messages(): ModelMessage[];
|
|
607
|
-
/** External tool calls the loop is currently parked on. */
|
|
608
249
|
get pendingToolCalls(): PendingToolCall[];
|
|
609
250
|
get pendingApprovals(): PermissionRequest[];
|
|
610
|
-
/** The session's scratch filesystem (see Runner.vfs) — the server's file
|
|
611
|
-
* routes serve deliverables straight from it. */
|
|
612
251
|
get vfs(): SandboxVfs | undefined;
|
|
613
252
|
info(): SessionInfo;
|
|
614
253
|
start(): Promise<void>;
|
|
615
|
-
/**
|
|
616
|
-
* Snapshot durable state, release engine resources, and go inert — the session
|
|
617
|
-
* continues in the snapshot, not in this object. Returns undefined when parking
|
|
618
|
-
* would lose work or has nothing to wait for: a turn in flight, no parked call,
|
|
619
|
-
* or an already-closed/parked runner.
|
|
620
|
-
*/
|
|
621
254
|
park(): RunnerSnapshot | undefined;
|
|
622
|
-
/**
|
|
623
|
-
* The same snapshot, taken without ending anything.
|
|
624
|
-
*
|
|
625
|
-
* `park()` and this are two operations that happen to produce the same value,
|
|
626
|
-
* and the difference is the whole point: `park()` *ends* the live runner
|
|
627
|
-
* (inert, listeners dropped, `onClose` called), which is right for deferred
|
|
628
|
-
* execution — the session has nothing to do for possibly days — and wrong for
|
|
629
|
-
* restart-survival, where the session is active and someone is mid-
|
|
630
|
-
* conversation. This one changes nothing at all: no status emit, no listener
|
|
631
|
-
* clear, no disposer. The host writes the value through to durable storage
|
|
632
|
-
* after each turn and keeps the runner live and warm, so a restart rebuilds
|
|
633
|
-
* from the last write through the existing `restore` path and the next message
|
|
634
|
-
* costs no wake.
|
|
635
|
-
*
|
|
636
|
-
* The gate is `park()`'s minus the requirement that there be something parked:
|
|
637
|
-
*
|
|
638
|
-
* - `#abort` set is refused for the reason it always was — a `generate()` in
|
|
639
|
-
* flight has produced messages that are not in the history yet, so the
|
|
640
|
-
* snapshot would be of a turn that half-happened.
|
|
641
|
-
* - Pending calls that are **not** all deferred are refused, which is
|
|
642
|
-
* `park()`'s rule wearing a different hat. An in-process execution's result
|
|
643
|
-
* is coming back to *this* runner and dies with the process; a restore would
|
|
644
|
-
* wait on it forever, and `state.dispatched` is what would stop the rebuilt
|
|
645
|
-
* runner from simply calling it again.
|
|
646
|
-
* - Idle with nothing pending — the case `park()` exists to refuse — is
|
|
647
|
-
* exactly the case this exists to allow.
|
|
648
|
-
*/
|
|
649
255
|
snapshot(): RunnerSnapshot | undefined;
|
|
650
256
|
sendMessage(text: string, attachments?: readonly AttachmentInput[]): void;
|
|
651
|
-
/**
|
|
652
|
-
* Deliver the result of an external (execute-less) tool call. Appends the
|
|
653
|
-
* tool-result message and, once no calls remain pending, re-enters the loop.
|
|
654
|
-
* Idempotent per toolCallId: unknown/already-settled ids return false.
|
|
655
|
-
*/
|
|
656
257
|
resolveToolCall(toolCallId: string, output: ToolCallOutput, options?: {
|
|
657
258
|
isError?: boolean;
|
|
658
259
|
}): boolean;
|
|
659
|
-
resolvePermission(
|
|
660
|
-
/** Emit `file_delivered` — the deliver_file tool's hand-over event (wired by
|
|
661
|
-
* createEngineSession via ToolContextOptions.onFileDelivered). */
|
|
260
|
+
resolvePermission(requestId: string, decision: PermissionDecision): boolean;
|
|
662
261
|
emitFileDelivered(file: {
|
|
663
262
|
path: string;
|
|
664
263
|
bytes: number;
|
|
665
264
|
description?: string;
|
|
666
265
|
}): void;
|
|
667
|
-
/**
|
|
668
|
-
* One plain generateText over the session's current model, billed into the
|
|
669
|
-
* running turn's usage accumulator — the web_fetch digest pass uses this so
|
|
670
|
-
* its tokens are never lost from the turn's accounting.
|
|
671
|
-
*/
|
|
672
266
|
generateDigest(prompt: string): Promise<string>;
|
|
673
|
-
/**
|
|
674
|
-
* Reset the conversation: drop the message array the next turn would have
|
|
675
|
-
* been built from. There is no engine round trip — this runner *is* where the
|
|
676
|
-
* transcript lives, so clearing it is the whole operation.
|
|
677
|
-
*
|
|
678
|
-
* Two things ride along, both already written elsewhere and both load-bearing
|
|
679
|
-
* here. `#emit`'s `conversation_reset` arm retires `#contextUsage` (the
|
|
680
|
-
* reading described a conversation that no longer exists), and the same arm
|
|
681
|
-
* in `restore` keeps a parked session that comes back after a clear from
|
|
682
|
-
* resurrecting it. Pending tool calls are NOT swept: a parked call is work a
|
|
683
|
-
* backend still owes an answer for, and a clear is not an interrupt — the
|
|
684
|
-
* refusal below is what keeps the two apart.
|
|
685
|
-
*/
|
|
686
267
|
clearContext(): Promise<void>;
|
|
687
268
|
interrupt(): Promise<void>;
|
|
688
269
|
setPermissionMode(mode: PermissionMode): Promise<void>;
|
|
689
270
|
setModel(model?: string): Promise<void>;
|
|
690
271
|
fail(message: string): void;
|
|
691
272
|
close(reason?: 'client' | 'server' | 'error'): void;
|
|
692
|
-
/** See `Runner.eventAt`. A linear scan: the one caller is a reader pressing
|
|
693
|
-
* "show everything" on one row, so a per-runner seq index would be a map
|
|
694
|
-
* maintained on every emit to save a walk nobody makes twice a minute. */
|
|
695
273
|
eventAt(seq: number): SessionEvent | undefined;
|
|
696
274
|
subscribe(listener: SessionEventListener, afterSeq?: number, options?: SubscribeOptions): () => void;
|
|
697
|
-
/**
|
|
698
|
-
* Deliver the result of an execution this runner dispatched. Used by the host
|
|
699
|
-
* when a backend settled out-of-band (a browser bridge answering later, a
|
|
700
|
-
* deferred executor). Idempotent by executionId.
|
|
701
|
-
*/
|
|
702
275
|
settleExecution(executionId: string, result: ToolExecutionResult): boolean;
|
|
703
|
-
/**
|
|
704
|
-
* This session's MCP servers, as the host assembled them.
|
|
705
|
-
*
|
|
706
|
-
* Always answers — an empty list when no MCP was wired — because the
|
|
707
|
-
* alternative (undefined, which the server turns into a 501) says "this
|
|
708
|
-
* engine cannot tell you", and this engine can: the host that built the
|
|
709
|
-
* session is the only party who knows, and it has been asked.
|
|
710
|
-
*/
|
|
711
276
|
mcpServers(): Promise<McpServerStatusInfo[] | undefined>;
|
|
712
|
-
/** Host-facing rename: writes `meta.title`, which `#title()` prefers. Clearing
|
|
713
|
-
* it (undefined) restores the derived title. The engine is never told. */
|
|
714
277
|
setTitle(title: string | undefined): void;
|
|
715
278
|
}
|
|
716
279
|
//#endregion
|
|
717
280
|
//#region src/engines/claude/auth.d.ts
|
|
718
|
-
/**
|
|
719
|
-
* Credential presence for one Claude Code environment, as the CLI itself reports
|
|
720
|
-
* it. 'unknown' means the check could not run at all (no binary, a CLI too old
|
|
721
|
-
* for `auth status`, unparseable output) — which is NOT evidence of a missing
|
|
722
|
-
* login and must never be surfaced as one.
|
|
723
|
-
*/
|
|
724
281
|
type ClaudeAuthStatus = 'logged_in' | 'logged_out' | 'unknown';
|
|
725
|
-
/** Injectable form of {@link checkClaudeAuth} (tests, custom probes). */
|
|
726
282
|
type ClaudeAuthProbe = (env: Record<string, string | undefined>) => Promise<ClaudeAuthStatus>;
|
|
727
|
-
/**
|
|
728
|
-
* The native Claude Code binary the Agent SDK itself spawns, resolved the way
|
|
729
|
-
* the SDK resolves it: the platform-specific optional dependency installed next
|
|
730
|
-
* to the SDK package (`@anthropic-ai/claude-agent-sdk-<platform>-<arch>/claude`).
|
|
731
|
-
* Probing this binary rather than whatever `claude` is on PATH means an auth
|
|
732
|
-
* check answers for the executable sessions will actually run — the two can be
|
|
733
|
-
* different versions logged into different places. Returns undefined when it
|
|
734
|
-
* can't be found (optional dep skipped, unsupported platform); callers degrade
|
|
735
|
-
* to 'unknown', and the SDK surfaces its own error if a session is created.
|
|
736
|
-
*/
|
|
737
283
|
declare function resolveBundledClaudeExecutable(): string | undefined;
|
|
738
|
-
/**
|
|
739
|
-
* Ask the CLI whether `env` holds usable credentials: `claude auth status`
|
|
740
|
-
* prints a JSON verdict covering every source the CLI itself consults for that
|
|
741
|
-
* environment — `<CLAUDE_CONFIG_DIR>/.credentials.json`, the macOS login
|
|
742
|
-
* Keychain, ANTHROPIC_API_KEY, CLAUDE_CODE_OAUTH_TOKEN, Bedrock/Vertex
|
|
743
|
-
* (verified against 2.1.217). Only the `loggedIn` boolean is ever read; the
|
|
744
|
-
* identity fields in the payload (email, org, subscription) never leave the
|
|
745
|
-
* parse. The exit code is deliberately ignored — 2.1.217 exits 1 on a
|
|
746
|
-
* logged-out verdict where other versions exit 0 — and anything that doesn't
|
|
747
|
-
* parse to a `loggedIn` boolean is 'unknown', because `auth status` is not a
|
|
748
|
-
* stable contract. Never rejects.
|
|
749
|
-
*/
|
|
750
284
|
declare function checkClaudeAuth(env: Record<string, string | undefined>, options?: {
|
|
751
285
|
executable?: string;
|
|
752
286
|
timeoutMs?: number;
|
|
753
287
|
}): Promise<ClaudeAuthStatus>;
|
|
754
288
|
//#endregion
|
|
755
289
|
//#region src/executors/quickjs-executor.d.ts
|
|
756
|
-
/** Resolve a URL to text for the guest. Runs host-side with host authority —
|
|
757
|
-
* this is where a credential may be attached, never inside the sandbox. */
|
|
758
290
|
type HostFetch = (url: string, signal: AbortSignal) => Promise<string>;
|
|
759
291
|
type QuickJsExecutorOptions = {
|
|
760
292
|
engine: SandboxEngine;
|
|
761
|
-
|
|
762
|
-
* Hostnames the guest may reach, exact or `*.example.com`. Empty/unset =
|
|
763
|
-
* no network at all (the guest's fetchText throws). Matched host-side; the
|
|
764
|
-
* guest is never told the allowlist and never holds a credential.
|
|
765
|
-
*/
|
|
766
|
-
allowedHosts?: string[]; /** Performs the actual request. Unset = global fetch, text body. */
|
|
293
|
+
allowedHosts?: string[];
|
|
767
294
|
hostFetch?: HostFetch;
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
fetchTimeoutMs?: number; /** Default guest wall-clock limit when the call doesn't set one. Default 5000. */
|
|
771
|
-
defaultTimeoutMs?: number; /** Default guest allocator cap when the call doesn't set one. Default 64 MiB. */
|
|
295
|
+
fetchTimeoutMs?: number;
|
|
296
|
+
defaultTimeoutMs?: number;
|
|
772
297
|
defaultMemoryLimitBytes?: number;
|
|
773
298
|
};
|
|
774
|
-
/**
|
|
775
|
-
* In-process execution backend: runs a tool's untrusted script in the QuickJS
|
|
776
|
-
* WASM guest. Always settles inline — nothing downstream assumes that, which is
|
|
777
|
-
* what lets a deferred backend replace it behind the same seam.
|
|
778
|
-
*/
|
|
779
299
|
declare class QuickJsExecutor implements ToolExecutor {
|
|
780
300
|
#private;
|
|
781
301
|
constructor(options: QuickJsExecutorOptions);
|
|
782
302
|
dispatch(call: ToolExecutionCall): Promise<ToolExecutionDispatch>;
|
|
783
303
|
}
|
|
784
|
-
/** Exact hostname match, or a single leading `*.` wildcard covering subdomains
|
|
785
|
-
* (not the bare parent). Only http(s) — no file:, data:, or other schemes. */
|
|
786
304
|
declare function isHostAllowed(url: string, allowedHosts: string[]): boolean;
|
|
787
305
|
//#endregion
|
|
788
306
|
//#region src/lib/pending-registry.d.ts
|
|
789
|
-
/**
|
|
790
|
-
* One registry for every request that leaves the runner and must come back:
|
|
791
|
-
* permission approvals, browser-bridged tool calls, and deferred executions.
|
|
792
|
-
* They differ only in who answers and how long that takes — the correlation,
|
|
793
|
-
* timeout, idempotent settle, and provenance tagging are identical, so they
|
|
794
|
-
* live here once.
|
|
795
|
-
*/
|
|
796
|
-
/** What kind of async request this is. Purely descriptive — the mechanics are shared. */
|
|
797
307
|
type PendingKind = 'approval' | 'tool_call' | 'execution';
|
|
798
|
-
/** Who settled a request. Mirrors the existing approval vocabulary. */
|
|
799
308
|
type SettledBy = 'client' | 'timeout' | 'policy' | 'server';
|
|
800
309
|
type PendingOutcome<T> = {
|
|
801
310
|
ok: true;
|
|
@@ -810,45 +319,30 @@ type PendingOutcome<T> = {
|
|
|
810
319
|
type PendingEntry = {
|
|
811
320
|
id: string;
|
|
812
321
|
kind: PendingKind;
|
|
813
|
-
createdAt: number;
|
|
814
|
-
expiresAt?: number;
|
|
322
|
+
createdAt: number;
|
|
323
|
+
expiresAt?: number;
|
|
815
324
|
meta?: Record<string, unknown>;
|
|
816
325
|
};
|
|
817
326
|
type RegisterOptions<T> = {
|
|
818
327
|
id: string;
|
|
819
328
|
kind: PendingKind;
|
|
820
|
-
/** Fail the request automatically after this long. Omit for no deadline
|
|
821
|
-
* (deferred executions whose watchdog lives elsewhere). */
|
|
822
329
|
timeoutMs?: number;
|
|
823
|
-
meta?: Record<string, unknown>;
|
|
330
|
+
meta?: Record<string, unknown>;
|
|
824
331
|
onSettle?: (outcome: PendingOutcome<T>, entry: PendingEntry) => void;
|
|
825
332
|
};
|
|
826
333
|
declare class PendingRequestRegistry {
|
|
827
334
|
#private;
|
|
828
335
|
get size(): number;
|
|
829
|
-
/**
|
|
830
|
-
* Register a request and get a promise for its outcome. The promise **never
|
|
831
|
-
* rejects**: a timeout or cancellation resolves with `ok: false` so callers
|
|
832
|
-
* feed the failure back into the agent loop instead of unwinding it.
|
|
833
|
-
*
|
|
834
|
-
* Re-registering a live id throws — silently replacing it would strand the
|
|
835
|
-
* first waiter forever.
|
|
836
|
-
*/
|
|
837
336
|
register<T>(options: RegisterOptions<T>): Promise<PendingOutcome<T>>;
|
|
838
|
-
/** Deliver a result. Returns false for unknown or already-settled ids —
|
|
839
|
-
* duplicate and late deliveries are no-ops, never a second application. */
|
|
840
337
|
settle<T>(id: string, value: T, settledBy?: SettledBy): boolean;
|
|
841
|
-
/** Fail a request. Same idempotence guarantee as {@link settle}. */
|
|
842
338
|
fail(id: string, reason: string, error: string, settledBy?: SettledBy): boolean;
|
|
843
339
|
has(id: string): boolean;
|
|
844
340
|
get(id: string): PendingEntry | undefined;
|
|
845
341
|
list(kind?: PendingKind): PendingEntry[];
|
|
846
|
-
/** Fail everything (optionally of one kind) — session close, turn interrupt. */
|
|
847
342
|
cancelAll(reason: string, error: string, kind?: PendingKind): number;
|
|
848
343
|
}
|
|
849
344
|
//#endregion
|
|
850
345
|
//#region src/executors/browser-bridge-executor.d.ts
|
|
851
|
-
/** Answer a bridged call, as delivered by the client over the wire. */
|
|
852
346
|
type BridgeAnswer = {
|
|
853
347
|
output: ToolExecutionOutput;
|
|
854
348
|
logs?: string[];
|
|
@@ -858,404 +352,163 @@ type BridgeAnswer = {
|
|
|
858
352
|
logs?: string[];
|
|
859
353
|
};
|
|
860
354
|
type BrowserBridgeExecutorOptions = {
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
* false means nobody is attached — the execution fails immediately rather
|
|
864
|
-
* than hanging until its deadline.
|
|
865
|
-
*/
|
|
866
|
-
send: (frame: ToolCallRequestFrame) => boolean; /** Tell the client to abandon a call the server gave up on. */
|
|
867
|
-
cancel?: (executionId: string, reason: string) => void; /** How long to wait for the client before failing the execution. Default 60000. */
|
|
355
|
+
send: (frame: ToolCallRequestFrame) => boolean;
|
|
356
|
+
cancel?: (executionId: string, reason: string) => void;
|
|
868
357
|
timeoutMs?: number;
|
|
869
|
-
/**
|
|
870
|
-
* Called once per dispatched execution when it reaches a terminal result,
|
|
871
|
-
* however it got there (client answer, timeout, abort, no client). This is
|
|
872
|
-
* the wire back into the agent loop — the host feeds it to the runner's
|
|
873
|
-
* `resolveToolCall`. A timeout arrives here as a failed result, not silence.
|
|
874
|
-
*/
|
|
875
358
|
onResult?: (executionId: string, result: ToolExecutionResult) => void;
|
|
876
|
-
/** Share the session's registry so approvals, bridged calls, and deferred
|
|
877
|
-
* executions live in one table. Omit to get a private one. */
|
|
878
359
|
registry?: PendingRequestRegistry;
|
|
879
360
|
};
|
|
880
|
-
/**
|
|
881
|
-
* Executes tool calls in the attached client's own sandbox. The first backend
|
|
882
|
-
* that genuinely returns `pending`: dispatch puts a request on the wire and
|
|
883
|
-
* returns, and the result arrives later through {@link resolve}.
|
|
884
|
-
*
|
|
885
|
-
* Data locality is the point — documents can stay in the browser and never
|
|
886
|
-
* reach the server. The tradeoff is trust: whatever comes back is untrusted
|
|
887
|
-
* input, fine for the user's own data but never a source for authoritative
|
|
888
|
-
* server state (that is why MCP and secret-bearing tools are never bridged).
|
|
889
|
-
*/
|
|
890
361
|
declare class BrowserBridgeExecutor implements ToolExecutor {
|
|
891
362
|
#private;
|
|
892
363
|
readonly registry: PendingRequestRegistry;
|
|
893
364
|
constructor(options: BrowserBridgeExecutorOptions);
|
|
894
365
|
dispatch(call: ToolExecutionCall): Promise<ToolExecutionDispatch>;
|
|
895
|
-
/**
|
|
896
|
-
* Apply a client's answer. Returns false when the id is unknown or already
|
|
897
|
-
* settled — a late result after a timeout must not re-open a settled call.
|
|
898
|
-
*/
|
|
899
366
|
resolve(executionId: string, answer: BridgeAnswer): boolean;
|
|
900
367
|
}
|
|
901
|
-
/** Map a registry outcome onto the executor's result contract. */
|
|
902
368
|
declare function toExecutionResult(outcome: PendingOutcome<BridgeAnswer>): ToolExecutionResult;
|
|
903
369
|
//#endregion
|
|
904
370
|
//#region src/executors/deferred-executor.d.ts
|
|
905
|
-
/** A dispatched execution, as handed to the backend that will run it. */
|
|
906
371
|
type DeferredDispatch = {
|
|
907
|
-
/** Correlation id. The result is delivered under it — `POST
|
|
908
|
-
* {basePath}/executions/:executionId/result` — and applied idempotently. */
|
|
909
372
|
executionId: string;
|
|
910
373
|
sessionId: string;
|
|
911
374
|
tool: string;
|
|
912
|
-
input: unknown;
|
|
375
|
+
input: unknown;
|
|
913
376
|
vfsSeed?: Record<string, string>;
|
|
914
377
|
limits?: {
|
|
915
378
|
timeoutMs?: number;
|
|
916
379
|
memoryLimitBytes?: number;
|
|
917
|
-
};
|
|
380
|
+
};
|
|
918
381
|
expiresAt?: number;
|
|
919
382
|
};
|
|
920
383
|
type DeferredExecutorOptions = {
|
|
921
|
-
/**
|
|
922
|
-
* Hand the call to whatever actually runs it — enqueue it, POST it to a worker,
|
|
923
|
-
* page a human. Called synchronously during dispatch; throwing fails the
|
|
924
|
-
* execution (the failure reaches the agent as ordinary tool output).
|
|
925
|
-
*/
|
|
926
384
|
onDispatch: (call: DeferredDispatch) => void | Promise<void>;
|
|
927
|
-
|
|
928
|
-
* Unset = no deadline; the execution then relies on the job's parked cap. */
|
|
929
|
-
timeoutMs?: number; /** Reported on `execution_dispatched`. Default 'remote'. */
|
|
385
|
+
timeoutMs?: number;
|
|
930
386
|
backend?: ToolExecutionBackend;
|
|
931
387
|
};
|
|
932
|
-
/**
|
|
933
|
-
* The executor for work that outlives the session's process residency: dispatch
|
|
934
|
-
* hands the call off and returns `pending` **without holding a promise**, because
|
|
935
|
-
* the runner it would resolve into is about to be torn down. The result can only
|
|
936
|
-
* come back through the host — the execution-result route → `settleExecution` on a
|
|
937
|
-
* rehydrated runner — which is exactly what makes a park durable rather than a
|
|
938
|
-
* long in-memory await.
|
|
939
|
-
*
|
|
940
|
-
* Contrast {@link BrowserBridgeExecutor}, which is also `pending` but keeps its
|
|
941
|
-
* answer in memory for the ~60s the tab has to reply.
|
|
942
|
-
*/
|
|
943
388
|
declare class DeferredExecutor implements ToolExecutor {
|
|
944
389
|
#private;
|
|
945
390
|
readonly backend: ToolExecutionBackend;
|
|
946
391
|
readonly timeoutMs: number | undefined;
|
|
947
392
|
constructor(options: DeferredExecutorOptions);
|
|
948
|
-
/** Every call this executor takes is deferred — route only the tools that
|
|
949
|
-
* belong on the remote side to it. */
|
|
950
393
|
describe(): ToolExecutionProfile;
|
|
951
394
|
dispatch(call: ToolExecutionCall): Promise<ToolExecutionDispatch>;
|
|
952
395
|
}
|
|
953
396
|
//#endregion
|
|
954
397
|
//#region src/engines/provider/web-fetch.d.ts
|
|
955
|
-
/**
|
|
956
|
-
* `web_fetch` backend, close to Claude Code's original WebFetch: fetch a URL,
|
|
957
|
-
* convert HTML to markdown, and (optionally) digest it with a model against the
|
|
958
|
-
* caller's prompt. Server-side only — this runs with server egress, which is
|
|
959
|
-
* exactly why it is an authoritative capability the operator grants explicitly.
|
|
960
|
-
*/
|
|
961
398
|
type WebFetchResult = {
|
|
962
|
-
|
|
963
|
-
digest?: string;
|
|
964
|
-
markdown?: string;
|
|
399
|
+
url: string;
|
|
400
|
+
digest?: string;
|
|
401
|
+
markdown?: string;
|
|
965
402
|
truncated?: boolean;
|
|
966
|
-
/** Redirect-to-a-different-host notice: the redirect is surfaced, not followed
|
|
967
|
-
* (the agent can decide to fetch `redirectUrl` itself). */
|
|
968
403
|
notice?: string;
|
|
969
404
|
redirectUrl?: string;
|
|
970
405
|
error?: string;
|
|
971
406
|
};
|
|
972
407
|
type WebFetchFn = (url: string, prompt: string) => Promise<WebFetchResult>;
|
|
973
|
-
/** Runs the digest pass over the fetched markdown. Wire the session's own model
|
|
974
|
-
* here (see createEngineSession) so its tokens land in the turn's usage. */
|
|
975
408
|
type WebFetchDigest = (markdown: string, prompt: string) => Promise<string>;
|
|
976
409
|
type WebFetchOptions = {
|
|
977
|
-
fetchImpl?: typeof fetch;
|
|
978
|
-
maxContentBytes?: number;
|
|
410
|
+
fetchImpl?: typeof fetch;
|
|
411
|
+
maxContentBytes?: number;
|
|
979
412
|
maxMarkdownBytes?: number;
|
|
980
|
-
/** Fetched-page cache TTL (keyed by URL; the digest is per-prompt and never
|
|
981
|
-
* cached). Default 15 minutes. */
|
|
982
413
|
cacheTtlMs?: number;
|
|
983
|
-
|
|
984
|
-
* Unset = any public host. */
|
|
985
|
-
allowedHosts?: string[]; /** Per-request timeout. Default 30000. */
|
|
414
|
+
allowedHosts?: string[];
|
|
986
415
|
timeoutMs?: number;
|
|
987
416
|
digest?: WebFetchDigest;
|
|
988
417
|
};
|
|
989
418
|
declare function createWebFetch(options?: WebFetchOptions): WebFetchFn;
|
|
990
|
-
/** Private / loopback / link-local / unspecified, IPv4 and IPv6 (incl. v4-mapped). */
|
|
991
419
|
declare function isPrivateAddress(address: string): boolean;
|
|
992
|
-
/**
|
|
993
|
-
* Dependency-free HTML → markdown, tuned for "give the model readable text":
|
|
994
|
-
* drops non-content subtrees, keeps headings/lists/links/emphasis/code, strips
|
|
995
|
-
* everything else. Not a spec-grade converter on purpose — a small predictable
|
|
996
|
-
* transform beats dragging a DOM into core.
|
|
997
|
-
*/
|
|
998
420
|
declare function htmlToMarkdown(html: string): string;
|
|
999
421
|
//#endregion
|
|
1000
422
|
//#region src/engines/provider/tools.d.ts
|
|
1001
|
-
/**
|
|
1002
|
-
* How much authority a tool carries, which decides where it may run.
|
|
1003
|
-
*
|
|
1004
|
-
* - `sandboxed` — no ambient authority; safe to execute anywhere, including an
|
|
1005
|
-
* untrusted browser tab. Its results are untrusted input.
|
|
1006
|
-
* - `authoritative` — runs server-side with server credentials (MCP, secret-bearing
|
|
1007
|
-
* APIs). **Never bridged to a client**: bridging it would hand a browser the
|
|
1008
|
-
* ability to forge authoritative results.
|
|
1009
|
-
*/
|
|
1010
423
|
type ToolTrust = 'sandboxed' | 'authoritative';
|
|
1011
424
|
type ToolDefinition = {
|
|
1012
425
|
name: string;
|
|
1013
426
|
trust: ToolTrust;
|
|
1014
|
-
/** The AI SDK tool. Sandboxed tools are declared WITHOUT `execute` so the loop
|
|
1015
|
-
* hands them to the ToolExecutor seam rather than running them inline. */
|
|
1016
427
|
tool: Tool$1;
|
|
1017
428
|
};
|
|
1018
429
|
type ToolContextOptions = {
|
|
1019
|
-
/** Executor for sandboxed tools. Selected per call by the host (browser bridge
|
|
1020
|
-
* when a client is attached, server QuickJS otherwise). */
|
|
1021
430
|
executor: ToolExecutor;
|
|
1022
|
-
sessionId: string;
|
|
1023
|
-
vfs?: SandboxVfs;
|
|
431
|
+
sessionId: string;
|
|
432
|
+
vfs?: SandboxVfs;
|
|
1024
433
|
search?: (query: string, limit: number) => Promise<Array<{
|
|
1025
434
|
title: string;
|
|
1026
435
|
url: string;
|
|
1027
436
|
snippet?: string;
|
|
1028
|
-
}>>;
|
|
437
|
+
}>>;
|
|
1029
438
|
download?: (url: string) => Promise<{
|
|
1030
439
|
contentType?: string;
|
|
1031
440
|
text: string;
|
|
1032
441
|
}>;
|
|
1033
|
-
/** Page digester for `web_fetch` (see {@link createWebFetch}). Omitted = the
|
|
1034
|
-
* tool is not granted. */
|
|
1035
442
|
webFetch?: WebFetchFn;
|
|
1036
|
-
/** Notified when the agent hands over a VFS file via `deliver_file`, so the
|
|
1037
|
-
* host can emit the `file_delivered` session event. The tool is only granted
|
|
1038
|
-
* when this is set — a delivery nobody hears is not a delivery. */
|
|
1039
443
|
onFileDelivered?: (file: {
|
|
1040
444
|
path: string;
|
|
1041
445
|
bytes: number;
|
|
1042
446
|
description?: string;
|
|
1043
|
-
}) => void;
|
|
447
|
+
}) => void;
|
|
1044
448
|
limits?: {
|
|
1045
449
|
timeoutMs?: number;
|
|
1046
450
|
memoryLimitBytes?: number;
|
|
1047
451
|
};
|
|
1048
|
-
/** Notified when a sandboxed execution is dispatched and when it settles, so
|
|
1049
|
-
* the host can emit execution_* events. */
|
|
1050
452
|
onDispatch?: (executionId: string, toolName: string) => void;
|
|
1051
453
|
onSettle?: (executionId: string, result: ToolExecutionResult) => void;
|
|
1052
454
|
};
|
|
1053
|
-
/** Everything a session's tools need, plus the tool set to hand the runner. */
|
|
1054
455
|
type ToolContext = {
|
|
1055
456
|
vfs: SandboxVfs;
|
|
1056
457
|
tools: ToolSet$1;
|
|
1057
|
-
definitions: ToolDefinition[];
|
|
458
|
+
definitions: ToolDefinition[];
|
|
1058
459
|
sandboxedToolNames: string[];
|
|
1059
460
|
};
|
|
1060
|
-
/**
|
|
1061
|
-
* Build the capability-scoped tool set for a session.
|
|
1062
|
-
*
|
|
1063
|
-
* The agent's authority is exactly what is granted here — there are no built-in
|
|
1064
|
-
* filesystem or shell tools, and nothing reaches the host filesystem: `fs_*`
|
|
1065
|
-
* operate on an in-memory scratch VFS. Tools whose backend is not supplied are
|
|
1066
|
-
* simply absent rather than present-and-failing, so a model cannot be tempted
|
|
1067
|
-
* by a capability the operator did not grant.
|
|
1068
|
-
*/
|
|
1069
461
|
declare function createToolContext(options: ToolContextOptions): ToolContext;
|
|
1070
|
-
/** Add host-side MCP tools to a context. They are ALWAYS authoritative: they run
|
|
1071
|
-
* server-side with server credentials, and must never be handed to a browser. */
|
|
1072
462
|
declare function withMcpTools(context: ToolContext, mcpTools: ToolSet$1): ToolContext;
|
|
1073
|
-
/** A tool the host supplies, with the trust level it is to run at. */
|
|
1074
463
|
type HostToolDefinition = {
|
|
1075
464
|
tool: Tool$1;
|
|
1076
|
-
/**
|
|
1077
|
-
* Where this tool may run. `authoritative` tools execute inline in the
|
|
1078
|
-
* gateway and MUST declare `execute`; `sandboxed` ones must NOT, because the
|
|
1079
|
-
* loop hands them to the {@link ToolExecutor} seam instead — which is what
|
|
1080
|
-
* makes them bridgeable to an untrusted tab.
|
|
1081
|
-
*/
|
|
1082
465
|
trust: ToolTrust;
|
|
1083
466
|
};
|
|
1084
|
-
|
|
1085
|
-
* Add host-supplied tools to a context at an explicit trust level.
|
|
1086
|
-
*
|
|
1087
|
-
* The trust level is the whole point of the seam: {@link withMcpTools} can only
|
|
1088
|
-
* produce authoritative tools, so a host tool that *should* be sandboxed — and
|
|
1089
|
-
* therefore executable in the browser tab that asked for it — had no way to be
|
|
1090
|
-
* expressed at all. Here the host says which it is, and the contradictions are
|
|
1091
|
-
* refused rather than silently resolved:
|
|
1092
|
-
*
|
|
1093
|
-
* - a `sandboxed` tool carrying `execute` would run inline in this process with
|
|
1094
|
-
* the gateway's ambient authority, which is exactly what sandboxing it was
|
|
1095
|
-
* meant to prevent;
|
|
1096
|
-
* - an `authoritative` tool *without* `execute` would park the turn on a call no
|
|
1097
|
-
* executor claims, and the session would simply stop.
|
|
1098
|
-
*/
|
|
1099
|
-
declare function withHostTools(context: ToolContext, hostTools: Record<string, HostToolDefinition>, /** What to call these in error messages ('MCP tool', 'host tool'). */
|
|
1100
|
-
|
|
1101
|
-
kind?: string): ToolContext;
|
|
467
|
+
declare function withHostTools(context: ToolContext, hostTools: Record<string, HostToolDefinition>, kind?: string): ToolContext;
|
|
1102
468
|
//#endregion
|
|
1103
469
|
//#region src/engines/provider/session.d.ts
|
|
1104
470
|
type EngineSessionOptions = {
|
|
1105
|
-
|
|
471
|
+
config: AiSdkRunnerConfig;
|
|
1106
472
|
profile?: ProfileInfo;
|
|
1107
|
-
/**
|
|
1108
|
-
* Resolve the profile's provider config into a model instance. The host owns
|
|
1109
|
-
* this so core never imports a provider SDK and never reads credentials —
|
|
1110
|
-
* they come from the operator's environment, exactly like the Claude chain.
|
|
1111
|
-
*/
|
|
1112
473
|
resolveModel: (profile: ProfileInfo | undefined, config: AiSdkRunnerConfig) => LanguageModel$1;
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
* attached and the server sandbox otherwise; the seam makes them
|
|
1116
|
-
* interchangeable, so this is the only place the choice is made.
|
|
1117
|
-
*/
|
|
1118
|
-
selectExecutor: () => ToolExecutor; /** Which backend `selectExecutor` returned, for the execution_* events. */
|
|
1119
|
-
backend?: 'server' | 'browser' | 'managed' | 'remote'; /** Backends for the granted capabilities. Omitted ones are simply not granted. */
|
|
474
|
+
selectExecutor: (() => ToolExecutor) | ((call: ToolExecutionCall) => ToolExecutor);
|
|
475
|
+
backend?: 'server' | 'browser' | 'managed' | 'remote' | ((call: ToolExecutionCall) => 'server' | 'browser' | 'managed' | 'remote');
|
|
1120
476
|
capabilities?: {
|
|
1121
477
|
search?: ToolContextOptions['search'];
|
|
1122
478
|
download?: ToolContextOptions['download'];
|
|
1123
|
-
/**
|
|
1124
|
-
* Grants `web_fetch`. Pass options (or `{}`) to use the built-in
|
|
1125
|
-
* {@link createWebFetch} backend — its digest pass then runs on the
|
|
1126
|
-
* session's own model, billed into the turn's usage. Pass `digest: false`
|
|
1127
|
-
* to skip the digest (the tool returns page markdown), a custom digest fn
|
|
1128
|
-
* to bring your own model, or a complete {@link WebFetchFn} to replace the
|
|
1129
|
-
* backend outright.
|
|
1130
|
-
*/
|
|
1131
479
|
webFetch?: WebFetchFn | (Omit<WebFetchOptions, 'digest'> & {
|
|
1132
480
|
digest?: WebFetchOptions['digest'] | false;
|
|
1133
481
|
});
|
|
1134
|
-
/** Grants `deliver_file`: the agent can hand VFS files over to the user
|
|
1135
|
-
* (emitting `file_delivered`, downloadable via the server's file routes).
|
|
1136
|
-
* Default true — set false to withhold it. */
|
|
1137
482
|
deliverFiles?: boolean;
|
|
1138
483
|
};
|
|
1139
|
-
/**
|
|
1140
|
-
* A live MCP connection from {@link connectMcpTools} — the preferred way to
|
|
1141
|
-
* hand MCP to a session, and the only one that can fail loudly.
|
|
1142
|
-
*
|
|
1143
|
-
* With this set, the session knows *which servers connected*, so two things
|
|
1144
|
-
* that were previously silent become impossible: a profile naming a server
|
|
1145
|
-
* that never connected refuses to build (see {@link mcpTools} for what that
|
|
1146
|
-
* used to look like), and `runner.mcpServers()` answers `GET
|
|
1147
|
-
* /sessions/:id/mcp` with the real per-server status instead of 501.
|
|
1148
|
-
*/
|
|
1149
484
|
mcp?: McpConnection;
|
|
1150
|
-
/** Authoritative tools that run server-side with server credentials (MCP).
|
|
1151
|
-
* Never bridged to a client. Namespaced `<server>__<tool>` by
|
|
1152
|
-
* {@link connectMcpTools}, which is how a profile grants servers by name.
|
|
1153
|
-
*
|
|
1154
|
-
* The bare tool set, for a host assembling one itself. Prefer {@link mcp}:
|
|
1155
|
-
* a tool set alone cannot distinguish "this server connected and exposes no
|
|
1156
|
-
* tools" from "this server never connected", so the check here has to be the
|
|
1157
|
-
* cruder one — a declared server contributing no tools is refused. */
|
|
1158
485
|
mcpTools?: ToolSet$1;
|
|
1159
|
-
/**
|
|
1160
|
-
* Extra host tools, each at an explicit trust level (see
|
|
1161
|
-
* {@link withHostTools}). This is the seam for a tool that is neither one of
|
|
1162
|
-
* the built-in capabilities nor MCP — including a **sandboxed** one, which
|
|
1163
|
-
* `mcpTools` cannot express because everything in it is authoritative by
|
|
1164
|
-
* construction.
|
|
1165
|
-
*
|
|
1166
|
-
* A sandboxed tool here rides the same {@link ToolExecutor} seam
|
|
1167
|
-
* `eval_script` does, so it executes wherever `selectExecutor` points — an
|
|
1168
|
-
* in-process QuickJS guest, or the browser tab that asked the question.
|
|
1169
|
-
*/
|
|
1170
486
|
tools?: Record<string, HostToolDefinition>;
|
|
1171
|
-
/** Extra instructions prepended to the session's system prompt. Overridden by
|
|
1172
|
-
* the profile's `session.instructions` when it declares one. */
|
|
1173
487
|
instructions?: string;
|
|
1174
488
|
executionLimits?: {
|
|
1175
489
|
timeoutMs?: number;
|
|
1176
490
|
memoryLimitBytes?: number;
|
|
1177
491
|
};
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
*
|
|
1184
|
-
* (Hand-building `config.vfs` still works and still wins — but then the
|
|
1185
|
-
* `restore ? undefined : createVfs(...)` dance is yours to get right.)
|
|
1186
|
-
*/
|
|
492
|
+
shouldApprove?: (call: {
|
|
493
|
+
toolName: string;
|
|
494
|
+
input: unknown;
|
|
495
|
+
}) => boolean;
|
|
496
|
+
approvalTimeoutMs?: number;
|
|
1187
497
|
seedVfs?: Record<string, string>;
|
|
1188
|
-
/**
|
|
1189
|
-
* Build the session under this id rather than minting one.
|
|
1190
|
-
*
|
|
1191
|
-
* Forward the server's `EngineRunnerContext.id` here, always: it is set when
|
|
1192
|
-
* the gateway is rehydrating a session across a restart, and a runner that
|
|
1193
|
-
* ignores it comes back as a *different* session — the rebuild is refused,
|
|
1194
|
-
* and every client's route and unread watermark is stranded. Ignored when
|
|
1195
|
-
* `config.restore` is present, which carries its own id.
|
|
1196
|
-
*/
|
|
1197
498
|
id?: string;
|
|
1198
499
|
};
|
|
1199
|
-
/**
|
|
1200
|
-
* Assemble a model-agnostic session: provider model, capability-scoped tools,
|
|
1201
|
-
* a scratch VFS, and the executor that runs the sandboxed ones.
|
|
1202
|
-
*
|
|
1203
|
-
* This is the piece an operator wires into the server's `createEngineRunner`.
|
|
1204
|
-
*
|
|
1205
|
-
* The host wires the *backends*; the profile and the session request decide which
|
|
1206
|
-
* of them are actually granted (`profile.session`, `config.capabilities`). A
|
|
1207
|
-
* backend that isn't granted is simply not built into the tool set, so withholding
|
|
1208
|
-
* a capability costs the host no branching. No declaration anywhere = everything
|
|
1209
|
-
* the host wired, which is what a host that ignores profiles gets.
|
|
1210
|
-
*/
|
|
1211
500
|
declare function createEngineSession(options: EngineSessionOptions): AiSdkRunner;
|
|
1212
501
|
type McpConnection = {
|
|
1213
502
|
tools: ToolSet$1;
|
|
1214
|
-
/**
|
|
1215
|
-
* One entry per configured server, connected or not — the truth a session was
|
|
1216
|
-
* assembled against. Handed to {@link createEngineSession} as `mcp`, it is
|
|
1217
|
-
* what `GET /sessions/:id/mcp` answers with and what makes a half-connected
|
|
1218
|
-
* session refuse to build rather than run degraded.
|
|
1219
|
-
*/
|
|
1220
503
|
servers: McpServerStatusInfo[];
|
|
1221
504
|
close: () => Promise<void>;
|
|
1222
505
|
};
|
|
1223
|
-
/**
|
|
1224
|
-
* Connect to MCP servers and return their tools, ready for {@link withMcpTools}.
|
|
1225
|
-
*
|
|
1226
|
-
* Server-side only, with server credentials: these tools are authoritative and
|
|
1227
|
-
* must never be bridged to a browser. `@ai-sdk/mcp` is imported lazily and is an
|
|
1228
|
-
* optional dependency — an operator who wires no MCP servers never needs it.
|
|
1229
|
-
*
|
|
1230
|
-
* **A stateless MCP server must answer `GET` with 405.** The client opens the
|
|
1231
|
-
* SSE stream with a `GET` before it sends anything, and a POST-only server
|
|
1232
|
-
* mounted under a framework's default 404 makes the whole connect fail with an
|
|
1233
|
-
* error that names neither the method nor the route. This is the single most
|
|
1234
|
-
* common way an otherwise-correct MCP mount fails.
|
|
1235
|
-
*/
|
|
1236
506
|
declare function connectMcpTools(servers: Record<string, McpServerConfigWire>, options?: {
|
|
1237
|
-
/** `onError` may fire more than once for a single server: transport-level
|
|
1238
|
-
* failures surface through the client's own uncaught-error channel as well as
|
|
1239
|
-
* the connect failure. Treat it as a report, not a count. */
|
|
1240
507
|
onError?: (name: string, error: unknown) => void;
|
|
1241
|
-
/**
|
|
1242
|
-
* Reject if any server fails to connect, after closing the ones that did.
|
|
1243
|
-
*
|
|
1244
|
-
* Off by default, which is right for an operator's fleet — one unreachable
|
|
1245
|
-
* server should not take a whole gateway's sessions down. Turn it **on**
|
|
1246
|
-
* when the servers are the app's own: an embedder who mounts one wiki server
|
|
1247
|
-
* and gets a session without it has a session that cannot do its job, and
|
|
1248
|
-
* finding that out at connect time beats finding it out from a transcript
|
|
1249
|
-
* where the agent apologises.
|
|
1250
|
-
*/
|
|
1251
508
|
required?: boolean;
|
|
1252
509
|
}): Promise<McpConnection>;
|
|
1253
510
|
//#endregion
|
|
1254
511
|
//#region src/lib/input-queue.d.ts
|
|
1255
|
-
/**
|
|
1256
|
-
* Push-based single-consumer AsyncIterable bridging imperative sendMessage() calls
|
|
1257
|
-
* into the streaming `prompt` the Agent SDK consumes.
|
|
1258
|
-
*/
|
|
1259
512
|
declare class InputQueue implements AsyncIterable<SDKUserMessage> {
|
|
1260
513
|
#private;
|
|
1261
514
|
push(message: SDKUserMessage): void;
|
|
@@ -1265,40 +518,19 @@ declare class InputQueue implements AsyncIterable<SDKUserMessage> {
|
|
|
1265
518
|
//#endregion
|
|
1266
519
|
//#region src/lib/normalize.d.ts
|
|
1267
520
|
declare function toApiMessage(message: unknown): ApiMessage;
|
|
1268
|
-
/**
|
|
1269
|
-
* The CLI's MCP status, as `McpServerStatusInfo`.
|
|
1270
|
-
*
|
|
1271
|
-
* The narrowing is the point: the SDK's config object carries `env` for stdio
|
|
1272
|
-
* servers and `headers` for HTTP ones, and both routinely hold API tokens. This
|
|
1273
|
-
* is the one place they are dropped, so no client — dashboard, phone, or a host
|
|
1274
|
-
* app reading the REST route — can turn "show me my MCP servers" into a
|
|
1275
|
-
* credential dump. Only the connection's identity survives.
|
|
1276
|
-
*/
|
|
1277
521
|
declare function mcpStatusInfo(status: McpServerStatus): McpServerStatusInfo;
|
|
1278
|
-
/** The half of the SDK's `ModelInfo` this package forwards. Structurally typed so
|
|
1279
|
-
* the mapping can be unit-tested without a live query. */
|
|
1280
522
|
type SdkModelInfo = {
|
|
1281
523
|
value: string;
|
|
1282
524
|
resolvedModel?: string;
|
|
1283
525
|
displayName: string;
|
|
1284
|
-
description?: string;
|
|
526
|
+
description?: string;
|
|
1285
527
|
supportedEffortLevels?: string[];
|
|
1286
528
|
supportsEffort?: boolean;
|
|
1287
529
|
};
|
|
1288
530
|
declare function modelOptionsFromSdk(models: readonly SdkModelInfo[]): ModelOption[];
|
|
1289
|
-
/**
|
|
1290
|
-
* Map one SDKMessage to a wire-protocol event body, or null for messages the runner
|
|
1291
|
-
* consumes itself (system_init and session-state changes carry runner state and are
|
|
1292
|
-
* emitted by the runner with extra context).
|
|
1293
|
-
*/
|
|
1294
531
|
declare function normalizeSdkMessage(msg: SDKMessage): SessionEventBody | null;
|
|
1295
532
|
//#endregion
|
|
1296
533
|
//#region src/engines/adapter.d.ts
|
|
1297
|
-
/**
|
|
1298
|
-
* A probe's verdict on one profile's credentials. 'unknown' means the probe
|
|
1299
|
-
* could not run at all — which is NOT evidence of a missing login and must
|
|
1300
|
-
* never be surfaced as one (the `checkClaudeAuth` discipline, generalized).
|
|
1301
|
-
*/
|
|
1302
534
|
type EngineAvailability = {
|
|
1303
535
|
available: true;
|
|
1304
536
|
} | {
|
|
@@ -1307,68 +539,22 @@ type EngineAvailability = {
|
|
|
1307
539
|
} | {
|
|
1308
540
|
available: 'unknown';
|
|
1309
541
|
};
|
|
1310
|
-
/**
|
|
1311
|
-
* A model catalog shipped with the release — the answer to "what can a create
|
|
1312
|
-
* form offer" with no process spawned, correct from a gateway's first request.
|
|
1313
|
-
*
|
|
1314
|
-
* Never contains a 'default' sentinel row (a choice, not a model — forms add
|
|
1315
|
-
* their own "Profile default" row mapping to an unset model). Staleness is
|
|
1316
|
-
* bounded by the release cadence: the release checklist re-runs each catalog's
|
|
1317
|
-
* extraction procedure (documented in its file header) and diffs.
|
|
1318
|
-
*/
|
|
1319
542
|
type ModelCatalog = {
|
|
1320
|
-
models: ModelOption[];
|
|
543
|
+
models: ModelOption[];
|
|
1321
544
|
provenance: string;
|
|
1322
545
|
};
|
|
1323
546
|
type EngineRunnerRequest = {
|
|
1324
547
|
config: SessionRunnerConfig;
|
|
1325
548
|
profile?: ProfileInfo;
|
|
1326
|
-
/** Rebuild a parked session instead of starting fresh. Engines that cannot
|
|
1327
|
-
* rehydrate throw. */
|
|
1328
549
|
restore?: RunnerSnapshot;
|
|
1329
|
-
/**
|
|
1330
|
-
* Adopt this session id instead of minting one. For rehydrating a session
|
|
1331
|
-
* across a gateway restart: the transcript comes back from the *engine's* own
|
|
1332
|
-
* store via `config.resume`, but every client keys its watermarks, unread
|
|
1333
|
-
* counts and routes on the WorkerDeck id, so that id has to survive too
|
|
1334
|
-
* (`SessionInfo.id` is documented as stable across resumes). A `restore`
|
|
1335
|
-
* carries its own id in the snapshot and does not need this.
|
|
1336
|
-
*/
|
|
1337
550
|
id?: string;
|
|
1338
551
|
};
|
|
1339
|
-
/**
|
|
1340
|
-
* One engine, as the server consumes it: its capability record, its shipped
|
|
1341
|
-
* model catalog, a credential probe, and a runner factory. The claude adapter
|
|
1342
|
-
* wraps `SessionRunner` without behaviour change; the codex adapter owns the
|
|
1343
|
-
* `codex app-server` integration; the provider adapter is a pseudo-adapter —
|
|
1344
|
-
* its runners are built by the host's `createEngineRunner` hook, so its
|
|
1345
|
-
* `createRunner` throws and the server routes around it.
|
|
1346
|
-
*/
|
|
1347
552
|
interface EngineAdapter {
|
|
1348
553
|
readonly engine: ProfileEngine;
|
|
1349
|
-
/** Must deep-equal ENGINE_CAPABILITIES[engine] — asserted by a core test, so
|
|
1350
|
-
* the protocol's browser-safe defaults can never drift from the adapter. */
|
|
1351
554
|
readonly capabilities: EngineCapabilities;
|
|
1352
555
|
readonly catalog: ModelCatalog;
|
|
1353
|
-
/**
|
|
1354
|
-
* Probe whether `profile`'s credentials are usable under `env` — the full
|
|
1355
|
-
* session environment the real assembly path produces, never a delta (codex
|
|
1356
|
-
* replaces the child env wholesale, and a delta would strand HOME/PATH and
|
|
1357
|
-
* the auth chain with it). Never rejects.
|
|
1358
|
-
*/
|
|
1359
556
|
checkAvailability(profile: ProfileInfo, env: Record<string, string | undefined>): Promise<EngineAvailability>;
|
|
1360
|
-
/** Build a Runner. Throwing fails the create (session POST 500s, job fails). */
|
|
1361
557
|
createRunner(request: EngineRunnerRequest): Runner | Promise<Runner>;
|
|
1362
|
-
/**
|
|
1363
|
-
* List the engine's on-disk resumable sessions (`GET /sdk-sessions`) —
|
|
1364
|
-
* present exactly when the capability record's `listSessions` is true. Must
|
|
1365
|
-
* not require a live session: the codex adapter answers over a short-lived
|
|
1366
|
-
* `thread/list` app-server child it closes before returning; the claude
|
|
1367
|
-
* adapter reads the Agent SDK's store directly. `env` follows the
|
|
1368
|
-
* checkAvailability contract (the profile's complete session environment,
|
|
1369
|
-
* never a delta). `dir` narrows to one project directory; `limit`/`offset`
|
|
1370
|
-
* page the newest-first result.
|
|
1371
|
-
*/
|
|
1372
558
|
listSessions?(options: {
|
|
1373
559
|
profile?: ProfileInfo;
|
|
1374
560
|
env: Record<string, string | undefined>;
|
|
@@ -1377,66 +563,18 @@ interface EngineAdapter {
|
|
|
1377
563
|
offset?: number;
|
|
1378
564
|
}): Promise<SdkSessionSummary[]>;
|
|
1379
565
|
}
|
|
1380
|
-
/** The in-repo adapter for an engine. An absent `engine` means 'claude'. */
|
|
1381
566
|
declare function getEngineAdapter(engine: ProfileEngine | undefined): EngineAdapter;
|
|
1382
567
|
//#endregion
|
|
1383
568
|
//#region src/engines/claude/adapter.d.ts
|
|
1384
|
-
/**
|
|
1385
|
-
* The Claude engine as an adapter — a thin, behaviourally inert wrapper:
|
|
1386
|
-
* `SessionRunner` unchanged, `checkClaudeAuth` as the probe, the static
|
|
1387
|
-
* catalog for create forms. Exists so catalogs, capabilities and availability
|
|
1388
|
-
* have one shape across engines; the runner itself is exactly what
|
|
1389
|
-
* `registry.prepare()` builds.
|
|
1390
|
-
*/
|
|
1391
569
|
declare const claudeAdapter: EngineAdapter;
|
|
1392
570
|
//#endregion
|
|
1393
571
|
//#region src/engines/claude/catalog.d.ts
|
|
1394
|
-
/**
|
|
1395
|
-
* The Claude engine's model catalog — what a create form offers before any
|
|
1396
|
-
* session has run.
|
|
1397
|
-
*
|
|
1398
|
-
* **Refresh procedure** (release checklist): run `supportedModels()` on a
|
|
1399
|
-
* throwaway SDK query (no tokens spent) and re-apply the shaping rules of
|
|
1400
|
-
* `modelOptionsFromSdk` (`src/normalize.ts`) at authoring time: drop the
|
|
1401
|
-
* `default` sentinel row, derive display names from resolved ids where
|
|
1402
|
-
* unambiguous, mark the newest of each family `primary`, sort by family rank.
|
|
1403
|
-
* A unit test replays the raw extraction through `modelOptionsFromSdk` and
|
|
1404
|
-
* asserts these rows match, so the rules cannot drift.
|
|
1405
|
-
*
|
|
1406
|
-
* Two things the live `capabilities` event can never offer:
|
|
1407
|
-
* - rows for **older models** the CLI no longer reports (hand-maintained, the
|
|
1408
|
-
* accepted cost of a static catalog; the CLI silently downgrades an effort a
|
|
1409
|
-
* model doesn't support, so `reasoningEfforts` is omitted on them and the
|
|
1410
|
-
* engine default set applies);
|
|
1411
|
-
* - an answer on a **cold server**. The live event still exists and remains
|
|
1412
|
-
* the in-session truth for the model switcher; this catalog is the
|
|
1413
|
-
* create-form truth.
|
|
1414
|
-
*
|
|
1415
|
-
* `defaultModel` is deliberately NOT here: a claude profile's default is the
|
|
1416
|
-
* operator's CLI config, unknowable statically.
|
|
1417
|
-
*/
|
|
1418
572
|
declare const CLAUDE_CATALOG: ModelCatalog;
|
|
1419
573
|
//#endregion
|
|
1420
574
|
//#region src/engines/codex/types.d.ts
|
|
1421
|
-
/**
|
|
1422
|
-
* Structural mirror of the slice of the `codex app-server` JSON-RPC v2 surface
|
|
1423
|
-
* this engine consumes. Local on purpose: no published client for this
|
|
1424
|
-
* protocol exists, the shapes are regenerated from the binary itself
|
|
1425
|
-
* (`codex app-server generate-json-schema --out <dir>`, verified 2026-08-05
|
|
1426
|
-
* against 0.146.0), and every open-ended axis is a plain string so a newer
|
|
1427
|
-
* binary degrades to the unknown-item path instead of a type error.
|
|
1428
|
-
*
|
|
1429
|
-
* Naming note: the v2 surface is camelCase (`aggregatedOutput`, `exitCode`,
|
|
1430
|
-
* `localImage`) where `codex exec`'s JSONL — the retired first transport, and
|
|
1431
|
-
* what OpenAI's own docs mostly show — is snake_case. The two vocabularies
|
|
1432
|
-
* look alike but are not interchangeable.
|
|
1433
|
-
*/
|
|
1434
|
-
/** `TokenUsageBreakdown` — one entry of `thread/tokenUsage/updated`. OpenAI
|
|
1435
|
-
* accounting: `inputTokens` INCLUDES the cached share (the relation the
|
|
1436
|
-
* runner's subtraction assumes, asserted in `smoke:codex`). */
|
|
1437
575
|
type AppServerTokenUsage = {
|
|
1438
576
|
inputTokens: number;
|
|
1439
|
-
cachedInputTokens: number;
|
|
577
|
+
cachedInputTokens: number;
|
|
1440
578
|
cacheWriteInputTokens?: number;
|
|
1441
579
|
outputTokens: number;
|
|
1442
580
|
reasoningOutputTokens: number;
|
|
@@ -1447,8 +585,6 @@ type AppServerAgentMessageItem = {
|
|
|
1447
585
|
type: 'agentMessage';
|
|
1448
586
|
text: string;
|
|
1449
587
|
};
|
|
1450
|
-
/** `summary` is what streams by default (`item/reasoning/summaryTextDelta`);
|
|
1451
|
-
* `content` is raw CoT and only populated when the operator's config asks. */
|
|
1452
588
|
type AppServerReasoningItem = {
|
|
1453
589
|
id: string;
|
|
1454
590
|
type: 'reasoning';
|
|
@@ -1460,11 +596,9 @@ type AppServerCommandExecutionItem = {
|
|
|
1460
596
|
type: 'commandExecution';
|
|
1461
597
|
command: string;
|
|
1462
598
|
aggregatedOutput?: string;
|
|
1463
|
-
exitCode?: number | null;
|
|
599
|
+
exitCode?: number | null;
|
|
1464
600
|
status: string;
|
|
1465
601
|
};
|
|
1466
|
-
/** v2 `kind` is an object (`{type: 'add'|'delete'|'update', move_path?}`) —
|
|
1467
|
-
* the snake_case JSONL's was a bare string; mapped defensively. */
|
|
1468
602
|
type AppServerFileChangeItem = {
|
|
1469
603
|
id: string;
|
|
1470
604
|
type: 'fileChange';
|
|
@@ -1494,18 +628,6 @@ type AppServerWebSearchItem = {
|
|
|
1494
628
|
type: 'webSearch';
|
|
1495
629
|
query: string;
|
|
1496
630
|
};
|
|
1497
|
-
/**
|
|
1498
|
-
* A picture the model made with codex's built-in `image_gen` tool.
|
|
1499
|
-
*
|
|
1500
|
-
* `savedPath` is an absolute path on the **host** — by default under
|
|
1501
|
-
* `$CODEX_HOME/generated_images/`, or inside the workspace when the model was
|
|
1502
|
-
* told the asset belongs to the project. It is the only reference we get: the
|
|
1503
|
-
* app-server never sends the bytes, and neither do we (the event log carries
|
|
1504
|
-
* references, never base64 — see the protocol's note on attachments).
|
|
1505
|
-
*
|
|
1506
|
-
* `result` is an undocumented free-form string. Treated as untrusted length:
|
|
1507
|
-
* short values are shown, anything long enough to be an encoded image is not.
|
|
1508
|
-
*/
|
|
1509
631
|
type AppServerImageGenerationItem = {
|
|
1510
632
|
id: string;
|
|
1511
633
|
type: 'imageGeneration';
|
|
@@ -1514,37 +636,22 @@ type AppServerImageGenerationItem = {
|
|
|
1514
636
|
result: string;
|
|
1515
637
|
savedPath?: string;
|
|
1516
638
|
};
|
|
1517
|
-
/** The model *looked at* an image on disk (`path`, host-absolute). */
|
|
1518
639
|
type AppServerImageViewItem = {
|
|
1519
640
|
id: string;
|
|
1520
641
|
type: 'imageView';
|
|
1521
642
|
path: string;
|
|
1522
643
|
};
|
|
1523
|
-
/**
|
|
1524
|
-
* A sub-agent lifecycle edge, on the thread that OWNS the agent. The spawn
|
|
1525
|
-
* signal (verified live against 0.146.0, `_docs/codex-subagent-trace-fixed.jsonl`):
|
|
1526
|
-
* `kind: 'started'` announces a new agent, and `id` is the `call_id` of the
|
|
1527
|
-
* model's own `spawn_agent` function call — a genuine tool-use id, which is what
|
|
1528
|
-
* lets the runner hang the whole sidechain off it. There is **no 'completed'
|
|
1529
|
-
* kind**: an agent's end travels as its own thread's `turn/completed`.
|
|
1530
|
-
*/
|
|
1531
644
|
type AppServerSubAgentActivityItem = {
|
|
1532
645
|
id: string;
|
|
1533
|
-
type: 'subAgentActivity';
|
|
1534
|
-
kind: string;
|
|
1535
|
-
agentThreadId: string;
|
|
646
|
+
type: 'subAgentActivity';
|
|
647
|
+
kind: string;
|
|
648
|
+
agentThreadId: string;
|
|
1536
649
|
agentPath?: string | null;
|
|
1537
650
|
};
|
|
1538
|
-
/**
|
|
1539
|
-
* The model's collab-agent tool surface (`spawnAgent | sendInput | resumeAgent |
|
|
1540
|
-
* wait | closeAgent`). Decoration, not the design's load-bearing signal: on the
|
|
1541
|
-
* wire only `wait` has been observed, with every rich field empty — the spawn
|
|
1542
|
-
* truth is {@link AppServerSubAgentActivityItem} (same trace as above).
|
|
1543
|
-
*/
|
|
1544
651
|
type AppServerCollabAgentToolCallItem = {
|
|
1545
652
|
id: string;
|
|
1546
653
|
type: 'collabAgentToolCall';
|
|
1547
|
-
tool: string;
|
|
654
|
+
tool: string;
|
|
1548
655
|
status: string;
|
|
1549
656
|
senderThreadId?: string | null;
|
|
1550
657
|
receiverThreadIds?: string[] | null;
|
|
@@ -1553,58 +660,38 @@ type AppServerCollabAgentToolCallItem = {
|
|
|
1553
660
|
reasoningEffort?: string | null;
|
|
1554
661
|
agentsStates?: Record<string, unknown> | null;
|
|
1555
662
|
};
|
|
1556
|
-
/** The user's own message, echoed back as an item — dropped (the runner
|
|
1557
|
-
* already emitted its `user_message`). */
|
|
1558
663
|
type AppServerUserMessageItem = {
|
|
1559
664
|
id: string;
|
|
1560
665
|
type: 'userMessage';
|
|
1561
666
|
content?: unknown;
|
|
1562
667
|
};
|
|
1563
668
|
type AppServerItem = AppServerAgentMessageItem | AppServerReasoningItem | AppServerCommandExecutionItem | AppServerFileChangeItem | AppServerMcpToolCallItem | AppServerWebSearchItem | AppServerImageGenerationItem | AppServerImageViewItem | AppServerUserMessageItem | AppServerSubAgentActivityItem | AppServerCollabAgentToolCallItem;
|
|
1564
|
-
/** The `Turn` object of `turn/started` / `turn/completed`. On a completed turn
|
|
1565
|
-
* `items` is a summary page whose final `agentMessage` is the turn's answer —
|
|
1566
|
-
* for a sub-agent's thread, that is the agent's report. */
|
|
1567
669
|
type AppServerTurn = {
|
|
1568
|
-
id: string;
|
|
670
|
+
id: string;
|
|
1569
671
|
status: string;
|
|
1570
672
|
error?: {
|
|
1571
673
|
message: string;
|
|
1572
674
|
} | null;
|
|
1573
675
|
items?: AppServerItem[];
|
|
1574
676
|
};
|
|
1575
|
-
/**
|
|
1576
|
-
* One historical turn as `thread/resume` / `thread/read {includeTurns: true}`
|
|
1577
|
-
* return it: the same `ThreadItem` vocabulary the live `item/completed`
|
|
1578
|
-
* notifications carry (so the live mapping replays it unchanged), plus an
|
|
1579
|
-
* `itemsView` marker ('full' | 'summary' | 'notLoaded') saying how much of
|
|
1580
|
-
* `items` was actually loaded. Measured against 0.146.0: both surfaces return
|
|
1581
|
-
* 'full' items in chronological order.
|
|
1582
|
-
*/
|
|
1583
677
|
type AppServerHistoryTurn = {
|
|
1584
678
|
id: string;
|
|
1585
679
|
items?: AppServerItem[];
|
|
1586
680
|
itemsView?: string;
|
|
1587
681
|
status?: string;
|
|
1588
682
|
};
|
|
1589
|
-
/**
|
|
1590
|
-
* One `thread/list` row (the summary Thread shape — its `turns` is always
|
|
1591
|
-
* empty on list responses). Timestamps are epoch **seconds** (the protocol's
|
|
1592
|
-
* summaries want ms). `id` is what `CreateSessionRequest.resume` feeds
|
|
1593
|
-
* `thread/resume`; the row's separate `sessionId` field is not it.
|
|
1594
|
-
*/
|
|
1595
683
|
type AppServerThreadSummary = {
|
|
1596
|
-
id: string;
|
|
1597
|
-
name?: string | null;
|
|
684
|
+
id: string;
|
|
685
|
+
name?: string | null;
|
|
1598
686
|
preview?: string | null;
|
|
1599
687
|
createdAt?: number | null;
|
|
1600
688
|
updatedAt?: number | null;
|
|
1601
|
-
cwd?: string | null;
|
|
689
|
+
cwd?: string | null;
|
|
1602
690
|
ephemeral?: boolean;
|
|
1603
691
|
gitInfo?: {
|
|
1604
692
|
branch?: string | null;
|
|
1605
693
|
} | null;
|
|
1606
694
|
};
|
|
1607
|
-
/** `thread/list` result: one page plus an opaque continuation cursor. */
|
|
1608
695
|
type AppServerThreadListResponse = {
|
|
1609
696
|
data?: AppServerThreadSummary[];
|
|
1610
697
|
nextCursor?: string | null;
|
|
@@ -1616,57 +703,21 @@ type AppServerUserInput = {
|
|
|
1616
703
|
type: 'localImage';
|
|
1617
704
|
path: string;
|
|
1618
705
|
};
|
|
1619
|
-
/**
|
|
1620
|
-
* One live `codex app-server` child as the runner consumes it. The real
|
|
1621
|
-
* implementation (`process.ts`) spawns the binary and frames JSON-RPC
|
|
1622
|
-
* over its stdio; unit tests inject a scripted one — no process, no
|
|
1623
|
-
* credentials.
|
|
1624
|
-
*/
|
|
1625
706
|
type AppServerConnection = {
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
request(method: string, params?: unknown): Promise<unknown>; /** Client→server notification (fire and forget). */
|
|
1629
|
-
notify(method: string, params?: unknown): void; /** Server→client notifications. One handler (the runner). */
|
|
707
|
+
request(method: string, params?: unknown): Promise<unknown>;
|
|
708
|
+
notify(method: string, params?: unknown): void;
|
|
1630
709
|
onNotification(handler: (method: string, params: unknown) => void): void;
|
|
1631
|
-
/** Server→client REQUESTS (approvals live here): the handler's resolution is
|
|
1632
|
-
* sent back as the JSON-RPC result; a throw becomes an error response. `id`
|
|
1633
|
-
* is the wire request id — `serverRequest/resolved` names it when codex
|
|
1634
|
-
* settles a request on its own (auto-resolution), so the runner can retire
|
|
1635
|
-
* the matching pending approval instead of leaving a stale card. */
|
|
1636
710
|
onRequest(handler: (method: string, params: unknown, id: string | number) => Promise<unknown>): void;
|
|
1637
|
-
|
|
1638
|
-
* The message carries an exit summary and a stderr tail for diagnostics. */
|
|
1639
|
-
onClose(handler: (message: string) => void): void; /** Tear the child down (session close). Suppresses the onClose callback. */
|
|
711
|
+
onClose(handler: (message: string) => void): void;
|
|
1640
712
|
close(): void;
|
|
1641
713
|
};
|
|
1642
714
|
type AppServerConnectOptions = {
|
|
1643
|
-
/** Complete child environment — a provided spawn env replaces process.env,
|
|
1644
|
-
* never merges with it (CODEX_HOME pin already applied). */
|
|
1645
715
|
env: Record<string, string>;
|
|
1646
716
|
};
|
|
1647
|
-
/** The injectable connection factory: `connectAppServer` under the resolved
|
|
1648
|
-
* binary in production, a scripted peer in tests. */
|
|
1649
717
|
type AppServerConnectFn = (options: AppServerConnectOptions) => AppServerConnection;
|
|
1650
718
|
//#endregion
|
|
1651
719
|
//#region src/engines/codex/adapter.d.ts
|
|
1652
|
-
/**
|
|
1653
|
-
* The codex binary sessions will run: the per-platform package installed next
|
|
1654
|
-
* to `@openai/codex`, `vendor/<target-triple>/bin/codex` — the same file the
|
|
1655
|
-
* npm wrapper's own `bin/codex.js` launcher execs. Probing this binary rather
|
|
1656
|
-
* than whatever `codex` is on PATH means the availability answer is about the
|
|
1657
|
-
* executable sessions will actually run. Undefined when it can't be found;
|
|
1658
|
-
* callers degrade to 'unknown'.
|
|
1659
|
-
*/
|
|
1660
720
|
declare function resolveBundledCodexExecutable(): string | undefined;
|
|
1661
|
-
/**
|
|
1662
|
-
* CODEX_HOME's threads over ONE short-lived `codex app-server` child: the
|
|
1663
|
-
* runner's own handshake (`experimentalApi` and all — one code path, no
|
|
1664
|
-
* second vocabulary to drift), `thread/list` pages walked by cursor, child
|
|
1665
|
-
* closed before returning. Requires no live session and costs no tokens —
|
|
1666
|
-
* it is how "resume" is offered before anything is running. The `connectFn`
|
|
1667
|
-
* seam exists for the scripted-peer tests; the adapter passes the real
|
|
1668
|
-
* spawn.
|
|
1669
|
-
*/
|
|
1670
721
|
declare function listCodexSessions(options: {
|
|
1671
722
|
connectFn: AppServerConnectFn;
|
|
1672
723
|
profile?: ProfileInfo;
|
|
@@ -1675,26 +726,24 @@ declare function listCodexSessions(options: {
|
|
|
1675
726
|
limit?: number;
|
|
1676
727
|
offset?: number;
|
|
1677
728
|
}): Promise<SdkSessionSummary[]>;
|
|
1678
|
-
/**
|
|
1679
|
-
* OpenAI Codex as an engine: the codex CLI binary driven over its `app-server`
|
|
1680
|
-
* JSON-RPC surface — structurally the Claude engine's sibling (a local agent
|
|
1681
|
-
* binary with sessions, sandboxing and resume, resolving its own credentials
|
|
1682
|
-
* from the operator's environment). `@openai/codex` — the npm package that
|
|
1683
|
-
* carries the binary — is an **optional peer**: absent, every codex profile
|
|
1684
|
-
* reports unavailable and createRunner throws the same message, and no
|
|
1685
|
-
* consumer downloads a ~40 MB per-platform binary it never uses.
|
|
1686
|
-
*/
|
|
1687
729
|
declare const codexAdapter: EngineAdapter;
|
|
1688
730
|
//#endregion
|
|
1689
731
|
//#region src/engines/codex/catalog.d.ts
|
|
1690
732
|
/**
|
|
1691
|
-
* The Codex engine's model catalog, seeded from the binary's own embedded
|
|
1692
|
-
*
|
|
1693
|
-
*
|
|
1694
|
-
*
|
|
1695
|
-
*
|
|
1696
|
-
*
|
|
1697
|
-
*
|
|
733
|
+
* The Codex engine's model catalog, seeded from the binary's own embedded model
|
|
734
|
+
* table (see `provenance` for the version) — that table, not the SDK's stale
|
|
735
|
+
* `ModelReasoningEffort` union, is the truth about which reasoning efforts each
|
|
736
|
+
* model takes. Mapping decisions: the internal `codex-auto-review` row is dropped
|
|
737
|
+
* (the codex analogue of the CLI's `default` sentinel), `primary` mirrors the
|
|
738
|
+
* binary's own `visibility` field so both UIs group the way codex's picker does,
|
|
739
|
+
* and `reasoningEfforts` carries `supported_reasoning_levels` verbatim — `max`
|
|
740
|
+
* and `ultra` go beyond the SDK union, so trust the binary and keep strings open.
|
|
741
|
+
*
|
|
742
|
+
* **Refresh procedure** (release checklist): extract the embedded JSON from the
|
|
743
|
+
* platform binary and diff. The two-hop resolve is NOT optional — under pnpm's
|
|
744
|
+
* strict layout the platform package is a dependency of `@openai/codex` and
|
|
745
|
+
* resolves only from that wrapper's location (MODULE_NOT_FOUND otherwise), the
|
|
746
|
+
* same two hops `resolveBundledCodexExecutable` makes.
|
|
1698
747
|
*
|
|
1699
748
|
* node -e 'const d=require("fs").readFileSync(process.argv[1]);
|
|
1700
749
|
* const s=d.indexOf(`{\n "models": [`);
|
|
@@ -1706,55 +755,17 @@ declare const codexAdapter: EngineAdapter;
|
|
|
1706
755
|
* const w=require.resolve("@openai/codex/package.json");
|
|
1707
756
|
* createRequire(w).resolve("@openai/codex-darwin-arm64/package.json")
|
|
1708
757
|
* .replace("package.json","vendor/aarch64-apple-darwin/bin/codex")')"
|
|
1709
|
-
*
|
|
1710
|
-
* The two-hop resolve is NOT optional: under pnpm's strict layout the platform
|
|
1711
|
-
* package is a dependency of `@openai/codex`, so it resolves only from that
|
|
1712
|
-
* wrapper's location, never from the repo root. Resolving it directly throws
|
|
1713
|
-
* MODULE_NOT_FOUND — the same two hops `resolveBundledCodexExecutable` makes.
|
|
1714
|
-
*
|
|
1715
|
-
* Mapping decisions:
|
|
1716
|
-
* - the internal `codex-auto-review` row is dropped (the codex analogue of
|
|
1717
|
-
* dropping the CLI's `default` sentinel);
|
|
1718
|
-
* - `primary` mirrors the binary's own `visibility` field ('list' = shown in
|
|
1719
|
-
* its picker, 'hide' = its "older models"), so both UIs group the way
|
|
1720
|
-
* codex's own picker does;
|
|
1721
|
-
* - `reasoningEfforts` carries `supported_reasoning_levels` verbatim — note
|
|
1722
|
-
* `max`/`ultra` beyond the SDK union; trust the binary, keep strings open.
|
|
1723
758
|
*/
|
|
1724
759
|
declare const CODEX_CATALOG: ModelCatalog;
|
|
1725
760
|
//#endregion
|
|
1726
761
|
//#region src/engines/codex/runner.d.ts
|
|
1727
762
|
type CodexRunnerConfig = CreateSessionRequest & {
|
|
1728
|
-
/** The injectable connection factory. The codex adapter passes
|
|
1729
|
-
* `connectAppServer` under the resolved binary; unit tests pass a scripted
|
|
1730
|
-
* peer. Required — this class never spawns anything itself. */
|
|
1731
763
|
connectFn: AppServerConnectFn;
|
|
1732
|
-
|
|
1733
|
-
* spawn **complete** — a child env replaces, never merges. */
|
|
1734
|
-
env?: Record<string, string | undefined>; /** CODEX_HOME pin from the profile (auth, config.toml, thread storage). */
|
|
764
|
+
env?: Record<string, string | undefined>;
|
|
1735
765
|
codexHome?: string;
|
|
1736
|
-
/** Timeout for pending approvals when the request itself doesn't set one.
|
|
1737
|
-
* Default 300000 — the SessionRunner default. */
|
|
1738
766
|
defaultApprovalTimeoutMs?: number;
|
|
1739
|
-
/** With `resume`: replay the thread's prior turns as `replay: true` events
|
|
1740
|
-
* before anything else, so late-attaching clients get a full transcript —
|
|
1741
|
-
* the SessionRunner option, same name, same default (true). */
|
|
1742
767
|
backfillHistory?: boolean;
|
|
1743
768
|
};
|
|
1744
|
-
/**
|
|
1745
|
-
* The Codex engine, over the binary's `app-server` JSON-RPC surface: ONE
|
|
1746
|
-
* `codex app-server` child per *session* (spawned lazily, held across turns),
|
|
1747
|
-
* streaming `item/agentMessage/delta` and the reasoning deltas token-by-token
|
|
1748
|
-
* (`streaming: 'token'`). Follows `SessionRunner`'s event-log/seq/status
|
|
1749
|
-
* discipline with `AiSdkRunner`'s turn-chain (one turn at a time; sendMessage
|
|
1750
|
-
* queues). The first codex transport was `codex exec --experimental-json` (one
|
|
1751
|
-
* child per turn) — retired because its JSONL carries no partial messages, so
|
|
1752
|
-
* a turn could never stream.
|
|
1753
|
-
*
|
|
1754
|
-
* A dead child is a failed *turn*, not a failed session: the thread persists
|
|
1755
|
-
* on disk, the connection is dropped, and the next message spawns a fresh
|
|
1756
|
-
* child that `thread/resume`s the same thread id.
|
|
1757
|
-
*/
|
|
1758
769
|
declare class CodexRunner implements Runner {
|
|
1759
770
|
#private;
|
|
1760
771
|
readonly id: string;
|
|
@@ -1765,119 +776,32 @@ declare class CodexRunner implements Runner {
|
|
|
1765
776
|
get lastSeq(): number;
|
|
1766
777
|
get pendingApprovals(): PermissionRequest[];
|
|
1767
778
|
info(): SessionInfo;
|
|
1768
|
-
/** Host-facing rename: writes `meta.title`, which `#title()` prefers. Clearing
|
|
1769
|
-
* it (undefined) restores the derived title. The engine is never told. */
|
|
1770
779
|
setTitle(title: string | undefined): void;
|
|
1771
780
|
start(): Promise<void>;
|
|
1772
781
|
sendMessage(text: string, attachments?: readonly AttachmentInput[]): void;
|
|
1773
|
-
/** Resolve a pending approval. Returns false if the id is unknown (e.g.
|
|
1774
|
-
* timed out, or already settled by codex itself). */
|
|
1775
782
|
resolvePermission(requestId: string, decision: PermissionDecision): boolean;
|
|
1776
783
|
interrupt(): Promise<void>;
|
|
1777
|
-
/**
|
|
1778
|
-
* Reset the conversation: a **fresh thread on the same session**.
|
|
1779
|
-
*
|
|
1780
|
-
* Codex has no clear/reset RPC — `thread/compact/start` summarises and
|
|
1781
|
-
* continues, `thread/fork` makes a second thread, and neither is "same
|
|
1782
|
-
* session, empty context". So the analog is to stop resuming the old thread
|
|
1783
|
-
* and start a new one, which is the path a dead child already takes minus the
|
|
1784
|
-
* resume. The old thread is NOT deleted: it stays in CODEX_HOME and stays
|
|
1785
|
-
* resumable from `GET /sdk-sessions`.
|
|
1786
|
-
*
|
|
1787
|
-
* Two things it does on the way through, both mirroring the Claude engine's
|
|
1788
|
-
* SDK-driven reset (`engines/claude/runner.ts`):
|
|
1789
|
-
*
|
|
1790
|
-
* 1. **The new thread id is adopted before `conversation_reset` is emitted**,
|
|
1791
|
-
* whenever a child is already up — the eager `thread/start` costs no
|
|
1792
|
-
* tokens and no model call, and it is what keeps the dormant record from
|
|
1793
|
-
* ever naming the conversation that was just cleared. With no child there
|
|
1794
|
-
* is nothing to start against and the id is simply dropped; the parking
|
|
1795
|
-
* service treats a resumable session with no engine session id as one with
|
|
1796
|
-
* nothing to come back to, and forgets the stale record.
|
|
1797
|
-
* 2. **The context reading is retired**, in `#emit`'s `conversation_reset`
|
|
1798
|
-
* arm. Codex cannot re-poll it the way Claude does — the only source is
|
|
1799
|
-
* `thread/tokenUsage/updated`, which arrives *during* a turn — so there is
|
|
1800
|
-
* no reading at all until the next turn runs, and the protocol's rule
|
|
1801
|
-
* applies: render nothing rather than a stale ring or a 0%.
|
|
1802
|
-
*
|
|
1803
|
-
* The turn counter stays monotonic across this, on purpose (it is an unread
|
|
1804
|
-
* cursor, not an item count), and so does `activityCount` — `#emit` owns both.
|
|
1805
|
-
*/
|
|
1806
784
|
clearContext(): Promise<void>;
|
|
1807
785
|
setPermissionMode(mode: PermissionMode): Promise<void>;
|
|
1808
786
|
setModel(model?: string): Promise<void>;
|
|
1809
787
|
fail(message: string): void;
|
|
1810
788
|
close(reason?: 'client' | 'server' | 'error'): void;
|
|
1811
|
-
/** See `Runner.eventAt`. A linear scan: the one caller is a reader pressing
|
|
1812
|
-
* "show everything" on one row, so a per-runner seq index would be a map
|
|
1813
|
-
* maintained on every emit to save a walk nobody makes twice a minute. */
|
|
1814
789
|
eventAt(seq: number): SessionEvent | undefined;
|
|
1815
790
|
subscribe(listener: SessionEventListener, afterSeq?: number, options?: SubscribeOptions): () => void;
|
|
1816
|
-
/**
|
|
1817
|
-
* The session's MCP servers, live from the binary.
|
|
1818
|
-
*
|
|
1819
|
-
* Two sources merged, because codex splits them: `mcpServerStatus/list` says
|
|
1820
|
-
* what is configured and what each server exposes (including every tool's
|
|
1821
|
-
* full JSON Schema, which the Agent SDK does not give us), and the
|
|
1822
|
-
* `mcpServer/startupStatus/updated` notifications say which of them are
|
|
1823
|
-
* actually up.
|
|
1824
|
-
*
|
|
1825
|
-
* Answers **before the session has connected**, over a throwaway child, for
|
|
1826
|
-
* the same reason the skill list does: a codex session spawns nothing until
|
|
1827
|
-
* it has work, and a panel that said "no MCP servers configured" until the
|
|
1828
|
-
* first turn would be stating something false about the operator's config.
|
|
1829
|
-
* The request blocks until the servers are enumerated (measured: complete on
|
|
1830
|
-
* the very first call), so there is no half-populated answer to race.
|
|
1831
|
-
*
|
|
1832
|
-
* Resolves undefined only when there is genuinely nothing to say — the
|
|
1833
|
-
* session is closed, or the child could not be spoken to. The route turns
|
|
1834
|
-
* that into a 501.
|
|
1835
|
-
*
|
|
1836
|
-
* **Listing only.** There is no per-server reconnect or toggle on this
|
|
1837
|
-
* transport — hence no `reconnectMcpServer`/`setMcpServerEnabled` here, and
|
|
1838
|
-
* `ENGINE_CAPABILITIES.codex.mcpServerActions: false` so clients render the
|
|
1839
|
-
* panel read-only instead of offering buttons that cannot work.
|
|
1840
|
-
*/
|
|
1841
791
|
mcpServers(): Promise<McpServerStatusInfo[] | undefined>;
|
|
1842
792
|
}
|
|
1843
793
|
//#endregion
|
|
1844
794
|
//#region src/engines/codex/process.d.ts
|
|
1845
|
-
/**
|
|
1846
|
-
* Spawn one `codex app-server` child and frame JSON-RPC over its stdio — the
|
|
1847
|
-
* real {@link AppServerConnectFn}. The child's env is passed **complete**
|
|
1848
|
-
* (a provided spawn env replaces process.env, never merges with it), with the
|
|
1849
|
-
* profile's CODEX_HOME pin already applied by the runner.
|
|
1850
|
-
*
|
|
1851
|
-
* No spawn cwd: the working directory is a thread/turn parameter, and a cwd
|
|
1852
|
-
* that doesn't exist should fail the *turn* with codex's own error, not the
|
|
1853
|
-
* spawn.
|
|
1854
|
-
*/
|
|
1855
795
|
declare function connectAppServer(options: {
|
|
1856
796
|
executable: string;
|
|
1857
797
|
env: Record<string, string>;
|
|
1858
798
|
}): AppServerConnection;
|
|
1859
799
|
//#endregion
|
|
1860
800
|
//#region src/engines/codex/jsonrpc.d.ts
|
|
1861
|
-
/**
|
|
1862
|
-
* A JSON-RPC error response from the peer, or one we return to it. `code`
|
|
1863
|
-
* follows the JSON-RPC 2.0 reserved ranges (-32601 = method not found).
|
|
1864
|
-
*/
|
|
1865
801
|
declare class JsonRpcError extends Error {
|
|
1866
802
|
readonly code: number;
|
|
1867
803
|
constructor(code: number, message: string);
|
|
1868
804
|
}
|
|
1869
|
-
/**
|
|
1870
|
-
* JSON-RPC over a `codex app-server` child's stdio: **newline-delimited JSON**,
|
|
1871
|
-
* one message per line, and — verified against 0.146.0 — an envelope *without*
|
|
1872
|
-
* the `jsonrpc: "2.0"` field (`{id, method, params}` / `{id, result}` /
|
|
1873
|
-
* `{id, error}`; the binary's own schema marks only those required). Server→
|
|
1874
|
-
* client notifications additionally carry a top-level `emittedAtMs`, ignored
|
|
1875
|
-
* here.
|
|
1876
|
-
*
|
|
1877
|
-
* Transport only: no method knowledge, no process ownership. The process
|
|
1878
|
-
* wrapper (`process.ts`) owns the child and calls {@link fail} when it dies so
|
|
1879
|
-
* every in-flight request rejects instead of hanging.
|
|
1880
|
-
*/
|
|
1881
805
|
declare class JsonRpcStdioConnection {
|
|
1882
806
|
#private;
|
|
1883
807
|
constructor(options: {
|
|
@@ -1888,23 +812,10 @@ declare class JsonRpcStdioConnection {
|
|
|
1888
812
|
notify(method: string, params?: unknown): void;
|
|
1889
813
|
onNotification(handler: (method: string, params: unknown) => void): void;
|
|
1890
814
|
onRequest(handler: (method: string, params: unknown, id: string | number) => Promise<unknown>): void;
|
|
1891
|
-
/** Reject everything in flight and refuse new traffic — the child is gone
|
|
1892
|
-
* (or the session is over). Idempotent. */
|
|
1893
815
|
fail(message: string): void;
|
|
1894
816
|
}
|
|
1895
817
|
//#endregion
|
|
1896
818
|
//#region src/engines/provider/adapter.d.ts
|
|
1897
|
-
/**
|
|
1898
|
-
* The model-agnostic provider engine as a pseudo-adapter: capabilities and an
|
|
1899
|
-
* env-var probe live here, but its runners are assembled by the host's
|
|
1900
|
-
* `createEngineRunner` hook (which is where provider credentials are resolved
|
|
1901
|
-
* and model SDKs are imported — neither belongs in this repo's import graph).
|
|
1902
|
-
* The server routes provider creates to the hook; `createRunner` here throws
|
|
1903
|
-
* so a mis-routed call fails loudly instead of quietly building nothing.
|
|
1904
|
-
*
|
|
1905
|
-
* The catalog is empty by the same token: provider model ids are operator-
|
|
1906
|
-
* declared per profile (`provider.models`), not shipped with releases.
|
|
1907
|
-
*/
|
|
1908
819
|
declare const providerAdapter: EngineAdapter;
|
|
1909
820
|
//#endregion
|
|
1910
821
|
export { AiSdkRunner, type AiSdkRunnerConfig, type AiSdkSessionState, type AppServerConnectFn, type AppServerConnectOptions, type AppServerConnection, type AppServerHistoryTurn, type AppServerItem, type AppServerThreadListResponse, type AppServerThreadSummary, type AppServerTokenUsage, type AppServerTurn, type AppServerUserInput, type AttachmentInput, type AttachmentKind, type BridgeAnswer, BrowserBridgeExecutor, type BrowserBridgeExecutorOptions, CLAUDE_CATALOG, CODEX_CATALOG, type ClaudeAuthProbe, type ClaudeAuthStatus, CodexRunner, type CodexRunnerConfig, type DeferredDispatch, DeferredExecutor, type DeferredExecutorOptions, type EngineAdapter, type EngineAvailability, type EngineRunnerRequest, type EngineSessionOptions, type HistoryFn, type HostFetch, type HostToolDefinition, InputQueue, JsonRpcError, JsonRpcStdioConnection, type LanguageModel, type McpConnection, type ModelCatalog, type ParkedExecution, type PendingEntry, type PendingKind, type PendingOutcome, PendingRequestRegistry, type PendingToolCall, type PermissionDecision, type QueryFn, QuickJsExecutor, type QuickJsExecutorOptions, type RegisterOptions, type Runner, type RunnerSnapshot, SUPPORTED_ATTACHMENT_TYPES, type SessionEventListener, SessionRunner, type SessionRunnerConfig, type SettledBy, type Tool, type ToolCallOutput, type ToolContext, type ToolContextOptions, type ToolDefinition, type ToolExecutionCall, type ToolExecutionDispatch, type ToolExecutionResult, type ToolExecutor, type ToolSet, type ToolTrust, type WebFetchDigest, type WebFetchFn, type WebFetchOptions, type WebFetchResult, attachmentContentBlocks, attachmentKind, attachmentRef, checkClaudeAuth, claudeAdapter, codexAdapter, connectAppServer, connectMcpTools, createEngineSession, createToolContext, createWebFetch, getEngineAdapter, htmlToMarkdown, isHostAllowed, isPrivateAddress, listCodexSessions, mcpStatusInfo, modelOptionsFromSdk, normalizeMediaType, normalizeSdkMessage, providerAdapter, replaySlice, resolveBundledClaudeExecutable, resolveBundledCodexExecutable, toApiMessage, toExecutionResult, truncateResultBlocks, withHostTools, withMcpTools };
|