zidane 4.0.2 → 4.1.3

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