zidane 4.1.8 → 5.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/README.md +11 -2
- package/dist/{index-bgh-k8Mv.d.ts → agent-JhicgLOV.d.ts} +2082 -1969
- package/dist/agent-JhicgLOV.d.ts.map +1 -0
- package/dist/chat.d.ts +340 -9
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +2 -2
- package/dist/contexts.d.ts +1 -1
- package/dist/{index-DRoG_udt.d.ts → index-2yLUyTbc.d.ts} +34 -4
- package/dist/{index-DRoG_udt.d.ts.map → index-2yLUyTbc.d.ts.map} +1 -1
- package/dist/{index-BB4kuRh3.d.ts → index-CXVvqTQj.d.ts} +1 -1
- package/dist/{index-BB4kuRh3.d.ts.map → index-CXVvqTQj.d.ts.map} +1 -1
- package/dist/{index-Ds5YpvfZ.d.ts → index-t_W9i7Ql.d.ts} +9 -4
- package/dist/index-t_W9i7Ql.d.ts.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +6 -6
- package/dist/{interpolate-CukJwP2G.js → interpolate-Ck970-61.js} +11 -2
- package/dist/interpolate-Ck970-61.js.map +1 -0
- package/dist/{mcp-8wClKY-3.js → mcp-Dw-fRPVk.js} +61 -65
- package/dist/mcp-Dw-fRPVk.js.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/presets-BRFH2qsQ.js +90 -0
- package/dist/presets-BRFH2qsQ.js.map +1 -0
- package/dist/presets.d.ts +3 -2
- package/dist/presets.js +2 -2
- package/dist/providers.d.ts +1 -1
- package/dist/session/sqlite.d.ts +13 -2
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +96 -38
- package/dist/session/sqlite.js.map +1 -1
- package/dist/{session-Cn68UASv.js → session-791hhrFa.js} +65 -30
- package/dist/session-791hhrFa.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +1 -1
- package/dist/skills.d.ts +2 -2
- package/dist/skills.js +1 -1
- package/dist/{stats-BT9l57RS.js → stats-DZIsGqzu.js} +15 -5
- package/dist/stats-DZIsGqzu.js.map +1 -0
- package/dist/theme-pJv47erq.d.ts +1202 -0
- package/dist/theme-pJv47erq.d.ts.map +1 -0
- package/dist/{tools-C8kDot0H.js → tools-CLazLRb4.js} +475 -318
- package/dist/tools-CLazLRb4.js.map +1 -0
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +1 -1
- package/dist/tui.d.ts +303 -18
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +3305 -509
- package/dist/tui.js.map +1 -1
- package/dist/turn-operations-5aQu4dJg.js +3587 -0
- package/dist/turn-operations-5aQu4dJg.js.map +1 -0
- package/dist/types.d.ts +3 -3
- package/dist/types.js +1 -1
- package/package.json +6 -1
- package/dist/index-Ds5YpvfZ.d.ts.map +0 -1
- package/dist/index-bgh-k8Mv.d.ts.map +0 -1
- package/dist/interpolate-CukJwP2G.js.map +0 -1
- package/dist/mcp-8wClKY-3.js.map +0 -1
- package/dist/presets-BzkJDW1K.js +0 -39
- package/dist/presets-BzkJDW1K.js.map +0 -1
- package/dist/session-Cn68UASv.js.map +0 -1
- package/dist/stats-BT9l57RS.js.map +0 -1
- package/dist/theme-BlXO6yHe.d.ts +0 -503
- package/dist/theme-BlXO6yHe.d.ts.map +0 -1
- package/dist/theme-context-MungM3SY.js +0 -1713
- package/dist/theme-context-MungM3SY.js.map +0 -1
- package/dist/tools-C8kDot0H.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as ExecutionContext, l as ExecutionHandle } from "./index-
|
|
1
|
+
import { c as ExecutionContext, l as ExecutionHandle } from "./index-CXVvqTQj.js";
|
|
2
2
|
import { Hookable } from "hookable";
|
|
3
3
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
4
4
|
//#region src/errors.d.ts
|
|
@@ -117,2257 +117,2370 @@ declare function matchesContextExceeded(message: unknown): boolean;
|
|
|
117
117
|
*/
|
|
118
118
|
declare function toTypedError(classification: ClassifiedError, provider: string, cause: unknown): AgentContextExceededError | AgentProviderError | AgentAbortedError;
|
|
119
119
|
//#endregion
|
|
120
|
-
//#region src/
|
|
121
|
-
interface McpConnection {
|
|
122
|
-
tools: Record<string, ToolDef>;
|
|
123
|
-
close: () => Promise<void>;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Normalize MCP server configs from any common shape to `McpServerConfig[]`.
|
|
127
|
-
*
|
|
128
|
-
* Accepts:
|
|
129
|
-
* - `McpServerConfig[]` — zidane native (pass-through).
|
|
130
|
-
* - `McpServerConfig` — a single config object (wrapped to a 1-element array).
|
|
131
|
-
* - `Record<string, RawShape>` — name-keyed map (common in host-SDK configs), where the key is the server name.
|
|
132
|
-
* - Mixed shapes with `type` vs `transport`, `httpUrl`/`sseUrl` vs `url`.
|
|
133
|
-
*
|
|
134
|
-
* Returns `[]` when `input` is nullish. Throws a descriptive error when the transport
|
|
135
|
-
* cannot be inferred from a given entry, or when the input shape is unsupported.
|
|
136
|
-
*/
|
|
137
|
-
declare function normalizeMcpServers(input: unknown): McpServerConfig[];
|
|
138
|
-
/**
|
|
139
|
-
* Lossy flattener — converts MCP `CallToolResult.content` blocks to a single
|
|
140
|
-
* string. Text blocks are extracted; non-text blocks are JSON-stringified.
|
|
141
|
-
*
|
|
142
|
-
* Use this only at UI / log boundaries that require a string. The agent
|
|
143
|
-
* loop itself routes through {@link normalizeMcpBlocks} so image blocks
|
|
144
|
-
* survive into provider-native tool_result content (Anthropic blocks,
|
|
145
|
-
* OpenAI companion-user-message).
|
|
146
|
-
*/
|
|
147
|
-
declare function resultToString(content: unknown[]): string;
|
|
148
|
-
/**
|
|
149
|
-
* Normalize MCP `CallToolResult.content` to zidane's {@link ToolResultContent[]} shape.
|
|
150
|
-
*
|
|
151
|
-
* Handles the four MCP content block types:
|
|
152
|
-
* - `text` → preserved as `{type:'text', text}`
|
|
153
|
-
* - `image` → preserved as `{type:'image', mediaType, data}` (MCP uses `mimeType`)
|
|
154
|
-
* - `resource` with embedded text → flattened to a text block
|
|
155
|
-
* - `resource` with embedded blob whose `mimeType` is `image/*` → flattened to an image block
|
|
156
|
-
* - Any unrecognized block → JSON-stringified fallback text block (lossy but safe)
|
|
157
|
-
*
|
|
158
|
-
* Returns `null` when the input is not an array — callers should fall back to an empty
|
|
159
|
-
* result in that case.
|
|
160
|
-
*/
|
|
161
|
-
declare function normalizeMcpBlocks(content: unknown): ToolResultContent[] | null;
|
|
162
|
-
/**
|
|
163
|
-
* Connect to MCP servers and discover their tools.
|
|
164
|
-
*
|
|
165
|
-
* Each tool is namespaced as `mcp_{serverName}_{toolName}` to avoid
|
|
166
|
-
* collisions with agent tools or tools from other servers.
|
|
167
|
-
*
|
|
168
|
-
* @param configs - Array of MCP server configurations
|
|
169
|
-
* @param _clientFactory - Internal: override client construction for testing
|
|
170
|
-
* @param hooks - Optional agent hooks for firing mcp:connect, mcp:error, mcp:close events
|
|
171
|
-
*/
|
|
172
|
-
declare function connectMcpServers(configs: McpServerConfig[], _clientFactory?: () => Client, hooks?: Hookable<AgentHooks>): Promise<McpConnection>;
|
|
173
|
-
//#endregion
|
|
174
|
-
//#region src/session/file-map.d.ts
|
|
175
|
-
/**
|
|
176
|
-
* Host-provided file-map adapter. Three methods exchanging `Record<string, string>`
|
|
177
|
-
* payloads — the whole persistence surface the wrapper needs.
|
|
178
|
-
*/
|
|
179
|
-
interface FileMapAdapter {
|
|
180
|
-
/** Load the current file map. Returns an empty `files` record when nothing is persisted. */
|
|
181
|
-
get: () => Promise<{
|
|
182
|
-
files: Record<string, string>;
|
|
183
|
-
}>;
|
|
184
|
-
/** Replace the persisted file map. Full-rewrite semantics. */
|
|
185
|
-
save: (files: Record<string, string>) => Promise<void>;
|
|
186
|
-
/** Delete all persisted state. */
|
|
187
|
-
delete: () => Promise<void>;
|
|
188
|
-
}
|
|
189
|
-
interface FileMapStoreOptions {
|
|
190
|
-
/** Filename for the JSONL turns log. Default: `turns.jsonl`. */
|
|
191
|
-
turnsFile?: string;
|
|
192
|
-
/** Filename for the metadata JSON. Default: `meta.json`. */
|
|
193
|
-
metaFile?: string;
|
|
194
|
-
}
|
|
120
|
+
//#region src/types.d.ts
|
|
195
121
|
/**
|
|
196
|
-
*
|
|
122
|
+
* Thinking / extended-reasoning configuration.
|
|
197
123
|
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
124
|
+
* - `'off'` — no thinking.
|
|
125
|
+
* - `'minimal' | 'low' | 'medium' | 'high'` — explicit token budget. Maps to
|
|
126
|
+
* provider-specific reasoning controls (Anthropic `thinking.type='enabled'`
|
|
127
|
+
* with a budget; OpenAI `reasoning_effort`).
|
|
128
|
+
* - `'adaptive'` — let the model decide per-turn whether and how much to think.
|
|
129
|
+
* Anthropic-only (`thinking.type='adaptive'`). Other providers fall back to
|
|
130
|
+
* no reasoning when this value is supplied.
|
|
204
131
|
*/
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
declare function fromOpenAI(msg: {
|
|
216
|
-
role: string;
|
|
217
|
-
content: unknown;
|
|
218
|
-
}): SessionMessage;
|
|
219
|
-
declare function toAnthropic(msg: SessionMessage): {
|
|
220
|
-
role: string;
|
|
221
|
-
content: unknown;
|
|
222
|
-
};
|
|
223
|
-
declare function toOpenAI(msg: SessionMessage): {
|
|
224
|
-
role: string;
|
|
225
|
-
content: unknown;
|
|
226
|
-
};
|
|
227
|
-
declare function autoDetectAndConvert(msg: {
|
|
228
|
-
role: string;
|
|
229
|
-
content: unknown;
|
|
230
|
-
}): SessionMessage;
|
|
231
|
-
//#endregion
|
|
232
|
-
//#region src/session/remote.d.ts
|
|
233
|
-
interface RemoteStoreOptions {
|
|
234
|
-
/** Base URL of the session API */
|
|
235
|
-
url: string;
|
|
236
|
-
/** Optional headers (e.g. for authentication) */
|
|
237
|
-
headers?: Record<string, string>;
|
|
238
|
-
}
|
|
239
|
-
declare function createRemoteStore(options: RemoteStoreOptions): SessionStore;
|
|
240
|
-
//#endregion
|
|
241
|
-
//#region src/session/index.d.ts
|
|
242
|
-
interface SessionRun {
|
|
243
|
-
id: string;
|
|
244
|
-
startedAt: number;
|
|
245
|
-
endedAt?: number;
|
|
246
|
-
prompt: string;
|
|
247
|
-
status: 'running' | 'completed' | 'aborted' | 'error';
|
|
248
|
-
turns?: number;
|
|
249
|
-
tokensIn?: number;
|
|
250
|
-
tokensOut?: number;
|
|
251
|
-
error?: string;
|
|
252
|
-
/** Per-turn usage breakdown */
|
|
253
|
-
turnUsage?: TurnUsage[];
|
|
254
|
-
/** Total usage across all turns */
|
|
255
|
-
totalUsage?: TurnUsage;
|
|
256
|
-
/** Estimated cost in USD */
|
|
257
|
-
cost?: number;
|
|
132
|
+
type ThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'adaptive';
|
|
133
|
+
interface McpServerConfig {
|
|
134
|
+
/** Display name (used for tool namespacing) */
|
|
135
|
+
name: string;
|
|
136
|
+
/** Transport type */
|
|
137
|
+
transport: 'stdio' | 'sse' | 'streamable-http';
|
|
138
|
+
/** For stdio: command to run */
|
|
139
|
+
command?: string;
|
|
140
|
+
/** For stdio: command arguments */
|
|
141
|
+
args?: string[];
|
|
258
142
|
/**
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
143
|
+
* For stdio: environment variables to pass to the server process.
|
|
144
|
+
*
|
|
145
|
+
* Merged on top of the MCP SDK's default inherited environment — a safety
|
|
146
|
+
* whitelist (`PATH`, `HOME`, `LANG`, `SHELL`, `USER` on POSIX; `APPDATA`,
|
|
147
|
+
* `PATH`, ... on Win32). Setting this to `{}` no longer strips `PATH` from
|
|
148
|
+
* the child process. Set {@link McpServerConfig.strictEnv} to `true` to
|
|
149
|
+
* pass `env` verbatim with no inherited defaults.
|
|
262
150
|
*/
|
|
263
|
-
|
|
151
|
+
env?: Record<string, string>;
|
|
264
152
|
/**
|
|
265
|
-
*
|
|
266
|
-
*
|
|
153
|
+
* When true, {@link McpServerConfig.env} is passed verbatim to the spawned
|
|
154
|
+
* process — the MCP SDK's default inherited environment (`PATH`, `HOME`, ...)
|
|
155
|
+
* is NOT merged in. Most consumers should leave this off; the default merge
|
|
156
|
+
* prevents `spawn ENOENT` when a stdio server declares an `env` without
|
|
157
|
+
* restating `PATH`.
|
|
267
158
|
*/
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
turns: SessionTurn[];
|
|
274
|
-
runs: SessionRun[];
|
|
275
|
-
status: 'idle' | 'running' | 'completed' | 'error';
|
|
276
|
-
metadata: Record<string, unknown>;
|
|
277
|
-
createdAt: number;
|
|
278
|
-
updatedAt: number;
|
|
279
|
-
}
|
|
280
|
-
interface SessionStore {
|
|
281
|
-
/** Optional: generate a session ID server-side (e.g. Supabase UUID). */
|
|
282
|
-
generateSessionId?: () => string | Promise<string>;
|
|
283
|
-
/** Optional: generate a turn ID server-side. */
|
|
284
|
-
generateTurnId?: () => string | Promise<string>;
|
|
285
|
-
/** Load a session by ID. Returns null if not found. */
|
|
286
|
-
load: (sessionId: string) => Promise<SessionData | null>;
|
|
287
|
-
/** Save a session (create or update, full document). */
|
|
288
|
-
save: (session: SessionData) => Promise<void>;
|
|
289
|
-
/** Delete a session. */
|
|
290
|
-
delete: (sessionId: string) => Promise<void>;
|
|
291
|
-
/** List session IDs, optionally filtered. */
|
|
292
|
-
list: (filter?: {
|
|
293
|
-
agentId?: string;
|
|
294
|
-
limit?: number;
|
|
295
|
-
}) => Promise<string[]>;
|
|
296
|
-
/** Append new turns to a session (incremental, avoids full re-save). */
|
|
297
|
-
appendTurns: (sessionId: string, turns: SessionTurn[]) => Promise<void>;
|
|
298
|
-
/** Return a slice of turns for a session. */
|
|
299
|
-
getTurns: (sessionId: string, from?: number, limit?: number) => Promise<SessionTurn[]>;
|
|
300
|
-
/** Persist an updated run record (called after completeRun / abortRun / errorRun). */
|
|
301
|
-
updateRun: (sessionId: string, run: SessionRun) => Promise<void>;
|
|
302
|
-
/** Update the top-level status of a session. */
|
|
303
|
-
updateStatus: (sessionId: string, status: SessionData['status']) => Promise<void>;
|
|
304
|
-
}
|
|
305
|
-
interface Session {
|
|
306
|
-
/** Session ID */
|
|
307
|
-
readonly id: string;
|
|
308
|
-
/** Agent ID (optional label) */
|
|
309
|
-
readonly agentId?: string;
|
|
310
|
-
/** Current turn history */
|
|
311
|
-
readonly turns: SessionTurn[];
|
|
159
|
+
strictEnv?: boolean;
|
|
160
|
+
/** For sse/streamable-http: server URL */
|
|
161
|
+
url?: string;
|
|
162
|
+
/** Optional headers for HTTP transports */
|
|
163
|
+
headers?: Record<string, string>;
|
|
312
164
|
/**
|
|
313
|
-
*
|
|
165
|
+
* Timeout in milliseconds for MCP server bootstrap (connect + tool discovery).
|
|
314
166
|
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
167
|
+
* Zidane connects MCP servers lazily on the first `run()`. Without a
|
|
168
|
+
* bootstrap timeout, a slow or hung server can delay the first provider call
|
|
169
|
+
* for an arbitrarily long time even when that MCP server is never used.
|
|
170
|
+
*
|
|
171
|
+
* Default: `10000`.
|
|
317
172
|
*/
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
|
|
321
|
-
/** All runs in this session */
|
|
322
|
-
readonly runs: SessionRun[];
|
|
323
|
-
/** Arbitrary metadata */
|
|
324
|
-
readonly metadata: Record<string, unknown>;
|
|
173
|
+
bootstrapTimeout?: number;
|
|
174
|
+
/** Timeout in milliseconds for MCP tool calls (default: 30000) */
|
|
175
|
+
toolTimeout?: number;
|
|
325
176
|
/**
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
177
|
+
* Allow-list of tool names to expose. Names match the upstream tool name
|
|
178
|
+
* (NOT the namespaced `mcp_{server}_{tool}` form). Tools not in the list are
|
|
179
|
+
* dropped before registration — the model never sees them in its catalog and
|
|
180
|
+
* the wire cost of advertising them is avoided.
|
|
181
|
+
*
|
|
182
|
+
* Mutually exclusive with {@link McpServerConfig.disabledTools} — passing both
|
|
183
|
+
* throws at bootstrap time.
|
|
184
|
+
*
|
|
185
|
+
* Composes with {@link McpServerConfig.toolFilter}: allow-list applies first,
|
|
186
|
+
* then the predicate. Composes with the `mcp:tools:filter` hook: config-side
|
|
187
|
+
* filters apply first, then the hook can further narrow the list.
|
|
329
188
|
*/
|
|
330
|
-
|
|
331
|
-
parentRunId?: string;
|
|
332
|
-
depth?: number;
|
|
333
|
-
}) => void;
|
|
334
|
-
/** Mark a run as completed */
|
|
335
|
-
completeRun: (runId: string, stats: {
|
|
336
|
-
turns: number;
|
|
337
|
-
tokensIn: number;
|
|
338
|
-
tokensOut: number;
|
|
339
|
-
turnUsage?: TurnUsage[];
|
|
340
|
-
cost?: number;
|
|
341
|
-
}) => void;
|
|
342
|
-
/** Mark a run as aborted */
|
|
343
|
-
abortRun: (runId: string) => void;
|
|
344
|
-
/** Mark a run as errored */
|
|
345
|
-
errorRun: (runId: string, error: string) => void;
|
|
346
|
-
/** Append turns to in-memory history AND persist via store.appendTurns (if store present) */
|
|
347
|
-
appendTurns: (turns: SessionTurn[]) => Promise<void>;
|
|
348
|
-
/** Replace all turns in-memory (does not persist — use save() for that) */
|
|
349
|
-
setTurns: (turns: SessionTurn[]) => void;
|
|
350
|
-
/** Update the session status in memory AND via store.updateStatus (if store present) */
|
|
351
|
-
updateStatus: (status: SessionData['status']) => Promise<void>;
|
|
352
|
-
/** Persist an updated run record via store.updateRun (if store present) */
|
|
353
|
-
updateRun: (run: SessionRun) => Promise<void>;
|
|
354
|
-
/** Generate a turn ID using store.generateTurnId if available, else crypto.randomUUID() */
|
|
355
|
-
generateTurnId: () => string | Promise<string>;
|
|
356
|
-
/** Set metadata key */
|
|
357
|
-
setMeta: (key: string, value: unknown) => void;
|
|
358
|
-
/** Persist the full session document to the store */
|
|
359
|
-
save: () => Promise<void>;
|
|
360
|
-
/** Serialize to SessionData */
|
|
361
|
-
toJSON: () => SessionData;
|
|
362
|
-
}
|
|
363
|
-
interface CreateSessionOptions {
|
|
364
|
-
/** Session ID. If omitted and store provides generateSessionId, that is used. */
|
|
365
|
-
id?: string;
|
|
366
|
-
/** Agent ID label */
|
|
367
|
-
agentId?: string;
|
|
368
|
-
/** Initial metadata */
|
|
369
|
-
metadata?: Record<string, unknown>;
|
|
370
|
-
/** Storage backend (optional, enables save/load) */
|
|
371
|
-
store?: SessionStore;
|
|
372
|
-
_data?: SessionData;
|
|
373
|
-
}
|
|
374
|
-
/**
|
|
375
|
-
* Create a new session.
|
|
376
|
-
* Async so stores that generate IDs server-side (e.g. Supabase) can be supported.
|
|
377
|
-
*/
|
|
378
|
-
declare function createSession(options?: CreateSessionOptions): Promise<Session>;
|
|
379
|
-
/**
|
|
380
|
-
* Load an existing session from a store.
|
|
381
|
-
*/
|
|
382
|
-
declare function loadSession(store: SessionStore, sessionId: string): Promise<Session | null>;
|
|
383
|
-
//#endregion
|
|
384
|
-
//#region src/skills/types.d.ts
|
|
385
|
-
/**
|
|
386
|
-
* Types for the Agent Skills system.
|
|
387
|
-
*
|
|
388
|
-
* Follows the Agent Skills open standard (agentskills.io/specification).
|
|
389
|
-
* Zidane-specific metadata conventionally uses the `zidane.` key prefix
|
|
390
|
-
* (e.g. `metadata['zidane.paths']`) to stay spec-compliant.
|
|
391
|
-
*/
|
|
392
|
-
interface SkillResource {
|
|
393
|
-
/** Relative path from skill directory */
|
|
394
|
-
path: string;
|
|
395
|
-
/** Resource type inferred from directory */
|
|
396
|
-
type: 'script' | 'reference' | 'asset' | 'other';
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Where the skill came from. Used for collision precedence (project beats user)
|
|
400
|
-
* and for host SDKs to gate project-level skills on a trust check.
|
|
401
|
-
*/
|
|
402
|
-
type SkillSource = 'project' | 'user' | 'inline' | 'builtin';
|
|
403
|
-
/** Severity + code for lenient-load warnings surfaced to host UIs. */
|
|
404
|
-
interface SkillDiagnostic {
|
|
405
|
-
severity: 'warning' | 'error';
|
|
406
|
-
/** Stable machine-readable code (e.g. `name-mismatch-directory`). */
|
|
407
|
-
code: string;
|
|
408
|
-
/** Human-readable description. */
|
|
409
|
-
message: string;
|
|
410
|
-
/** Optional frontmatter field name the diagnostic relates to. */
|
|
411
|
-
field?: string;
|
|
412
|
-
}
|
|
413
|
-
interface SkillConfig {
|
|
414
|
-
/** Skill name: 1-64 chars, lowercase alphanumeric + hyphens */
|
|
415
|
-
name: string;
|
|
416
|
-
/** What the skill does and when to use it (1-1024 chars) */
|
|
417
|
-
description: string;
|
|
418
|
-
/** The SKILL.md body content (after YAML frontmatter) */
|
|
419
|
-
instructions: string;
|
|
189
|
+
enabledTools?: string[];
|
|
420
190
|
/**
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
* fixtures that omit it are treated as `'project'` by downstream readers.
|
|
191
|
+
* Deny-list of tool names. Tools matching are dropped before registration.
|
|
192
|
+
* Same matching semantics as {@link McpServerConfig.enabledTools}.
|
|
424
193
|
*/
|
|
425
|
-
|
|
426
|
-
/** Absolute path to SKILL.md (undefined for inline skills) */
|
|
427
|
-
location?: string;
|
|
428
|
-
/** Skill directory path for resolving relative references */
|
|
429
|
-
baseDir?: string;
|
|
430
|
-
/** License identifier or reference */
|
|
431
|
-
license?: string;
|
|
432
|
-
/** Environment requirements */
|
|
433
|
-
compatibility?: string;
|
|
194
|
+
disabledTools?: string[];
|
|
434
195
|
/**
|
|
435
|
-
*
|
|
436
|
-
*
|
|
196
|
+
* Custom predicate run on each upstream tool. Return `true` to keep, `false`
|
|
197
|
+
* to drop. Receives the raw `listTools()` payload — useful for filtering by
|
|
198
|
+
* description, schema shape, or other metadata that an allow/deny list can't
|
|
199
|
+
* express.
|
|
200
|
+
*
|
|
201
|
+
* Runs after the allow/deny filter but before the `mcp:tools:filter` hook.
|
|
437
202
|
*/
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
203
|
+
toolFilter?: (tool: {
|
|
204
|
+
name: string;
|
|
205
|
+
description?: string | null;
|
|
206
|
+
inputSchema?: unknown;
|
|
207
|
+
}) => boolean;
|
|
443
208
|
/**
|
|
444
|
-
*
|
|
445
|
-
*
|
|
209
|
+
* Per-server override for {@link AgentBehavior.toolDisclosure}. When set,
|
|
210
|
+
* this server's tools follow this disclosure mode regardless of the
|
|
211
|
+
* agent-wide default. Useful when one big MCP server (200+ tools) should
|
|
212
|
+
* stay lazy while smaller servers stay eager.
|
|
213
|
+
*
|
|
214
|
+
* Default: inherits from `behavior.toolDisclosure`.
|
|
446
215
|
*/
|
|
447
|
-
|
|
216
|
+
disclosure?: 'eager' | 'lazy';
|
|
448
217
|
}
|
|
449
|
-
|
|
218
|
+
type ToolExecutionMode = 'sequential' | 'parallel';
|
|
219
|
+
interface AgentBehavior {
|
|
220
|
+
/** Tool execution mode (default: 'sequential') */
|
|
221
|
+
toolExecution?: ToolExecutionMode;
|
|
450
222
|
/**
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
454
|
-
*
|
|
223
|
+
* Max agent loop iterations.
|
|
224
|
+
*
|
|
225
|
+
* Default: unlimited (Infinity). The loop runs until the model signals
|
|
226
|
+
* completion (no tool calls / `end_turn`), the abort signal fires, or this
|
|
227
|
+
* cap is hit. Set a finite value as a safety net for runaway loops.
|
|
455
228
|
*/
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
|
|
461
|
-
/**
|
|
462
|
-
|
|
463
|
-
/** Skip default scan paths (~/.agents/skills, .zidane/skills, etc.) */
|
|
464
|
-
skipDefaultPaths?: boolean;
|
|
229
|
+
maxTurns?: number;
|
|
230
|
+
/** Max tokens per LLM response (default: 16384) */
|
|
231
|
+
maxTokens?: number;
|
|
232
|
+
/** Thinking token budget — overrides the level-based default when set */
|
|
233
|
+
thinkingBudget?: number;
|
|
234
|
+
/** JSON Schema for structured output enforcement */
|
|
235
|
+
schema?: Record<string, unknown>;
|
|
465
236
|
/**
|
|
466
|
-
*
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
*
|
|
237
|
+
* Enable provider prompt caching. When on (default), the provider marks the
|
|
238
|
+
* system prompt, tools, and the last stable message with cache breakpoints so
|
|
239
|
+
* the shared prefix is served from cache across turns.
|
|
240
|
+
*
|
|
241
|
+
* - Anthropic: `cache_control: { type: 'ephemeral' }` on the last `system`
|
|
242
|
+
* content part, the last tool, and the last message content part.
|
|
243
|
+
* - OpenAI-compatible / OpenRouter: same shape — honored by Anthropic-backed
|
|
244
|
+
* OpenRouter routes and by Gemini; ignored (no-op) by providers that cache
|
|
245
|
+
* automatically (OpenAI, DeepSeek, Grok, Groq, Moonshot).
|
|
246
|
+
*
|
|
247
|
+
* Usage is surfaced via `TurnUsage.cacheRead` / `TurnUsage.cacheCreation`.
|
|
248
|
+
*
|
|
249
|
+
* Default: `true`.
|
|
470
250
|
*/
|
|
471
|
-
|
|
251
|
+
cache?: boolean;
|
|
472
252
|
/**
|
|
473
|
-
*
|
|
474
|
-
*
|
|
253
|
+
* Soft per-turn cap on total tool-output bytes. When the sum of `outputBytes`
|
|
254
|
+
* across a turn's tool results exceeds this value, the loop injects a
|
|
255
|
+
* synthetic user message instructing the model to summarize before calling
|
|
256
|
+
* more tools, and fires the `budget:exceeded` hook.
|
|
257
|
+
*
|
|
258
|
+
* Measured **post-`tool:transform`** so consumer truncation counts toward the
|
|
259
|
+
* budget. Off by default (undefined / `0` disables the check). A reasonable
|
|
260
|
+
* starting value for OSS-model integrations is `32768`.
|
|
475
261
|
*/
|
|
476
|
-
|
|
477
|
-
/** Script timeout for `skills_run_script`, in milliseconds. Default `60000`. */
|
|
478
|
-
scriptTimeoutMs?: number;
|
|
262
|
+
toolOutputBudget?: number;
|
|
479
263
|
/**
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
264
|
+
* Deduplicate identical re-reads of the same file in `read_file`. When the
|
|
265
|
+
* model re-reads a file with the same slice and the bytes haven't changed
|
|
266
|
+
* since the last read in this session, the tool returns a short stub
|
|
267
|
+
* instead of re-emitting the full content. Pairs with the read-before-edit
|
|
268
|
+
* guard in `edit` / `multi_edit`.
|
|
269
|
+
*
|
|
270
|
+
* Requires a session (set via `createSession()`); without one, the flag is
|
|
271
|
+
* a no-op since per-session state has nowhere to live.
|
|
272
|
+
*
|
|
273
|
+
* Default: `true`.
|
|
483
274
|
*/
|
|
484
|
-
|
|
485
|
-
}
|
|
486
|
-
//#endregion
|
|
487
|
-
//#region src/skills/activation.d.ts
|
|
488
|
-
/** How a skill was activated. Surfaced in `skills:activate` hook ctx. */
|
|
489
|
-
type ActivationVia = 'model' | 'explicit' | 'resume';
|
|
490
|
-
/** Reason a skill was deactivated. Surfaced in `skills:deactivate` hook ctx. */
|
|
491
|
-
type DeactivationReason = 'run-end' | 'explicit' | 'reset';
|
|
492
|
-
/** A skill currently active in the state machine. */
|
|
493
|
-
interface ActiveSkill {
|
|
494
|
-
skill: SkillConfig;
|
|
495
|
-
activatedAt: number;
|
|
496
|
-
activatedVia: ActivationVia;
|
|
497
|
-
}
|
|
498
|
-
/**
|
|
499
|
-
* Per-agent skill activation state. Public read-surface is the `active()` list
|
|
500
|
-
* and `isActive(name)` predicate; writes go through `activate()` / `deactivate()`.
|
|
501
|
-
*/
|
|
502
|
-
interface SkillActivationState {
|
|
503
|
-
/** List of currently active skills in activation order. Returns a snapshot. */
|
|
504
|
-
active: () => readonly ActiveSkill[];
|
|
505
|
-
/** Is the skill with this canonical name currently active? */
|
|
506
|
-
isActive: (name: string) => boolean;
|
|
507
|
-
/** Retrieve the `ActiveSkill` record by name, or `undefined`. */
|
|
508
|
-
get: (name: string) => ActiveSkill | undefined;
|
|
275
|
+
dedupReads?: boolean;
|
|
509
276
|
/**
|
|
510
|
-
*
|
|
511
|
-
*
|
|
512
|
-
*
|
|
513
|
-
*
|
|
277
|
+
* Taper the thinking budget over the course of a run. Late turns are
|
|
278
|
+
* usually checkpoint / cleanup work where reasoning rarely pays for
|
|
279
|
+
* itself; early turns benefit most. Two forms:
|
|
280
|
+
*
|
|
281
|
+
* - **Struct** — geometric decay starting after `afterTurn`, multiplying by
|
|
282
|
+
* `factor` each subsequent turn, clamped to `floor`. Example
|
|
283
|
+
* `{ afterTurn: 5, factor: 0.5, floor: 1024 }` with a base budget of 8192:
|
|
284
|
+
* turns 1-5 = 8192, turn 6 = 4096, turn 7 = 2048, turn 8+ = 1024.
|
|
285
|
+
* - **Function** — `(runTurn, baseBudget) => number`. Arbitrary curves;
|
|
286
|
+
* `runTurn` is 1-indexed, run-relative (resumed sessions reset).
|
|
287
|
+
*
|
|
288
|
+
* No-op when `thinkingBudget` is unset. Honored by every provider that
|
|
289
|
+
* respects `thinkingBudget` (anthropic explicit-budget `enabled` path,
|
|
290
|
+
* adaptive `maxTokensCap`, openai-compat `max_tokens` padding).
|
|
291
|
+
*
|
|
292
|
+
* Default: `undefined` (no decay).
|
|
514
293
|
*/
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
deactivate: (name: string) => ActiveSkill | undefined;
|
|
521
|
-
/** Remove every active skill. Returns the list of removed records. */
|
|
522
|
-
clear: () => readonly ActiveSkill[];
|
|
523
|
-
}
|
|
524
|
-
interface SkillActivationStateOptions {
|
|
525
|
-
/**
|
|
526
|
-
* Cap on concurrent activations. `undefined` (the default) disables the cap.
|
|
527
|
-
* When set, `activate()` returns `'cap-reached'` once the set is at size `maxActive`.
|
|
528
|
-
*/
|
|
529
|
-
maxActive?: number;
|
|
530
|
-
}
|
|
531
|
-
declare function createSkillActivationState(options?: SkillActivationStateOptions): SkillActivationState;
|
|
532
|
-
//#endregion
|
|
533
|
-
//#region src/agent.d.ts
|
|
534
|
-
interface AgentHooks {
|
|
535
|
-
'system:before': (ctx: {
|
|
536
|
-
system: string;
|
|
537
|
-
}) => void;
|
|
538
|
-
'turn:before': (ctx: {
|
|
539
|
-
turn: number;
|
|
540
|
-
turnId: string;
|
|
541
|
-
options: StreamOptions;
|
|
542
|
-
}) => void;
|
|
294
|
+
thinkingDecay?: {
|
|
295
|
+
afterTurn: number;
|
|
296
|
+
factor: number;
|
|
297
|
+
floor: number;
|
|
298
|
+
} | ((runTurn: number, baseBudget: number) => number);
|
|
543
299
|
/**
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
*
|
|
300
|
+
* Per-tool soft call budget for this run. Keyed by **canonical** tool name.
|
|
301
|
+
* On the first call after the run-cumulative dispatched count for that tool
|
|
302
|
+
* reaches `max`, the framework fires `onExceed`:
|
|
547
303
|
*
|
|
548
|
-
* `
|
|
549
|
-
* turn
|
|
550
|
-
*
|
|
551
|
-
*
|
|
304
|
+
* - `'steer'` (default) — let the call execute, but emit a synthetic user
|
|
305
|
+
* message after the turn that nudges the model away from re-calling the
|
|
306
|
+
* tool. Reuses the existing post-turn steer pathway used by
|
|
307
|
+
* `toolOutputBudget`. Fires `tool-budget:exceeded` with `mode: 'steer'`.
|
|
308
|
+
* - `'block'` — refuse the call via `tool:gate` `block`. The model sees a
|
|
309
|
+
* `Blocked: <reason>` tool result. Fires `tool-budget:exceeded` with
|
|
310
|
+
* `mode: 'block'`.
|
|
311
|
+
* - **Function** — `(ctx) => { mode, message }`. The consumer supplies the
|
|
312
|
+
* steering / refusal text and chooses the mode dynamically.
|
|
552
313
|
*
|
|
553
|
-
*
|
|
554
|
-
*
|
|
555
|
-
*
|
|
556
|
-
*
|
|
557
|
-
* just answered without the tool running). Resumed sessions start a fresh
|
|
558
|
-
* run with empty counts.
|
|
314
|
+
* Counts include both real dispatches and dedup substitutes (Z19 hits).
|
|
315
|
+
* Excludes calls already blocked by an earlier gate (skill allow-list,
|
|
316
|
+
* consumer hook). Tool dispatched by spawned subagents has its own per-run
|
|
317
|
+
* counter — child counts never charge the parent.
|
|
559
318
|
*
|
|
560
|
-
*
|
|
319
|
+
* For MCP tools, key by the namespaced wire name (`mcp_<server>_<tool>`).
|
|
320
|
+
*
|
|
321
|
+
* Atomic in parallel mode: the middleware tracks its own per-tool
|
|
322
|
+
* approval counter, incremented synchronously at gate-time. A
|
|
323
|
+
* 4-call parallel batch against `max: 2` will let the first 2 through
|
|
324
|
+
* and refuse the rest, even though the loop's `runToolCounts` only
|
|
325
|
+
* propagates between calls (not within a single batch's gate fan-out).
|
|
326
|
+
*
|
|
327
|
+
* Default: `undefined` (no budget enforcement).
|
|
561
328
|
*/
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
delta: string;
|
|
574
|
-
text: string;
|
|
575
|
-
}) => void;
|
|
576
|
-
'stream:end': (ctx: StreamHookContext & {
|
|
577
|
-
text: string;
|
|
578
|
-
}) => void;
|
|
579
|
-
'stream:thinking': (ctx: StreamHookContext & {
|
|
580
|
-
delta: string;
|
|
581
|
-
thinking: string;
|
|
582
|
-
}) => void;
|
|
583
|
-
'oauth:refresh': (ctx: OAuthRefreshHookContext) => void;
|
|
329
|
+
toolBudgets?: Record<string, {
|
|
330
|
+
max: number;
|
|
331
|
+
onExceed?: 'steer' | 'block' | ((ctx: {
|
|
332
|
+
tool: string;
|
|
333
|
+
count: number;
|
|
334
|
+
max: number;
|
|
335
|
+
}) => {
|
|
336
|
+
mode: 'steer' | 'block';
|
|
337
|
+
message: string;
|
|
338
|
+
});
|
|
339
|
+
}>;
|
|
584
340
|
/**
|
|
585
|
-
*
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
* - Set `block = true` (with a `reason`) to refuse the call. The model
|
|
589
|
-
* sees a `Blocked: <reason>` tool result; `tool:before` / `tool:after`
|
|
590
|
-
* do **not** fire.
|
|
591
|
-
* - Set `result` to substitute a successful tool_result and skip
|
|
592
|
-
* execution. The model sees the substitute as a normal tool_result;
|
|
593
|
-
* `tool:before` does not fire, but `tool:after` and `tool:transform`
|
|
594
|
-
* do — so byte budgets, telemetry, and post-mutation hooks see the
|
|
595
|
-
* substitute. Useful for cache hits, dedup, idempotency guards,
|
|
596
|
-
* plan-mode synthetic acks.
|
|
341
|
+
* Generic per-tool argument deduplication. Keyed by the tool's **canonical**
|
|
342
|
+
* name (alias-stable). Each entry is a hasher: `(input) => string | undefined`.
|
|
597
343
|
*
|
|
598
|
-
*
|
|
599
|
-
* `block` wins — refusal beats substitution, so a policy gate
|
|
600
|
-
* (skills allow-list, custom security) can always override an upstream
|
|
601
|
-
* consumer's cache substitute. Mirrors the writable-`result` shape on
|
|
602
|
-
* `tool:unknown` and `tool:error` so consumers learn one pattern.
|
|
344
|
+
* **Hasher contract** — three return values, three meanings:
|
|
603
345
|
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
*
|
|
607
|
-
*
|
|
346
|
+
* | Return | Meaning |
|
|
347
|
+
* |-------------------------|------------------------------------------------------------------------|
|
|
348
|
+
* | a non-empty string | Cache key for this call. Equal keys (most-recent-only, this session) |
|
|
349
|
+
* | | replay the prior recorded result without re-dispatching the tool. |
|
|
350
|
+
* | `undefined` | **Skip dedup for this call.** The tool runs normally; nothing recorded.|
|
|
351
|
+
* | `''` / non-string | Treated identically to `undefined` (defensive: no dedup, no error). |
|
|
608
352
|
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
613
|
-
* `behavior.toolBudgets` enforces atomically even within a parallel
|
|
614
|
-
* batch.
|
|
615
|
-
*/
|
|
616
|
-
'tool:gate': (ctx: ToolHookContext & {
|
|
617
|
-
block: boolean;
|
|
618
|
-
reason: string;
|
|
619
|
-
result?: string | ToolResultContent[];
|
|
620
|
-
runToolCounts: Readonly<Record<string, number>>;
|
|
621
|
-
}) => void;
|
|
622
|
-
'tool:before': (ctx: ToolHookContext & {
|
|
623
|
-
coercions?: readonly string[];
|
|
624
|
-
runToolCounts: Readonly<Record<string, number>>;
|
|
625
|
-
}) => void;
|
|
626
|
-
'tool:after': (ctx: ToolHookContext & {
|
|
627
|
-
result: string | ToolResultContent[];
|
|
628
|
-
outputBytes: number;
|
|
629
|
-
coercions?: readonly string[];
|
|
630
|
-
runToolCounts: Readonly<Record<string, number>>;
|
|
631
|
-
}) => void;
|
|
632
|
-
/**
|
|
633
|
-
* Fires when a tool throws during execution. Mutate `result` to substitute a
|
|
634
|
-
* tool-output payload that gets sent back to the model in place of the
|
|
635
|
-
* default `Tool error: <msg>` string — useful for OSS-model error rewriting
|
|
636
|
-
* (collapse stack traces, hide internal paths, prepend recovery hints).
|
|
353
|
+
* The `undefined` opt-out is the way to say *"this specific call is not
|
|
354
|
+
* cacheable"* (timestamps in input, randomness baked in, debug flags). It
|
|
355
|
+
* is **not** the same as `JSON.stringify(input)` — that would dedup against
|
|
356
|
+
* the verbatim input. Pick one explicitly:
|
|
637
357
|
*
|
|
638
|
-
*
|
|
639
|
-
*
|
|
640
|
-
|
|
641
|
-
'tool:error': (ctx: ToolHookContext & {
|
|
642
|
-
error: Error;
|
|
643
|
-
result?: string | ToolResultContent[];
|
|
644
|
-
}) => void;
|
|
645
|
-
'tool:transform': (ctx: ToolHookContext & {
|
|
646
|
-
result: string | ToolResultContent[];
|
|
647
|
-
isError: boolean;
|
|
648
|
-
outputBytes: number;
|
|
649
|
-
coercions?: readonly string[];
|
|
650
|
-
}) => void;
|
|
651
|
-
/**
|
|
652
|
-
* Fires before the generic "Unknown tool" error when the model invokes a tool
|
|
653
|
-
* that isn't registered (hallucinated names, dropped MCP servers, dangling
|
|
654
|
-
* aliases). Mutate `result` to substitute a friendly response or set
|
|
655
|
-
* `suppressError: true` to skip the companion `tool:error` emission.
|
|
358
|
+
* ```ts
|
|
359
|
+
* // Always cache by full input — every identical re-call dedups.
|
|
360
|
+
* dedupTools: { todowrite: input => JSON.stringify(input) }
|
|
656
361
|
*
|
|
657
|
-
*
|
|
658
|
-
*
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
*
|
|
666
|
-
* to satisfy the tool's `inputSchema`. Observational — the tool call still
|
|
667
|
-
* surfaces a `Validation error: …` string back to the model. Useful for
|
|
668
|
-
* counting validation failures separately from runtime tool errors.
|
|
669
|
-
*/
|
|
670
|
-
'validation:reject': (ctx: ToolHookContext & {
|
|
671
|
-
reason: string;
|
|
672
|
-
schema: Record<string, unknown>;
|
|
673
|
-
}) => void;
|
|
674
|
-
/**
|
|
675
|
-
* Fires when `validateToolArgs` successfully auto-coerced one or more input
|
|
676
|
-
* fields to satisfy the tool's `inputSchema`. **Only fires when at least one
|
|
677
|
-
* coercion happened** — never on perfectly-shaped inputs. Useful for counting
|
|
678
|
-
* model "wrongness rate" without re-running validation downstream.
|
|
362
|
+
* // Cache by a normalized subset; non-cacheable shapes opt out.
|
|
363
|
+
* dedupTools: {
|
|
364
|
+
* execute_sql: (input) => {
|
|
365
|
+
* const q = typeof input.query === 'string' ? input.query.trim().toLowerCase() : undefined
|
|
366
|
+
* if (!q || q.includes('now()') || q.includes('random()')) return undefined
|
|
367
|
+
* return q
|
|
368
|
+
* },
|
|
369
|
+
* }
|
|
370
|
+
* ```
|
|
679
371
|
*
|
|
680
|
-
*
|
|
681
|
-
*
|
|
682
|
-
*
|
|
683
|
-
*/
|
|
684
|
-
'validation:coerce': (ctx: ToolHookContext & {
|
|
685
|
-
coercions: readonly string[];
|
|
686
|
-
schema: Record<string, unknown>;
|
|
687
|
-
}) => void;
|
|
688
|
-
'context:transform': (ctx: {
|
|
689
|
-
messages: SessionMessage[];
|
|
690
|
-
}) => void;
|
|
691
|
-
/**
|
|
692
|
-
* Fires per request, after `context:transform` and before the request goes
|
|
693
|
-
* out. Mutating `ctx.system` updates the system prompt the provider sends
|
|
694
|
-
* for this turn — useful for runtime-derived sections (e.g. listing files
|
|
695
|
-
* already read in the session, surfacing live tool budgets, injecting
|
|
696
|
-
* skill activation reminders).
|
|
372
|
+
* On a hit, the previously-recorded result is replayed as the tool_result
|
|
373
|
+
* without dispatching the tool. The substitution flows through `tool:gate`
|
|
374
|
+
* `result` (Z20), so `tool:after` and `tool:transform` still fire.
|
|
697
375
|
*
|
|
698
|
-
*
|
|
699
|
-
*
|
|
700
|
-
*
|
|
376
|
+
* Requires a session (`createSession()`); without one, the map is a silent
|
|
377
|
+
* no-op since per-session state has nowhere to live. Tools with side
|
|
378
|
+
* effects or non-deterministic outputs (network, time, randomness) MUST
|
|
379
|
+
* NOT be listed — there is no safety net beyond the consumer's hasher.
|
|
701
380
|
*
|
|
702
|
-
*
|
|
703
|
-
*
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
messages: readonly SessionMessage[];
|
|
708
|
-
turn: number;
|
|
709
|
-
turnId: string;
|
|
710
|
-
session?: Session;
|
|
711
|
-
}) => void;
|
|
712
|
-
'steer:inject': (ctx: {
|
|
713
|
-
message: string;
|
|
714
|
-
}) => void;
|
|
715
|
-
'spawn:before': (ctx: SpawnHookContext) => void;
|
|
716
|
-
'spawn:complete': (ctx: ChildRunStats) => void;
|
|
717
|
-
'spawn:error': (ctx: SpawnHookContext & {
|
|
718
|
-
error: Error;
|
|
719
|
-
}) => void;
|
|
720
|
-
'child:stream:text': (ctx: StreamHookContext & {
|
|
721
|
-
delta: string;
|
|
722
|
-
text: string;
|
|
723
|
-
childId: string;
|
|
724
|
-
depth: number;
|
|
725
|
-
}) => void;
|
|
726
|
-
'child:stream:thinking': (ctx: StreamHookContext & {
|
|
727
|
-
delta: string;
|
|
728
|
-
thinking: string;
|
|
729
|
-
childId: string;
|
|
730
|
-
depth: number;
|
|
731
|
-
}) => void;
|
|
732
|
-
'child:stream:end': (ctx: StreamHookContext & {
|
|
733
|
-
text: string;
|
|
734
|
-
childId: string;
|
|
735
|
-
depth: number;
|
|
736
|
-
}) => void;
|
|
737
|
-
/**
|
|
738
|
-
* Gate-style child events. Unlike the other `child:*` events, the bubble
|
|
739
|
-
* passes the **same `ctx` reference** the subagent's loop is awaiting on:
|
|
740
|
-
* setting `ctx.block` / `ctx.reason` / `ctx.result` on a parent listener
|
|
741
|
-
* propagates straight back to the child, refusing or substituting the call.
|
|
381
|
+
* For MCP tools, key by the namespaced wire name (`mcp_<server>_<tool>`).
|
|
382
|
+
* Parallel mode (`toolExecution: 'parallel'`, the default) sees calls in
|
|
383
|
+
* the SAME assistant turn race against each other — none can dedup against
|
|
384
|
+
* a sibling that started in the same batch. Sequential mode honors order
|
|
385
|
+
* within a turn.
|
|
742
386
|
*
|
|
743
|
-
*
|
|
744
|
-
*
|
|
745
|
-
*
|
|
746
|
-
*
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
runToolCounts: Readonly<Record<string, number>>;
|
|
753
|
-
childId: string;
|
|
754
|
-
depth: number;
|
|
755
|
-
}) => void;
|
|
756
|
-
'child:mcp:tool:gate': (ctx: McpToolHookContext & {
|
|
757
|
-
block: boolean;
|
|
758
|
-
reason: string;
|
|
759
|
-
result?: string | ToolResultContent[];
|
|
760
|
-
childId: string;
|
|
761
|
-
depth: number;
|
|
762
|
-
}) => void;
|
|
763
|
-
'child:tool:before': (ctx: ToolHookContext & {
|
|
764
|
-
coercions?: readonly string[];
|
|
765
|
-
runToolCounts: Readonly<Record<string, number>>;
|
|
766
|
-
childId: string;
|
|
767
|
-
depth: number;
|
|
768
|
-
}) => void;
|
|
769
|
-
'child:tool:after': (ctx: ToolHookContext & {
|
|
770
|
-
result: string | ToolResultContent[];
|
|
771
|
-
outputBytes: number;
|
|
772
|
-
coercions?: readonly string[];
|
|
773
|
-
runToolCounts: Readonly<Record<string, number>>;
|
|
774
|
-
childId: string;
|
|
775
|
-
depth: number;
|
|
776
|
-
}) => void;
|
|
777
|
-
'child:tool:error': (ctx: ToolHookContext & {
|
|
778
|
-
error: Error;
|
|
779
|
-
childId: string;
|
|
780
|
-
depth: number;
|
|
781
|
-
}) => void;
|
|
782
|
-
'child:turn:after': (ctx: {
|
|
783
|
-
turn: number;
|
|
784
|
-
turnId: string;
|
|
785
|
-
usage: TurnUsage;
|
|
786
|
-
message: SessionTurn;
|
|
787
|
-
toolCounts: {
|
|
788
|
-
turn: Readonly<Record<string, number>>;
|
|
789
|
-
run: Readonly<Record<string, number>>;
|
|
790
|
-
};
|
|
791
|
-
childId: string;
|
|
792
|
-
depth: number;
|
|
793
|
-
}) => void;
|
|
794
|
-
'mcp:connect': (ctx: {
|
|
795
|
-
name: string;
|
|
796
|
-
transport: string;
|
|
797
|
-
tools: string[];
|
|
798
|
-
}) => void;
|
|
799
|
-
'mcp:error': (ctx: {
|
|
800
|
-
name: string;
|
|
801
|
-
error: Error;
|
|
802
|
-
}) => void;
|
|
803
|
-
'mcp:close': (ctx: {
|
|
804
|
-
name: string;
|
|
805
|
-
}) => void;
|
|
806
|
-
/**
|
|
807
|
-
* Fires at the start of a per-server bootstrap attempt, before any network I/O.
|
|
808
|
-
* Pairs with `mcp:bootstrap:end` and is always emitted, regardless of outcome.
|
|
809
|
-
*/
|
|
810
|
-
'mcp:bootstrap:start': (ctx: {
|
|
811
|
-
name: string;
|
|
812
|
-
transport: string;
|
|
813
|
-
}) => void;
|
|
814
|
-
/**
|
|
815
|
-
* Fires at the end of a per-server bootstrap attempt. `durationMs` spans from
|
|
816
|
-
* the matching `mcp:bootstrap:start`. On `ok: false` carries the originating
|
|
817
|
-
* error so consumers can log / trace without relying on a separate `mcp:error`.
|
|
818
|
-
*/
|
|
819
|
-
'mcp:bootstrap:end': (ctx: {
|
|
820
|
-
name: string;
|
|
821
|
-
transport: string;
|
|
822
|
-
durationMs: number;
|
|
823
|
-
} & ({
|
|
824
|
-
ok: true;
|
|
825
|
-
toolCount: number;
|
|
826
|
-
} | {
|
|
827
|
-
ok: false;
|
|
828
|
-
error: Error;
|
|
829
|
-
})) => void;
|
|
387
|
+
* **Cache policy**: only the most recent `(hash, result)` per tool is
|
|
388
|
+
* retained. Interleaved patterns (input A, input B, input A) miss on the
|
|
389
|
+
* second A because B overwrote it. Sufficient for the common spam-the-
|
|
390
|
+
* same-call loop; consumers needing a richer cache should hook
|
|
391
|
+
* `tool:gate` directly.
|
|
392
|
+
*
|
|
393
|
+
* Default: `undefined` (no per-tool dedup).
|
|
394
|
+
*/
|
|
395
|
+
dedupTools?: Record<string, (input: Record<string, unknown>) => string | undefined>;
|
|
830
396
|
/**
|
|
831
|
-
*
|
|
832
|
-
*
|
|
833
|
-
*
|
|
834
|
-
*
|
|
397
|
+
* Require `read_file` before `edit` / `multi_edit` on the same path, and
|
|
398
|
+
* reject edits when the file has changed on disk since the last read in
|
|
399
|
+
* this session. Eliminates the silent-corruption failure mode where a
|
|
400
|
+
* model "remembers" stale content and applies a substring edit against
|
|
401
|
+
* bytes that have moved.
|
|
835
402
|
*
|
|
836
|
-
*
|
|
837
|
-
*
|
|
838
|
-
* environment, or capability-driven decisions that the config can't express.
|
|
403
|
+
* Requires a session. Off by default; turn it on for stricter eval-grade
|
|
404
|
+
* runs where silent edit corruption would invalidate the result.
|
|
839
405
|
*
|
|
840
|
-
*
|
|
406
|
+
* Default: `false`.
|
|
841
407
|
*/
|
|
842
|
-
|
|
843
|
-
server: string;
|
|
844
|
-
transport: 'stdio' | 'sse' | 'streamable-http';
|
|
845
|
-
tools: Array<{
|
|
846
|
-
name: string;
|
|
847
|
-
description?: string | null;
|
|
848
|
-
inputSchema?: unknown;
|
|
849
|
-
}>;
|
|
850
|
-
}) => void;
|
|
408
|
+
requireReadBeforeEdit?: boolean;
|
|
851
409
|
/**
|
|
852
|
-
*
|
|
853
|
-
*
|
|
854
|
-
*
|
|
410
|
+
* Client-side context compaction strategy. Use this for non-Anthropic
|
|
411
|
+
* providers (OSS via cerebras / openai-compat / openrouter) that don't
|
|
412
|
+
* have a server-side equivalent. Anthropic users should prefer the
|
|
413
|
+
* server-side `context-management-2025-06-27` beta — see
|
|
414
|
+
* `AnthropicParams.contextManagement`.
|
|
855
415
|
*
|
|
856
|
-
*
|
|
857
|
-
*
|
|
858
|
-
*
|
|
859
|
-
*
|
|
860
|
-
*
|
|
861
|
-
*
|
|
416
|
+
* - `'off'` (default) — no client-side compaction.
|
|
417
|
+
* - `'tail'` — when total tool-output bytes in the persisted history
|
|
418
|
+
* exceed `compactThreshold`, replace older `tool_result` outputs with a
|
|
419
|
+
* short stub, keeping the newest `compactKeepTurns` turns intact. The
|
|
420
|
+
* compaction is applied to the wire-level message list only; the
|
|
421
|
+
* underlying session turns are not modified.
|
|
422
|
+
*
|
|
423
|
+
* Default: `'off'`.
|
|
862
424
|
*/
|
|
863
|
-
'
|
|
864
|
-
block: boolean;
|
|
865
|
-
reason: string;
|
|
866
|
-
result?: string | ToolResultContent[];
|
|
867
|
-
}) => void;
|
|
868
|
-
'mcp:tool:before': (ctx: McpToolHookContext) => void;
|
|
869
|
-
'mcp:tool:after': (ctx: McpToolHookContext & {
|
|
870
|
-
result: string | ToolResultContent[];
|
|
871
|
-
outputBytes: number;
|
|
872
|
-
}) => void;
|
|
873
|
-
'mcp:tool:transform': (ctx: McpToolHookContext & {
|
|
874
|
-
result: string | ToolResultContent[];
|
|
875
|
-
outputBytes: number;
|
|
876
|
-
}) => void;
|
|
877
|
-
'mcp:tool:error': (ctx: McpToolHookContext & {
|
|
878
|
-
error: Error;
|
|
879
|
-
}) => void;
|
|
880
|
-
'skills:resolve': (ctx: {
|
|
881
|
-
skills: SkillConfig[];
|
|
882
|
-
}) => void;
|
|
883
|
-
'skills:catalog': (ctx: {
|
|
884
|
-
catalog: string;
|
|
885
|
-
skills: SkillConfig[];
|
|
886
|
-
}) => void;
|
|
887
|
-
'skills:activate': (ctx: {
|
|
888
|
-
skill: SkillConfig;
|
|
889
|
-
via: ActivationVia;
|
|
890
|
-
}) => void;
|
|
891
|
-
'skills:deactivate': (ctx: {
|
|
892
|
-
skill: SkillConfig;
|
|
893
|
-
reason: DeactivationReason;
|
|
894
|
-
}) => void;
|
|
895
|
-
'usage': (ctx: {
|
|
896
|
-
turn: number;
|
|
897
|
-
turnId: string;
|
|
898
|
-
usage: TurnUsage;
|
|
899
|
-
totalIn: number;
|
|
900
|
-
totalOut: number;
|
|
901
|
-
}) => void;
|
|
902
|
-
'output': (ctx: {
|
|
903
|
-
output: Record<string, unknown>;
|
|
904
|
-
schema: Record<string, unknown>;
|
|
905
|
-
}) => void;
|
|
425
|
+
compactStrategy?: 'off' | 'tail';
|
|
906
426
|
/**
|
|
907
|
-
*
|
|
908
|
-
*
|
|
909
|
-
*
|
|
427
|
+
* Soft byte threshold that triggers tail compaction when
|
|
428
|
+
* `compactStrategy === 'tail'`. Counts the post-`context:transform` bytes
|
|
429
|
+
* of `tool_result` outputs across all messages. Default: `131_072` (128
|
|
430
|
+
* KiB). Ignored when compaction is off.
|
|
910
431
|
*/
|
|
911
|
-
|
|
912
|
-
turn: number;
|
|
913
|
-
turnId: string;
|
|
914
|
-
bytes: number;
|
|
915
|
-
budget: number;
|
|
916
|
-
}) => void;
|
|
432
|
+
compactThreshold?: number;
|
|
917
433
|
/**
|
|
918
|
-
*
|
|
919
|
-
*
|
|
920
|
-
*
|
|
921
|
-
* refuses the call outright with `Blocked: <message>`.
|
|
922
|
-
*
|
|
923
|
-
* `count` is the run-cumulative dispatched count just before this call.
|
|
924
|
-
* Use `turnId` to correlate with `turn:after` if you need the integer turn
|
|
925
|
-
* index. Distinct from `budget:exceeded` (byte-level) so consumers can
|
|
926
|
-
* subscribe specifically; both can fire in the same turn.
|
|
434
|
+
* Number of trailing turns to leave untouched during tail compaction. The
|
|
435
|
+
* most-recent `compactKeepTurns` user/assistant messages are not eligible
|
|
436
|
+
* for elision so the model keeps the freshest tool context. Default: `4`.
|
|
927
437
|
*/
|
|
928
|
-
|
|
929
|
-
tool: string;
|
|
930
|
-
count: number;
|
|
931
|
-
max: number;
|
|
932
|
-
turnId: string;
|
|
933
|
-
mode: 'steer' | 'block';
|
|
934
|
-
}) => void;
|
|
935
|
-
'agent:abort': (ctx: object) => void;
|
|
438
|
+
compactKeepTurns?: number;
|
|
936
439
|
/**
|
|
937
|
-
*
|
|
440
|
+
* Prefix every line of `read_file` output with its 1-indexed line number
|
|
441
|
+
* followed by a tab (`<N>\t<content>`) — the compact `cat -n`-style
|
|
442
|
+
* format Claude Code emits. The `edit` tool strips the prefix from
|
|
443
|
+
* `old_string` / `new_string` so the model can paste back a numbered
|
|
444
|
+
* chunk verbatim without breaking the match.
|
|
938
445
|
*
|
|
939
|
-
*
|
|
940
|
-
*
|
|
941
|
-
* (
|
|
942
|
-
* For parent-loop-only counts use `ctx.turnUsage` (parent-only array);
|
|
943
|
-
* for tree-wide turn counts use `flattenTurns(ctx).length`.
|
|
944
|
-
*/
|
|
945
|
-
'agent:done': (ctx: AgentStats) => void;
|
|
946
|
-
'session:start': (ctx: SessionHookContext & {
|
|
947
|
-
runId: string;
|
|
948
|
-
prompt: string;
|
|
949
|
-
}) => void;
|
|
950
|
-
'session:end': (ctx: SessionHookContext & {
|
|
951
|
-
runId: string;
|
|
952
|
-
status: SessionEndStatus;
|
|
953
|
-
turnRange: [number, number];
|
|
954
|
-
}) => void;
|
|
955
|
-
'session:turns': (ctx: SessionHookContext & {
|
|
956
|
-
turns: SessionTurn[];
|
|
957
|
-
count: number;
|
|
958
|
-
}) => void;
|
|
959
|
-
'session:meta': (ctx: SessionHookContext & {
|
|
960
|
-
key: string;
|
|
961
|
-
value: unknown;
|
|
962
|
-
}) => void;
|
|
963
|
-
'session:save': (ctx: SessionHookContext) => void;
|
|
964
|
-
}
|
|
965
|
-
interface AgentOptions {
|
|
966
|
-
provider: Provider;
|
|
967
|
-
/** Display name for the agent (used in traces/logs). */
|
|
968
|
-
name?: string;
|
|
969
|
-
/** Default system prompt injected when no system is provided at run time. */
|
|
970
|
-
system?: string;
|
|
971
|
-
/** Tool definitions available to the agent. Defaults to no tools. */
|
|
972
|
-
tools?: Record<string, ToolDef>;
|
|
973
|
-
/**
|
|
974
|
-
* Map canonical tool names to LLM-facing (aliased) names.
|
|
446
|
+
* Set `false` to opt out — useful for callers piping `read_file` into
|
|
447
|
+
* downstream parsers that don't recognize the prefix. Per-call
|
|
448
|
+
* `read_file({ lineNumbers: false })` overrides this default.
|
|
975
449
|
*
|
|
976
|
-
*
|
|
977
|
-
* carries and what the model calls the tool; the canonical name is what lives in
|
|
978
|
-
* `session.turns` and what the agent uses to look up the tool implementation.
|
|
450
|
+
* Default: `true`.
|
|
979
451
|
*/
|
|
980
|
-
|
|
981
|
-
/** Agent-level behavior defaults (overridden by run-level behavior) */
|
|
982
|
-
behavior?: AgentBehavior;
|
|
983
|
-
/** Execution context: where tools run. Defaults to in-process. */
|
|
984
|
-
execution?: ExecutionContext;
|
|
985
|
-
/** MCP servers to connect and expose as tools */
|
|
986
|
-
mcpServers?: McpServerConfig[];
|
|
987
|
-
/** Session for identity, turn persistence, and run tracking */
|
|
988
|
-
session?: Session;
|
|
989
|
-
/** Skills configuration */
|
|
990
|
-
skills?: SkillsConfig;
|
|
452
|
+
readLineNumbers?: boolean;
|
|
991
453
|
/**
|
|
992
|
-
*
|
|
993
|
-
*
|
|
994
|
-
*
|
|
995
|
-
*
|
|
454
|
+
* Replace older `read_file` `tool_result` blocks with a short stub when
|
|
455
|
+
* a successful `edit` / `multi_edit` / `write_file` later in the same
|
|
456
|
+
* run modified the same path. The replacement is applied to the
|
|
457
|
+
* wire-level message list only — persisted session turns keep the
|
|
458
|
+
* original content.
|
|
996
459
|
*
|
|
997
|
-
*
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
* Pre-connect MCP servers in the background as soon as `createAgent` returns,
|
|
1002
|
-
* instead of deferring the bootstrap to the first `agent.run()`.
|
|
460
|
+
* Eliminates the common waste pattern where the model carries the
|
|
461
|
+
* pre-edit file body forward across many turns "in case it needs it".
|
|
462
|
+
* Pairs cleanly with `compactStrategy: 'tail'`: stale reads shrink
|
|
463
|
+
* first, then the byte-threshold compaction fires if anything's left.
|
|
1003
464
|
*
|
|
1004
|
-
*
|
|
1005
|
-
*
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
1008
|
-
* promise is `await`ed by both paths so the error is never silently lost.
|
|
465
|
+
* Detection is conservative — only triggers when the corresponding
|
|
466
|
+
* tool_result confirms success (`Edited …`, `Created …`, `Updated …`).
|
|
467
|
+
* Failed edits and `No change needed` write_file calls do NOT
|
|
468
|
+
* invalidate prior reads.
|
|
1009
469
|
*
|
|
1010
|
-
*
|
|
470
|
+
* Default: `false`.
|
|
1011
471
|
*/
|
|
1012
|
-
|
|
1013
|
-
}
|
|
1014
|
-
interface Agent {
|
|
1015
|
-
hooks: Hookable<AgentHooks>;
|
|
1016
|
-
run: (options: AgentRunOptions) => Promise<AgentStats>;
|
|
1017
|
-
abort: () => void;
|
|
1018
|
-
steer: (message: string) => void;
|
|
1019
|
-
followUp: (message: string) => void;
|
|
1020
|
-
waitForIdle: () => Promise<void>;
|
|
472
|
+
elideStaleReads?: boolean;
|
|
1021
473
|
/**
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
1024
|
-
*
|
|
474
|
+
* Tool disclosure strategy. Controls whether the model sees every tool's
|
|
475
|
+
* full `inputSchema` in its tool list every turn ("eager") or whether MCP
|
|
476
|
+
* tools are advertised as a name+description catalog in the system prompt
|
|
477
|
+
* and only get full schemas after being surfaced via the `tool_search`
|
|
478
|
+
* native tool ("lazy" / progressive disclosure).
|
|
479
|
+
*
|
|
480
|
+
* Native tools (those passed to `createAgent({ tools })`) and skill tools
|
|
481
|
+
* are always eager — they are core to the agent and cheap. Only MCP tools
|
|
482
|
+
* are eligible for lazy disclosure.
|
|
483
|
+
*
|
|
484
|
+
* When `'lazy'`, the agent:
|
|
485
|
+
* - Appends a `<searchable_tools>` section to the system prompt listing
|
|
486
|
+
* every MCP tool by `name` + `description` only (no `inputSchema`).
|
|
487
|
+
* - Auto-injects a `tool_search` native tool (opt out via
|
|
488
|
+
* {@link AgentBehavior.toolSearch}) the model uses to load schemas on
|
|
489
|
+
* demand. Surfaced tools persist for the rest of the run.
|
|
490
|
+
* - Rebuilds the wire-level tool list each turn, appending newly-unlocked
|
|
491
|
+
* tools at the end so the prefix-cache breakpoint advances cleanly.
|
|
492
|
+
*
|
|
493
|
+
* Trade-off: every `tool_search` invocation expands the tool list and
|
|
494
|
+
* invalidates the tool-list cache breakpoint for one turn. With many
|
|
495
|
+
* MCP servers, the savings on cold turns (fewer schemas in context) are
|
|
496
|
+
* substantial; with one tiny MCP server, the overhead may not pay back.
|
|
497
|
+
*
|
|
498
|
+
* Default: `'eager'`.
|
|
1025
499
|
*/
|
|
1026
|
-
|
|
500
|
+
toolDisclosure?: 'eager' | 'lazy';
|
|
1027
501
|
/**
|
|
1028
|
-
*
|
|
1029
|
-
*
|
|
502
|
+
* Fine-grained config for the `tool_search` tool auto-injected when
|
|
503
|
+
* {@link AgentBehavior.toolDisclosure} is `'lazy'`. No-op in eager mode.
|
|
504
|
+
*
|
|
505
|
+
* - `tool: false` — opt out of the auto-injection entirely. Use when the
|
|
506
|
+
* host wants to ship a custom discovery tool. Note that the catalog
|
|
507
|
+
* text drops the call-to-action prose in this case so the model isn't
|
|
508
|
+
* pointed at a non-existent tool.
|
|
509
|
+
* - `limit` — default cap on results returned per `tool_search` call when
|
|
510
|
+
* the model omits the parameter. Default: `20`.
|
|
511
|
+
*
|
|
512
|
+
* Note on host-defined `tool_search`: a tool the host registers under the
|
|
513
|
+
* name `tool_search` (or under any alias whose canonical is `tool_search`)
|
|
514
|
+
* will shadow the auto-injected one — the catalog text will point at the
|
|
515
|
+
* host's wire name, but driving the unlock flow requires either using
|
|
516
|
+
* `createToolSearchTool({ catalog, unlocked })` from `tools/tool-search`
|
|
517
|
+
* (which internally mutates the unlock set) or fully opting out via
|
|
518
|
+
* `toolSearch.tool: false` and treating discovery as a host-side concern.
|
|
519
|
+
* A bare host tool that doesn't touch the unlock set will not advance the
|
|
520
|
+
* lazy disclosure state and the hard gate will keep refusing lazy calls.
|
|
521
|
+
*
|
|
522
|
+
* Default: `undefined` (auto-inject with the default limit).
|
|
1030
523
|
*/
|
|
1031
|
-
|
|
524
|
+
toolSearch?: {
|
|
525
|
+
tool?: false;
|
|
526
|
+
limit?: number;
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* One block of a multimodal user prompt.
|
|
531
|
+
*
|
|
532
|
+
* `agent.run({ prompt })` accepts either a plain string (treated as a single
|
|
533
|
+
* text part) or an array of these parts for multimodal inputs.
|
|
534
|
+
*
|
|
535
|
+
* `document` parts are routed per provider: PDF-style mime types are sent as
|
|
536
|
+
* native document blocks when the provider supports them; text documents are
|
|
537
|
+
* inlined as text with an attachment header. Providers that cannot handle an
|
|
538
|
+
* image or document throw early.
|
|
539
|
+
*/
|
|
540
|
+
type PromptPart = PromptTextPart | PromptImagePart | PromptDocumentPart;
|
|
541
|
+
interface PromptTextPart {
|
|
542
|
+
type: 'text';
|
|
543
|
+
text: string;
|
|
544
|
+
}
|
|
545
|
+
interface PromptImagePart {
|
|
546
|
+
type: 'image';
|
|
547
|
+
/** IANA media type (e.g. `image/png`, `image/jpeg`) */
|
|
548
|
+
mediaType: string;
|
|
549
|
+
/** Base64-encoded payload */
|
|
550
|
+
data: string;
|
|
551
|
+
/** Optional display name */
|
|
552
|
+
name?: string;
|
|
553
|
+
}
|
|
554
|
+
interface PromptDocumentPart {
|
|
555
|
+
type: 'document';
|
|
556
|
+
/** IANA media type (e.g. `application/pdf`, `text/plain`) */
|
|
557
|
+
mediaType: string;
|
|
558
|
+
/** Either a base64-encoded payload (`encoding: 'base64'`) or raw text (`encoding: 'text'`) */
|
|
559
|
+
data: string;
|
|
560
|
+
encoding: 'base64' | 'text';
|
|
561
|
+
/** Optional display name used in attachment headers */
|
|
562
|
+
name?: string;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* A single block of structured tool-result content.
|
|
566
|
+
*
|
|
567
|
+
* MCP servers can return a mix of text, image, resource, and audio blocks. Tools
|
|
568
|
+
* return `string` for the common text-only case or `ToolResultContent[]` when they
|
|
569
|
+
* need to preserve non-text content (e.g. screenshots from a browser MCP).
|
|
570
|
+
*
|
|
571
|
+
* Providers that support native multi-part tool results (Anthropic, OpenAI Codex via
|
|
572
|
+
* pi-ai) route image blocks into their wire format verbatim; OpenAI-compat providers
|
|
573
|
+
* route them via a companion-user-message fallback when the underlying model/endpoint
|
|
574
|
+
* does not accept images inside tool-role messages.
|
|
575
|
+
*/
|
|
576
|
+
type ToolResultContent = ToolResultTextContent | ToolResultImageContent;
|
|
577
|
+
interface ToolResultTextContent {
|
|
578
|
+
type: 'text';
|
|
579
|
+
text: string;
|
|
580
|
+
}
|
|
581
|
+
interface ToolResultImageContent {
|
|
582
|
+
type: 'image';
|
|
583
|
+
/** IANA media type (e.g. `image/png`, `image/jpeg`) */
|
|
584
|
+
mediaType: string;
|
|
585
|
+
/** Base64-encoded payload */
|
|
586
|
+
data: string;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Lossy flattener — converts `ToolResultContent[]` (or a plain string) to a single
|
|
590
|
+
* string. Image blocks are replaced with `[image: <media> — <n> b64 bytes]` markers.
|
|
591
|
+
*
|
|
592
|
+
* Use at UI boundaries where a string is required; providers that understand
|
|
593
|
+
* structured content should route the array through without flattening.
|
|
594
|
+
*/
|
|
595
|
+
declare function toolResultToText(content: string | ToolResultContent[]): string;
|
|
596
|
+
/**
|
|
597
|
+
* Approximate byte length of a tool output as it goes back to the model.
|
|
598
|
+
*
|
|
599
|
+
* - Plain text: UTF-8 byte length.
|
|
600
|
+
* - Structured content: text blocks contribute their UTF-8 byte length; image
|
|
601
|
+
* blocks contribute their **base64 character length**, since that is what
|
|
602
|
+
* the model tokenizes (the wire-encoded payload, not the decoded image).
|
|
603
|
+
*
|
|
604
|
+
* Used by the agent loop to populate `outputBytes` on `tool:after`,
|
|
605
|
+
* `tool:transform`, `mcp:tool:after`, and `mcp:tool:transform` hooks so
|
|
606
|
+
* consumers can size-budget tool output without re-counting bytes themselves.
|
|
607
|
+
*/
|
|
608
|
+
declare function toolOutputByteLength(content: string | ToolResultContent[]): number;
|
|
609
|
+
type SessionContentBlock = {
|
|
610
|
+
type: 'text';
|
|
611
|
+
text: string;
|
|
612
|
+
} | {
|
|
613
|
+
type: 'image';
|
|
614
|
+
mediaType: string;
|
|
615
|
+
data: string;
|
|
616
|
+
} | {
|
|
617
|
+
type: 'tool_call';
|
|
618
|
+
id: string;
|
|
619
|
+
name: string;
|
|
620
|
+
input: Record<string, unknown>;
|
|
621
|
+
} | {
|
|
622
|
+
type: 'tool_result';
|
|
623
|
+
callId: string;
|
|
1032
624
|
/**
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
1035
|
-
* if the `maxActive` cap is reached. Idempotent — activating an already-active
|
|
1036
|
-
* skill is a no-op.
|
|
625
|
+
* Tool output — either a plain string (text-only, the common case) or a structured
|
|
626
|
+
* array of content blocks (text + image for multimodal tools such as screenshots).
|
|
1037
627
|
*/
|
|
1038
|
-
|
|
628
|
+
output: string | ToolResultContent[];
|
|
629
|
+
isError?: boolean;
|
|
630
|
+
} | {
|
|
631
|
+
type: 'thinking';
|
|
632
|
+
text: string;
|
|
633
|
+
signature?: string;
|
|
1039
634
|
/**
|
|
1040
|
-
*
|
|
1041
|
-
*
|
|
635
|
+
* Provider that minted `signature`. Signatures are provider-bound (Anthropic
|
|
636
|
+
* HMAC vs. OpenAI `encrypted_content`) and are dropped on cross-provider
|
|
637
|
+
* hops to avoid 400s. Unset means legacy/unknown — forwarded as-is.
|
|
1042
638
|
*/
|
|
1043
|
-
|
|
639
|
+
signatureProducer?: 'anthropic' | 'openai';
|
|
640
|
+
} | {
|
|
641
|
+
type: 'redacted_thinking';
|
|
642
|
+
data: string;
|
|
643
|
+
} | {
|
|
1044
644
|
/**
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
645
|
+
* Opaque round-trip envelope for reasoning state minted by an OpenAI-compat
|
|
646
|
+
* gateway (currently OpenRouter). The gateway expects its own
|
|
647
|
+
* `reasoning_details` array echoed back verbatim on the next turn so the
|
|
648
|
+
* upstream model can resume an extended-reasoning chain across tool calls.
|
|
1049
649
|
*
|
|
1050
|
-
*
|
|
1051
|
-
*
|
|
1052
|
-
*
|
|
650
|
+
* Stored opaquely because the items are provider-bound (Anthropic HMAC
|
|
651
|
+
* signatures, OpenAI `encrypted_content`, model-specific summary formats
|
|
652
|
+
* — all flowing through the gateway's normalized envelope).
|
|
1053
653
|
*/
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
readonly execution: ExecutionContext;
|
|
1058
|
-
readonly handle: ExecutionHandle | null;
|
|
1059
|
-
readonly session: Session | null;
|
|
1060
|
-
/** Snapshot of currently active skills. */
|
|
1061
|
-
readonly activeSkills: readonly ActiveSkill[];
|
|
654
|
+
type: 'provider_reasoning';
|
|
655
|
+
producer: 'openrouter';
|
|
656
|
+
details: unknown[];
|
|
1062
657
|
/**
|
|
1063
|
-
*
|
|
1064
|
-
*
|
|
1065
|
-
*
|
|
1066
|
-
* model / capability defaults, construct a new provider.
|
|
658
|
+
* Model id that produced the details. Reasoning is bound to a specific
|
|
659
|
+
* upstream route — a model switch on the next turn invalidates the
|
|
660
|
+
* embedded signatures, so the sender drops the block on mismatch.
|
|
1067
661
|
*/
|
|
1068
|
-
|
|
662
|
+
model?: string;
|
|
663
|
+
};
|
|
664
|
+
interface SessionMessage {
|
|
665
|
+
role: 'user' | 'assistant';
|
|
666
|
+
content: SessionContentBlock[];
|
|
667
|
+
}
|
|
668
|
+
interface SessionTurn {
|
|
669
|
+
/** UUID — generated by the store if it provides generateTurnId, else crypto.randomUUID() */
|
|
670
|
+
id: string;
|
|
671
|
+
/** Run that produced this turn (e.g. 'run_1') */
|
|
672
|
+
runId?: string;
|
|
673
|
+
role: 'user' | 'assistant' | 'system';
|
|
674
|
+
content: SessionContentBlock[];
|
|
675
|
+
/** Token usage — only present on assistant turns */
|
|
676
|
+
usage?: TurnUsage;
|
|
677
|
+
/** Unix timestamp (Date.now()) when the turn was created */
|
|
678
|
+
createdAt: number;
|
|
1069
679
|
}
|
|
1070
|
-
declare function createAgent({
|
|
1071
|
-
provider,
|
|
1072
|
-
name: agentName,
|
|
1073
|
-
system: agentSystem,
|
|
1074
|
-
tools: agentTools,
|
|
1075
|
-
toolAliases,
|
|
1076
|
-
behavior: agentBehavior,
|
|
1077
|
-
execution,
|
|
1078
|
-
mcpServers,
|
|
1079
|
-
session,
|
|
1080
|
-
skills: agentSkills,
|
|
1081
|
-
mcpConnector,
|
|
1082
|
-
eager
|
|
1083
|
-
}: AgentOptions): Agent;
|
|
1084
|
-
//#endregion
|
|
1085
|
-
//#region src/tools/types.d.ts
|
|
1086
680
|
/**
|
|
1087
|
-
*
|
|
1088
|
-
*
|
|
1089
|
-
*
|
|
1090
|
-
* The preset-y fields (`name`, `system`, `tools`, `toolAliases`, `mcpServers`, `skills`,
|
|
1091
|
-
* `behavior`) mirror the agent's own options so child-spawning tools can inherit them.
|
|
681
|
+
* Per-run hook registrations. Each entry can be a single handler or an array of handlers.
|
|
682
|
+
* Keys are `AgentHooks` event names (loose-typed here to avoid a circular import; agent.ts
|
|
683
|
+
* narrows it to the strongly-typed map).
|
|
1092
684
|
*/
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
/** Abort signal — tools should check this for early termination */
|
|
1097
|
-
signal: AbortSignal;
|
|
1098
|
-
/** The execution context (shell, filesystem, etc.) */
|
|
1099
|
-
execution: ExecutionContext;
|
|
1100
|
-
/** The active execution handle for the current agent run */
|
|
1101
|
-
handle: ExecutionHandle;
|
|
1102
|
-
/** Agent hooks for emitting events (e.g. spawn:complete) */
|
|
1103
|
-
hooks: Hookable<AgentHooks>;
|
|
1104
|
-
/** Agent display name (preset or user-supplied) */
|
|
1105
|
-
name?: string;
|
|
1106
|
-
/** Agent default system prompt */
|
|
1107
|
-
system?: string;
|
|
1108
|
-
/** Source tool map the agent was created with (pre-MCP-merge, pre-skills-injection) */
|
|
1109
|
-
tools: Record<string, ToolDef>;
|
|
685
|
+
type RunHookMap = Record<string, ((ctx: any) => unknown) | ((ctx: any) => unknown)[]>;
|
|
686
|
+
interface AgentRunOptions {
|
|
687
|
+
model?: string;
|
|
1110
688
|
/**
|
|
1111
|
-
*
|
|
1112
|
-
*
|
|
1113
|
-
*
|
|
1114
|
-
*
|
|
1115
|
-
* what appears in `ToolHookContext.displayName` / `McpToolHookContext.displayName`.
|
|
1116
|
-
* - The canonical name is what lives in `session.turns`, `ToolHookContext.name`, and
|
|
1117
|
-
* what the agent uses to look up the tool implementation. Alias changes never
|
|
1118
|
-
* desync persisted history.
|
|
689
|
+
* User prompt. Optional when resuming a session with existing turns.
|
|
690
|
+
*
|
|
691
|
+
* Accepts either a plain string (single text part) or an array of `PromptPart`s for
|
|
692
|
+
* multimodal inputs (text, images, documents). See {@link PromptPart}.
|
|
1119
693
|
*/
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
/**
|
|
1124
|
-
|
|
1125
|
-
/** Behavior
|
|
694
|
+
prompt?: string | PromptPart[];
|
|
695
|
+
system?: string;
|
|
696
|
+
thinking?: ThinkingLevel;
|
|
697
|
+
/** Abort signal — when triggered, the agent stops after the current turn */
|
|
698
|
+
signal?: AbortSignal;
|
|
699
|
+
/** Behavior overrides for this run (overrides agent defaults) */
|
|
1126
700
|
behavior?: AgentBehavior;
|
|
1127
|
-
/**
|
|
1128
|
-
|
|
1129
|
-
/** Tool call ID from the model */
|
|
1130
|
-
callId: string;
|
|
701
|
+
/** Tool overrides for this run. Pass {} for no tools. Omit to use agent tools. */
|
|
702
|
+
tools?: Record<string, ToolDef>;
|
|
1131
703
|
/**
|
|
1132
|
-
*
|
|
1133
|
-
*
|
|
1134
|
-
* by hand (tests, direct tool invocations) doesn't have to synthesize one.
|
|
704
|
+
* Per-run hook registrations. Each hook is attached before the run starts and
|
|
705
|
+
* detached in a finally block so handlers never leak across runs.
|
|
1135
706
|
*
|
|
1136
|
-
*
|
|
1137
|
-
* the subagent tree can be reconstructed from a persisted session.
|
|
707
|
+
* Accepts either a single handler or an array (all handlers register).
|
|
1138
708
|
*/
|
|
1139
|
-
|
|
709
|
+
hooks?: RunHookMap;
|
|
1140
710
|
/**
|
|
1141
|
-
*
|
|
1142
|
-
*
|
|
1143
|
-
* parent
|
|
711
|
+
* Parent run id. Populated automatically by the `spawn` tool when the child
|
|
712
|
+
* shares the parent's session; recorded on the resulting `SessionRun` so the
|
|
713
|
+
* parent↔child run tree can be reconstructed from a persisted session.
|
|
1144
714
|
*/
|
|
1145
|
-
|
|
715
|
+
parentRunId?: string;
|
|
1146
716
|
/**
|
|
1147
|
-
*
|
|
1148
|
-
*
|
|
1149
|
-
*
|
|
717
|
+
* Zero-based subagent depth. 0 = top-level `agent.run()`, 1 = first-level
|
|
718
|
+
* child spawned by a parent agent, and so on. Used by the spawn tool to
|
|
719
|
+
* enforce `maxDepth` and to stamp `child:*` forwarded hook payloads.
|
|
1150
720
|
*/
|
|
1151
721
|
depth?: number;
|
|
1152
722
|
}
|
|
1153
|
-
interface ToolDef {
|
|
1154
|
-
spec: ToolSpec;
|
|
1155
|
-
/**
|
|
1156
|
-
* Execute the tool and return its output.
|
|
1157
|
-
*
|
|
1158
|
-
* Return a plain string for text-only tools (the common case). Return a
|
|
1159
|
-
* `ToolResultContent[]` when the tool produces non-text content (images, mixed
|
|
1160
|
-
* text+image) that the provider can route through natively (Anthropic
|
|
1161
|
-
* `tool_result.content` arrays, OpenAI Codex pi-ai) or through the
|
|
1162
|
-
* companion-user-message fallback (OpenAI Chat Completions).
|
|
1163
|
-
*/
|
|
1164
|
-
execute: (input: Record<string, unknown>, ctx: ToolContext) => Promise<string | ToolResultContent[]>;
|
|
1165
|
-
}
|
|
1166
|
-
type ToolMap = Map<string, ToolDef>;
|
|
1167
|
-
//#endregion
|
|
1168
|
-
//#region src/types.d.ts
|
|
1169
723
|
/**
|
|
1170
|
-
*
|
|
724
|
+
* Reason the provider gave for stopping the turn.
|
|
1171
725
|
*
|
|
1172
|
-
* - `'
|
|
1173
|
-
* - `'
|
|
1174
|
-
*
|
|
1175
|
-
*
|
|
1176
|
-
*
|
|
1177
|
-
*
|
|
1178
|
-
*
|
|
726
|
+
* - `'stop'` — natural turn end (`end_turn` / `stop_sequence`).
|
|
727
|
+
* - `'tool-calls'` — model emitted tool_use blocks.
|
|
728
|
+
* - `'length'` — `max_tokens` reached, or (Anthropic 4.6+) the response bumped
|
|
729
|
+
* against the model's context window mid-stream
|
|
730
|
+
* (`model_context_window_exceeded`). The partial response is preserved; the
|
|
731
|
+
* loop emits this reason so consumers can prune/retry.
|
|
732
|
+
* - `'content-filter'` — model refused.
|
|
733
|
+
* - `'pause'` — Anthropic `pause_turn`: a server-side mid-turn pause for very
|
|
734
|
+
* long thinking. The loop continues with a synthetic "Please continue."
|
|
735
|
+
* user message rather than terminating; consumers see the pause via this
|
|
736
|
+
* finish reason on the prior assistant turn.
|
|
737
|
+
* - `'error'` — provider classified the turn as failed.
|
|
738
|
+
* - `'other'` — unknown / unmapped.
|
|
1179
739
|
*/
|
|
1180
|
-
type
|
|
1181
|
-
interface
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
/**
|
|
1185
|
-
|
|
1186
|
-
/**
|
|
1187
|
-
|
|
1188
|
-
/**
|
|
1189
|
-
|
|
740
|
+
type TurnFinishReason = 'stop' | 'tool-calls' | 'length' | 'content-filter' | 'pause' | 'error' | 'other';
|
|
741
|
+
interface TurnUsage {
|
|
742
|
+
input: number;
|
|
743
|
+
output: number;
|
|
744
|
+
/** Tokens written to cache (Anthropic) */
|
|
745
|
+
cacheCreation?: number;
|
|
746
|
+
/** Tokens read from cache (Anthropic) */
|
|
747
|
+
cacheRead?: number;
|
|
748
|
+
/** Thinking/reasoning tokens used */
|
|
749
|
+
thinking?: number;
|
|
750
|
+
/** Cost in USD as reported by the provider (OpenRouter) */
|
|
751
|
+
cost?: number;
|
|
1190
752
|
/**
|
|
1191
|
-
*
|
|
1192
|
-
*
|
|
1193
|
-
* Merged on top of the MCP SDK's default inherited environment — a safety
|
|
1194
|
-
* whitelist (`PATH`, `HOME`, `LANG`, `SHELL`, `USER` on POSIX; `APPDATA`,
|
|
1195
|
-
* `PATH`, ... on Win32). Setting this to `{}` no longer strips `PATH` from
|
|
1196
|
-
* the child process. Set {@link McpServerConfig.strictEnv} to `true` to
|
|
1197
|
-
* pass `env` verbatim with no inherited defaults.
|
|
753
|
+
* Why the model stopped this turn. Providers normalize native stop reasons to this union.
|
|
754
|
+
* Absent when the provider did not surface a reason (e.g. mock turns).
|
|
1198
755
|
*/
|
|
1199
|
-
|
|
756
|
+
finishReason?: TurnFinishReason;
|
|
1200
757
|
/**
|
|
1201
|
-
*
|
|
1202
|
-
*
|
|
1203
|
-
* is NOT merged in. Most consumers should leave this off; the default merge
|
|
1204
|
-
* prevents `spawn ENOENT` when a stdio server declares an `env` without
|
|
1205
|
-
* restating `PATH`.
|
|
758
|
+
* The model ID the provider ultimately used. May differ from the requested model when the
|
|
759
|
+
* provider remaps aliases. Absent for providers that do not echo a model ID.
|
|
1206
760
|
*/
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
/** Optional headers for HTTP transports */
|
|
1211
|
-
headers?: Record<string, string>;
|
|
761
|
+
modelId?: string;
|
|
762
|
+
}
|
|
763
|
+
interface AgentStats {
|
|
1212
764
|
/**
|
|
1213
|
-
*
|
|
1214
|
-
*
|
|
1215
|
-
*
|
|
1216
|
-
* bootstrap timeout, a slow or hung server can delay the first provider call
|
|
1217
|
-
* for an arbitrarily long time even when that MCP server is never used.
|
|
1218
|
-
*
|
|
1219
|
-
* Default: `10000`.
|
|
765
|
+
* Cumulative input tokens across the parent agent loop **and** every
|
|
766
|
+
* recursively-spawned sub-agent. Use this for billing / token-ledger
|
|
767
|
+
* consumption.
|
|
1220
768
|
*/
|
|
1221
|
-
|
|
1222
|
-
/**
|
|
1223
|
-
|
|
769
|
+
totalIn: number;
|
|
770
|
+
/** Cumulative output tokens. Same semantics as {@link AgentStats.totalIn}. */
|
|
771
|
+
totalOut: number;
|
|
1224
772
|
/**
|
|
1225
|
-
*
|
|
1226
|
-
*
|
|
1227
|
-
*
|
|
1228
|
-
*
|
|
1229
|
-
*
|
|
1230
|
-
*
|
|
1231
|
-
* throws at bootstrap time.
|
|
1232
|
-
*
|
|
1233
|
-
* Composes with {@link McpServerConfig.toolFilter}: allow-list applies first,
|
|
1234
|
-
* then the predicate. Composes with the `mcp:tools:filter` hook: config-side
|
|
1235
|
-
* filters apply first, then the hook can further narrow the list.
|
|
773
|
+
* Cumulative cache-read tokens across the parent agent loop and every
|
|
774
|
+
* recursively-spawned sub-agent. Surfaced at the top level (rather than
|
|
775
|
+
* only per-`TurnUsage`) because Anthropic prices cache reads at a separate
|
|
776
|
+
* line-item rate from regular input — billing-correct cost computation
|
|
777
|
+
* needs this number directly. Always `0` for providers that don't report
|
|
778
|
+
* cache usage.
|
|
1236
779
|
*/
|
|
1237
|
-
|
|
780
|
+
totalCacheRead: number;
|
|
1238
781
|
/**
|
|
1239
|
-
*
|
|
1240
|
-
* Same
|
|
782
|
+
* Cumulative cache-creation tokens across the parent agent loop and every
|
|
783
|
+
* recursively-spawned sub-agent. Same rationale as
|
|
784
|
+
* {@link AgentStats.totalCacheRead} — separate Anthropic billing rate.
|
|
785
|
+
* Always `0` for providers that don't report cache usage.
|
|
1241
786
|
*/
|
|
1242
|
-
|
|
787
|
+
totalCacheCreation: number;
|
|
1243
788
|
/**
|
|
1244
|
-
*
|
|
1245
|
-
*
|
|
1246
|
-
*
|
|
1247
|
-
*
|
|
789
|
+
* Number of parent agent-loop turns. Children's turn counts live under
|
|
790
|
+
* `children[].stats.turns` and are NOT folded in here — a single "turns"
|
|
791
|
+
* number for the whole tree would conflate two different measures
|
|
792
|
+
* (parent-loop iterations vs. tree-wide tool-call rounds).
|
|
1248
793
|
*
|
|
1249
|
-
*
|
|
794
|
+
* Tree-wide turn count: `flattenTurns(stats).length`.
|
|
1250
795
|
*/
|
|
1251
|
-
|
|
1252
|
-
name: string;
|
|
1253
|
-
description?: string | null;
|
|
1254
|
-
inputSchema?: unknown;
|
|
1255
|
-
}) => boolean;
|
|
796
|
+
turns: number;
|
|
1256
797
|
/**
|
|
1257
|
-
*
|
|
1258
|
-
*
|
|
1259
|
-
*
|
|
1260
|
-
*
|
|
1261
|
-
*
|
|
1262
|
-
* Default: inherits from `behavior.toolDisclosure`.
|
|
798
|
+
* Wall-clock duration of the top-level `agent.run()` call, in milliseconds.
|
|
799
|
+
* Children run during parent tool calls so this naturally subsumes child
|
|
800
|
+
* wall time — sequential children inflate it, parallel children compress
|
|
801
|
+
* into the parent's window.
|
|
1263
802
|
*/
|
|
1264
|
-
|
|
1265
|
-
}
|
|
1266
|
-
type ToolExecutionMode = 'sequential' | 'parallel';
|
|
1267
|
-
interface AgentBehavior {
|
|
1268
|
-
/** Tool execution mode (default: 'sequential') */
|
|
1269
|
-
toolExecution?: ToolExecutionMode;
|
|
803
|
+
elapsed: number;
|
|
1270
804
|
/**
|
|
1271
|
-
*
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1274
|
-
* completion (no tool calls / `end_turn`), the abort signal fires, or this
|
|
1275
|
-
* cap is hit. Set a finite value as a safety net for runaway loops.
|
|
805
|
+
* Per-turn usage breakdown for the **parent loop only**. Children's per-turn
|
|
806
|
+
* usages live under `children[].stats.turnUsage`. Use {@link flattenTurns}
|
|
807
|
+
* to walk the full tree.
|
|
1276
808
|
*/
|
|
1277
|
-
|
|
1278
|
-
/** Max tokens per LLM response (default: 16384) */
|
|
1279
|
-
maxTokens?: number;
|
|
1280
|
-
/** Thinking token budget — overrides the level-based default when set */
|
|
1281
|
-
thinkingBudget?: number;
|
|
1282
|
-
/** JSON Schema for structured output enforcement */
|
|
1283
|
-
schema?: Record<string, unknown>;
|
|
809
|
+
turnUsage?: TurnUsage[];
|
|
1284
810
|
/**
|
|
1285
|
-
*
|
|
1286
|
-
*
|
|
1287
|
-
*
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
*
|
|
811
|
+
* Cumulative cost in USD — parent loop plus every recursively-spawned
|
|
812
|
+
* sub-agent. Sums per-turn `TurnUsage.cost` reported by the provider.
|
|
813
|
+
* Absent when neither parent nor any descendant reported a non-zero cost.
|
|
814
|
+
*/
|
|
815
|
+
cost?: number;
|
|
816
|
+
/** Stats from child agents spawned during this run, in completion order. Recursive. */
|
|
817
|
+
children?: ChildRunStats[];
|
|
818
|
+
/** Structured output from schema enforcement (only present when behavior.schema is set) */
|
|
819
|
+
output?: Record<string, unknown>;
|
|
820
|
+
/**
|
|
821
|
+
* Milliseconds from the start of `agent.run()` to the first observable signal from the
|
|
822
|
+
* provider (first `stream:text`, `stream:thinking`, or `tool:before` event).
|
|
1296
823
|
*
|
|
1297
|
-
*
|
|
824
|
+
* Absent when the run produced no observable signals (e.g. aborted before any stream event).
|
|
825
|
+
*/
|
|
826
|
+
timeTillFirstTokenMs?: number;
|
|
827
|
+
}
|
|
828
|
+
interface ChildRunStats {
|
|
829
|
+
id: string;
|
|
830
|
+
task: string;
|
|
831
|
+
/**
|
|
832
|
+
* The child agent's full {@link AgentStats}. Cumulative for that child's
|
|
833
|
+
* own subtree (child loop + its grandchildren). Do **not** sum
|
|
834
|
+
* `ctx.stats.totalIn` across `spawn:complete` events to derive top-level
|
|
835
|
+
* totals — `agent.run()`'s return value is the canonical cumulative root.
|
|
1298
836
|
*/
|
|
1299
|
-
|
|
837
|
+
stats: AgentStats;
|
|
1300
838
|
/**
|
|
1301
|
-
*
|
|
1302
|
-
*
|
|
1303
|
-
*
|
|
1304
|
-
* more tools, and fires the `budget:exceeded` hook.
|
|
1305
|
-
*
|
|
1306
|
-
* Measured **post-`tool:transform`** so consumer truncation counts toward the
|
|
1307
|
-
* budget. Off by default (undefined / `0` disables the check). A reasonable
|
|
1308
|
-
* starting value for OSS-model integrations is `32768`.
|
|
839
|
+
* Subagent depth when this child ran. 1 = direct child of the top-level
|
|
840
|
+
* agent, 2 = grandchild, etc. Useful for telemetry that wants to group
|
|
841
|
+
* runs by depth.
|
|
1309
842
|
*/
|
|
1310
|
-
|
|
843
|
+
depth?: number;
|
|
1311
844
|
/**
|
|
1312
|
-
*
|
|
1313
|
-
*
|
|
1314
|
-
*
|
|
1315
|
-
* instead of re-emitting the full content. Pairs with the read-before-edit
|
|
1316
|
-
* guard in `edit` / `multi_edit`.
|
|
1317
|
-
*
|
|
1318
|
-
* Requires a session (set via `createSession()`); without one, the flag is
|
|
1319
|
-
* a no-op since per-session state has nowhere to live.
|
|
1320
|
-
*
|
|
1321
|
-
* Default: `true`.
|
|
845
|
+
* Terminal state of the child run. `'completed'` is the default. Exposed so
|
|
846
|
+
* a parent reading `stats.children` can distinguish aborted/timed-out
|
|
847
|
+
* children without re-parsing the returned string.
|
|
1322
848
|
*/
|
|
1323
|
-
|
|
849
|
+
status?: 'completed' | 'aborted' | 'timeout' | 'error';
|
|
1324
850
|
/**
|
|
1325
|
-
*
|
|
1326
|
-
*
|
|
1327
|
-
*
|
|
1328
|
-
*
|
|
1329
|
-
* - **Struct** — geometric decay starting after `afterTurn`, multiplying by
|
|
1330
|
-
* `factor` each subsequent turn, clamped to `floor`. Example
|
|
1331
|
-
* `{ afterTurn: 5, factor: 0.5, floor: 1024 }` with a base budget of 8192:
|
|
1332
|
-
* turns 1-5 = 8192, turn 6 = 4096, turn 7 = 2048, turn 8+ = 1024.
|
|
1333
|
-
* - **Function** — `(runTurn, baseBudget) => number`. Arbitrary curves;
|
|
1334
|
-
* `runTurn` is 1-indexed, run-relative (resumed sessions reset).
|
|
1335
|
-
*
|
|
1336
|
-
* No-op when `thinkingBudget` is unset. Honored by every provider that
|
|
1337
|
-
* respects `thinkingBudget` (anthropic explicit-budget `enabled` path,
|
|
1338
|
-
* adaptive `maxTokensCap`, openai-compat `max_tokens` padding).
|
|
1339
|
-
*
|
|
1340
|
-
* Default: `undefined` (no decay).
|
|
851
|
+
* Final structured output when the child was run with `behavior.schema`.
|
|
852
|
+
* Mirrors `AgentStats.output` but is surfaced here so the parent can read
|
|
853
|
+
* it without peeking at the nested `stats` bag.
|
|
1341
854
|
*/
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
855
|
+
output?: Record<string, unknown>;
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Base context for tool execution hooks.
|
|
859
|
+
*
|
|
860
|
+
* `name` is the canonical tool identity — the spec name registered on the agent (or the
|
|
861
|
+
* `mcp_{server}_{tool}` name for MCP tools). Hooks should policy-match against `name`.
|
|
862
|
+
*
|
|
863
|
+
* `displayName` is the outward-facing name — the alias surfaced to the LLM when
|
|
864
|
+
* `AgentOptions.toolAliases` maps the canonical name; otherwise equal to `name`.
|
|
865
|
+
* UI/telemetry adapters should emit `displayName`.
|
|
866
|
+
*
|
|
867
|
+
* Canonical vs. alias matters on session resume: `session.turns` persists canonical
|
|
868
|
+
* names only, so renaming an alias cannot desync history.
|
|
869
|
+
*/
|
|
870
|
+
interface ToolHookContext {
|
|
871
|
+
turnId: string;
|
|
872
|
+
callId: string;
|
|
873
|
+
/** Canonical tool name (spec name). Stable across alias-map changes. */
|
|
874
|
+
name: string;
|
|
875
|
+
/** Aliased (wire) name — equal to `name` when no alias is defined. */
|
|
876
|
+
displayName: string;
|
|
877
|
+
input: Record<string, unknown>;
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* Base context for MCP tool hooks.
|
|
881
|
+
*
|
|
882
|
+
* `tool` is the native tool name on the MCP server. `server` is the configured server
|
|
883
|
+
* name. The canonical zidane-namespaced identity is `mcp_{server}_{tool}`.
|
|
884
|
+
*
|
|
885
|
+
* `displayName` equals the canonical namespaced name unless the agent has aliased
|
|
886
|
+
* this MCP tool via `AgentOptions.toolAliases`; in which case `displayName` is the
|
|
887
|
+
* alias that the LLM sees.
|
|
888
|
+
*/
|
|
889
|
+
interface McpToolHookContext {
|
|
890
|
+
turnId: string;
|
|
891
|
+
callId: string;
|
|
892
|
+
server: string;
|
|
893
|
+
tool: string;
|
|
894
|
+
/** Aliased wire name for this MCP tool, or the canonical `mcp_{server}_{tool}` name. */
|
|
895
|
+
displayName: string;
|
|
896
|
+
input: Record<string, unknown>;
|
|
897
|
+
}
|
|
898
|
+
/** Base context for session hooks */
|
|
899
|
+
interface SessionHookContext {
|
|
900
|
+
sessionId: string;
|
|
901
|
+
}
|
|
902
|
+
/** Base context for spawn hooks */
|
|
903
|
+
interface SpawnHookContext {
|
|
904
|
+
id: string;
|
|
905
|
+
task: string;
|
|
1347
906
|
/**
|
|
1348
|
-
*
|
|
1349
|
-
*
|
|
1350
|
-
*
|
|
1351
|
-
*
|
|
1352
|
-
* - `'steer'` (default) — let the call execute, but emit a synthetic user
|
|
1353
|
-
* message after the turn that nudges the model away from re-calling the
|
|
1354
|
-
* tool. Reuses the existing post-turn steer pathway used by
|
|
1355
|
-
* `toolOutputBudget`. Fires `tool-budget:exceeded` with `mode: 'steer'`.
|
|
1356
|
-
* - `'block'` — refuse the call via `tool:gate` `block`. The model sees a
|
|
1357
|
-
* `Blocked: <reason>` tool result. Fires `tool-budget:exceeded` with
|
|
1358
|
-
* `mode: 'block'`.
|
|
1359
|
-
* - **Function** — `(ctx) => { mode, message }`. The consumer supplies the
|
|
1360
|
-
* steering / refusal text and chooses the mode dynamically.
|
|
1361
|
-
*
|
|
1362
|
-
* Counts include both real dispatches and dedup substitutes (Z19 hits).
|
|
1363
|
-
* Excludes calls already blocked by an earlier gate (skill allow-list,
|
|
1364
|
-
* consumer hook). Tool dispatched by spawned subagents has its own per-run
|
|
1365
|
-
* counter — child counts never charge the parent.
|
|
1366
|
-
*
|
|
1367
|
-
* For MCP tools, key by the namespaced wire name (`mcp_<server>_<tool>`).
|
|
1368
|
-
*
|
|
1369
|
-
* Atomic in parallel mode: the middleware tracks its own per-tool
|
|
1370
|
-
* approval counter, incremented synchronously at gate-time. A
|
|
1371
|
-
* 4-call parallel batch against `max: 2` will let the first 2 through
|
|
1372
|
-
* and refuse the rest, even though the loop's `runToolCounts` only
|
|
1373
|
-
* propagates between calls (not within a single batch's gate fan-out).
|
|
1374
|
-
*
|
|
1375
|
-
* Default: `undefined` (no budget enforcement).
|
|
907
|
+
* Subagent depth for the spawn. 1 = direct child of the top-level agent.
|
|
908
|
+
* Present on spawn:before/complete/error. Absent for grandchild spawns that
|
|
909
|
+
* bubble through `child:*` events (which carry their own `depth`).
|
|
1376
910
|
*/
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
911
|
+
depth?: number;
|
|
912
|
+
}
|
|
913
|
+
/** Context for stream hooks */
|
|
914
|
+
interface StreamHookContext {
|
|
915
|
+
turnId: string;
|
|
916
|
+
}
|
|
917
|
+
/** Context for OAuth refresh hooks */
|
|
918
|
+
interface OAuthRefreshHookContext {
|
|
919
|
+
provider: string;
|
|
920
|
+
providerId: string;
|
|
921
|
+
source: 'params' | 'file';
|
|
922
|
+
previousCredentials: Record<string, unknown> & {
|
|
923
|
+
access: string;
|
|
924
|
+
refresh: string;
|
|
925
|
+
expires: number;
|
|
926
|
+
};
|
|
927
|
+
credentials: Record<string, unknown> & {
|
|
928
|
+
access: string;
|
|
929
|
+
refresh: string;
|
|
930
|
+
expires: number;
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
type SessionEndStatus = 'completed' | 'aborted' | 'error';
|
|
934
|
+
//#endregion
|
|
935
|
+
//#region src/providers/anthropic.d.ts
|
|
936
|
+
/**
|
|
937
|
+
* Server-side context-management config — the body of `context_management` on
|
|
938
|
+
* the Messages API. Typed loosely (Record-of-unknown) so we don't pin a specific
|
|
939
|
+
* SDK schema version: the v0.90 SDK does not yet type this field, but the wire
|
|
940
|
+
* format is stable behind the `context-management-2025-06-27` beta.
|
|
941
|
+
*
|
|
942
|
+
* See: https://docs.anthropic.com/en/docs/build-with-claude/context-management
|
|
943
|
+
*/
|
|
944
|
+
interface AnthropicContextManagement {
|
|
945
|
+
edits?: Array<Record<string, unknown>>;
|
|
946
|
+
[key: string]: unknown;
|
|
947
|
+
}
|
|
948
|
+
interface AnthropicParams {
|
|
949
|
+
apiKey?: string;
|
|
950
|
+
access?: string;
|
|
951
|
+
refresh?: string;
|
|
952
|
+
expires?: number;
|
|
953
|
+
defaultModel?: string;
|
|
1388
954
|
/**
|
|
1389
|
-
*
|
|
1390
|
-
*
|
|
1391
|
-
*
|
|
1392
|
-
* **Hasher contract** — three return values, three meanings:
|
|
1393
|
-
*
|
|
1394
|
-
* | Return | Meaning |
|
|
1395
|
-
* |-------------------------|------------------------------------------------------------------------|
|
|
1396
|
-
* | a non-empty string | Cache key for this call. Equal keys (most-recent-only, this session) |
|
|
1397
|
-
* | | replay the prior recorded result without re-dispatching the tool. |
|
|
1398
|
-
* | `undefined` | **Skip dedup for this call.** The tool runs normally; nothing recorded.|
|
|
1399
|
-
* | `''` / non-string | Treated identically to `undefined` (defensive: no dedup, no error). |
|
|
1400
|
-
*
|
|
1401
|
-
* The `undefined` opt-out is the way to say *"this specific call is not
|
|
1402
|
-
* cacheable"* (timestamps in input, randomness baked in, debug flags). It
|
|
1403
|
-
* is **not** the same as `JSON.stringify(input)` — that would dedup against
|
|
1404
|
-
* the verbatim input. Pick one explicitly:
|
|
1405
|
-
*
|
|
1406
|
-
* ```ts
|
|
1407
|
-
* // Always cache by full input — every identical re-call dedups.
|
|
1408
|
-
* dedupTools: { todowrite: input => JSON.stringify(input) }
|
|
1409
|
-
*
|
|
1410
|
-
* // Cache by a normalized subset; non-cacheable shapes opt out.
|
|
1411
|
-
* dedupTools: {
|
|
1412
|
-
* execute_sql: (input) => {
|
|
1413
|
-
* const q = typeof input.query === 'string' ? input.query.trim().toLowerCase() : undefined
|
|
1414
|
-
* if (!q || q.includes('now()') || q.includes('random()')) return undefined
|
|
1415
|
-
* return q
|
|
1416
|
-
* },
|
|
1417
|
-
* }
|
|
1418
|
-
* ```
|
|
1419
|
-
*
|
|
1420
|
-
* On a hit, the previously-recorded result is replayed as the tool_result
|
|
1421
|
-
* without dispatching the tool. The substitution flows through `tool:gate`
|
|
1422
|
-
* `result` (Z20), so `tool:after` and `tool:transform` still fire.
|
|
1423
|
-
*
|
|
1424
|
-
* Requires a session (`createSession()`); without one, the map is a silent
|
|
1425
|
-
* no-op since per-session state has nowhere to live. Tools with side
|
|
1426
|
-
* effects or non-deterministic outputs (network, time, randomness) MUST
|
|
1427
|
-
* NOT be listed — there is no safety net beyond the consumer's hasher.
|
|
1428
|
-
*
|
|
1429
|
-
* For MCP tools, key by the namespaced wire name (`mcp_<server>_<tool>`).
|
|
1430
|
-
* Parallel mode (`toolExecution: 'parallel'`, the default) sees calls in
|
|
1431
|
-
* the SAME assistant turn race against each other — none can dedup against
|
|
1432
|
-
* a sibling that started in the same batch. Sequential mode honors order
|
|
1433
|
-
* within a turn.
|
|
1434
|
-
*
|
|
1435
|
-
* **Cache policy**: only the most recent `(hash, result)` per tool is
|
|
1436
|
-
* retained. Interleaved patterns (input A, input B, input A) miss on the
|
|
1437
|
-
* second A because B overwrote it. Sufficient for the common spam-the-
|
|
1438
|
-
* same-call loop; consumers needing a richer cache should hook
|
|
1439
|
-
* `tool:gate` directly.
|
|
1440
|
-
*
|
|
1441
|
-
* Default: `undefined` (no per-tool dedup).
|
|
955
|
+
* Optional override for the Anthropic SDK base URL. Honored end-to-end — headers and
|
|
956
|
+
* routing pass through to the forwarded host. Useful for proxies (e.g. corporate
|
|
957
|
+
* gateways, internal router).
|
|
1442
958
|
*/
|
|
1443
|
-
|
|
959
|
+
baseURL?: string;
|
|
1444
960
|
/**
|
|
1445
|
-
*
|
|
1446
|
-
*
|
|
1447
|
-
*
|
|
1448
|
-
* model "remembers" stale content and applies a substring edit against
|
|
1449
|
-
* bytes that have moved.
|
|
961
|
+
* Additional `anthropic-beta` flags to opt into. Merged with the OAuth-path
|
|
962
|
+
* defaults (`claude-code-20250219`, `oauth-2025-04-20`); duplicates are
|
|
963
|
+
* de-duped. Examples:
|
|
1450
964
|
*
|
|
1451
|
-
*
|
|
1452
|
-
*
|
|
965
|
+
* - `'context-management-2025-06-27'` — server-side context compaction
|
|
966
|
+
* (token-accurate; pair with {@link AnthropicParams.contextManagement}).
|
|
967
|
+
* - `'token-efficient-tools-2026-03-28'` — terser tool_use wire format.
|
|
968
|
+
* - `'interleaved-thinking-2025-05-14'` — think between tool calls within
|
|
969
|
+
* one turn.
|
|
970
|
+
* - `'redact-thinking-2026-02-12'` — replace large thinking blocks with
|
|
971
|
+
* stubs server-side.
|
|
972
|
+
* - `'prompt-caching-scope-2026-01-05'` — extended prompt-cache scope.
|
|
1453
973
|
*
|
|
1454
|
-
*
|
|
974
|
+
* Honored on both the OAuth and API-key paths.
|
|
1455
975
|
*/
|
|
1456
|
-
|
|
976
|
+
extraBetas?: readonly string[];
|
|
1457
977
|
/**
|
|
1458
|
-
*
|
|
1459
|
-
*
|
|
1460
|
-
*
|
|
1461
|
-
* server-side `context-management-2025-06-27` beta — see
|
|
1462
|
-
* `AnthropicParams.contextManagement`.
|
|
978
|
+
* Server-side context-management directive. Sent on the request body as
|
|
979
|
+
* `context_management`. Requires the `context-management-2025-06-27` beta —
|
|
980
|
+
* add it to {@link AnthropicParams.extraBetas}.
|
|
1463
981
|
*
|
|
1464
|
-
*
|
|
1465
|
-
*
|
|
1466
|
-
* exceed `compactThreshold`, replace older `tool_result` outputs with a
|
|
1467
|
-
* short stub, keeping the newest `compactKeepTurns` turns intact. The
|
|
1468
|
-
* compaction is applied to the wire-level message list only; the
|
|
1469
|
-
* underlying session turns are not modified.
|
|
982
|
+
* Typed loosely so future Anthropic schema additions land without an SDK
|
|
983
|
+
* bump. A typical compaction edit:
|
|
1470
984
|
*
|
|
1471
|
-
*
|
|
985
|
+
* ```ts
|
|
986
|
+
* contextManagement: {
|
|
987
|
+
* edits: [{
|
|
988
|
+
* type: 'clear_tool_uses_20250919',
|
|
989
|
+
* trigger: { type: 'input_tokens', value: 180_000 },
|
|
990
|
+
* clear_at_least: { type: 'input_tokens', value: 140_000 },
|
|
991
|
+
* clear_tool_inputs: ['Read', 'Bash', 'Grep'],
|
|
992
|
+
* }],
|
|
993
|
+
* }
|
|
994
|
+
* ```
|
|
1472
995
|
*/
|
|
1473
|
-
|
|
996
|
+
contextManagement?: AnthropicContextManagement;
|
|
1474
997
|
/**
|
|
1475
|
-
*
|
|
1476
|
-
*
|
|
1477
|
-
*
|
|
1478
|
-
*
|
|
998
|
+
* Generic pass-through for fields on the Messages API request body that the
|
|
999
|
+
* SDK does not yet type. Spread into the request before the typed fields,
|
|
1000
|
+
* so explicit options ({@link AnthropicParams.contextManagement} and the
|
|
1001
|
+
* built-in fields like `model` / `tools` / `messages`) win on collision.
|
|
1002
|
+
*
|
|
1003
|
+
* Forward-compat escape hatch for new Anthropic betas — when a future flag
|
|
1004
|
+
* ships before zidane has a dedicated typed knob, set it here without
|
|
1005
|
+
* waiting on a release. Most fields will still need the matching beta in
|
|
1006
|
+
* {@link AnthropicParams.extraBetas}.
|
|
1479
1007
|
*/
|
|
1480
|
-
|
|
1008
|
+
extraBodyParams?: Record<string, unknown>;
|
|
1009
|
+
}
|
|
1010
|
+
declare function anthropic(anthropicParams?: AnthropicParams): Provider;
|
|
1011
|
+
//#endregion
|
|
1012
|
+
//#region src/providers/cerebras.d.ts
|
|
1013
|
+
interface CerebrasParams {
|
|
1014
|
+
apiKey?: string;
|
|
1015
|
+
defaultModel?: string;
|
|
1481
1016
|
/**
|
|
1482
|
-
*
|
|
1483
|
-
*
|
|
1484
|
-
*
|
|
1017
|
+
* Provider capability flags. Cerebras currently serves text-only OSS models
|
|
1018
|
+
* (GLM, Llama-family, Qwen-family) — default: `{ vision: false, imageInToolResult: false }`.
|
|
1019
|
+
* Override when routing to a vision-capable deployment.
|
|
1485
1020
|
*/
|
|
1486
|
-
|
|
1021
|
+
capabilities?: ProviderCapabilities;
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Cerebras provider.
|
|
1025
|
+
*
|
|
1026
|
+
* Thin wrapper around {@link openaiCompat} with Cerebras-specific defaults
|
|
1027
|
+
* (base URL, default model).
|
|
1028
|
+
*/
|
|
1029
|
+
declare function cerebras(params?: CerebrasParams): Provider;
|
|
1030
|
+
//#endregion
|
|
1031
|
+
//#region src/providers/openai.d.ts
|
|
1032
|
+
interface OpenAIParams {
|
|
1033
|
+
/** OpenAI Codex OAuth access token. Falls back to OPENAI_CODEX_API_KEY and .credentials.json. */
|
|
1034
|
+
apiKey?: string;
|
|
1035
|
+
/** Alias for apiKey, matching the OAuth credential field. */
|
|
1036
|
+
access?: string;
|
|
1037
|
+
refresh?: string;
|
|
1038
|
+
expires?: number;
|
|
1039
|
+
accountId?: string;
|
|
1040
|
+
defaultModel?: string;
|
|
1041
|
+
transport?: 'sse' | 'websocket' | 'auto';
|
|
1042
|
+
}
|
|
1043
|
+
declare function openai(params?: OpenAIParams): Provider;
|
|
1044
|
+
//#endregion
|
|
1045
|
+
//#region src/providers/openai-compat.d.ts
|
|
1046
|
+
/**
|
|
1047
|
+
* HTTP error thrown when an OpenAI-compatible endpoint returns a non-OK response.
|
|
1048
|
+
*
|
|
1049
|
+
* The body is best-effort JSON-parsed; `error.message` / `error.code` / `error.type`
|
|
1050
|
+
* are extracted for clean downstream classification.
|
|
1051
|
+
*/
|
|
1052
|
+
declare class OpenAICompatHttpError extends Error {
|
|
1053
|
+
readonly status: number;
|
|
1054
|
+
readonly providerCode?: string;
|
|
1055
|
+
readonly bodyText: string;
|
|
1056
|
+
constructor(status: number, bodyText: string);
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Classify an OpenAI-compatible error into `ClassifiedError`.
|
|
1060
|
+
*
|
|
1061
|
+
* Recognizes:
|
|
1062
|
+
* - `AbortError` (from fetch) → `aborted`.
|
|
1063
|
+
* - `OpenAICompatHttpError` with a context-exceeded code or message → `context_exceeded`.
|
|
1064
|
+
* - Any other `OpenAICompatHttpError` → `provider_error`.
|
|
1065
|
+
*
|
|
1066
|
+
* Returns `null` for unrecognized error shapes (the loop falls back to `AgentProviderError`).
|
|
1067
|
+
*/
|
|
1068
|
+
declare function classifyOpenAICompatError(err: unknown): ClassifiedError | null;
|
|
1069
|
+
/**
|
|
1070
|
+
* Map an OpenAI-compatible `finish_reason` string to the zidane `TurnFinishReason` union.
|
|
1071
|
+
*/
|
|
1072
|
+
declare function mapOAIFinishReason(reason: string | null | undefined): TurnFinishReason | undefined;
|
|
1073
|
+
/**
|
|
1074
|
+
* Auth header config. `scheme` is prepended to the api key with a space, e.g.
|
|
1075
|
+
* `{ name: 'Authorization', scheme: 'Bearer' }` → `Authorization: Bearer <key>`.
|
|
1076
|
+
* Omit `scheme` for raw header values (e.g. `{ name: 'X-Api-Key' }` → `X-Api-Key: <key>`).
|
|
1077
|
+
*
|
|
1078
|
+
* Real-world examples:
|
|
1079
|
+
* - Default OpenAI / OpenRouter / Cerebras: `{ name: 'Authorization', scheme: 'Bearer' }`.
|
|
1080
|
+
* - Baseten: `{ name: 'Authorization', scheme: 'Api-Key' }`.
|
|
1081
|
+
* - Some gateways: `{ name: 'X-Api-Key' }`.
|
|
1082
|
+
*/
|
|
1083
|
+
interface OpenAICompatAuthHeader {
|
|
1084
|
+
name: string;
|
|
1085
|
+
scheme?: string;
|
|
1086
|
+
}
|
|
1087
|
+
interface OpenAICompatParams {
|
|
1088
|
+
/** Bearer-style API key. */
|
|
1089
|
+
apiKey: string;
|
|
1090
|
+
/** Base URL — `/chat/completions` is appended. */
|
|
1091
|
+
baseURL: string;
|
|
1092
|
+
/** Default model id when `run({ model })` is omitted. */
|
|
1093
|
+
defaultModel?: string;
|
|
1094
|
+
/** Provider name exposed as `Provider.name`. Defaults to `'openai-compat'`. */
|
|
1095
|
+
name?: string;
|
|
1096
|
+
/** Auth header shape. Defaults to `{ name: 'Authorization', scheme: 'Bearer' }`. */
|
|
1097
|
+
authHeader?: OpenAICompatAuthHeader;
|
|
1098
|
+
/** Extra headers sent with every request (e.g. referer, user-agent). */
|
|
1099
|
+
extraHeaders?: Record<string, string>;
|
|
1487
1100
|
/**
|
|
1488
|
-
*
|
|
1489
|
-
*
|
|
1490
|
-
*
|
|
1491
|
-
* `old_string` / `new_string` so the model can paste back a numbered
|
|
1492
|
-
* chunk verbatim without breaking the match.
|
|
1493
|
-
*
|
|
1494
|
-
* Set `false` to opt out — useful for callers piping `read_file` into
|
|
1495
|
-
* downstream parsers that don't recognize the prefix. Per-call
|
|
1496
|
-
* `read_file({ lineNumbers: false })` overrides this default.
|
|
1101
|
+
* Provider-level capability flags. Routed into the message shaper and the
|
|
1102
|
+
* agent loop so images in tool results + user messages are handled correctly
|
|
1103
|
+
* for the underlying model.
|
|
1497
1104
|
*
|
|
1498
|
-
*
|
|
1105
|
+
* Defaults when omitted: `vision: false`, `imageInToolResult: false` — a
|
|
1106
|
+
* conservative assumption matching most OSS text-only OpenAI-compat
|
|
1107
|
+
* endpoints. Override when routing to a known vision-capable endpoint
|
|
1108
|
+
* (e.g. OpenRouter vision models, Baseten image-capable deployments).
|
|
1499
1109
|
*/
|
|
1500
|
-
|
|
1110
|
+
capabilities?: ProviderCapabilities;
|
|
1501
1111
|
/**
|
|
1502
|
-
*
|
|
1503
|
-
*
|
|
1504
|
-
* run modified the same path. The replacement is applied to the
|
|
1505
|
-
* wire-level message list only — persisted session turns keep the
|
|
1506
|
-
* original content.
|
|
1507
|
-
*
|
|
1508
|
-
* Eliminates the common waste pattern where the model carries the
|
|
1509
|
-
* pre-edit file body forward across many turns "in case it needs it".
|
|
1510
|
-
* Pairs cleanly with `compactStrategy: 'tail'`: stale reads shrink
|
|
1511
|
-
* first, then the byte-threshold compaction fires if anything's left.
|
|
1112
|
+
* Whether this endpoint honors `cache_control: { type: 'ephemeral' }` markers
|
|
1113
|
+
* on message content parts and tool definitions.
|
|
1512
1114
|
*
|
|
1513
|
-
*
|
|
1514
|
-
*
|
|
1515
|
-
*
|
|
1516
|
-
*
|
|
1115
|
+
* - `true` — inject markers when the caller asks for caching. OpenRouter routes
|
|
1116
|
+
* to Anthropic/Gemini forward the markers; routes to OpenAI/DeepSeek/
|
|
1117
|
+
* Grok/Groq/Moonshot ignore them (those backends cache automatically).
|
|
1118
|
+
* - `false` — never inject markers. Safe default for endpoints that strictly
|
|
1119
|
+
* validate the request schema (OpenAI direct, most OSS inference
|
|
1120
|
+
* servers) and would reject unknown fields.
|
|
1517
1121
|
*
|
|
1518
|
-
* Default: `false`.
|
|
1122
|
+
* Default: `false`. The `openrouter` wrapper sets this to `true`.
|
|
1519
1123
|
*/
|
|
1520
|
-
|
|
1124
|
+
cacheBreakpoints?: boolean;
|
|
1521
1125
|
/**
|
|
1522
|
-
*
|
|
1523
|
-
*
|
|
1524
|
-
*
|
|
1525
|
-
*
|
|
1526
|
-
* native tool ("lazy" / progressive disclosure).
|
|
1527
|
-
*
|
|
1528
|
-
* Native tools (those passed to `createAgent({ tools })`) and skill tools
|
|
1529
|
-
* are always eager — they are core to the agent and cheap. Only MCP tools
|
|
1530
|
-
* are eligible for lazy disclosure.
|
|
1531
|
-
*
|
|
1532
|
-
* When `'lazy'`, the agent:
|
|
1533
|
-
* - Appends a `<searchable_tools>` section to the system prompt listing
|
|
1534
|
-
* every MCP tool by `name` + `description` only (no `inputSchema`).
|
|
1535
|
-
* - Auto-injects a `tool_search` native tool (opt out via
|
|
1536
|
-
* {@link AgentBehavior.toolSearch}) the model uses to load schemas on
|
|
1537
|
-
* demand. Surfaced tools persist for the rest of the run.
|
|
1538
|
-
* - Rebuilds the wire-level tool list each turn, appending newly-unlocked
|
|
1539
|
-
* tools at the end so the prefix-cache breakpoint advances cleanly.
|
|
1126
|
+
* Whether this endpoint speaks OpenRouter's normalized reasoning envelope —
|
|
1127
|
+
* `reasoning: { effort | max_tokens | exclude }` on requests and structured
|
|
1128
|
+
* `reasoning_details[]` on assistant messages, round-tripped to preserve
|
|
1129
|
+
* extended-reasoning state across turns.
|
|
1540
1130
|
*
|
|
1541
|
-
*
|
|
1542
|
-
*
|
|
1543
|
-
*
|
|
1544
|
-
*
|
|
1131
|
+
* - `true` — map zidane's `behavior.thinking` / `behavior.thinkingBudget` to
|
|
1132
|
+
* the request's `reasoning` field, capture `reasoning_details`
|
|
1133
|
+
* from streaming responses into `provider_reasoning` blocks, and
|
|
1134
|
+
* echo them back on subsequent assistant messages.
|
|
1135
|
+
* - `false` — never set the field; drop any stored `provider_reasoning`
|
|
1136
|
+
* blocks before sending. Safe default for hosts that strict-
|
|
1137
|
+
* validate the request schema.
|
|
1545
1138
|
*
|
|
1546
|
-
* Default: `
|
|
1139
|
+
* Default: `false`. The `openrouter` wrapper sets this to `true`.
|
|
1547
1140
|
*/
|
|
1548
|
-
|
|
1549
|
-
/**
|
|
1550
|
-
*
|
|
1551
|
-
*
|
|
1552
|
-
*
|
|
1553
|
-
*
|
|
1554
|
-
* host wants to ship a custom discovery tool. Note that the catalog
|
|
1555
|
-
* text drops the call-to-action prose in this case so the model isn't
|
|
1556
|
-
* pointed at a non-existent tool.
|
|
1557
|
-
* - `limit` — default cap on results returned per `tool_search` call when
|
|
1558
|
-
* the model omits the parameter. Default: `20`.
|
|
1559
|
-
*
|
|
1560
|
-
* Note on host-defined `tool_search`: a tool the host registers under the
|
|
1561
|
-
* name `tool_search` (or under any alias whose canonical is `tool_search`)
|
|
1562
|
-
* will shadow the auto-injected one — the catalog text will point at the
|
|
1563
|
-
* host's wire name, but driving the unlock flow requires either using
|
|
1564
|
-
* `createToolSearchTool({ catalog, unlocked })` from `tools/tool-search`
|
|
1565
|
-
* (which internally mutates the unlock set) or fully opting out via
|
|
1566
|
-
* `toolSearch.tool: false` and treating discovery as a host-side concern.
|
|
1567
|
-
* A bare host tool that doesn't touch the unlock set will not advance the
|
|
1568
|
-
* lazy disclosure state and the hard gate will keep refusing lazy calls.
|
|
1141
|
+
supportsReasoning?: boolean;
|
|
1142
|
+
/**
|
|
1143
|
+
* Generic pass-through for fields on the Chat Completions request body that
|
|
1144
|
+
* zidane does not yet type. Spread into the request before the typed core
|
|
1145
|
+
* (model / messages / tools / max_tokens / stream / tool_choice), so
|
|
1146
|
+
* explicit options always win on collision.
|
|
1569
1147
|
*
|
|
1570
|
-
*
|
|
1148
|
+
* Forward-compat escape hatch for endpoints that ship one-off fields ahead
|
|
1149
|
+
* of zidane (e.g. OpenAI `reasoning_effort`, OpenRouter `provider` routing,
|
|
1150
|
+
* vendor-specific `safety_level` knobs).
|
|
1571
1151
|
*/
|
|
1572
|
-
|
|
1573
|
-
tool?: false;
|
|
1574
|
-
limit?: number;
|
|
1575
|
-
};
|
|
1152
|
+
extraBodyParams?: Record<string, unknown>;
|
|
1576
1153
|
}
|
|
1577
1154
|
/**
|
|
1578
|
-
*
|
|
1155
|
+
* Factory for any OpenAI-compatible HTTP endpoint.
|
|
1579
1156
|
*
|
|
1580
|
-
*
|
|
1581
|
-
*
|
|
1157
|
+
* Speaks the standard `POST /chat/completions` + `stream: true` + SSE dialect.
|
|
1158
|
+
* Thin wrappers (`openrouter`, `cerebras`) call this with pinned defaults.
|
|
1582
1159
|
*
|
|
1583
|
-
*
|
|
1584
|
-
*
|
|
1585
|
-
*
|
|
1586
|
-
*
|
|
1160
|
+
* @example Baseten (non-standard auth scheme)
|
|
1161
|
+
* ```ts
|
|
1162
|
+
* openaiCompat({
|
|
1163
|
+
* name: 'baseten',
|
|
1164
|
+
* apiKey: process.env.BASETEN_API_KEY!,
|
|
1165
|
+
* baseURL: process.env.BASETEN_PROXY_URL!,
|
|
1166
|
+
* authHeader: { name: 'Authorization', scheme: 'Api-Key' },
|
|
1167
|
+
* })
|
|
1168
|
+
* ```
|
|
1587
1169
|
*/
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1170
|
+
declare function openaiCompat(params: OpenAICompatParams): Provider;
|
|
1171
|
+
//#endregion
|
|
1172
|
+
//#region src/providers/openrouter.d.ts
|
|
1173
|
+
interface OpenRouterParams {
|
|
1174
|
+
apiKey?: string;
|
|
1175
|
+
defaultModel?: string;
|
|
1176
|
+
/**
|
|
1177
|
+
* Provider capability flags. OpenRouter itself is a router — whether vision or
|
|
1178
|
+
* native image-in-tool-result are supported depends on the downstream model.
|
|
1179
|
+
* Default: `{ vision: true, imageInToolResult: false }` — matches the default
|
|
1180
|
+
* `anthropic/claude-sonnet-4-6` model (vision-capable via companion user-message
|
|
1181
|
+
* fallback since OpenRouter exposes Claude over the Chat Completions dialect).
|
|
1182
|
+
*
|
|
1183
|
+
* Override when routing to a known-text-only model (e.g. `meta-llama/llama-3-8b-instruct`).
|
|
1184
|
+
*/
|
|
1185
|
+
capabilities?: ProviderCapabilities;
|
|
1592
1186
|
}
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1187
|
+
/**
|
|
1188
|
+
* OpenRouter provider.
|
|
1189
|
+
*
|
|
1190
|
+
* Thin wrapper around {@link openaiCompat} with OpenRouter-specific defaults
|
|
1191
|
+
* (base URL, default model) and required attribution headers.
|
|
1192
|
+
*/
|
|
1193
|
+
declare function openrouter(params?: OpenRouterParams): Provider;
|
|
1194
|
+
//#endregion
|
|
1195
|
+
//#region src/providers/index.d.ts
|
|
1196
|
+
interface ToolSpec {
|
|
1197
|
+
name: string;
|
|
1198
|
+
description: string;
|
|
1199
|
+
inputSchema: Record<string, unknown>;
|
|
1601
1200
|
}
|
|
1602
|
-
interface
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
/**
|
|
1610
|
-
|
|
1201
|
+
interface ToolCall {
|
|
1202
|
+
id: string;
|
|
1203
|
+
name: string;
|
|
1204
|
+
input: Record<string, unknown>;
|
|
1205
|
+
}
|
|
1206
|
+
interface ToolResult {
|
|
1207
|
+
id: string;
|
|
1208
|
+
/**
|
|
1209
|
+
* Tool output — plain string for text-only tools (the common case) or a structured
|
|
1210
|
+
* array of content blocks for tools that return images or mixed content (e.g. an
|
|
1211
|
+
* MCP browser server returning a screenshot).
|
|
1212
|
+
*
|
|
1213
|
+
* Use `toolResultToText(content)` when a downstream consumer only handles strings.
|
|
1214
|
+
*/
|
|
1215
|
+
content: string | ToolResultContent[];
|
|
1611
1216
|
}
|
|
1612
1217
|
/**
|
|
1613
|
-
*
|
|
1614
|
-
*
|
|
1615
|
-
* MCP servers can return a mix of text, image, resource, and audio blocks. Tools
|
|
1616
|
-
* return `string` for the common text-only case or `ToolResultContent[]` when they
|
|
1617
|
-
* need to preserve non-text content (e.g. screenshots from a browser MCP).
|
|
1218
|
+
* Provider-level capability flags used by the agent loop to route tool results
|
|
1219
|
+
* and user messages appropriately.
|
|
1618
1220
|
*
|
|
1619
|
-
*
|
|
1620
|
-
*
|
|
1621
|
-
*
|
|
1622
|
-
* does not accept images inside tool-role messages.
|
|
1221
|
+
* When a flag is `undefined` (omitted), the loop applies the conservative
|
|
1222
|
+
* text-only default — images are stripped and replaced with a text marker so
|
|
1223
|
+
* non-vision models do not confabulate about content they cannot see.
|
|
1623
1224
|
*/
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1225
|
+
interface ProviderCapabilities {
|
|
1226
|
+
/**
|
|
1227
|
+
* Model accepts image input anywhere (user messages and tool results).
|
|
1228
|
+
*
|
|
1229
|
+
* When `false`, the loop replaces image blocks with
|
|
1230
|
+
* `"[image omitted — model does not support vision]"` before they reach the provider.
|
|
1231
|
+
* Gives the model an honest marker instead of letting JSON-stringified base64 slip
|
|
1232
|
+
* through and get confabulated over.
|
|
1233
|
+
*/
|
|
1234
|
+
vision?: boolean;
|
|
1235
|
+
/**
|
|
1236
|
+
* Provider wire format embeds images inside tool-role messages natively
|
|
1237
|
+
* (Anthropic `tool_result.content` arrays, OpenAI Codex pi-ai `toolResult` blocks).
|
|
1238
|
+
*
|
|
1239
|
+
* When `false`, a vision-capable provider still gets images — but via a
|
|
1240
|
+
* companion `user` message emitted immediately after the flattened
|
|
1241
|
+
* `tool`/`tool_result` marker. This is the Claude Desktop / Cline pattern
|
|
1242
|
+
* and works on any OpenAI Chat Completions endpoint that accepts image
|
|
1243
|
+
* URLs in user messages.
|
|
1244
|
+
*/
|
|
1245
|
+
imageInToolResult?: boolean;
|
|
1246
|
+
}
|
|
1247
|
+
interface StreamCallbacks {
|
|
1248
|
+
onText: (delta: string) => void;
|
|
1249
|
+
onThinking?: (delta: string) => void;
|
|
1250
|
+
onOAuthRefresh?: (ctx: OAuthRefreshHookContext) => void | Promise<void>;
|
|
1251
|
+
}
|
|
1252
|
+
interface TurnResult {
|
|
1253
|
+
/** Full assistant turn as a SessionMessage */
|
|
1254
|
+
assistantMessage: SessionMessage;
|
|
1255
|
+
/** Text content blocks concatenated */
|
|
1627
1256
|
text: string;
|
|
1257
|
+
/** Tool calls requested by the model */
|
|
1258
|
+
toolCalls: ToolCall[];
|
|
1259
|
+
/** Whether the model wants to stop */
|
|
1260
|
+
done: boolean;
|
|
1261
|
+
usage: TurnUsage;
|
|
1628
1262
|
}
|
|
1629
|
-
interface
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1263
|
+
interface StreamOptions {
|
|
1264
|
+
model: string;
|
|
1265
|
+
system: string;
|
|
1266
|
+
tools: unknown[];
|
|
1267
|
+
messages: SessionMessage[];
|
|
1268
|
+
maxTokens: number;
|
|
1269
|
+
/** Thinking/reasoning level (optional, default: off) */
|
|
1270
|
+
thinking?: ThinkingLevel;
|
|
1271
|
+
/** Exact thinking token budget — overrides the level-based default when set */
|
|
1272
|
+
thinkingBudget?: number;
|
|
1273
|
+
/** Force tool selection behavior */
|
|
1274
|
+
toolChoice?: {
|
|
1275
|
+
type: 'auto' | 'required' | 'tool';
|
|
1276
|
+
name?: string;
|
|
1277
|
+
};
|
|
1278
|
+
/**
|
|
1279
|
+
* Enable prompt caching on this call. When `true`, providers that support it
|
|
1280
|
+
* insert `cache_control` breakpoints on the system prompt, last tool, and
|
|
1281
|
+
* last stable message so the shared prefix is cached across turns.
|
|
1282
|
+
*
|
|
1283
|
+
* Default: `false` (providers opt callers in — the agent loop passes `true`).
|
|
1284
|
+
*/
|
|
1285
|
+
cache?: boolean;
|
|
1286
|
+
/** Abort signal for cancellation */
|
|
1287
|
+
signal?: AbortSignal;
|
|
1288
|
+
}
|
|
1289
|
+
interface Provider {
|
|
1290
|
+
readonly name: string;
|
|
1291
|
+
readonly meta: {
|
|
1292
|
+
defaultModel: string; /** Provider-level capability flags. See {@link ProviderCapabilities}. */
|
|
1293
|
+
capabilities?: ProviderCapabilities;
|
|
1294
|
+
} & Record<string, unknown>;
|
|
1295
|
+
/** Format tool specs for this provider */
|
|
1296
|
+
formatTools: (tools: ToolSpec[]) => unknown[];
|
|
1297
|
+
/** Create a text-only user message. Multimodal content goes through `promptMessage`. */
|
|
1298
|
+
userMessage: (content: string) => SessionMessage;
|
|
1299
|
+
/** Create an assistant message (for priming) */
|
|
1300
|
+
assistantMessage: (content: string) => SessionMessage;
|
|
1301
|
+
/** Create a tool results message to send back */
|
|
1302
|
+
toolResultsMessage: (results: ToolResult[]) => SessionMessage;
|
|
1303
|
+
/** Stream a turn, calling onText for each text delta */
|
|
1304
|
+
stream: (options: StreamOptions, callbacks: StreamCallbacks) => Promise<TurnResult>;
|
|
1305
|
+
/**
|
|
1306
|
+
* Build a user `SessionMessage` from multimodal prompt parts.
|
|
1307
|
+
*
|
|
1308
|
+
* Providers that cannot handle a particular part type (e.g. document) should throw.
|
|
1309
|
+
* The agent loop always canonicalizes the run-level prompt into parts before calling
|
|
1310
|
+
* this method; providers may fall back to `userMessage` for the text-only path if
|
|
1311
|
+
* they do not implement this.
|
|
1312
|
+
*/
|
|
1313
|
+
promptMessage?: (parts: PromptPart[]) => SessionMessage;
|
|
1314
|
+
/**
|
|
1315
|
+
* Classify a native provider error for downstream typed-error wrapping.
|
|
1316
|
+
*
|
|
1317
|
+
* Return `null` when the error is not recognized — the loop will wrap it in
|
|
1318
|
+
* `AgentProviderError` with the provider's name. Return a `ClassifiedError` to
|
|
1319
|
+
* route it to one of the typed error classes.
|
|
1320
|
+
*/
|
|
1321
|
+
classifyError?: (err: unknown) => ClassifiedError | null;
|
|
1635
1322
|
}
|
|
1323
|
+
//#endregion
|
|
1324
|
+
//#region src/session/file-map.d.ts
|
|
1636
1325
|
/**
|
|
1637
|
-
*
|
|
1638
|
-
*
|
|
1639
|
-
*
|
|
1640
|
-
* Use at UI boundaries where a string is required; providers that understand
|
|
1641
|
-
* structured content should route the array through without flattening.
|
|
1326
|
+
* Host-provided file-map adapter. Three methods exchanging `Record<string, string>`
|
|
1327
|
+
* payloads — the whole persistence surface the wrapper needs.
|
|
1642
1328
|
*/
|
|
1643
|
-
|
|
1329
|
+
interface FileMapAdapter {
|
|
1330
|
+
/** Load the current file map. Returns an empty `files` record when nothing is persisted. */
|
|
1331
|
+
get: () => Promise<{
|
|
1332
|
+
files: Record<string, string>;
|
|
1333
|
+
}>;
|
|
1334
|
+
/** Replace the persisted file map. Full-rewrite semantics. */
|
|
1335
|
+
save: (files: Record<string, string>) => Promise<void>;
|
|
1336
|
+
/** Delete all persisted state. */
|
|
1337
|
+
delete: () => Promise<void>;
|
|
1338
|
+
}
|
|
1339
|
+
interface FileMapStoreOptions {
|
|
1340
|
+
/** Filename for the JSONL turns log. Default: `turns.jsonl`. */
|
|
1341
|
+
turnsFile?: string;
|
|
1342
|
+
/** Filename for the metadata JSON. Default: `meta.json`. */
|
|
1343
|
+
metaFile?: string;
|
|
1344
|
+
}
|
|
1644
1345
|
/**
|
|
1645
|
-
*
|
|
1646
|
-
*
|
|
1647
|
-
* - Plain text: UTF-8 byte length.
|
|
1648
|
-
* - Structured content: text blocks contribute their UTF-8 byte length; image
|
|
1649
|
-
* blocks contribute their **base64 character length**, since that is what
|
|
1650
|
-
* the model tokenizes (the wire-encoded payload, not the decoded image).
|
|
1346
|
+
* Create a single-session `SessionStore` backed by a file-map adapter.
|
|
1651
1347
|
*
|
|
1652
|
-
*
|
|
1653
|
-
*
|
|
1654
|
-
*
|
|
1348
|
+
* @example
|
|
1349
|
+
* ```ts
|
|
1350
|
+
* const session = await createSession({
|
|
1351
|
+
* store: createFileMapStore(hostSessionStore),
|
|
1352
|
+
* })
|
|
1353
|
+
* ```
|
|
1655
1354
|
*/
|
|
1656
|
-
declare function
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1355
|
+
declare function createFileMapStore(adapter: FileMapAdapter, options?: FileMapStoreOptions): SessionStore;
|
|
1356
|
+
//#endregion
|
|
1357
|
+
//#region src/session/memory.d.ts
|
|
1358
|
+
declare function createMemoryStore(): SessionStore;
|
|
1359
|
+
//#endregion
|
|
1360
|
+
//#region src/session/messages.d.ts
|
|
1361
|
+
declare function fromAnthropic(msg: {
|
|
1362
|
+
role: string;
|
|
1363
|
+
content: unknown;
|
|
1364
|
+
}): SessionMessage;
|
|
1365
|
+
declare function fromOpenAI(msg: {
|
|
1366
|
+
role: string;
|
|
1367
|
+
content: unknown;
|
|
1368
|
+
}): SessionMessage;
|
|
1369
|
+
declare function toAnthropic(msg: SessionMessage): {
|
|
1370
|
+
role: string;
|
|
1371
|
+
content: unknown;
|
|
1372
|
+
};
|
|
1373
|
+
declare function toOpenAI(msg: SessionMessage): {
|
|
1374
|
+
role: string;
|
|
1375
|
+
content: unknown;
|
|
1376
|
+
};
|
|
1377
|
+
declare function autoDetectAndConvert(msg: {
|
|
1378
|
+
role: string;
|
|
1379
|
+
content: unknown;
|
|
1380
|
+
}): SessionMessage;
|
|
1381
|
+
//#endregion
|
|
1382
|
+
//#region src/session/remote.d.ts
|
|
1383
|
+
interface RemoteStoreOptions {
|
|
1384
|
+
/** Base URL of the session API */
|
|
1385
|
+
url: string;
|
|
1386
|
+
/** Optional headers (e.g. for authentication) */
|
|
1387
|
+
headers?: Record<string, string>;
|
|
1388
|
+
}
|
|
1389
|
+
declare function createRemoteStore(options: RemoteStoreOptions): SessionStore;
|
|
1390
|
+
//#endregion
|
|
1391
|
+
//#region src/session/index.d.ts
|
|
1392
|
+
interface SessionRun {
|
|
1666
1393
|
id: string;
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1394
|
+
startedAt: number;
|
|
1395
|
+
endedAt?: number;
|
|
1396
|
+
prompt: string;
|
|
1397
|
+
status: 'running' | 'completed' | 'aborted' | 'error';
|
|
1398
|
+
turns?: number;
|
|
1399
|
+
tokensIn?: number;
|
|
1400
|
+
tokensOut?: number;
|
|
1401
|
+
error?: string;
|
|
1402
|
+
/** Per-turn usage breakdown */
|
|
1403
|
+
turnUsage?: TurnUsage[];
|
|
1404
|
+
/** Total usage across all turns */
|
|
1405
|
+
totalUsage?: TurnUsage;
|
|
1406
|
+
/** Estimated cost in USD */
|
|
1407
|
+
cost?: number;
|
|
1672
1408
|
/**
|
|
1673
|
-
*
|
|
1674
|
-
*
|
|
1409
|
+
* The run that spawned this one, when the agent is a subagent sharing its
|
|
1410
|
+
* parent's session. Undefined on top-level `agent.run()`. Consumers can walk
|
|
1411
|
+
* `runs` by `parentRunId` to reconstruct the subagent tree.
|
|
1675
1412
|
*/
|
|
1676
|
-
|
|
1677
|
-
isError?: boolean;
|
|
1678
|
-
} | {
|
|
1679
|
-
type: 'thinking';
|
|
1680
|
-
text: string;
|
|
1681
|
-
signature?: string;
|
|
1413
|
+
parentRunId?: string;
|
|
1682
1414
|
/**
|
|
1683
|
-
*
|
|
1684
|
-
*
|
|
1685
|
-
* hops to avoid 400s. Unset means legacy/unknown — forwarded as-is.
|
|
1415
|
+
* Zero-based subagent depth. 0 = top-level run, 1 = direct child, …
|
|
1416
|
+
* Recorded here so hosts can query/filter by level without walking the tree.
|
|
1686
1417
|
*/
|
|
1687
|
-
|
|
1688
|
-
}
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1418
|
+
depth?: number;
|
|
1419
|
+
}
|
|
1420
|
+
interface SessionData {
|
|
1421
|
+
id: string;
|
|
1422
|
+
agentId?: string;
|
|
1692
1423
|
/**
|
|
1693
|
-
*
|
|
1694
|
-
*
|
|
1695
|
-
* `
|
|
1696
|
-
*
|
|
1424
|
+
* Absolute path of the project this session belongs to — typically
|
|
1425
|
+
* the git root resolved from `cwd` at creation time, falling back to
|
|
1426
|
+
* `cwd` itself when not in a git repo. Set ONCE on creation and never
|
|
1427
|
+
* mutated thereafter (the session "belongs" to that project forever).
|
|
1697
1428
|
*
|
|
1698
|
-
*
|
|
1699
|
-
*
|
|
1700
|
-
* —
|
|
1429
|
+
* Used by the TUI's sessions list to filter rows by current project,
|
|
1430
|
+
* so the user only sees conversations relevant to where they are
|
|
1431
|
+
* working — without needing one `.{prefix}/` directory per project.
|
|
1432
|
+
*
|
|
1433
|
+
* `undefined` on pre-tagging legacy sessions; the chat layer treats
|
|
1434
|
+
* those as "untagged" and hides them unless `Settings.showAllProjects`
|
|
1435
|
+
* is on.
|
|
1701
1436
|
*/
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1437
|
+
projectRoot?: string;
|
|
1438
|
+
turns: SessionTurn[];
|
|
1439
|
+
runs: SessionRun[];
|
|
1440
|
+
status: 'idle' | 'running' | 'completed' | 'error';
|
|
1441
|
+
metadata: Record<string, unknown>;
|
|
1442
|
+
createdAt: number;
|
|
1443
|
+
updatedAt: number;
|
|
1444
|
+
}
|
|
1445
|
+
interface SessionStore {
|
|
1446
|
+
/** Optional: generate a session ID server-side (e.g. Supabase UUID). */
|
|
1447
|
+
generateSessionId?: () => string | Promise<string>;
|
|
1448
|
+
/** Optional: generate a turn ID server-side. */
|
|
1449
|
+
generateTurnId?: () => string | Promise<string>;
|
|
1450
|
+
/** Load a session by ID. Returns null if not found. */
|
|
1451
|
+
load: (sessionId: string) => Promise<SessionData | null>;
|
|
1452
|
+
/** Save a session (create or update, full document). */
|
|
1453
|
+
save: (session: SessionData) => Promise<void>;
|
|
1454
|
+
/** Delete a session. */
|
|
1455
|
+
delete: (sessionId: string) => Promise<void>;
|
|
1705
1456
|
/**
|
|
1706
|
-
*
|
|
1707
|
-
*
|
|
1708
|
-
*
|
|
1457
|
+
* List session IDs, optionally filtered. `projectRoot` restricts to
|
|
1458
|
+
* sessions whose `SessionData.projectRoot` matches exactly — untagged
|
|
1459
|
+
* (legacy) sessions are NOT returned under that filter; pass `null`
|
|
1460
|
+
* explicitly to ask for untagged ones, or omit the field to ignore
|
|
1461
|
+
* the axis entirely. `agentId` filters by recorded agent; the two
|
|
1462
|
+
* conditions AND together when both are set.
|
|
1709
1463
|
*/
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
/**
|
|
1718
|
-
|
|
1719
|
-
/**
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
/** Token usage — only present on assistant turns */
|
|
1724
|
-
usage?: TurnUsage;
|
|
1725
|
-
/** Unix timestamp (Date.now()) when the turn was created */
|
|
1726
|
-
createdAt: number;
|
|
1464
|
+
list: (filter?: {
|
|
1465
|
+
agentId?: string;
|
|
1466
|
+
limit?: number;
|
|
1467
|
+
projectRoot?: string | null;
|
|
1468
|
+
}) => Promise<string[]>;
|
|
1469
|
+
/** Append new turns to a session (incremental, avoids full re-save). */
|
|
1470
|
+
appendTurns: (sessionId: string, turns: SessionTurn[]) => Promise<void>;
|
|
1471
|
+
/** Return a slice of turns for a session. */
|
|
1472
|
+
getTurns: (sessionId: string, from?: number, limit?: number) => Promise<SessionTurn[]>;
|
|
1473
|
+
/** Persist an updated run record (called after completeRun / abortRun / errorRun). */
|
|
1474
|
+
updateRun: (sessionId: string, run: SessionRun) => Promise<void>;
|
|
1475
|
+
/** Update the top-level status of a session. */
|
|
1476
|
+
updateStatus: (sessionId: string, status: SessionData['status']) => Promise<void>;
|
|
1727
1477
|
}
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
type RunHookMap = Record<string, ((ctx: any) => unknown) | ((ctx: any) => unknown)[]>;
|
|
1734
|
-
interface AgentRunOptions {
|
|
1735
|
-
model?: string;
|
|
1478
|
+
interface Session {
|
|
1479
|
+
/** Session ID */
|
|
1480
|
+
readonly id: string;
|
|
1481
|
+
/** Agent ID (optional label) */
|
|
1482
|
+
readonly agentId?: string;
|
|
1736
1483
|
/**
|
|
1737
|
-
*
|
|
1738
|
-
*
|
|
1739
|
-
* Accepts either a plain string (single text part) or an array of `PromptPart`s for
|
|
1740
|
-
* multimodal inputs (text, images, documents). See {@link PromptPart}.
|
|
1484
|
+
* Project this session was created under — see {@link SessionData.projectRoot}.
|
|
1485
|
+
* Set once on creation; surfaces here for read-only inspection.
|
|
1741
1486
|
*/
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
/** Abort signal — when triggered, the agent stops after the current turn */
|
|
1746
|
-
signal?: AbortSignal;
|
|
1747
|
-
/** Behavior overrides for this run (overrides agent defaults) */
|
|
1748
|
-
behavior?: AgentBehavior;
|
|
1749
|
-
/** Tool overrides for this run. Pass {} for no tools. Omit to use agent tools. */
|
|
1750
|
-
tools?: Record<string, ToolDef>;
|
|
1487
|
+
readonly projectRoot?: string;
|
|
1488
|
+
/** Current turn history */
|
|
1489
|
+
readonly turns: SessionTurn[];
|
|
1751
1490
|
/**
|
|
1752
|
-
*
|
|
1753
|
-
* detached in a finally block so handlers never leak across runs.
|
|
1491
|
+
* True when this session has no turns yet.
|
|
1754
1492
|
*
|
|
1755
|
-
*
|
|
1493
|
+
* Use this as a first-prompt signal when setting up a run — e.g. writing initial
|
|
1494
|
+
* configuration only on fresh sessions. Equivalent to `turns.length === 0`.
|
|
1756
1495
|
*/
|
|
1757
|
-
|
|
1496
|
+
readonly isEmpty: boolean;
|
|
1497
|
+
/** Top-level session status */
|
|
1498
|
+
readonly status: SessionData['status'];
|
|
1499
|
+
/** All runs in this session */
|
|
1500
|
+
readonly runs: SessionRun[];
|
|
1501
|
+
/** Arbitrary metadata */
|
|
1502
|
+
readonly metadata: Record<string, unknown>;
|
|
1758
1503
|
/**
|
|
1759
|
-
*
|
|
1760
|
-
*
|
|
1761
|
-
*
|
|
1504
|
+
* Start tracking a new run. `extras.parentRunId` + `extras.depth` are
|
|
1505
|
+
* populated by the spawn tool when a child agent shares its parent's
|
|
1506
|
+
* session; regular top-level `agent.run()` calls omit them.
|
|
1762
1507
|
*/
|
|
1763
|
-
|
|
1508
|
+
startRun: (runId: string, prompt?: string, extras?: {
|
|
1509
|
+
parentRunId?: string;
|
|
1510
|
+
depth?: number;
|
|
1511
|
+
}) => void;
|
|
1512
|
+
/** Mark a run as completed */
|
|
1513
|
+
completeRun: (runId: string, stats: {
|
|
1514
|
+
turns: number;
|
|
1515
|
+
tokensIn: number;
|
|
1516
|
+
tokensOut: number;
|
|
1517
|
+
turnUsage?: TurnUsage[];
|
|
1518
|
+
cost?: number;
|
|
1519
|
+
}) => void;
|
|
1520
|
+
/** Mark a run as aborted */
|
|
1521
|
+
/**
|
|
1522
|
+
* Optional `stats` lets the agent backfill the run's token totals when
|
|
1523
|
+
* the abort happened *after* the loop accumulated meaningful usage —
|
|
1524
|
+
* common when the user presses esc mid-streaming. Without it, the run
|
|
1525
|
+
* record reads `0 in / 0 out` on reload regardless of how much was
|
|
1526
|
+
* spent before the abort. Same shape as `completeRun`'s stats so the
|
|
1527
|
+
* persisted `totalUsage` aggregate stays consistent across paths.
|
|
1528
|
+
*/
|
|
1529
|
+
abortRun: (runId: string, stats?: {
|
|
1530
|
+
turns: number;
|
|
1531
|
+
tokensIn: number;
|
|
1532
|
+
tokensOut: number;
|
|
1533
|
+
turnUsage?: TurnUsage[];
|
|
1534
|
+
cost?: number;
|
|
1535
|
+
}) => void;
|
|
1536
|
+
/** Mark a run as errored */
|
|
1537
|
+
/** Optional `stats` — same rationale as `abortRun.stats`. */
|
|
1538
|
+
errorRun: (runId: string, error: string, stats?: {
|
|
1539
|
+
turns: number;
|
|
1540
|
+
tokensIn: number;
|
|
1541
|
+
tokensOut: number;
|
|
1542
|
+
turnUsage?: TurnUsage[];
|
|
1543
|
+
cost?: number;
|
|
1544
|
+
}) => void;
|
|
1545
|
+
/** Append turns to in-memory history AND persist via store.appendTurns (if store present) */
|
|
1546
|
+
appendTurns: (turns: SessionTurn[]) => Promise<void>;
|
|
1547
|
+
/** Replace all turns in-memory (does not persist — use save() for that) */
|
|
1548
|
+
setTurns: (turns: SessionTurn[]) => void;
|
|
1549
|
+
/**
|
|
1550
|
+
* Replace all runs in-memory (does not persist — use save() for that).
|
|
1551
|
+
* Mirrors {@link setTurns} for the fork / restore case: callers that
|
|
1552
|
+
* bootstrap a session from an externally-derived snapshot (e.g.
|
|
1553
|
+
* `onForkTurn` copying parent runs into a child session) need this so
|
|
1554
|
+
* the cloned runs land in `data.runs` before the first `save()`.
|
|
1555
|
+
* Production agent runs continue to mutate runs via `startRun` /
|
|
1556
|
+
* `completeRun` / `updateRun`; this is the bulk-replace escape hatch.
|
|
1557
|
+
*/
|
|
1558
|
+
setRuns: (runs: SessionRun[]) => void;
|
|
1559
|
+
/** Update the session status in memory AND via store.updateStatus (if store present) */
|
|
1560
|
+
updateStatus: (status: SessionData['status']) => Promise<void>;
|
|
1561
|
+
/** Persist an updated run record via store.updateRun (if store present) */
|
|
1562
|
+
updateRun: (run: SessionRun) => Promise<void>;
|
|
1563
|
+
/** Generate a turn ID using store.generateTurnId if available, else crypto.randomUUID() */
|
|
1564
|
+
generateTurnId: () => string | Promise<string>;
|
|
1565
|
+
/** Set metadata key */
|
|
1566
|
+
setMeta: (key: string, value: unknown) => void;
|
|
1567
|
+
/** Persist the full session document to the store */
|
|
1568
|
+
save: () => Promise<void>;
|
|
1569
|
+
/** Serialize to SessionData */
|
|
1570
|
+
toJSON: () => SessionData;
|
|
1571
|
+
}
|
|
1572
|
+
interface CreateSessionOptions {
|
|
1573
|
+
/** Session ID. If omitted and store provides generateSessionId, that is used. */
|
|
1574
|
+
id?: string;
|
|
1575
|
+
/** Agent ID label */
|
|
1576
|
+
agentId?: string;
|
|
1764
1577
|
/**
|
|
1765
|
-
*
|
|
1766
|
-
*
|
|
1767
|
-
*
|
|
1578
|
+
* Project tag — see {@link SessionData.projectRoot}. Stamped once on
|
|
1579
|
+
* creation; ignored when `_data` is set (restoring an existing
|
|
1580
|
+
* session preserves whatever was already persisted there). The TUI
|
|
1581
|
+
* resolves this from `findGitRoot(cwd) ?? cwd` so sessions started
|
|
1582
|
+
* from the same repo (no matter which subdir) share one tag.
|
|
1768
1583
|
*/
|
|
1769
|
-
|
|
1584
|
+
projectRoot?: string;
|
|
1585
|
+
/** Initial metadata */
|
|
1586
|
+
metadata?: Record<string, unknown>;
|
|
1587
|
+
/** Storage backend (optional, enables save/load) */
|
|
1588
|
+
store?: SessionStore;
|
|
1589
|
+
_data?: SessionData;
|
|
1770
1590
|
}
|
|
1771
1591
|
/**
|
|
1772
|
-
*
|
|
1592
|
+
* Create a new session.
|
|
1593
|
+
* Async so stores that generate IDs server-side (e.g. Supabase) can be supported.
|
|
1594
|
+
*/
|
|
1595
|
+
declare function createSession(options?: CreateSessionOptions): Promise<Session>;
|
|
1596
|
+
/**
|
|
1597
|
+
* Load an existing session from a store.
|
|
1598
|
+
*/
|
|
1599
|
+
declare function loadSession(store: SessionStore, sessionId: string): Promise<Session | null>;
|
|
1600
|
+
//#endregion
|
|
1601
|
+
//#region src/skills/types.d.ts
|
|
1602
|
+
/**
|
|
1603
|
+
* Types for the Agent Skills system.
|
|
1773
1604
|
*
|
|
1774
|
-
*
|
|
1775
|
-
* -
|
|
1776
|
-
*
|
|
1777
|
-
* against the model's context window mid-stream
|
|
1778
|
-
* (`model_context_window_exceeded`). The partial response is preserved; the
|
|
1779
|
-
* loop emits this reason so consumers can prune/retry.
|
|
1780
|
-
* - `'content-filter'` — model refused.
|
|
1781
|
-
* - `'pause'` — Anthropic `pause_turn`: a server-side mid-turn pause for very
|
|
1782
|
-
* long thinking. The loop continues with a synthetic "Please continue."
|
|
1783
|
-
* user message rather than terminating; consumers see the pause via this
|
|
1784
|
-
* finish reason on the prior assistant turn.
|
|
1785
|
-
* - `'error'` — provider classified the turn as failed.
|
|
1786
|
-
* - `'other'` — unknown / unmapped.
|
|
1605
|
+
* Follows the Agent Skills open standard (agentskills.io/specification).
|
|
1606
|
+
* Zidane-specific metadata conventionally uses the `zidane.` key prefix
|
|
1607
|
+
* (e.g. `metadata['zidane.paths']`) to stay spec-compliant.
|
|
1787
1608
|
*/
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
cacheCreation?: number;
|
|
1794
|
-
/** Tokens read from cache (Anthropic) */
|
|
1795
|
-
cacheRead?: number;
|
|
1796
|
-
/** Thinking/reasoning tokens used */
|
|
1797
|
-
thinking?: number;
|
|
1798
|
-
/** Cost in USD as reported by the provider (OpenRouter) */
|
|
1799
|
-
cost?: number;
|
|
1800
|
-
/**
|
|
1801
|
-
* Why the model stopped this turn. Providers normalize native stop reasons to this union.
|
|
1802
|
-
* Absent when the provider did not surface a reason (e.g. mock turns).
|
|
1803
|
-
*/
|
|
1804
|
-
finishReason?: TurnFinishReason;
|
|
1805
|
-
/**
|
|
1806
|
-
* The model ID the provider ultimately used. May differ from the requested model when the
|
|
1807
|
-
* provider remaps aliases. Absent for providers that do not echo a model ID.
|
|
1808
|
-
*/
|
|
1809
|
-
modelId?: string;
|
|
1609
|
+
interface SkillResource {
|
|
1610
|
+
/** Relative path from skill directory */
|
|
1611
|
+
path: string;
|
|
1612
|
+
/** Resource type inferred from directory */
|
|
1613
|
+
type: 'script' | 'reference' | 'asset' | 'other';
|
|
1810
1614
|
}
|
|
1811
|
-
|
|
1615
|
+
/**
|
|
1616
|
+
* Where the skill came from. Used for collision precedence (project beats user)
|
|
1617
|
+
* and for host SDKs to gate project-level skills on a trust check.
|
|
1618
|
+
*/
|
|
1619
|
+
type SkillSource = 'project' | 'user' | 'inline' | 'builtin';
|
|
1620
|
+
/** Severity + code for lenient-load warnings surfaced to host UIs. */
|
|
1621
|
+
interface SkillDiagnostic {
|
|
1622
|
+
severity: 'warning' | 'error';
|
|
1623
|
+
/** Stable machine-readable code (e.g. `name-mismatch-directory`). */
|
|
1624
|
+
code: string;
|
|
1625
|
+
/** Human-readable description. */
|
|
1626
|
+
message: string;
|
|
1627
|
+
/** Optional frontmatter field name the diagnostic relates to. */
|
|
1628
|
+
field?: string;
|
|
1629
|
+
}
|
|
1630
|
+
interface SkillConfig {
|
|
1631
|
+
/** Skill name: 1-64 chars, lowercase alphanumeric + hyphens */
|
|
1632
|
+
name: string;
|
|
1633
|
+
/** What the skill does and when to use it (1-1024 chars) */
|
|
1634
|
+
description: string;
|
|
1635
|
+
/** The SKILL.md body content (after YAML frontmatter) */
|
|
1636
|
+
instructions: string;
|
|
1812
1637
|
/**
|
|
1813
|
-
*
|
|
1814
|
-
*
|
|
1815
|
-
*
|
|
1638
|
+
* Where this skill was loaded from. Drives collision precedence and the
|
|
1639
|
+
* `trustProjectSkills` gate. Optional — `parseSkillFile` stamps it; raw
|
|
1640
|
+
* fixtures that omit it are treated as `'project'` by downstream readers.
|
|
1816
1641
|
*/
|
|
1817
|
-
|
|
1818
|
-
/**
|
|
1819
|
-
|
|
1642
|
+
source?: SkillSource;
|
|
1643
|
+
/** Absolute path to SKILL.md (undefined for inline skills) */
|
|
1644
|
+
location?: string;
|
|
1645
|
+
/** Skill directory path for resolving relative references */
|
|
1646
|
+
baseDir?: string;
|
|
1647
|
+
/** License identifier or reference */
|
|
1648
|
+
license?: string;
|
|
1649
|
+
/** Environment requirements */
|
|
1650
|
+
compatibility?: string;
|
|
1820
1651
|
/**
|
|
1821
|
-
*
|
|
1822
|
-
*
|
|
1823
|
-
* only per-`TurnUsage`) because Anthropic prices cache reads at a separate
|
|
1824
|
-
* line-item rate from regular input — billing-correct cost computation
|
|
1825
|
-
* needs this number directly. Always `0` for providers that don't report
|
|
1826
|
-
* cache usage.
|
|
1652
|
+
* Flat key-value metadata bag per the spec. For Zidane-specific hints,
|
|
1653
|
+
* use the `zidane.` key prefix (e.g. `metadata['zidane.paths']`).
|
|
1827
1654
|
*/
|
|
1828
|
-
|
|
1655
|
+
metadata?: Record<string, string>;
|
|
1656
|
+
/** Pre-approved tool names (experimental per spec) */
|
|
1657
|
+
allowedTools?: string[];
|
|
1658
|
+
/** Bundled resource files discovered in the skill directory */
|
|
1659
|
+
resources?: SkillResource[];
|
|
1829
1660
|
/**
|
|
1830
|
-
*
|
|
1831
|
-
*
|
|
1832
|
-
* {@link AgentStats.totalCacheRead} — separate Anthropic billing rate.
|
|
1833
|
-
* Always `0` for providers that don't report cache usage.
|
|
1661
|
+
* Lenient-load warnings recorded during parsing. Host SDKs can surface these
|
|
1662
|
+
* as inline UI hints. Absent when no issues were found.
|
|
1834
1663
|
*/
|
|
1835
|
-
|
|
1664
|
+
diagnostics?: SkillDiagnostic[];
|
|
1665
|
+
}
|
|
1666
|
+
interface SkillsConfig {
|
|
1836
1667
|
/**
|
|
1837
|
-
*
|
|
1838
|
-
* `
|
|
1839
|
-
*
|
|
1840
|
-
*
|
|
1841
|
-
*
|
|
1842
|
-
* Tree-wide turn count: `flattenTurns(stats).length`.
|
|
1668
|
+
* Control which skills are active.
|
|
1669
|
+
* - `true` (default): all discovered skills are enabled
|
|
1670
|
+
* - `false` or `[]`: fully disable the skills system (no resolution, no catalog, no hooks)
|
|
1671
|
+
* - `string[]`: allowlist — only skills with matching names are enabled
|
|
1843
1672
|
*/
|
|
1844
|
-
|
|
1673
|
+
enabled?: boolean | string[];
|
|
1674
|
+
/** Directories to scan for SKILL.md files */
|
|
1675
|
+
scan?: string[];
|
|
1676
|
+
/** Dynamic skills written to disk at agent start, then loaded normally */
|
|
1677
|
+
write?: SkillConfig[];
|
|
1678
|
+
/** Skill names to exclude from the catalog */
|
|
1679
|
+
exclude?: string[];
|
|
1680
|
+
/** Skip default scan paths (~/.agents/skills, .zidane/skills, etc.) */
|
|
1681
|
+
skipDefaultPaths?: boolean;
|
|
1845
1682
|
/**
|
|
1846
|
-
*
|
|
1847
|
-
*
|
|
1848
|
-
*
|
|
1849
|
-
*
|
|
1683
|
+
* Auto-inject `skills_use` / `skills_read` / `skills_run_script` tools
|
|
1684
|
+
* when the catalog is non-empty. Default `true`. Set `false` to opt out
|
|
1685
|
+
* (the system prompt will then instruct the model to use its file-read
|
|
1686
|
+
* tool instead).
|
|
1850
1687
|
*/
|
|
1851
|
-
|
|
1688
|
+
tool?: boolean;
|
|
1852
1689
|
/**
|
|
1853
|
-
*
|
|
1854
|
-
*
|
|
1855
|
-
* to walk the full tree.
|
|
1690
|
+
* Cap on concurrently active skills per run. Default `undefined` (unlimited).
|
|
1691
|
+
* Attempts to activate past the cap throw from `skills_use`.
|
|
1856
1692
|
*/
|
|
1857
|
-
|
|
1693
|
+
maxActive?: number;
|
|
1694
|
+
/** Script timeout for `skills_run_script`, in milliseconds. Default `60000`. */
|
|
1695
|
+
scriptTimeoutMs?: number;
|
|
1858
1696
|
/**
|
|
1859
|
-
*
|
|
1860
|
-
*
|
|
1861
|
-
*
|
|
1697
|
+
* When `false`, skills with `source: 'project'` are skipped during
|
|
1698
|
+
* resolution with a diagnostic. Default `true` (preserves existing behavior).
|
|
1699
|
+
* Useful for host SDKs handling untrusted repositories.
|
|
1862
1700
|
*/
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1701
|
+
trustProjectSkills?: boolean;
|
|
1702
|
+
}
|
|
1703
|
+
//#endregion
|
|
1704
|
+
//#region src/tools/types.d.ts
|
|
1705
|
+
/**
|
|
1706
|
+
* Runtime context passed to every tool execution.
|
|
1707
|
+
* Provides access to the agent's provider, abort signal, execution environment, and hooks.
|
|
1708
|
+
*
|
|
1709
|
+
* The preset-y fields (`name`, `system`, `tools`, `toolAliases`, `mcpServers`, `skills`,
|
|
1710
|
+
* `behavior`) mirror the agent's own options so child-spawning tools can inherit them.
|
|
1711
|
+
*/
|
|
1712
|
+
interface ToolContext {
|
|
1713
|
+
/** The LLM provider for this agent run */
|
|
1714
|
+
provider: Provider;
|
|
1715
|
+
/** Abort signal — tools should check this for early termination */
|
|
1716
|
+
signal: AbortSignal;
|
|
1717
|
+
/** The execution context (shell, filesystem, etc.) */
|
|
1718
|
+
execution: ExecutionContext;
|
|
1719
|
+
/** The active execution handle for the current agent run */
|
|
1720
|
+
handle: ExecutionHandle;
|
|
1721
|
+
/** Agent hooks for emitting events (e.g. spawn:complete) */
|
|
1722
|
+
hooks: Hookable<AgentHooks>;
|
|
1723
|
+
/** Agent display name (preset or user-supplied) */
|
|
1724
|
+
name?: string;
|
|
1725
|
+
/** Agent default system prompt */
|
|
1726
|
+
system?: string;
|
|
1727
|
+
/** Source tool map the agent was created with (pre-MCP-merge, pre-skills-injection) */
|
|
1728
|
+
tools: Record<string, ToolDef>;
|
|
1868
1729
|
/**
|
|
1869
|
-
*
|
|
1870
|
-
* provider (first `stream:text`, `stream:thinking`, or `tool:before` event).
|
|
1730
|
+
* Map canonical tool names to LLM-facing (aliased) names.
|
|
1871
1731
|
*
|
|
1872
|
-
*
|
|
1732
|
+
* Aliasing is **LLM-boundary-only**:
|
|
1733
|
+
* - The alias is what the provider's tool spec carries, what the model calls it, and
|
|
1734
|
+
* what appears in `ToolHookContext.displayName` / `McpToolHookContext.displayName`.
|
|
1735
|
+
* - The canonical name is what lives in `session.turns`, `ToolHookContext.name`, and
|
|
1736
|
+
* what the agent uses to look up the tool implementation. Alias changes never
|
|
1737
|
+
* desync persisted history.
|
|
1873
1738
|
*/
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1739
|
+
toolAliases?: Record<string, string>;
|
|
1740
|
+
/** MCP servers configured on the agent (for child inheritance) */
|
|
1741
|
+
mcpServers?: McpServerConfig[];
|
|
1742
|
+
/** Skills configuration (for child inheritance) */
|
|
1743
|
+
skills?: SkillsConfig;
|
|
1744
|
+
/** Behavior defaults (for child inheritance) */
|
|
1745
|
+
behavior?: AgentBehavior;
|
|
1746
|
+
/** Turn ID that requested this tool call */
|
|
1747
|
+
turnId: string;
|
|
1748
|
+
/** Tool call ID from the model */
|
|
1749
|
+
callId: string;
|
|
1879
1750
|
/**
|
|
1880
|
-
* The
|
|
1881
|
-
*
|
|
1882
|
-
*
|
|
1883
|
-
*
|
|
1751
|
+
* The run id this tool call is part of. Populated by the agent loop when
|
|
1752
|
+
* invoking tools. Optional on the type so host code constructing contexts
|
|
1753
|
+
* by hand (tests, direct tool invocations) doesn't have to synthesize one.
|
|
1754
|
+
*
|
|
1755
|
+
* Spawn-style tools rely on this to tag child runs with `parentRunId` so
|
|
1756
|
+
* the subagent tree can be reconstructed from a persisted session.
|
|
1884
1757
|
*/
|
|
1885
|
-
|
|
1758
|
+
runId?: string;
|
|
1886
1759
|
/**
|
|
1887
|
-
*
|
|
1888
|
-
*
|
|
1889
|
-
*
|
|
1760
|
+
* The agent's session, when one was provided to `createAgent`. Tools that
|
|
1761
|
+
* want to persist their own state (or, in the case of `spawn`, inherit the
|
|
1762
|
+
* parent's session for child persistence) can read from here.
|
|
1890
1763
|
*/
|
|
1891
|
-
|
|
1764
|
+
session?: Session;
|
|
1892
1765
|
/**
|
|
1893
|
-
*
|
|
1894
|
-
*
|
|
1895
|
-
*
|
|
1766
|
+
* Subagent depth for the agent owning this tool call. 0 = top-level,
|
|
1767
|
+
* 1 = first-level child, … Used by spawn to enforce a `maxDepth` cap.
|
|
1768
|
+
* Undefined is treated as 0 by spawn.
|
|
1896
1769
|
*/
|
|
1897
|
-
|
|
1770
|
+
depth?: number;
|
|
1771
|
+
}
|
|
1772
|
+
interface ToolDef {
|
|
1773
|
+
spec: ToolSpec;
|
|
1898
1774
|
/**
|
|
1899
|
-
*
|
|
1900
|
-
*
|
|
1901
|
-
*
|
|
1775
|
+
* Execute the tool and return its output.
|
|
1776
|
+
*
|
|
1777
|
+
* Return a plain string for text-only tools (the common case). Return a
|
|
1778
|
+
* `ToolResultContent[]` when the tool produces non-text content (images, mixed
|
|
1779
|
+
* text+image) that the provider can route through natively (Anthropic
|
|
1780
|
+
* `tool_result.content` arrays, OpenAI Codex pi-ai) or through the
|
|
1781
|
+
* companion-user-message fallback (OpenAI Chat Completions).
|
|
1902
1782
|
*/
|
|
1903
|
-
|
|
1783
|
+
execute: (input: Record<string, unknown>, ctx: ToolContext) => Promise<string | ToolResultContent[]>;
|
|
1784
|
+
}
|
|
1785
|
+
type ToolMap = Map<string, ToolDef>;
|
|
1786
|
+
//#endregion
|
|
1787
|
+
//#region src/mcp/index.d.ts
|
|
1788
|
+
interface McpConnection {
|
|
1789
|
+
tools: Record<string, ToolDef>;
|
|
1790
|
+
close: () => Promise<void>;
|
|
1904
1791
|
}
|
|
1905
1792
|
/**
|
|
1906
|
-
*
|
|
1793
|
+
* Normalize MCP server configs from any common shape to `McpServerConfig[]`.
|
|
1907
1794
|
*
|
|
1908
|
-
*
|
|
1909
|
-
* `
|
|
1795
|
+
* Accepts:
|
|
1796
|
+
* - `McpServerConfig[]` — zidane native (pass-through).
|
|
1797
|
+
* - `McpServerConfig` — a single config object (wrapped to a 1-element array).
|
|
1798
|
+
* - `Record<string, RawShape>` — name-keyed map (common in host-SDK configs), where the key is the server name.
|
|
1799
|
+
* - Mixed shapes with `type` vs `transport`, `httpUrl`/`sseUrl` vs `url`.
|
|
1910
1800
|
*
|
|
1911
|
-
* `
|
|
1912
|
-
*
|
|
1913
|
-
|
|
1801
|
+
* Returns `[]` when `input` is nullish. Throws a descriptive error when the transport
|
|
1802
|
+
* cannot be inferred from a given entry, or when the input shape is unsupported.
|
|
1803
|
+
*/
|
|
1804
|
+
declare function normalizeMcpServers(input: unknown): McpServerConfig[];
|
|
1805
|
+
/**
|
|
1806
|
+
* Lossy flattener — converts MCP `CallToolResult.content` blocks to a single
|
|
1807
|
+
* string. Text blocks are extracted; non-text blocks are JSON-stringified.
|
|
1914
1808
|
*
|
|
1915
|
-
*
|
|
1916
|
-
*
|
|
1809
|
+
* Use this only at UI / log boundaries that require a string. The agent
|
|
1810
|
+
* loop itself routes through {@link normalizeMcpBlocks} so image blocks
|
|
1811
|
+
* survive into provider-native tool_result content (Anthropic blocks,
|
|
1812
|
+
* OpenAI companion-user-message).
|
|
1917
1813
|
*/
|
|
1918
|
-
|
|
1919
|
-
turnId: string;
|
|
1920
|
-
callId: string;
|
|
1921
|
-
/** Canonical tool name (spec name). Stable across alias-map changes. */
|
|
1922
|
-
name: string;
|
|
1923
|
-
/** Aliased (wire) name — equal to `name` when no alias is defined. */
|
|
1924
|
-
displayName: string;
|
|
1925
|
-
input: Record<string, unknown>;
|
|
1926
|
-
}
|
|
1814
|
+
declare function resultToString(content: unknown[]): string;
|
|
1927
1815
|
/**
|
|
1928
|
-
*
|
|
1816
|
+
* Normalize MCP `CallToolResult.content` to zidane's {@link ToolResultContent[]} shape.
|
|
1929
1817
|
*
|
|
1930
|
-
*
|
|
1931
|
-
*
|
|
1818
|
+
* Handles the four MCP content block types:
|
|
1819
|
+
* - `text` → preserved as `{type:'text', text}`
|
|
1820
|
+
* - `image` → preserved as `{type:'image', mediaType, data}` (MCP uses `mimeType`)
|
|
1821
|
+
* - `resource` with embedded text → flattened to a text block
|
|
1822
|
+
* - `resource` with embedded blob whose `mimeType` is `image/*` → flattened to an image block
|
|
1823
|
+
* - Any unrecognized block → JSON-stringified fallback text block (lossy but safe)
|
|
1932
1824
|
*
|
|
1933
|
-
* `
|
|
1934
|
-
*
|
|
1935
|
-
* alias that the LLM sees.
|
|
1825
|
+
* Returns `null` when the input is not an array — callers should fall back to an empty
|
|
1826
|
+
* result in that case.
|
|
1936
1827
|
*/
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1828
|
+
declare function normalizeMcpBlocks(content: unknown): ToolResultContent[] | null;
|
|
1829
|
+
/**
|
|
1830
|
+
* Connect to MCP servers and discover their tools.
|
|
1831
|
+
*
|
|
1832
|
+
* Each tool is namespaced as `mcp_{serverName}_{toolName}` to avoid
|
|
1833
|
+
* collisions with agent tools or tools from other servers.
|
|
1834
|
+
*
|
|
1835
|
+
* @param configs - Array of MCP server configurations
|
|
1836
|
+
* @param _clientFactory - Internal: override client construction for testing
|
|
1837
|
+
* @param hooks - Optional agent hooks for firing mcp:connect, mcp:error, mcp:close events
|
|
1838
|
+
*/
|
|
1839
|
+
declare function connectMcpServers(configs: McpServerConfig[], _clientFactory?: () => Client, hooks?: Hookable<AgentHooks>): Promise<McpConnection>;
|
|
1840
|
+
//#endregion
|
|
1841
|
+
//#region src/skills/activation.d.ts
|
|
1842
|
+
/** How a skill was activated. Surfaced in `skills:activate` hook ctx. */
|
|
1843
|
+
type ActivationVia = 'model' | 'explicit' | 'resume';
|
|
1844
|
+
/** Reason a skill was deactivated. Surfaced in `skills:deactivate` hook ctx. */
|
|
1845
|
+
type DeactivationReason = 'run-end' | 'explicit' | 'reset';
|
|
1846
|
+
/** A skill currently active in the state machine. */
|
|
1847
|
+
interface ActiveSkill {
|
|
1848
|
+
skill: SkillConfig;
|
|
1849
|
+
activatedAt: number;
|
|
1850
|
+
activatedVia: ActivationVia;
|
|
1945
1851
|
}
|
|
1946
|
-
/**
|
|
1947
|
-
|
|
1948
|
-
|
|
1852
|
+
/**
|
|
1853
|
+
* Per-agent skill activation state. Public read-surface is the `active()` list
|
|
1854
|
+
* and `isActive(name)` predicate; writes go through `activate()` / `deactivate()`.
|
|
1855
|
+
*/
|
|
1856
|
+
interface SkillActivationState {
|
|
1857
|
+
/** List of currently active skills in activation order. Returns a snapshot. */
|
|
1858
|
+
active: () => readonly ActiveSkill[];
|
|
1859
|
+
/** Is the skill with this canonical name currently active? */
|
|
1860
|
+
isActive: (name: string) => boolean;
|
|
1861
|
+
/** Retrieve the `ActiveSkill` record by name, or `undefined`. */
|
|
1862
|
+
get: (name: string) => ActiveSkill | undefined;
|
|
1863
|
+
/**
|
|
1864
|
+
* Mark a skill as active.
|
|
1865
|
+
* - Returns `'ok'` on a fresh activation (caller should fire `skills:activate`).
|
|
1866
|
+
* - Returns `'already-active'` if the skill was already in the set (idempotent).
|
|
1867
|
+
* - Returns `'cap-reached'` if the `maxActive` cap would be exceeded. State is unchanged.
|
|
1868
|
+
*/
|
|
1869
|
+
activate: (skill: SkillConfig, via: ActivationVia) => 'ok' | 'already-active' | 'cap-reached';
|
|
1870
|
+
/**
|
|
1871
|
+
* Mark a skill as inactive. Returns the removed `ActiveSkill` record or `undefined`
|
|
1872
|
+
* if it wasn't active. Callers fire `skills:deactivate` on removal.
|
|
1873
|
+
*/
|
|
1874
|
+
deactivate: (name: string) => ActiveSkill | undefined;
|
|
1875
|
+
/** Remove every active skill. Returns the list of removed records. */
|
|
1876
|
+
clear: () => readonly ActiveSkill[];
|
|
1949
1877
|
}
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1878
|
+
interface SkillActivationStateOptions {
|
|
1879
|
+
/**
|
|
1880
|
+
* Cap on concurrent activations. `undefined` (the default) disables the cap.
|
|
1881
|
+
* When set, `activate()` returns `'cap-reached'` once the set is at size `maxActive`.
|
|
1882
|
+
*/
|
|
1883
|
+
maxActive?: number;
|
|
1884
|
+
}
|
|
1885
|
+
declare function createSkillActivationState(options?: SkillActivationStateOptions): SkillActivationState;
|
|
1886
|
+
//#endregion
|
|
1887
|
+
//#region src/agent.d.ts
|
|
1888
|
+
interface AgentHooks {
|
|
1889
|
+
'system:before': (ctx: {
|
|
1890
|
+
system: string;
|
|
1891
|
+
}) => void;
|
|
1892
|
+
'turn:before': (ctx: {
|
|
1893
|
+
turn: number;
|
|
1894
|
+
turnId: string;
|
|
1895
|
+
options: StreamOptions;
|
|
1896
|
+
}) => void;
|
|
1897
|
+
/**
|
|
1898
|
+
* Fires after each assistant turn (before its tool-result follow-up
|
|
1899
|
+
* dispatches; the loop iterates back to a fresh `turn:before` once the
|
|
1900
|
+
* tool results are produced).
|
|
1901
|
+
*
|
|
1902
|
+
* `toolCounts.turn` — calls **emitted** by the model in this assistant
|
|
1903
|
+
* turn, keyed by canonical tool name. Reflects what the model asked for,
|
|
1904
|
+
* regardless of downstream gate outcome. Most useful for spotting per-turn
|
|
1905
|
+
* spikes ("the model called todowrite 4 times in one turn").
|
|
1906
|
+
*
|
|
1907
|
+
* `toolCounts.run` — cumulative running counter of **dispatched** calls
|
|
1908
|
+
* scoped to this `runId`, captured at fire time. Excludes calls that were
|
|
1909
|
+
* `block`ed by `tool:gate` handlers. Includes calls short-circuited via
|
|
1910
|
+
* `tool:gate` `result` substitution (the model still asked, the framework
|
|
1911
|
+
* just answered without the tool running). Resumed sessions start a fresh
|
|
1912
|
+
* run with empty counts.
|
|
1913
|
+
*
|
|
1914
|
+
* Both fields are frozen snapshots; mutate-safe.
|
|
1915
|
+
*/
|
|
1916
|
+
'turn:after': (ctx: {
|
|
1917
|
+
turn: number;
|
|
1918
|
+
turnId: string;
|
|
1919
|
+
usage: TurnUsage;
|
|
1920
|
+
message: SessionTurn;
|
|
1921
|
+
toolCounts: {
|
|
1922
|
+
turn: Readonly<Record<string, number>>;
|
|
1923
|
+
run: Readonly<Record<string, number>>;
|
|
1924
|
+
};
|
|
1925
|
+
}) => void;
|
|
1926
|
+
/**
|
|
1927
|
+
* Fires after a tool-results user turn is pushed onto the conversation,
|
|
1928
|
+
* before* any byte-budget enforcement or follow-up steering. Symmetric
|
|
1929
|
+
* with `turn:after` but for the user-role tool_result turn that closes the
|
|
1930
|
+
* round-trip.
|
|
1931
|
+
*
|
|
1932
|
+
* Why it exists: persistence layers must write tool_use/tool_result turn
|
|
1933
|
+
* pairs together — if only the assistant turn (carrying tool_use blocks)
|
|
1934
|
+
* is durable, a process death between turns leaves the DB with an orphan
|
|
1935
|
+
* tool_use that Anthropic rejects on resume. Subscribe here to persist
|
|
1936
|
+
* the tool-results turn before the loop continues.
|
|
1937
|
+
*/
|
|
1938
|
+
'tool-results:after': (ctx: {
|
|
1939
|
+
turn: number;
|
|
1940
|
+
turnId: string;
|
|
1941
|
+
message: SessionTurn; /** Frozen list of tool results that were packed into `message`. */
|
|
1942
|
+
results: readonly ToolResult[];
|
|
1943
|
+
}) => void;
|
|
1944
|
+
'stream:text': (ctx: StreamHookContext & {
|
|
1945
|
+
delta: string;
|
|
1946
|
+
text: string;
|
|
1947
|
+
}) => void;
|
|
1948
|
+
'stream:end': (ctx: StreamHookContext & {
|
|
1949
|
+
text: string;
|
|
1950
|
+
}) => void;
|
|
1951
|
+
'stream:thinking': (ctx: StreamHookContext & {
|
|
1952
|
+
delta: string;
|
|
1953
|
+
thinking: string;
|
|
1954
|
+
}) => void;
|
|
1955
|
+
'oauth:refresh': (ctx: OAuthRefreshHookContext) => void;
|
|
1956
|
+
/**
|
|
1957
|
+
* Fires before validation, `tool:before`, and `execute`. Two ways to
|
|
1958
|
+
* intercept:
|
|
1959
|
+
*
|
|
1960
|
+
* - Set `block = true` (with a `reason`) to refuse the call. The model
|
|
1961
|
+
* sees a `Blocked: <reason>` tool result; `tool:before` / `tool:after`
|
|
1962
|
+
* do **not** fire.
|
|
1963
|
+
* - Set `result` to substitute a successful tool_result and skip
|
|
1964
|
+
* execution. The model sees the substitute as a normal tool_result;
|
|
1965
|
+
* `tool:before` does not fire, but `tool:after` and `tool:transform`
|
|
1966
|
+
* do — so byte budgets, telemetry, and post-mutation hooks see the
|
|
1967
|
+
* substitute. Useful for cache hits, dedup, idempotency guards,
|
|
1968
|
+
* plan-mode synthetic acks.
|
|
1969
|
+
*
|
|
1970
|
+
* If multiple handlers along the chain set both `block` and `result`,
|
|
1971
|
+
* `block` wins — refusal beats substitution, so a policy gate
|
|
1972
|
+
* (skills allow-list, custom security) can always override an upstream
|
|
1973
|
+
* consumer's cache substitute. Mirrors the writable-`result` shape on
|
|
1974
|
+
* `tool:unknown` and `tool:error` so consumers learn one pattern.
|
|
1975
|
+
*
|
|
1976
|
+
* `runToolCounts` — frozen pre-call snapshot of per-tool dispatched
|
|
1977
|
+
* counts in this run. Use it to self-throttle, drive observability, or
|
|
1978
|
+
* implement budget guards. Counts every call that passed gate, including
|
|
1979
|
+
* dedup substitutes (Z19); excludes `block`ed calls.
|
|
1980
|
+
*
|
|
1981
|
+
* **Parallel mode** (`toolExecution: 'parallel'`, the default): the
|
|
1982
|
+
* snapshot is taken before any dispatches in the batch, so consumer
|
|
1983
|
+
* hooks reading `runToolCounts` see the pre-batch view. Built-in
|
|
1984
|
+
* budget / dedup middleware uses internal per-call reservation, so
|
|
1985
|
+
* `behavior.toolBudgets` enforces atomically even within a parallel
|
|
1986
|
+
* batch.
|
|
1987
|
+
*/
|
|
1988
|
+
'tool:gate': (ctx: ToolHookContext & {
|
|
1989
|
+
block: boolean;
|
|
1990
|
+
reason: string;
|
|
1991
|
+
result?: string | ToolResultContent[];
|
|
1992
|
+
runToolCounts: Readonly<Record<string, number>>;
|
|
1993
|
+
}) => void;
|
|
1994
|
+
'tool:before': (ctx: ToolHookContext & {
|
|
1995
|
+
coercions?: readonly string[];
|
|
1996
|
+
runToolCounts: Readonly<Record<string, number>>;
|
|
1997
|
+
}) => void;
|
|
1998
|
+
'tool:after': (ctx: ToolHookContext & {
|
|
1999
|
+
result: string | ToolResultContent[];
|
|
2000
|
+
outputBytes: number;
|
|
2001
|
+
coercions?: readonly string[];
|
|
2002
|
+
runToolCounts: Readonly<Record<string, number>>;
|
|
2003
|
+
}) => void;
|
|
1954
2004
|
/**
|
|
1955
|
-
*
|
|
1956
|
-
*
|
|
1957
|
-
*
|
|
2005
|
+
* Fires when a tool throws during execution. Mutate `result` to substitute a
|
|
2006
|
+
* tool-output payload that gets sent back to the model in place of the
|
|
2007
|
+
* default `Tool error: <msg>` string — useful for OSS-model error rewriting
|
|
2008
|
+
* (collapse stack traces, hide internal paths, prepend recovery hints).
|
|
2009
|
+
*
|
|
2010
|
+
* The post-hook value flows through `tool:transform` like a normal output, so
|
|
2011
|
+
* downstream byte-budgeting and image-stripping still apply.
|
|
1958
2012
|
*/
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
source: 'params' | 'file';
|
|
1970
|
-
previousCredentials: Record<string, unknown> & {
|
|
1971
|
-
access: string;
|
|
1972
|
-
refresh: string;
|
|
1973
|
-
expires: number;
|
|
1974
|
-
};
|
|
1975
|
-
credentials: Record<string, unknown> & {
|
|
1976
|
-
access: string;
|
|
1977
|
-
refresh: string;
|
|
1978
|
-
expires: number;
|
|
1979
|
-
};
|
|
1980
|
-
}
|
|
1981
|
-
type SessionEndStatus = 'completed' | 'aborted' | 'error';
|
|
1982
|
-
//#endregion
|
|
1983
|
-
//#region src/providers/anthropic.d.ts
|
|
1984
|
-
/**
|
|
1985
|
-
* Server-side context-management config — the body of `context_management` on
|
|
1986
|
-
* the Messages API. Typed loosely (Record-of-unknown) so we don't pin a specific
|
|
1987
|
-
* SDK schema version: the v0.90 SDK does not yet type this field, but the wire
|
|
1988
|
-
* format is stable behind the `context-management-2025-06-27` beta.
|
|
1989
|
-
*
|
|
1990
|
-
* See: https://docs.anthropic.com/en/docs/build-with-claude/context-management
|
|
1991
|
-
*/
|
|
1992
|
-
interface AnthropicContextManagement {
|
|
1993
|
-
edits?: Array<Record<string, unknown>>;
|
|
1994
|
-
[key: string]: unknown;
|
|
1995
|
-
}
|
|
1996
|
-
interface AnthropicParams {
|
|
1997
|
-
apiKey?: string;
|
|
1998
|
-
access?: string;
|
|
1999
|
-
refresh?: string;
|
|
2000
|
-
expires?: number;
|
|
2001
|
-
defaultModel?: string;
|
|
2013
|
+
'tool:error': (ctx: ToolHookContext & {
|
|
2014
|
+
error: Error;
|
|
2015
|
+
result?: string | ToolResultContent[];
|
|
2016
|
+
}) => void;
|
|
2017
|
+
'tool:transform': (ctx: ToolHookContext & {
|
|
2018
|
+
result: string | ToolResultContent[];
|
|
2019
|
+
isError: boolean;
|
|
2020
|
+
outputBytes: number;
|
|
2021
|
+
coercions?: readonly string[];
|
|
2022
|
+
}) => void;
|
|
2002
2023
|
/**
|
|
2003
|
-
*
|
|
2004
|
-
*
|
|
2005
|
-
*
|
|
2024
|
+
* Fires before the generic "Unknown tool" error when the model invokes a tool
|
|
2025
|
+
* that isn't registered (hallucinated names, dropped MCP servers, dangling
|
|
2026
|
+
* aliases). Mutate `result` to substitute a friendly response or set
|
|
2027
|
+
* `suppressError: true` to skip the companion `tool:error` emission.
|
|
2028
|
+
*
|
|
2029
|
+
* Fires for any unknown tool name — including hallucinated MCP-style names
|
|
2030
|
+
* (`mcp_supabase_xxx`); branch on `name.startsWith('mcp_')` to differentiate.
|
|
2006
2031
|
*/
|
|
2007
|
-
|
|
2032
|
+
'tool:unknown': (ctx: ToolHookContext & {
|
|
2033
|
+
result?: string | ToolResultContent[];
|
|
2034
|
+
suppressError: boolean;
|
|
2035
|
+
}) => void;
|
|
2008
2036
|
/**
|
|
2009
|
-
*
|
|
2010
|
-
*
|
|
2011
|
-
*
|
|
2012
|
-
*
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
*
|
|
2020
|
-
*
|
|
2037
|
+
* Fires when `validateToolArgs` rejects an input that could not be auto-coerced
|
|
2038
|
+
* to satisfy the tool's `inputSchema`. Observational — the tool call still
|
|
2039
|
+
* surfaces a `Validation error: …` string back to the model. Useful for
|
|
2040
|
+
* counting validation failures separately from runtime tool errors.
|
|
2041
|
+
*/
|
|
2042
|
+
'validation:reject': (ctx: ToolHookContext & {
|
|
2043
|
+
reason: string;
|
|
2044
|
+
schema: Record<string, unknown>;
|
|
2045
|
+
}) => void;
|
|
2046
|
+
/**
|
|
2047
|
+
* Fires when `validateToolArgs` successfully auto-coerced one or more input
|
|
2048
|
+
* fields to satisfy the tool's `inputSchema`. **Only fires when at least one
|
|
2049
|
+
* coercion happened** — never on perfectly-shaped inputs. Useful for counting
|
|
2050
|
+
* model "wrongness rate" without re-running validation downstream.
|
|
2021
2051
|
*
|
|
2022
|
-
*
|
|
2052
|
+
* `coercions` lists the field names that were coerced. The values landed in
|
|
2053
|
+
* the input that the tool actually received; consumers wanting before/after
|
|
2054
|
+
* comparison can re-run `validateToolArgs(ctx.input, ctx.schema)`.
|
|
2023
2055
|
*/
|
|
2024
|
-
|
|
2056
|
+
'validation:coerce': (ctx: ToolHookContext & {
|
|
2057
|
+
coercions: readonly string[];
|
|
2058
|
+
schema: Record<string, unknown>;
|
|
2059
|
+
}) => void;
|
|
2060
|
+
'context:transform': (ctx: {
|
|
2061
|
+
messages: SessionMessage[];
|
|
2062
|
+
}) => void;
|
|
2025
2063
|
/**
|
|
2026
|
-
*
|
|
2027
|
-
* `
|
|
2028
|
-
*
|
|
2064
|
+
* Fires per request, after `context:transform` and before the request goes
|
|
2065
|
+
* out. Mutating `ctx.system` updates the system prompt the provider sends
|
|
2066
|
+
* for this turn — useful for runtime-derived sections (e.g. listing files
|
|
2067
|
+
* already read in the session, surfacing live tool budgets, injecting
|
|
2068
|
+
* skill activation reminders).
|
|
2029
2069
|
*
|
|
2030
|
-
*
|
|
2031
|
-
*
|
|
2070
|
+
* Cache breakpoints are applied inside the provider after this hook, so
|
|
2071
|
+
* mutations land in the cache key naturally — repeated turns with the
|
|
2072
|
+
* same derived system text still hit the cache.
|
|
2032
2073
|
*
|
|
2033
|
-
*
|
|
2034
|
-
*
|
|
2035
|
-
* edits: [{
|
|
2036
|
-
* type: 'clear_tool_uses_20250919',
|
|
2037
|
-
* trigger: { type: 'input_tokens', value: 180_000 },
|
|
2038
|
-
* clear_at_least: { type: 'input_tokens', value: 140_000 },
|
|
2039
|
-
* clear_tool_inputs: ['Read', 'Bash', 'Grep'],
|
|
2040
|
-
* }],
|
|
2041
|
-
* }
|
|
2042
|
-
* ```
|
|
2074
|
+
* `messages` is read-only here; use `context:transform` for message
|
|
2075
|
+
* surgery. `session` is `undefined` when the run is sessionless.
|
|
2043
2076
|
*/
|
|
2044
|
-
|
|
2077
|
+
'system:transform': (ctx: {
|
|
2078
|
+
system: string;
|
|
2079
|
+
messages: readonly SessionMessage[];
|
|
2080
|
+
turn: number;
|
|
2081
|
+
turnId: string;
|
|
2082
|
+
session?: Session;
|
|
2083
|
+
}) => void;
|
|
2084
|
+
'steer:inject': (ctx: {
|
|
2085
|
+
message: string;
|
|
2086
|
+
}) => void;
|
|
2087
|
+
'spawn:before': (ctx: SpawnHookContext) => void;
|
|
2088
|
+
'spawn:complete': (ctx: ChildRunStats) => void;
|
|
2089
|
+
'spawn:error': (ctx: SpawnHookContext & {
|
|
2090
|
+
error: Error;
|
|
2091
|
+
}) => void;
|
|
2092
|
+
'child:stream:text': (ctx: StreamHookContext & {
|
|
2093
|
+
delta: string;
|
|
2094
|
+
text: string;
|
|
2095
|
+
childId: string;
|
|
2096
|
+
depth: number;
|
|
2097
|
+
}) => void;
|
|
2098
|
+
'child:stream:thinking': (ctx: StreamHookContext & {
|
|
2099
|
+
delta: string;
|
|
2100
|
+
thinking: string;
|
|
2101
|
+
childId: string;
|
|
2102
|
+
depth: number;
|
|
2103
|
+
}) => void;
|
|
2104
|
+
'child:stream:end': (ctx: StreamHookContext & {
|
|
2105
|
+
text: string;
|
|
2106
|
+
childId: string;
|
|
2107
|
+
depth: number;
|
|
2108
|
+
}) => void;
|
|
2045
2109
|
/**
|
|
2046
|
-
*
|
|
2047
|
-
*
|
|
2048
|
-
*
|
|
2049
|
-
*
|
|
2110
|
+
* Gate-style child events. Unlike the other `child:*` events, the bubble
|
|
2111
|
+
* passes the **same `ctx` reference** the subagent's loop is awaiting on:
|
|
2112
|
+
* setting `ctx.block` / `ctx.reason` / `ctx.result` on a parent listener
|
|
2113
|
+
* propagates straight back to the child, refusing or substituting the call.
|
|
2050
2114
|
*
|
|
2051
|
-
*
|
|
2052
|
-
*
|
|
2053
|
-
*
|
|
2054
|
-
*
|
|
2115
|
+
* Use these to gate subagent tool calls (native + MCP) from the parent
|
|
2116
|
+
* without registering listeners on every child agent. The parent's own
|
|
2117
|
+
* `tool:gate` / `mcp:tool:gate` listeners are NOT auto-shared with
|
|
2118
|
+
* children — that would also share their budgets and dedup state.
|
|
2055
2119
|
*/
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2120
|
+
'child:tool:gate': (ctx: ToolHookContext & {
|
|
2121
|
+
block: boolean;
|
|
2122
|
+
reason: string;
|
|
2123
|
+
result?: string | ToolResultContent[];
|
|
2124
|
+
runToolCounts: Readonly<Record<string, number>>;
|
|
2125
|
+
childId: string;
|
|
2126
|
+
depth: number;
|
|
2127
|
+
}) => void;
|
|
2128
|
+
'child:mcp:tool:gate': (ctx: McpToolHookContext & {
|
|
2129
|
+
block: boolean;
|
|
2130
|
+
reason: string;
|
|
2131
|
+
result?: string | ToolResultContent[];
|
|
2132
|
+
childId: string;
|
|
2133
|
+
depth: number;
|
|
2134
|
+
}) => void;
|
|
2135
|
+
'child:tool:before': (ctx: ToolHookContext & {
|
|
2136
|
+
coercions?: readonly string[];
|
|
2137
|
+
runToolCounts: Readonly<Record<string, number>>;
|
|
2138
|
+
childId: string;
|
|
2139
|
+
depth: number;
|
|
2140
|
+
}) => void;
|
|
2141
|
+
'child:tool:after': (ctx: ToolHookContext & {
|
|
2142
|
+
result: string | ToolResultContent[];
|
|
2143
|
+
outputBytes: number;
|
|
2144
|
+
coercions?: readonly string[];
|
|
2145
|
+
runToolCounts: Readonly<Record<string, number>>;
|
|
2146
|
+
childId: string;
|
|
2147
|
+
depth: number;
|
|
2148
|
+
}) => void;
|
|
2149
|
+
'child:tool:error': (ctx: ToolHookContext & {
|
|
2150
|
+
error: Error;
|
|
2151
|
+
childId: string;
|
|
2152
|
+
depth: number;
|
|
2153
|
+
}) => void;
|
|
2154
|
+
'child:turn:after': (ctx: {
|
|
2155
|
+
turn: number;
|
|
2156
|
+
turnId: string;
|
|
2157
|
+
usage: TurnUsage;
|
|
2158
|
+
message: SessionTurn;
|
|
2159
|
+
toolCounts: {
|
|
2160
|
+
turn: Readonly<Record<string, number>>;
|
|
2161
|
+
run: Readonly<Record<string, number>>;
|
|
2162
|
+
};
|
|
2163
|
+
childId: string;
|
|
2164
|
+
depth: number;
|
|
2165
|
+
}) => void;
|
|
2166
|
+
'mcp:connect': (ctx: {
|
|
2167
|
+
name: string;
|
|
2168
|
+
transport: string;
|
|
2169
|
+
tools: string[];
|
|
2170
|
+
}) => void;
|
|
2171
|
+
'mcp:error': (ctx: {
|
|
2172
|
+
name: string;
|
|
2173
|
+
error: Error;
|
|
2174
|
+
}) => void;
|
|
2175
|
+
'mcp:close': (ctx: {
|
|
2176
|
+
name: string;
|
|
2177
|
+
}) => void;
|
|
2064
2178
|
/**
|
|
2065
|
-
*
|
|
2066
|
-
*
|
|
2067
|
-
* Override when routing to a vision-capable deployment.
|
|
2179
|
+
* Fires at the start of a per-server bootstrap attempt, before any network I/O.
|
|
2180
|
+
* Pairs with `mcp:bootstrap:end` and is always emitted, regardless of outcome.
|
|
2068
2181
|
*/
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
*
|
|
2074
|
-
* Thin wrapper around {@link openaiCompat} with Cerebras-specific defaults
|
|
2075
|
-
* (base URL, default model).
|
|
2076
|
-
*/
|
|
2077
|
-
declare function cerebras(params?: CerebrasParams): Provider;
|
|
2078
|
-
//#endregion
|
|
2079
|
-
//#region src/providers/openai.d.ts
|
|
2080
|
-
interface OpenAIParams {
|
|
2081
|
-
/** OpenAI Codex OAuth access token. Falls back to OPENAI_CODEX_API_KEY and .credentials.json. */
|
|
2082
|
-
apiKey?: string;
|
|
2083
|
-
/** Alias for apiKey, matching the OAuth credential field. */
|
|
2084
|
-
access?: string;
|
|
2085
|
-
refresh?: string;
|
|
2086
|
-
expires?: number;
|
|
2087
|
-
accountId?: string;
|
|
2088
|
-
defaultModel?: string;
|
|
2089
|
-
transport?: 'sse' | 'websocket' | 'auto';
|
|
2090
|
-
}
|
|
2091
|
-
declare function openai(params?: OpenAIParams): Provider;
|
|
2092
|
-
//#endregion
|
|
2093
|
-
//#region src/providers/openai-compat.d.ts
|
|
2094
|
-
/**
|
|
2095
|
-
* HTTP error thrown when an OpenAI-compatible endpoint returns a non-OK response.
|
|
2096
|
-
*
|
|
2097
|
-
* The body is best-effort JSON-parsed; `error.message` / `error.code` / `error.type`
|
|
2098
|
-
* are extracted for clean downstream classification.
|
|
2099
|
-
*/
|
|
2100
|
-
declare class OpenAICompatHttpError extends Error {
|
|
2101
|
-
readonly status: number;
|
|
2102
|
-
readonly providerCode?: string;
|
|
2103
|
-
readonly bodyText: string;
|
|
2104
|
-
constructor(status: number, bodyText: string);
|
|
2105
|
-
}
|
|
2106
|
-
/**
|
|
2107
|
-
* Classify an OpenAI-compatible error into `ClassifiedError`.
|
|
2108
|
-
*
|
|
2109
|
-
* Recognizes:
|
|
2110
|
-
* - `AbortError` (from fetch) → `aborted`.
|
|
2111
|
-
* - `OpenAICompatHttpError` with a context-exceeded code or message → `context_exceeded`.
|
|
2112
|
-
* - Any other `OpenAICompatHttpError` → `provider_error`.
|
|
2113
|
-
*
|
|
2114
|
-
* Returns `null` for unrecognized error shapes (the loop falls back to `AgentProviderError`).
|
|
2115
|
-
*/
|
|
2116
|
-
declare function classifyOpenAICompatError(err: unknown): ClassifiedError | null;
|
|
2117
|
-
/**
|
|
2118
|
-
* Map an OpenAI-compatible `finish_reason` string to the zidane `TurnFinishReason` union.
|
|
2119
|
-
*/
|
|
2120
|
-
declare function mapOAIFinishReason(reason: string | null | undefined): TurnFinishReason | undefined;
|
|
2121
|
-
/**
|
|
2122
|
-
* Auth header config. `scheme` is prepended to the api key with a space, e.g.
|
|
2123
|
-
* `{ name: 'Authorization', scheme: 'Bearer' }` → `Authorization: Bearer <key>`.
|
|
2124
|
-
* Omit `scheme` for raw header values (e.g. `{ name: 'X-Api-Key' }` → `X-Api-Key: <key>`).
|
|
2125
|
-
*
|
|
2126
|
-
* Real-world examples:
|
|
2127
|
-
* - Default OpenAI / OpenRouter / Cerebras: `{ name: 'Authorization', scheme: 'Bearer' }`.
|
|
2128
|
-
* - Baseten: `{ name: 'Authorization', scheme: 'Api-Key' }`.
|
|
2129
|
-
* - Some gateways: `{ name: 'X-Api-Key' }`.
|
|
2130
|
-
*/
|
|
2131
|
-
interface OpenAICompatAuthHeader {
|
|
2132
|
-
name: string;
|
|
2133
|
-
scheme?: string;
|
|
2134
|
-
}
|
|
2135
|
-
interface OpenAICompatParams {
|
|
2136
|
-
/** Bearer-style API key. */
|
|
2137
|
-
apiKey: string;
|
|
2138
|
-
/** Base URL — `/chat/completions` is appended. */
|
|
2139
|
-
baseURL: string;
|
|
2140
|
-
/** Default model id when `run({ model })` is omitted. */
|
|
2141
|
-
defaultModel?: string;
|
|
2142
|
-
/** Provider name exposed as `Provider.name`. Defaults to `'openai-compat'`. */
|
|
2143
|
-
name?: string;
|
|
2144
|
-
/** Auth header shape. Defaults to `{ name: 'Authorization', scheme: 'Bearer' }`. */
|
|
2145
|
-
authHeader?: OpenAICompatAuthHeader;
|
|
2146
|
-
/** Extra headers sent with every request (e.g. referer, user-agent). */
|
|
2147
|
-
extraHeaders?: Record<string, string>;
|
|
2182
|
+
'mcp:bootstrap:start': (ctx: {
|
|
2183
|
+
name: string;
|
|
2184
|
+
transport: string;
|
|
2185
|
+
}) => void;
|
|
2148
2186
|
/**
|
|
2149
|
-
*
|
|
2150
|
-
*
|
|
2151
|
-
*
|
|
2152
|
-
*
|
|
2153
|
-
* Defaults when omitted: `vision: false`, `imageInToolResult: false` — a
|
|
2154
|
-
* conservative assumption matching most OSS text-only OpenAI-compat
|
|
2155
|
-
* endpoints. Override when routing to a known vision-capable endpoint
|
|
2156
|
-
* (e.g. OpenRouter vision models, Baseten image-capable deployments).
|
|
2187
|
+
* Fires at the end of a per-server bootstrap attempt. `durationMs` spans from
|
|
2188
|
+
* the matching `mcp:bootstrap:start`. On `ok: false` carries the originating
|
|
2189
|
+
* error so consumers can log / trace without relying on a separate `mcp:error`.
|
|
2157
2190
|
*/
|
|
2158
|
-
|
|
2191
|
+
'mcp:bootstrap:end': (ctx: {
|
|
2192
|
+
name: string;
|
|
2193
|
+
transport: string;
|
|
2194
|
+
durationMs: number;
|
|
2195
|
+
} & ({
|
|
2196
|
+
ok: true;
|
|
2197
|
+
toolCount: number;
|
|
2198
|
+
} | {
|
|
2199
|
+
ok: false;
|
|
2200
|
+
error: Error;
|
|
2201
|
+
})) => void;
|
|
2159
2202
|
/**
|
|
2160
|
-
*
|
|
2161
|
-
*
|
|
2203
|
+
* Fires once per server after `listTools()` and after the config-side filters
|
|
2204
|
+
* (`enabledTools` / `disabledTools` / `toolFilter`) have applied, but BEFORE
|
|
2205
|
+
* tools are registered. Handlers may mutate `ctx.tools` in place — splicing,
|
|
2206
|
+
* reordering, or replacing entries — to further narrow what the model sees.
|
|
2162
2207
|
*
|
|
2163
|
-
* -
|
|
2164
|
-
*
|
|
2165
|
-
*
|
|
2166
|
-
* - `false` — never inject markers. Safe default for endpoints that strictly
|
|
2167
|
-
* validate the request schema (OpenAI direct, most OSS inference
|
|
2168
|
-
* servers) and would reject unknown fields.
|
|
2208
|
+
* Composes with config-side filters: config drops tools the host's static
|
|
2209
|
+
* policy excludes; this hook is the runtime escape hatch for per-user, per-
|
|
2210
|
+
* environment, or capability-driven decisions that the config can't express.
|
|
2169
2211
|
*
|
|
2170
|
-
*
|
|
2212
|
+
* Items are upstream tool descriptors (NOT yet namespaced as `mcp_<server>_<tool>`).
|
|
2171
2213
|
*/
|
|
2172
|
-
|
|
2214
|
+
'mcp:tools:filter': (ctx: {
|
|
2215
|
+
server: string;
|
|
2216
|
+
transport: 'stdio' | 'sse' | 'streamable-http';
|
|
2217
|
+
tools: Array<{
|
|
2218
|
+
name: string;
|
|
2219
|
+
description?: string | null;
|
|
2220
|
+
inputSchema?: unknown;
|
|
2221
|
+
}>;
|
|
2222
|
+
}) => void;
|
|
2173
2223
|
/**
|
|
2174
|
-
*
|
|
2175
|
-
* `
|
|
2176
|
-
* `
|
|
2177
|
-
* extended-reasoning state across turns.
|
|
2178
|
-
*
|
|
2179
|
-
* - `true` — map zidane's `behavior.thinking` / `behavior.thinkingBudget` to
|
|
2180
|
-
* the request's `reasoning` field, capture `reasoning_details`
|
|
2181
|
-
* from streaming responses into `provider_reasoning` blocks, and
|
|
2182
|
-
* echo them back on subsequent assistant messages.
|
|
2183
|
-
* - `false` — never set the field; drop any stored `provider_reasoning`
|
|
2184
|
-
* blocks before sending. Safe default for hosts that strict-
|
|
2185
|
-
* validate the request schema.
|
|
2224
|
+
* MCP-side counterpart of `tool:gate`. Same shape: set `block` to refuse,
|
|
2225
|
+
* set `result` to substitute a successful payload and skip the upstream
|
|
2226
|
+
* MCP `callTool`. When both are set across the handler chain, `block` wins.
|
|
2186
2227
|
*
|
|
2187
|
-
*
|
|
2228
|
+
* Fires INSIDE the MCP wrapper's `execute`, after the loop's `tool:gate`
|
|
2229
|
+
* already ran. Does **not** carry `runToolCounts` — those are loop-level
|
|
2230
|
+
* and already exposed on `tool:gate` for MCP tools (which are registered
|
|
2231
|
+
* as agent tools under their namespaced name `mcp_<server>_<tool>`). Use
|
|
2232
|
+
* `tool:gate` for budget / dedup logic; reserve `mcp:tool:gate` for
|
|
2233
|
+
* MCP-specific concerns (per-server routing, transport-aware refusals).
|
|
2188
2234
|
*/
|
|
2189
|
-
|
|
2235
|
+
'mcp:tool:gate': (ctx: McpToolHookContext & {
|
|
2236
|
+
block: boolean;
|
|
2237
|
+
reason: string;
|
|
2238
|
+
result?: string | ToolResultContent[];
|
|
2239
|
+
}) => void;
|
|
2240
|
+
'mcp:tool:before': (ctx: McpToolHookContext) => void;
|
|
2241
|
+
'mcp:tool:after': (ctx: McpToolHookContext & {
|
|
2242
|
+
result: string | ToolResultContent[];
|
|
2243
|
+
outputBytes: number;
|
|
2244
|
+
}) => void;
|
|
2245
|
+
'mcp:tool:transform': (ctx: McpToolHookContext & {
|
|
2246
|
+
result: string | ToolResultContent[];
|
|
2247
|
+
outputBytes: number;
|
|
2248
|
+
}) => void;
|
|
2249
|
+
'mcp:tool:error': (ctx: McpToolHookContext & {
|
|
2250
|
+
error: Error;
|
|
2251
|
+
}) => void;
|
|
2252
|
+
'skills:resolve': (ctx: {
|
|
2253
|
+
skills: SkillConfig[];
|
|
2254
|
+
}) => void;
|
|
2255
|
+
'skills:catalog': (ctx: {
|
|
2256
|
+
catalog: string;
|
|
2257
|
+
skills: SkillConfig[];
|
|
2258
|
+
}) => void;
|
|
2259
|
+
'skills:activate': (ctx: {
|
|
2260
|
+
skill: SkillConfig;
|
|
2261
|
+
via: ActivationVia;
|
|
2262
|
+
}) => void;
|
|
2263
|
+
'skills:deactivate': (ctx: {
|
|
2264
|
+
skill: SkillConfig;
|
|
2265
|
+
reason: DeactivationReason;
|
|
2266
|
+
}) => void;
|
|
2267
|
+
'usage': (ctx: {
|
|
2268
|
+
turn: number;
|
|
2269
|
+
turnId: string;
|
|
2270
|
+
usage: TurnUsage;
|
|
2271
|
+
totalIn: number;
|
|
2272
|
+
totalOut: number;
|
|
2273
|
+
}) => void;
|
|
2274
|
+
'output': (ctx: {
|
|
2275
|
+
output: Record<string, unknown>;
|
|
2276
|
+
schema: Record<string, unknown>;
|
|
2277
|
+
}) => void;
|
|
2190
2278
|
/**
|
|
2191
|
-
*
|
|
2192
|
-
*
|
|
2193
|
-
*
|
|
2194
|
-
|
|
2279
|
+
* Fires when a turn's total tool-output bytes exceed `behavior.toolOutputBudget`.
|
|
2280
|
+
* Measured post-`tool:transform`. Loop injects a synthetic user message after
|
|
2281
|
+
* the tool-results turn instructing the model to summarize.
|
|
2282
|
+
*/
|
|
2283
|
+
'budget:exceeded': (ctx: {
|
|
2284
|
+
turn: number;
|
|
2285
|
+
turnId: string;
|
|
2286
|
+
bytes: number;
|
|
2287
|
+
budget: number;
|
|
2288
|
+
}) => void;
|
|
2289
|
+
/**
|
|
2290
|
+
* Fires when a per-tool budget configured via `behavior.toolBudgets` is
|
|
2291
|
+
* exceeded for a specific tool. `mode` reflects how the framework reacted:
|
|
2292
|
+
* `'steer'` lets the call run and queues a post-turn nudge; `'block'`
|
|
2293
|
+
* refuses the call outright with `Blocked: <message>`.
|
|
2195
2294
|
*
|
|
2196
|
-
*
|
|
2197
|
-
*
|
|
2198
|
-
*
|
|
2295
|
+
* `count` is the run-cumulative dispatched count just before this call.
|
|
2296
|
+
* Use `turnId` to correlate with `turn:after` if you need the integer turn
|
|
2297
|
+
* index. Distinct from `budget:exceeded` (byte-level) so consumers can
|
|
2298
|
+
* subscribe specifically; both can fire in the same turn.
|
|
2199
2299
|
*/
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
* @example Baseten (non-standard auth scheme)
|
|
2209
|
-
* ```ts
|
|
2210
|
-
* openaiCompat({
|
|
2211
|
-
* name: 'baseten',
|
|
2212
|
-
* apiKey: process.env.BASETEN_API_KEY!,
|
|
2213
|
-
* baseURL: process.env.BASETEN_PROXY_URL!,
|
|
2214
|
-
* authHeader: { name: 'Authorization', scheme: 'Api-Key' },
|
|
2215
|
-
* })
|
|
2216
|
-
* ```
|
|
2217
|
-
*/
|
|
2218
|
-
declare function openaiCompat(params: OpenAICompatParams): Provider;
|
|
2219
|
-
//#endregion
|
|
2220
|
-
//#region src/providers/openrouter.d.ts
|
|
2221
|
-
interface OpenRouterParams {
|
|
2222
|
-
apiKey?: string;
|
|
2223
|
-
defaultModel?: string;
|
|
2300
|
+
'tool-budget:exceeded': (ctx: {
|
|
2301
|
+
tool: string;
|
|
2302
|
+
count: number;
|
|
2303
|
+
max: number;
|
|
2304
|
+
turnId: string;
|
|
2305
|
+
mode: 'steer' | 'block';
|
|
2306
|
+
}) => void;
|
|
2307
|
+
'agent:abort': (ctx: object) => void;
|
|
2224
2308
|
/**
|
|
2225
|
-
*
|
|
2226
|
-
* native image-in-tool-result are supported depends on the downstream model.
|
|
2227
|
-
* Default: `{ vision: true, imageInToolResult: false }` — matches the default
|
|
2228
|
-
* `anthropic/claude-sonnet-4-6` model (vision-capable via companion user-message
|
|
2229
|
-
* fallback since OpenRouter exposes Claude over the Chat Completions dialect).
|
|
2309
|
+
* Run finished — fires on all exit paths (completion, maxTurns, abort).
|
|
2230
2310
|
*
|
|
2231
|
-
*
|
|
2311
|
+
* Since 4.0 the `AgentStats` carried here is **cumulative** across the
|
|
2312
|
+
* parent agent loop and every recursively-spawned sub-agent
|
|
2313
|
+
* (`totalIn` / `totalOut` / `cost` / `totalCacheRead` / `totalCacheCreation`).
|
|
2314
|
+
* For parent-loop-only counts use `ctx.turnUsage` (parent-only array);
|
|
2315
|
+
* for tree-wide turn counts use `flattenTurns(ctx).length`.
|
|
2232
2316
|
*/
|
|
2233
|
-
|
|
2317
|
+
'agent:done': (ctx: AgentStats) => void;
|
|
2318
|
+
'session:start': (ctx: SessionHookContext & {
|
|
2319
|
+
runId: string;
|
|
2320
|
+
prompt: string;
|
|
2321
|
+
}) => void;
|
|
2322
|
+
'session:end': (ctx: SessionHookContext & {
|
|
2323
|
+
runId: string;
|
|
2324
|
+
status: SessionEndStatus;
|
|
2325
|
+
turnRange: [number, number];
|
|
2326
|
+
}) => void;
|
|
2327
|
+
'session:turns': (ctx: SessionHookContext & {
|
|
2328
|
+
turns: SessionTurn[];
|
|
2329
|
+
count: number;
|
|
2330
|
+
}) => void;
|
|
2331
|
+
'session:meta': (ctx: SessionHookContext & {
|
|
2332
|
+
key: string;
|
|
2333
|
+
value: unknown;
|
|
2334
|
+
}) => void;
|
|
2335
|
+
'session:save': (ctx: SessionHookContext) => void;
|
|
2234
2336
|
}
|
|
2235
2337
|
/**
|
|
2236
|
-
*
|
|
2338
|
+
* Strongly-typed hook registration map accepted on {@link AgentOptions.hooks}
|
|
2339
|
+
* (and therefore on any {@link Preset}). Each entry is a single handler or an
|
|
2340
|
+
* array of handlers — arrays are what {@link composePresets} produces when
|
|
2341
|
+
* multiple presets register handlers for the same event.
|
|
2237
2342
|
*
|
|
2238
|
-
*
|
|
2239
|
-
*
|
|
2343
|
+
* Handlers registered here live for the **lifetime of the agent**. They fire
|
|
2344
|
+
* across every `run()`, mirroring a manual `agent.hooks.hook(event, fn)` call
|
|
2345
|
+
* made right after `createAgent` returns. For per-run handlers (auto-detached
|
|
2346
|
+
* at run end) use {@link AgentRunOptions.hooks} instead.
|
|
2240
2347
|
*/
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
name
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
id: string;
|
|
2251
|
-
name: string;
|
|
2252
|
-
input: Record<string, unknown>;
|
|
2253
|
-
}
|
|
2254
|
-
interface ToolResult {
|
|
2255
|
-
id: string;
|
|
2348
|
+
type AgentHookMap = Partial<{ [K in keyof AgentHooks]: AgentHooks[K] | AgentHooks[K][] }>;
|
|
2349
|
+
interface AgentOptions {
|
|
2350
|
+
provider: Provider;
|
|
2351
|
+
/** Display name for the agent (used in traces/logs). */
|
|
2352
|
+
name?: string;
|
|
2353
|
+
/** Default system prompt injected when no system is provided at run time. */
|
|
2354
|
+
system?: string;
|
|
2355
|
+
/** Tool definitions available to the agent. Defaults to no tools. */
|
|
2356
|
+
tools?: Record<string, ToolDef>;
|
|
2256
2357
|
/**
|
|
2257
|
-
*
|
|
2258
|
-
* array of content blocks for tools that return images or mixed content (e.g. an
|
|
2259
|
-
* MCP browser server returning a screenshot).
|
|
2358
|
+
* Map canonical tool names to LLM-facing (aliased) names.
|
|
2260
2359
|
*
|
|
2261
|
-
*
|
|
2360
|
+
* Aliasing is **LLM-boundary-only**: the alias is what the provider's tool spec
|
|
2361
|
+
* carries and what the model calls the tool; the canonical name is what lives in
|
|
2362
|
+
* `session.turns` and what the agent uses to look up the tool implementation.
|
|
2262
2363
|
*/
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
*/
|
|
2273
|
-
|
|
2364
|
+
toolAliases?: Record<string, string>;
|
|
2365
|
+
/** Agent-level behavior defaults (overridden by run-level behavior) */
|
|
2366
|
+
behavior?: AgentBehavior;
|
|
2367
|
+
/** Execution context: where tools run. Defaults to in-process. */
|
|
2368
|
+
execution?: ExecutionContext;
|
|
2369
|
+
/** MCP servers to connect and expose as tools */
|
|
2370
|
+
mcpServers?: McpServerConfig[];
|
|
2371
|
+
/** Session for identity, turn persistence, and run tracking */
|
|
2372
|
+
session?: Session;
|
|
2373
|
+
/** Skills configuration */
|
|
2374
|
+
skills?: SkillsConfig;
|
|
2274
2375
|
/**
|
|
2275
|
-
*
|
|
2376
|
+
* Agent-lifetime hook registrations. Registered once when `createAgent`
|
|
2377
|
+
* returns; identical in effect to calling `agent.hooks.hook(event, fn)` for
|
|
2378
|
+
* each entry. Use this to bake observability / policy hooks into a
|
|
2379
|
+
* {@link Preset} so consumers get them automatically via `...spread`.
|
|
2276
2380
|
*
|
|
2277
|
-
*
|
|
2278
|
-
* `
|
|
2279
|
-
*
|
|
2280
|
-
*
|
|
2381
|
+
* Handlers may be a single function or an array — the array form is what
|
|
2382
|
+
* `composePresets()` produces when multiple presets register handlers for
|
|
2383
|
+
* the same event. Unknown event names throw at agent construction so typos
|
|
2384
|
+
* never silently no-op.
|
|
2385
|
+
*
|
|
2386
|
+
* For per-run handlers (auto-detached at run end) use
|
|
2387
|
+
* {@link AgentRunOptions.hooks}.
|
|
2281
2388
|
*/
|
|
2282
|
-
|
|
2389
|
+
hooks?: AgentHookMap;
|
|
2283
2390
|
/**
|
|
2284
|
-
*
|
|
2285
|
-
*
|
|
2391
|
+
* Test seam — replaces the default MCP connector with a custom
|
|
2392
|
+
* implementation. Bypasses the `mcpServers` normalization layer entirely
|
|
2393
|
+
* and is **not** part of the supported public API. Subject to change or
|
|
2394
|
+
* removal in any release.
|
|
2286
2395
|
*
|
|
2287
|
-
*
|
|
2288
|
-
* companion `user` message emitted immediately after the flattened
|
|
2289
|
-
* `tool`/`tool_result` marker. This is the Claude Desktop / Cline pattern
|
|
2290
|
-
* and works on any OpenAI Chat Completions endpoint that accepts image
|
|
2291
|
-
* URLs in user messages.
|
|
2396
|
+
* @internal
|
|
2292
2397
|
*/
|
|
2293
|
-
|
|
2294
|
-
}
|
|
2295
|
-
interface StreamCallbacks {
|
|
2296
|
-
onText: (delta: string) => void;
|
|
2297
|
-
onThinking?: (delta: string) => void;
|
|
2298
|
-
onOAuthRefresh?: (ctx: OAuthRefreshHookContext) => void | Promise<void>;
|
|
2299
|
-
}
|
|
2300
|
-
interface TurnResult {
|
|
2301
|
-
/** Full assistant turn as a SessionMessage */
|
|
2302
|
-
assistantMessage: SessionMessage;
|
|
2303
|
-
/** Text content blocks concatenated */
|
|
2304
|
-
text: string;
|
|
2305
|
-
/** Tool calls requested by the model */
|
|
2306
|
-
toolCalls: ToolCall[];
|
|
2307
|
-
/** Whether the model wants to stop */
|
|
2308
|
-
done: boolean;
|
|
2309
|
-
usage: TurnUsage;
|
|
2310
|
-
}
|
|
2311
|
-
interface StreamOptions {
|
|
2312
|
-
model: string;
|
|
2313
|
-
system: string;
|
|
2314
|
-
tools: unknown[];
|
|
2315
|
-
messages: SessionMessage[];
|
|
2316
|
-
maxTokens: number;
|
|
2317
|
-
/** Thinking/reasoning level (optional, default: off) */
|
|
2318
|
-
thinking?: ThinkingLevel;
|
|
2319
|
-
/** Exact thinking token budget — overrides the level-based default when set */
|
|
2320
|
-
thinkingBudget?: number;
|
|
2321
|
-
/** Force tool selection behavior */
|
|
2322
|
-
toolChoice?: {
|
|
2323
|
-
type: 'auto' | 'required' | 'tool';
|
|
2324
|
-
name?: string;
|
|
2325
|
-
};
|
|
2398
|
+
mcpConnector?: (configs: McpServerConfig[]) => Promise<McpConnection>;
|
|
2326
2399
|
/**
|
|
2327
|
-
*
|
|
2328
|
-
*
|
|
2329
|
-
* last stable message so the shared prefix is cached across turns.
|
|
2400
|
+
* Pre-connect MCP servers in the background as soon as `createAgent` returns,
|
|
2401
|
+
* instead of deferring the bootstrap to the first `agent.run()`.
|
|
2330
2402
|
*
|
|
2331
|
-
*
|
|
2403
|
+
* Useful when MCP latency is the dominant cost of a cold start: callers that
|
|
2404
|
+
* construct the agent early (e.g. at process init) can hide the bootstrap
|
|
2405
|
+
* behind other setup work. If bootstrap fails, the error is stored and
|
|
2406
|
+
* surfaced on the first `agent.run()` / `agent.warmup()`; the in-flight
|
|
2407
|
+
* promise is `await`ed by both paths so the error is never silently lost.
|
|
2408
|
+
*
|
|
2409
|
+
* No-op when `mcpServers` is empty. Default: `false`.
|
|
2332
2410
|
*/
|
|
2333
|
-
|
|
2334
|
-
/** Abort signal for cancellation */
|
|
2335
|
-
signal?: AbortSignal;
|
|
2411
|
+
eager?: boolean;
|
|
2336
2412
|
}
|
|
2337
|
-
interface
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
formatTools: (tools: ToolSpec[]) => unknown[];
|
|
2345
|
-
/** Create a text-only user message. Multimodal content goes through `promptMessage`. */
|
|
2346
|
-
userMessage: (content: string) => SessionMessage;
|
|
2347
|
-
/** Create an assistant message (for priming) */
|
|
2348
|
-
assistantMessage: (content: string) => SessionMessage;
|
|
2349
|
-
/** Create a tool results message to send back */
|
|
2350
|
-
toolResultsMessage: (results: ToolResult[]) => SessionMessage;
|
|
2351
|
-
/** Stream a turn, calling onText for each text delta */
|
|
2352
|
-
stream: (options: StreamOptions, callbacks: StreamCallbacks) => Promise<TurnResult>;
|
|
2413
|
+
interface Agent {
|
|
2414
|
+
hooks: Hookable<AgentHooks>;
|
|
2415
|
+
run: (options: AgentRunOptions) => Promise<AgentStats>;
|
|
2416
|
+
abort: () => void;
|
|
2417
|
+
steer: (message: string) => void;
|
|
2418
|
+
followUp: (message: string) => void;
|
|
2419
|
+
waitForIdle: () => Promise<void>;
|
|
2353
2420
|
/**
|
|
2354
|
-
*
|
|
2355
|
-
*
|
|
2356
|
-
*
|
|
2357
|
-
* The agent loop always canonicalizes the run-level prompt into parts before calling
|
|
2358
|
-
* this method; providers may fall back to `userMessage` for the text-only path if
|
|
2359
|
-
* they do not implement this.
|
|
2421
|
+
* Clear the agent's in-memory state (turns, queues, skill activations).
|
|
2422
|
+
* Fires `skills:deactivate` with `reason: 'reset'` for each previously active
|
|
2423
|
+
* skill. Awaiting lets host apps observe listener rejections.
|
|
2360
2424
|
*/
|
|
2361
|
-
|
|
2425
|
+
reset: () => Promise<void>;
|
|
2362
2426
|
/**
|
|
2363
|
-
*
|
|
2427
|
+
* Destroy the execution context and clean up resources.
|
|
2428
|
+
* Idempotent — safe to call from both a `finally` block and a signal handler.
|
|
2429
|
+
*/
|
|
2430
|
+
destroy: () => Promise<void>;
|
|
2431
|
+
/**
|
|
2432
|
+
* Explicitly activate a skill by name. Fires `skills:activate` with
|
|
2433
|
+
* `via: 'explicit'`. Throws if the skill isn't in the resolved catalog or
|
|
2434
|
+
* if the `maxActive` cap is reached. Idempotent — activating an already-active
|
|
2435
|
+
* skill is a no-op.
|
|
2436
|
+
*/
|
|
2437
|
+
activateSkill: (name: string) => Promise<void>;
|
|
2438
|
+
/**
|
|
2439
|
+
* Deactivate a skill by name. Fires `skills:deactivate` with `reason: 'explicit'`.
|
|
2440
|
+
* No-op when the skill wasn't active.
|
|
2441
|
+
*/
|
|
2442
|
+
deactivateSkill: (name: string) => Promise<void>;
|
|
2443
|
+
/**
|
|
2444
|
+
* Pre-connect MCP servers without running a turn. Idempotent and concurrency-safe:
|
|
2445
|
+
* - No MCP servers configured → resolves immediately.
|
|
2446
|
+
* - Connection already established → resolves immediately.
|
|
2447
|
+
* - Another `warmup()` / `run()` is bootstrapping → awaits the in-flight promise.
|
|
2364
2448
|
*
|
|
2365
|
-
*
|
|
2366
|
-
*
|
|
2367
|
-
*
|
|
2449
|
+
* Use from host code that wants to hide MCP bootstrap latency behind other
|
|
2450
|
+
* startup work (UI init, auth, etc.). Safe to call multiple times and from
|
|
2451
|
+
* multiple callers concurrently.
|
|
2368
2452
|
*/
|
|
2369
|
-
|
|
2453
|
+
warmup: () => Promise<void>;
|
|
2454
|
+
readonly isRunning: boolean;
|
|
2455
|
+
readonly turns: SessionTurn[];
|
|
2456
|
+
readonly execution: ExecutionContext;
|
|
2457
|
+
readonly handle: ExecutionHandle | null;
|
|
2458
|
+
readonly session: Session | null;
|
|
2459
|
+
/** Snapshot of currently active skills. */
|
|
2460
|
+
readonly activeSkills: readonly ActiveSkill[];
|
|
2461
|
+
/**
|
|
2462
|
+
* Frozen view of the underlying `provider.meta`. Read-only to prevent
|
|
2463
|
+
* accidental cross-agent contamination — writes are rejected at runtime
|
|
2464
|
+
* (via `Object.freeze`) and at compile time (via `Readonly`). To override
|
|
2465
|
+
* model / capability defaults, construct a new provider.
|
|
2466
|
+
*/
|
|
2467
|
+
readonly meta: Readonly<Record<string, unknown>>;
|
|
2370
2468
|
}
|
|
2469
|
+
declare function createAgent({
|
|
2470
|
+
provider,
|
|
2471
|
+
name: agentName,
|
|
2472
|
+
system: agentSystem,
|
|
2473
|
+
tools: agentTools,
|
|
2474
|
+
toolAliases,
|
|
2475
|
+
behavior: agentBehavior,
|
|
2476
|
+
execution,
|
|
2477
|
+
mcpServers,
|
|
2478
|
+
session,
|
|
2479
|
+
skills: agentSkills,
|
|
2480
|
+
mcpConnector,
|
|
2481
|
+
eager,
|
|
2482
|
+
hooks: initialHooks
|
|
2483
|
+
}: AgentOptions): Agent;
|
|
2371
2484
|
//#endregion
|
|
2372
|
-
export {
|
|
2373
|
-
//# sourceMappingURL=
|
|
2485
|
+
export { OpenAICompatAuthHeader as $, createSession as A, ThinkingLevel as At, FileMapAdapter as B, AgentAbortedError as Bt, SkillSource as C, SessionContentBlock as Ct, SessionData as D, SessionTurn as Dt, Session as E, SessionMessage as Et, fromAnthropic as F, ToolResultTextContent as Ft, StreamCallbacks as G, ClassifiedError as Gt, createFileMapStore as H, AgentProviderError as Ht, fromOpenAI as I, TurnFinishReason as It, ToolResult as J, toTypedError as Jt, StreamOptions as K, ClassifiedErrorKind as Kt, toAnthropic as L, TurnUsage as Lt, RemoteStoreOptions as M, ToolHookContext as Mt, createRemoteStore as N, ToolResultContent as Nt, SessionRun as O, SpawnHookContext as Ot, autoDetectAndConvert as P, ToolResultImageContent as Pt, openrouter as Q, toOpenAI as R, toolOutputByteLength as Rt, SkillResource as S, RunHookMap as St, CreateSessionOptions as T, SessionHookContext as Tt, Provider as U, AgentToolNotAllowedError as Ut, FileMapStoreOptions as V, AgentContextExceededError as Vt, ProviderCapabilities as W, CONTEXT_EXCEEDED_MESSAGE_PATTERNS as Wt, TurnResult as X, ToolSpec as Y, OpenRouterParams as Z, ToolContext as _, OAuthRefreshHookContext as _t, createAgent as a, OpenAIParams as at, SkillConfig as b, PromptPart as bt, DeactivationReason as c, cerebras as ct, createSkillActivationState as d, AgentBehavior as dt, OpenAICompatHttpError as et, McpConnection as f, AgentRunOptions as ft, resultToString as g, McpToolHookContext as gt, normalizeMcpServers as h, McpServerConfig as ht, AgentOptions as i, openaiCompat as it, loadSession as j, ToolExecutionMode as jt, SessionStore as k, StreamHookContext as kt, SkillActivationState as l, AnthropicParams as lt, normalizeMcpBlocks as m, ChildRunStats as mt, AgentHookMap as n, classifyOpenAICompatError as nt, ActivationVia as o, openai as ot, connectMcpServers as p, AgentStats as pt, ToolCall as q, matchesContextExceeded as qt, AgentHooks as r, mapOAIFinishReason as rt, ActiveSkill as s, CerebrasParams as st, Agent as t, OpenAICompatParams as tt, SkillActivationStateOptions as u, anthropic as ut, ToolDef as v, PromptDocumentPart as vt, SkillsConfig as w, SessionEndStatus as wt, SkillDiagnostic as x, PromptTextPart as xt, ToolMap as y, PromptImagePart as yt, createMemoryStore as z, toolResultToText as zt };
|
|
2486
|
+
//# sourceMappingURL=agent-JhicgLOV.d.ts.map
|