zidane 2.2.1 → 2.2.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.
package/README.md CHANGED
@@ -4,7 +4,29 @@
4
4
 
5
5
  An agent that goes straight to the goal.
6
6
 
7
- Minimal TypeScript agent loop built with [Bun](https://bun.sh). Hook into every step using [hookable](https://github.com/unjs/hookable). Built to be embedded.
7
+ Minimal TypeScript agent loop built with [Bun](https://bun.sh).
8
+
9
+ Hook into every step using [hookable](https://github.com/unjs/hookable).
10
+
11
+ Built to be embedded.
12
+
13
+ ## Features
14
+
15
+ - 🧠 **Multi-provider** — Anthropic, OpenAI Codex, OpenRouter, Cerebras, plus a generic `openaiCompat` factory (Baseten, Fireworks, Groq, local servers). OAuth + API-key auth, auto-refreshing tokens.
16
+ - 🔁 **Streaming turn loop** — stream text + thinking deltas, tool calls, and tool results with hookable events at every step.
17
+ - 🛠 **Tools first-class** — shell, file IO, glob, spawn, human-in-the-loop, plus any [MCP](https://modelcontextprotocol.io) server. Sequential or parallel execution, per-call gates, typed hooks.
18
+ - 🧩 **[Agent Skills](https://agentskills.io/specification) spec-aligned** — discover, activate, and run skills with `allowed-tools` enforcement and session-resume rehydration.
19
+ - 💾 **Pluggable sessions** — in-memory, SQLite, remote HTTP, or a file-map adapter. Turns persist incrementally — a crash leaves valid partial history.
20
+ - 🖼 **Multimodal** — images + documents via `PromptPart[]`; tools can return image blocks (screenshots, diagrams) routed natively on vision providers and via companion messages elsewhere.
21
+ - 🧠 **Extended thinking** — named levels (`off` / `minimal` / `low` / `medium` / `high`) or exact token budgets; traces streamed + persisted.
22
+ - ⚡ **Prompt caching** — auto-injected `cache_control` breakpoints on Anthropic + OpenRouter routes; cache-read / cache-write surfaced on `TurnUsage`.
23
+ - 🚀 **Parallel MCP bootstrap** — every server connects concurrently with per-server timeouts; `agent.warmup()` + `eager: true` hide cold-start latency.
24
+ - 🎯 **Structured output** — force the final answer to match a JSON Schema (Zod v4 interop), no brittle parsing.
25
+ - 🧵 **Sub-agent spawning** — delegate to child agents with inherited or overridden preset; child stream/tool events bubble to the parent.
26
+ - 🧭 **Typed errors** — `AgentContextExceededError` / `AgentProviderError` / `AgentAbortedError` instead of sniffing error strings.
27
+ - 🔌 **Execution contexts** — run tools in-process, in Docker, or in a remote sandbox (E2B / Rivet / any `SandboxProvider`).
28
+ - 🪝 **Hookable everything** — ~40 typed hook events covering turn, stream, tool, MCP, session, skills, spawn, OAuth refresh, and bootstrap timing.
29
+ - 🧪 **915+ tests, zero API keys** — mock providers + mock execution contexts; suite runs in under 2 seconds.
8
30
 
9
31
  ## Quickstart
10
32
 
@@ -47,9 +69,11 @@ createAgent({
47
69
  maxTurns: 50, // max loop iterations
48
70
  maxTokens: 16384, // max tokens per LLM response
49
71
  thinkingBudget: 10240, // exact thinking token budget
72
+ cache: true, // prompt-cache breakpoints on supported providers (default: true)
50
73
  },
51
74
  execution: createProcessContext(), // where tools run
52
75
  mcpServers: [], // MCP tool servers
76
+ eager: true, // pre-warm MCP bootstrap in the background (default: false)
53
77
  skills: {}, // skills configuration
54
78
  })
55
79
  ```
@@ -148,6 +172,39 @@ cerebras({ apiKey: 'csk-...', defaultModel: 'zai-glm-4.7' })
148
172
 
149
173
  Fallback: `params.apiKey` > `CEREBRAS_API_KEY` env
150
174
 
175
+ ### OpenAI-compatible (custom endpoints)
176
+
177
+ Any OpenAI Chat Completions endpoint — Baseten, Fireworks, Groq, local LM servers, corporate proxies:
178
+
179
+ ```ts
180
+ import { openaiCompat } from 'zidane/providers'
181
+
182
+ openaiCompat({
183
+ name: 'baseten',
184
+ apiKey: process.env.BASETEN_API_KEY!,
185
+ baseURL: process.env.BASETEN_PROXY_URL!,
186
+ authHeader: { name: 'Authorization', scheme: 'Api-Key' }, // vendor-specific scheme
187
+ capabilities: { vision: false, imageInToolResult: false },
188
+ cacheBreakpoints: false, // set true only for endpoints that honor `cache_control`
189
+ })
190
+ ```
191
+
192
+ `openrouter` and `cerebras` are thin wrappers around this factory with vendor defaults pinned. Reach for `openaiCompat` directly when adding a new backend instead of forking a bespoke provider.
193
+
194
+ ### Prompt caching
195
+
196
+ Enabled by default via `behavior.cache`. The provider inserts `cache_control: { type: 'ephemeral' }` markers on the three largest stable prefixes — system prompt, tool definitions, and the last message's final content block — so the shared prefix is served from cache across turns.
197
+
198
+ | Provider | Behavior |
199
+ |---|---|
200
+ | `anthropic` | Breakpoints honored natively. |
201
+ | `openrouter` | Breakpoints forwarded; Anthropic + Gemini routes honor them, OpenAI / DeepSeek / Grok / Groq / Moonshot routes cache automatically and ignore the markers. |
202
+ | `openaiCompat` | Opt-in via `cacheBreakpoints: true`. Default off so strict-schema endpoints (OpenAI direct, most OSS servers) don't reject unknown fields. |
203
+ | `cerebras` | Off (factory doesn't enable breakpoints). |
204
+ | `openai` (Codex) | Not affected — separate wire format (pi-ai). |
205
+
206
+ Cache hits + writes land on `TurnUsage.cacheRead` / `TurnUsage.cacheCreation` and are surfaced via the `usage` hook.
207
+
151
208
  ## Presets
152
209
 
153
210
  Reusable slices of `AgentOptions` — spread them into `createAgent()`.
@@ -157,11 +214,13 @@ The `basic` preset bundles:
157
214
  | Tool | Description |
158
215
  |---|---|
159
216
  | `shell` | Execute shell commands |
160
- | `read_file` | Read file contents |
161
- | `write_file` | Write/create files |
162
- | `list_files` | List directory contents |
217
+ | `readFile` | Read file contents |
218
+ | `writeFile` | Write/create files |
219
+ | `listFiles` | List directory contents |
163
220
  | `spawn` | Spawn a sub-agent |
164
221
 
222
+ Extra tools live alongside: `glob` (pattern-based file matching), `createInteractionTool` (human-in-the-loop factory), and the three `skills_use` / `skills_read` / `skills_run_script` tools that auto-inject when the skills catalog is non-empty.
223
+
165
224
  Define a custom preset:
166
225
 
167
226
  ```ts
@@ -395,13 +454,17 @@ Turns are persisted incrementally after each turn — not as a full save. If the
395
454
  ### Storage backends
396
455
 
397
456
  ```ts
398
- import { createMemoryStore, createSqliteStore, createRemoteStore } from 'zidane/session'
457
+ import { createMemoryStore, createRemoteStore, createFileMapStore } from 'zidane/session'
458
+ import { createSqliteStore } from 'zidane/session/sqlite' // separate subpath (Bun-only)
399
459
 
400
460
  createMemoryStore() // in-memory, no persistence
401
- createSqliteStore({ path: './sessions.db' }) // SQLite (Bun built-in)
461
+ createSqliteStore({ path: './sessions.db' }) // SQLite via bun:sqlite — WAL mode, per-turn flush
402
462
  createRemoteStore({ url: 'https://api.example.com' }) // HTTP REST API
463
+ createFileMapStore(hostAdapter) // bridge to any { get, save, delete } file-map backend
403
464
  ```
404
465
 
466
+ `createSqliteStore` lives on its own subpath because it depends on `bun:sqlite`. Non-Bun consumers importing from `zidane` or `zidane/session` never evaluate that module.
467
+
405
468
  ### Restoring a session
406
469
 
407
470
  ```ts
@@ -431,13 +494,47 @@ const agent = createAgent({
431
494
  ...basic,
432
495
  provider,
433
496
  mcpServers: [
434
- { name: 'fs', transport: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', '.'] },
497
+ { name: 'fs', transport: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', '.'], bootstrapTimeout: 10_000 },
435
498
  { name: 'api', transport: 'streamable-http', url: 'http://localhost:3002/mcp' },
436
499
  ],
437
500
  })
438
501
  ```
439
502
 
440
503
  MCP servers can live on a preset too (they're just `AgentOptions` fields). Connections are lazy (first `run()`) and reused.
504
+ Set `bootstrapTimeout` to cap how long a slow `connect + listTools` phase can delay the first model request.
505
+
506
+ ### Hiding bootstrap latency
507
+
508
+ Every server is bootstrapped in parallel, but the first `run()` still waits for the slowest one. Two knobs to hide the cost:
509
+
510
+ ```ts
511
+ // Option 1 — pre-warm manually behind other setup work.
512
+ const agent = createAgent({ provider, mcpServers })
513
+ await Promise.all([agent.warmup(), authenticate(), loadConfig()])
514
+ await agent.run({ prompt: 'go' }) // no MCP wait here
515
+
516
+ // Option 2 — let createAgent kick the warmup off for you.
517
+ const agent = createAgent({ provider, mcpServers, eager: true })
518
+ // ... unrelated startup work ...
519
+ await agent.run({ prompt: 'go' }) // awaits the in-flight warmup
520
+ ```
521
+
522
+ `warmup()` is idempotent and safe to call from multiple callers concurrently. Failures are surfaced on the next `warmup()` / `run()` rather than crashing the eager kickoff.
523
+
524
+ ### Observability
525
+
526
+ Two hooks fire around each per-server bootstrap, regardless of success:
527
+
528
+ ```ts
529
+ agent.hooks.hook('mcp:bootstrap:start', ({ name, transport }) => { /* ... */ })
530
+ agent.hooks.hook('mcp:bootstrap:end', (ctx) => {
531
+ // ctx.name, ctx.transport, ctx.durationMs
532
+ // ctx.ok === true → ctx.toolCount
533
+ // ctx.ok === false → ctx.error
534
+ })
535
+ ```
536
+
537
+ Use these to attribute cold-start latency per server — the only way to know if a specific MCP (e.g. a remote GitHub MCP) is the one stretching your first `run()`.
441
538
 
442
539
  ## Skills
443
540
 
@@ -541,6 +638,7 @@ agent.isRunning // is a run in progress?
541
638
  agent.turns // conversation history (SessionTurn[])
542
639
  agent.abort() // cancel the current run
543
640
  agent.reset() // clear messages and queues
641
+ await agent.warmup() // pre-connect MCP (idempotent, safe to call concurrently)
544
642
  await agent.destroy() // clean up context + MCP connections
545
643
  await agent.waitForIdle() // wait for current run to complete
546
644
  ```
@@ -554,8 +652,12 @@ type SessionContentBlock =
554
652
  | { type: 'text', text: string }
555
653
  | { type: 'image', mediaType: string, data: string }
556
654
  | { type: 'tool_call', id: string, name: string, input: Record<string, unknown> }
557
- | { type: 'tool_result', callId: string, output: string, isError?: boolean }
558
- | { type: 'thinking', text: string }
655
+ | { type: 'tool_result', callId: string, output: string | ToolResultContent[], isError?: boolean }
656
+ | { type: 'thinking', text: string, signature?: string }
657
+
658
+ type ToolResultContent =
659
+ | { type: 'text', text: string }
660
+ | { type: 'image', mediaType: string, data: string }
559
661
 
560
662
  interface SessionMessage {
561
663
  role: 'user' | 'assistant'
@@ -563,12 +665,39 @@ interface SessionMessage {
563
665
  }
564
666
  ```
565
667
 
668
+ Tool results can carry structured content — pure-text tools keep returning a `string`, tools that produce images (MCP browser servers, screenshot tools) return a `ToolResultContent[]` that the loop routes natively on providers with `imageInToolResult: true` and via a companion user message elsewhere. Use `toolResultToText(output)` to flatten when a consumer only handles strings.
669
+
566
670
  Converters for external interop:
567
671
 
568
672
  ```ts
569
673
  import { fromAnthropic, toAnthropic, fromOpenAI, toOpenAI, autoDetectAndConvert } from 'zidane'
570
674
  ```
571
675
 
676
+ ## Typed Errors
677
+
678
+ Provider failures are wrapped into typed error classes before leaving `agent.run()` — match on `instanceof` instead of sniffing strings.
679
+
680
+ ```ts
681
+ import { AgentAbortedError, AgentContextExceededError, AgentProviderError } from 'zidane'
682
+
683
+ try {
684
+ await agent.run({ prompt })
685
+ }
686
+ catch (err) {
687
+ if (err instanceof AgentContextExceededError) {
688
+ // prune history, retry
689
+ }
690
+ else if (err instanceof AgentAbortedError) {
691
+ // user cancelled
692
+ }
693
+ else if (err instanceof AgentProviderError) {
694
+ console.error(`${err.provider}: ${err.message} (${err.providerCode})`)
695
+ }
696
+ }
697
+ ```
698
+
699
+ Every provider ships a `classifyError(err)` that maps native errors into a `ClassifiedError` union — unrecognized errors fall through as `AgentProviderError`. Abort paths (`agent.abort()` or a triggered `AbortSignal`) always produce `AgentAbortedError` regardless of classification.
700
+
572
701
  ## Structured Output
573
702
 
574
703
  Force the agent's final response to match a JSON Schema via provider-level tool forcing.
@@ -612,8 +741,9 @@ const schema = zodToJsonSchema(z.toJsonSchema(z.object({ name: z.string() })))
612
741
 
613
742
  ```ts
614
743
  const stats = await agent.run({ prompt: 'hello' })
615
- stats.turnUsage // TurnUsage[] — per-turn { input, output, cacheCreation?, cacheRead?, thinking?, cost? }
616
- stats.cost // total USD cost (if reported by provider)
744
+ stats.turnUsage // TurnUsage[] — per-turn { input, output, cacheCreation?, cacheRead?, thinking?, cost?, finishReason?, modelId? }
745
+ stats.cost // total USD cost (if reported by provider)
746
+ stats.timeTillFirstTokenMs // ms from run() start to the first stream/tool event
617
747
  ```
618
748
 
619
749
  ## Types
@@ -633,7 +763,11 @@ import type { ToolHookContext, McpToolHookContext, SessionHookContext, StreamHoo
633
763
  bun test
634
764
  ```
635
765
 
636
- 495+ tests with mock provider and execution context. No API keys or Docker needed.
766
+ 915+ tests with mock provider and execution context. No API keys or Docker needed; the suite runs in under 2 seconds.
767
+
768
+ ## Benchmarks
769
+
770
+ Harness integrations for running zidane against public agent benchmarks live in [`benchmarks/`](./benchmarks). First integration: [Terminal-Bench](./benchmarks/terminal-bench).
637
771
 
638
772
  ## License
639
773
 
@@ -153,6 +153,16 @@ interface McpServerConfig {
153
153
  url?: string;
154
154
  /** Optional headers for HTTP transports */
155
155
  headers?: Record<string, string>;
156
+ /**
157
+ * Timeout in milliseconds for MCP server bootstrap (connect + tool discovery).
158
+ *
159
+ * Zidane connects MCP servers lazily on the first `run()`. Without a
160
+ * bootstrap timeout, a slow or hung server can delay the first provider call
161
+ * for an arbitrarily long time even when that MCP server is never used.
162
+ *
163
+ * Default: `10000`.
164
+ */
165
+ bootstrapTimeout?: number;
156
166
  /** Timeout in milliseconds for MCP tool calls (default: 30000) */
157
167
  toolTimeout?: number;
158
168
  }
@@ -166,8 +176,24 @@ interface AgentBehavior {
166
176
  maxTokens?: number;
167
177
  /** Thinking token budget — overrides the level-based default when set */
168
178
  thinkingBudget?: number;
169
- /** JSON Schema for structured output. When set, the agent's final turn produces JSON matching this schema. */
179
+ /** JSON Schema for structured output enforcement */
170
180
  schema?: Record<string, unknown>;
181
+ /**
182
+ * Enable provider prompt caching. When on (default), the provider marks the
183
+ * system prompt, tools, and the last stable message with cache breakpoints so
184
+ * the shared prefix is served from cache across turns.
185
+ *
186
+ * - Anthropic: `cache_control: { type: 'ephemeral' }` on the last `system`
187
+ * content part, the last tool, and the last message content part.
188
+ * - OpenAI-compatible / OpenRouter: same shape — honored by Anthropic-backed
189
+ * OpenRouter routes and by Gemini; ignored (no-op) by providers that cache
190
+ * automatically (OpenAI, DeepSeek, Grok, Groq, Moonshot).
191
+ *
192
+ * Usage is surfaced via `TurnUsage.cacheRead` / `TurnUsage.cacheCreation`.
193
+ *
194
+ * Default: `true`.
195
+ */
196
+ cache?: boolean;
171
197
  }
172
198
  interface ImageContent {
173
199
  type: 'image';
@@ -600,6 +626,20 @@ interface OpenAICompatParams {
600
626
  * (e.g. OpenRouter vision models, Baseten image-capable deployments).
601
627
  */
602
628
  capabilities?: ProviderCapabilities;
629
+ /**
630
+ * Whether this endpoint honors `cache_control: { type: 'ephemeral' }` markers
631
+ * on message content parts and tool definitions.
632
+ *
633
+ * - `true` — inject markers when the caller asks for caching. OpenRouter routes
634
+ * to Anthropic/Gemini forward the markers; routes to OpenAI/DeepSeek/
635
+ * Grok/Groq/Moonshot ignore them (those backends cache automatically).
636
+ * - `false` — never inject markers. Safe default for endpoints that strictly
637
+ * validate the request schema (OpenAI direct, most OSS inference
638
+ * servers) and would reject unknown fields.
639
+ *
640
+ * Default: `false`. The `openrouter` wrapper sets this to `true`.
641
+ */
642
+ cacheBreakpoints?: boolean;
603
643
  }
604
644
  /**
605
645
  * Factory for any OpenAI-compatible HTTP endpoint.
@@ -723,6 +763,14 @@ interface StreamOptions {
723
763
  type: 'auto' | 'required' | 'tool';
724
764
  name?: string;
725
765
  };
766
+ /**
767
+ * Enable prompt caching on this call. When `true`, providers that support it
768
+ * insert `cache_control` breakpoints on the system prompt, last tool, and
769
+ * last stable message so the shared prefix is cached across turns.
770
+ *
771
+ * Default: `false` (providers opt callers in — the agent loop passes `true`).
772
+ */
773
+ cache?: boolean;
726
774
  /** Abort signal for cancellation */
727
775
  signal?: AbortSignal;
728
776
  }
@@ -1448,6 +1496,30 @@ interface AgentHooks {
1448
1496
  'mcp:close': (ctx: {
1449
1497
  name: string;
1450
1498
  }) => void;
1499
+ /**
1500
+ * Fires at the start of a per-server bootstrap attempt, before any network I/O.
1501
+ * Pairs with `mcp:bootstrap:end` and is always emitted, regardless of outcome.
1502
+ */
1503
+ 'mcp:bootstrap:start': (ctx: {
1504
+ name: string;
1505
+ transport: string;
1506
+ }) => void;
1507
+ /**
1508
+ * Fires at the end of a per-server bootstrap attempt. `durationMs` spans from
1509
+ * the matching `mcp:bootstrap:start`. On `ok: false` carries the originating
1510
+ * error so consumers can log / trace without relying on a separate `mcp:error`.
1511
+ */
1512
+ 'mcp:bootstrap:end': (ctx: {
1513
+ name: string;
1514
+ transport: string;
1515
+ durationMs: number;
1516
+ } & ({
1517
+ ok: true;
1518
+ toolCount: number;
1519
+ } | {
1520
+ ok: false;
1521
+ error: Error;
1522
+ })) => void;
1451
1523
  'mcp:tool:gate': (ctx: McpToolHookContext & {
1452
1524
  block: boolean;
1453
1525
  reason: string;
@@ -1535,8 +1607,21 @@ interface AgentOptions {
1535
1607
  session?: Session;
1536
1608
  /** Skills configuration */
1537
1609
  skills?: SkillsConfig;
1538
- /** @internal Test-only override for the MCP connector. Public consumers should not rely on this. */
1610
+ /** @internal */
1539
1611
  mcpConnector?: (configs: McpServerConfig[]) => Promise<McpConnection>;
1612
+ /**
1613
+ * Pre-connect MCP servers in the background as soon as `createAgent` returns,
1614
+ * instead of deferring the bootstrap to the first `agent.run()`.
1615
+ *
1616
+ * Useful when MCP latency is the dominant cost of a cold start: callers that
1617
+ * construct the agent early (e.g. at process init) can hide the bootstrap
1618
+ * behind other setup work. If bootstrap fails, the error is stored and
1619
+ * surfaced on the first `agent.run()` / `agent.warmup()`; the in-flight
1620
+ * promise is `await`ed by both paths so the error is never silently lost.
1621
+ *
1622
+ * No-op when `mcpServers` is empty. Default: `false`.
1623
+ */
1624
+ eager?: boolean;
1540
1625
  }
1541
1626
  interface Agent {
1542
1627
  hooks: Hookable<AgentHooks>;
@@ -1568,6 +1653,17 @@ interface Agent {
1568
1653
  * No-op when the skill wasn't active.
1569
1654
  */
1570
1655
  deactivateSkill: (name: string) => Promise<void>;
1656
+ /**
1657
+ * Pre-connect MCP servers without running a turn. Idempotent and concurrency-safe:
1658
+ * - No MCP servers configured → resolves immediately.
1659
+ * - Connection already established → resolves immediately.
1660
+ * - Another `warmup()` / `run()` is bootstrapping → awaits the in-flight promise.
1661
+ *
1662
+ * Use from host code that wants to hide MCP bootstrap latency behind other
1663
+ * startup work (UI init, auth, etc.). Safe to call multiple times and from
1664
+ * multiple callers concurrently.
1665
+ */
1666
+ warmup: () => Promise<void>;
1571
1667
  readonly isRunning: boolean;
1572
1668
  readonly turns: SessionTurn[];
1573
1669
  readonly execution: ExecutionContext;
@@ -1577,6 +1673,6 @@ interface Agent {
1577
1673
  readonly activeSkills: readonly ActiveSkill[];
1578
1674
  meta: Record<string, unknown>;
1579
1675
  }
1580
- declare function createAgent({ provider, name: agentName, system: agentSystem, tools: agentTools, toolAliases, behavior: agentBehavior, execution, mcpServers, session, skills: agentSkills, mcpConnector }: AgentOptions): Agent;
1676
+ declare function createAgent({ provider, name: agentName, system: agentSystem, tools: agentTools, toolAliases, behavior: agentBehavior, execution, mcpServers, session, skills: agentSkills, mcpConnector, eager }: AgentOptions): Agent;
1581
1677
 
1582
1678
  export { type ToolHookContext as $, type Agent as A, type SessionData as B, CONTEXT_EXCEEDED_MESSAGE_PATTERNS as C, type SessionEndStatus as D, type SessionHookContext as E, type SessionMessage as F, type SessionRun as G, type SessionStore as H, type ImageContent as I, type SessionTurn as J, type SkillConfig as K, type SkillResource as L, type McpConnection as M, type SkillsConfig as N, type OAuthRefreshHookContext as O, type PromptDocumentPart as P, type SpawnHookContext as Q, type RemoteStoreOptions as R, type Session as S, type StreamCallbacks as T, type StreamHookContext as U, type StreamOptions as V, type ThinkingLevel as W, type ToolCall as X, type ToolContext as Y, type ToolDef as Z, type ToolExecutionMode as _, AgentAbortedError as a, type ToolMap as a0, type ToolResult as a1, type ToolResultContent as a2, type ToolResultImageContent as a3, type ToolResultTextContent as a4, type ToolSpec as a5, type TurnFinishReason as a6, type TurnResult as a7, type TurnUsage as a8, matchesContextExceeded as a9, loadSession as aA, mapOAIFinishReason as aB, normalizeMcpBlocks as aC, normalizeMcpServers as aD, openai as aE, openaiCompat as aF, openrouter as aG, resultToString as aH, toAnthropic as aI, toOpenAI as aJ, toTypedError as aK, toolResultToText as aa, type ActivationVia as ab, type ActiveSkill as ac, type DeactivationReason as ad, type FileMapAdapter as ae, type FileMapStoreOptions as af, type OpenAICompatAuthHeader as ag, OpenAICompatHttpError as ah, type OpenAICompatParams as ai, type SkillActivationState as aj, type SkillActivationStateOptions as ak, type SkillDiagnostic as al, type SkillSource as am, anthropic as an, autoDetectAndConvert as ao, cerebras as ap, classifyOpenAICompatError as aq, connectMcpServers as ar, createAgent as as, createFileMapStore as at, createMemoryStore as au, createRemoteStore as av, createSession as aw, createSkillActivationState as ax, fromAnthropic as ay, fromOpenAI as az, type AgentBehavior as b, AgentContextExceededError as c, type AgentHooks as d, type AgentOptions as e, AgentProviderError as f, type AgentRunOptions as g, type AgentStats as h, AgentToolNotAllowedError as i, type AnthropicParams as j, type CerebrasParams as k, type ChildRunStats as l, type ClassifiedError as m, type ClassifiedErrorKind as n, type CreateSessionOptions as o, type McpServerConfig as p, type McpToolHookContext as q, type OpenAIParams as r, type OpenRouterParams as s, type PromptImagePart as t, type PromptPart as u, type PromptTextPart as v, type Provider as w, type ProviderCapabilities as x, type RunHookMap as y, type SessionContentBlock as z };
@@ -84,10 +84,14 @@ async function consumeSSE(response, callbacks, signal) {
84
84
  }
85
85
  const chunkUsage = chunk.usage;
86
86
  if (chunkUsage) {
87
+ const cachedRead = chunkUsage.prompt_tokens_details?.cached_tokens;
88
+ const cachedWrite = chunkUsage.prompt_tokens_details?.cache_creation_input_tokens ?? chunkUsage.prompt_tokens_details?.cache_write_tokens ?? chunkUsage.cache_creation_input_tokens;
87
89
  usage = {
88
90
  input: chunkUsage.prompt_tokens ?? 0,
89
91
  output: chunkUsage.completion_tokens ?? 0,
90
- cost: chunkUsage.total_cost ?? void 0
92
+ cost: chunkUsage.total_cost ?? void 0,
93
+ ...typeof cachedRead === "number" && cachedRead > 0 ? { cacheRead: cachedRead } : {},
94
+ ...typeof cachedWrite === "number" && cachedWrite > 0 ? { cacheCreation: cachedWrite } : {}
91
95
  };
92
96
  }
93
97
  }
@@ -204,6 +208,38 @@ ${attachedMarker}` : attachedMarker;
204
208
  }
205
209
  return out;
206
210
  }
211
+ var EPHEMERAL = { type: "ephemeral" };
212
+ function applyOAICacheBreakpoints(messages) {
213
+ if (messages.length === 0)
214
+ return;
215
+ const first = messages[0];
216
+ if (first.role === "system")
217
+ markLastContentPart(first);
218
+ const lastIdx = messages.length - 1;
219
+ if (lastIdx > 0)
220
+ markLastContentPart(messages[lastIdx]);
221
+ }
222
+ function markLastContentPart(msg) {
223
+ if (typeof msg.content === "string") {
224
+ if (msg.content.length === 0)
225
+ return;
226
+ msg.content = [{ type: "text", text: msg.content, cache_control: EPHEMERAL }];
227
+ return;
228
+ }
229
+ if (!Array.isArray(msg.content) || msg.content.length === 0)
230
+ return;
231
+ const parts = msg.content;
232
+ const lastBlockIdx = parts.length - 1;
233
+ parts[lastBlockIdx] = { ...parts[lastBlockIdx], cache_control: EPHEMERAL };
234
+ }
235
+ function applyOAIToolCacheBreakpoint(tools) {
236
+ if (tools.length === 0)
237
+ return tools;
238
+ const lastIdx = tools.length - 1;
239
+ return tools.map(
240
+ (tool, i) => i === lastIdx ? { ...tool, cache_control: EPHEMERAL } : tool
241
+ );
242
+ }
207
243
  function formatTools(tools) {
208
244
  return tools.map((t) => ({
209
245
  type: "function",
@@ -337,6 +373,7 @@ function openaiCompat(params) {
337
373
  vision: params.capabilities?.vision ?? false,
338
374
  imageInToolResult: params.capabilities?.imageInToolResult ?? false
339
375
  };
376
+ const cacheBreakpointsEnabled = params.cacheBreakpoints === true;
340
377
  return {
341
378
  name,
342
379
  meta: { defaultModel, capabilities },
@@ -350,6 +387,10 @@ function openaiCompat(params) {
350
387
  const messages = toOAIMessages(options.system, options.messages, {
351
388
  imageInToolResult: capabilities.imageInToolResult === true
352
389
  });
390
+ const shouldCache = cacheBreakpointsEnabled && options.cache !== false;
391
+ if (shouldCache) {
392
+ applyOAICacheBreakpoints(messages);
393
+ }
353
394
  const maxTokens = options.thinkingBudget ? options.thinkingBudget + options.maxTokens : options.maxTokens;
354
395
  const body = {
355
396
  model: modelId,
@@ -357,8 +398,9 @@ function openaiCompat(params) {
357
398
  max_tokens: maxTokens,
358
399
  stream: true
359
400
  };
360
- if (options.tools && options.tools.length > 0)
361
- body.tools = options.tools;
401
+ if (options.tools && options.tools.length > 0) {
402
+ body.tools = shouldCache ? applyOAIToolCacheBreakpoint(options.tools) : options.tools;
403
+ }
362
404
  if (options.toolChoice) {
363
405
  if (options.toolChoice.type === "tool" && options.toolChoice.name)
364
406
  body.tool_choice = { type: "function", function: { name: options.toolChoice.name } };
@@ -3,6 +3,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
3
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
4
4
  import { getDefaultEnvironment, StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
5
5
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
6
+ var DEFAULT_MCP_BOOTSTRAP_TIMEOUT_MS = 1e4;
6
7
  function inferTransport(raw) {
7
8
  if (raw.transport === "stdio" || raw.transport === "sse" || raw.transport === "streamable-http")
8
9
  return raw.transport;
@@ -34,6 +35,8 @@ function normalizeOne(name, raw) {
34
35
  config.url = url;
35
36
  if (raw.headers)
36
37
  config.headers = raw.headers;
38
+ if (typeof raw.bootstrapTimeout === "number")
39
+ config.bootstrapTimeout = raw.bootstrapTimeout;
37
40
  if (typeof raw.toolTimeout === "number")
38
41
  config.toolTimeout = raw.toolTimeout;
39
42
  return config;
@@ -148,113 +151,25 @@ async function connectMcpServers(configs, _clientFactory, hooks) {
148
151
  const tools = {};
149
152
  const errors = [];
150
153
  let closed = false;
151
- for (const config of configs) {
152
- try {
153
- const client = _clientFactory ? _clientFactory() : new Client({ name: "zidane", version: "1.0.0" });
154
- const transport = createTransport(config);
155
- await client.connect(transport);
156
- connections.push({ name: config.name, client });
157
- const { tools: mcpTools } = await client.listTools();
158
- const toolNames = [];
159
- for (const tool of mcpTools) {
160
- const namespacedName = `mcp_${config.name}_${tool.name}`;
161
- toolNames.push(namespacedName);
162
- tools[namespacedName] = {
163
- spec: {
164
- name: namespacedName,
165
- description: tool.description || "",
166
- inputSchema: tool.inputSchema ?? { type: "object", properties: {} }
167
- },
168
- execute: async (input, ctx) => {
169
- const { turnId, callId, signal } = ctx;
170
- const displayName = ctx.toolAliases?.[namespacedName] ?? namespacedName;
171
- const gateCtx = {
172
- turnId,
173
- callId,
174
- server: config.name,
175
- tool: tool.name,
176
- displayName,
177
- input,
178
- block: false,
179
- reason: "MCP tool execution was blocked"
180
- };
181
- await hooks?.callHook("mcp:tool:gate", gateCtx);
182
- if (gateCtx.block)
183
- return `Blocked: ${gateCtx.reason}`;
184
- const effectiveInput = gateCtx.input;
185
- await hooks?.callHook("mcp:tool:before", {
186
- turnId,
187
- callId,
188
- server: config.name,
189
- tool: tool.name,
190
- displayName,
191
- input: effectiveInput
192
- });
193
- const timeout = config.toolTimeout ?? 3e4;
194
- try {
195
- const result = await raceWithTimeoutAndSignal(
196
- () => client.callTool({ name: tool.name, arguments: effectiveInput }),
197
- timeout,
198
- `MCP tool "${tool.name}" on server "${config.name}" timed out after ${timeout}ms`,
199
- signal
200
- );
201
- let output = packMcpResult(result.content);
202
- const transformCtx = {
203
- turnId,
204
- callId,
205
- server: config.name,
206
- tool: tool.name,
207
- displayName,
208
- input: effectiveInput,
209
- result: output
210
- };
211
- await hooks?.callHook("mcp:tool:transform", transformCtx);
212
- output = transformCtx.result;
213
- await hooks?.callHook("mcp:tool:after", {
214
- turnId,
215
- callId,
216
- server: config.name,
217
- tool: tool.name,
218
- displayName,
219
- input: effectiveInput,
220
- result: output
221
- });
222
- return output;
223
- } catch (err) {
224
- const error = err instanceof Error ? err : new Error(String(err));
225
- await hooks?.callHook("mcp:tool:error", {
226
- turnId,
227
- callId,
228
- server: config.name,
229
- tool: tool.name,
230
- displayName,
231
- input: effectiveInput,
232
- error
233
- });
234
- await hooks?.callHook("mcp:tool:after", {
235
- turnId,
236
- callId,
237
- server: config.name,
238
- tool: tool.name,
239
- displayName,
240
- input: effectiveInput,
241
- result: error.message
242
- });
243
- throw error;
244
- }
245
- }
246
- };
247
- }
248
- await hooks?.callHook("mcp:connect", {
249
- name: config.name,
250
- transport: config.transport,
251
- tools: toolNames
252
- });
253
- } catch (err) {
254
- const error = err instanceof Error ? err : new Error(String(err));
255
- errors.push({ name: config.name, error });
256
- await hooks?.callHook("mcp:error", { name: config.name, error });
154
+ const bootstrapResults = await Promise.all(configs.map((config) => bootstrapServer(config, _clientFactory, hooks)));
155
+ for (const result of bootstrapResults) {
156
+ if (!result.ok) {
157
+ errors.push({ name: result.name, error: result.error });
158
+ await hooks?.callHook("mcp:error", { name: result.name, error: result.error });
159
+ continue;
160
+ }
161
+ connections.push({ name: result.name, client: result.client });
162
+ const toolNames = [];
163
+ for (const tool of result.tools) {
164
+ const namespacedName = `mcp_${result.config.name}_${tool.name}`;
165
+ toolNames.push(namespacedName);
166
+ tools[namespacedName] = buildMcpToolDef(result.config, result.client, tool, namespacedName, hooks);
257
167
  }
168
+ await hooks?.callHook("mcp:connect", {
169
+ name: result.name,
170
+ transport: result.config.transport,
171
+ tools: toolNames
172
+ });
258
173
  }
259
174
  if (errors.length > 0 && connections.length === 0) {
260
175
  const messages = errors.map((e) => `${e.name}: ${e.error.message}`).join(", ");
@@ -275,6 +190,153 @@ async function connectMcpServers(configs, _clientFactory, hooks) {
275
190
  }
276
191
  };
277
192
  }
193
+ async function bootstrapServer(config, _clientFactory, hooks) {
194
+ const start = Date.now();
195
+ await hooks?.callHook("mcp:bootstrap:start", { name: config.name, transport: config.transport });
196
+ let client = null;
197
+ try {
198
+ client = _clientFactory ? _clientFactory() : new Client({ name: "zidane", version: "1.0.0" });
199
+ const currentClient = client;
200
+ const transport = createTransport(config);
201
+ const bootstrapTimeout = config.bootstrapTimeout ?? DEFAULT_MCP_BOOTSTRAP_TIMEOUT_MS;
202
+ const { tools: mcpTools } = await raceWithTimeout(
203
+ async () => {
204
+ await currentClient.connect(transport);
205
+ return await currentClient.listTools();
206
+ },
207
+ bootstrapTimeout,
208
+ `MCP server "${config.name}" bootstrap timed out after ${bootstrapTimeout}ms`
209
+ );
210
+ const durationMs = Date.now() - start;
211
+ await hooks?.callHook("mcp:bootstrap:end", {
212
+ name: config.name,
213
+ transport: config.transport,
214
+ durationMs,
215
+ ok: true,
216
+ toolCount: mcpTools.length
217
+ });
218
+ return { ok: true, name: config.name, config, client: currentClient, tools: mcpTools };
219
+ } catch (err) {
220
+ const error = err instanceof Error ? err : new Error(String(err));
221
+ await closeClientQuietly(client);
222
+ const durationMs = Date.now() - start;
223
+ await hooks?.callHook("mcp:bootstrap:end", {
224
+ name: config.name,
225
+ transport: config.transport,
226
+ durationMs,
227
+ ok: false,
228
+ error
229
+ });
230
+ return { ok: false, name: config.name, error };
231
+ }
232
+ }
233
+ function buildMcpToolDef(config, client, tool, namespacedName, hooks) {
234
+ return {
235
+ spec: {
236
+ name: namespacedName,
237
+ description: tool.description || "",
238
+ inputSchema: tool.inputSchema ?? { type: "object", properties: {} }
239
+ },
240
+ execute: async (input, ctx) => {
241
+ const { turnId, callId, signal } = ctx;
242
+ const displayName = ctx.toolAliases?.[namespacedName] ?? namespacedName;
243
+ const gateCtx = {
244
+ turnId,
245
+ callId,
246
+ server: config.name,
247
+ tool: tool.name,
248
+ displayName,
249
+ input,
250
+ block: false,
251
+ reason: "MCP tool execution was blocked"
252
+ };
253
+ await hooks?.callHook("mcp:tool:gate", gateCtx);
254
+ if (gateCtx.block)
255
+ return `Blocked: ${gateCtx.reason}`;
256
+ const effectiveInput = gateCtx.input;
257
+ await hooks?.callHook("mcp:tool:before", {
258
+ turnId,
259
+ callId,
260
+ server: config.name,
261
+ tool: tool.name,
262
+ displayName,
263
+ input: effectiveInput
264
+ });
265
+ const timeout = config.toolTimeout ?? 3e4;
266
+ try {
267
+ const result = await raceWithTimeoutAndSignal(
268
+ () => client.callTool({ name: tool.name, arguments: effectiveInput }),
269
+ timeout,
270
+ `MCP tool "${tool.name}" on server "${config.name}" timed out after ${timeout}ms`,
271
+ signal
272
+ );
273
+ let output = packMcpResult(result.content);
274
+ const transformCtx = {
275
+ turnId,
276
+ callId,
277
+ server: config.name,
278
+ tool: tool.name,
279
+ displayName,
280
+ input: effectiveInput,
281
+ result: output
282
+ };
283
+ await hooks?.callHook("mcp:tool:transform", transformCtx);
284
+ output = transformCtx.result;
285
+ await hooks?.callHook("mcp:tool:after", {
286
+ turnId,
287
+ callId,
288
+ server: config.name,
289
+ tool: tool.name,
290
+ displayName,
291
+ input: effectiveInput,
292
+ result: output
293
+ });
294
+ return output;
295
+ } catch (err) {
296
+ const error = err instanceof Error ? err : new Error(String(err));
297
+ await hooks?.callHook("mcp:tool:error", {
298
+ turnId,
299
+ callId,
300
+ server: config.name,
301
+ tool: tool.name,
302
+ displayName,
303
+ input: effectiveInput,
304
+ error
305
+ });
306
+ await hooks?.callHook("mcp:tool:after", {
307
+ turnId,
308
+ callId,
309
+ server: config.name,
310
+ tool: tool.name,
311
+ displayName,
312
+ input: effectiveInput,
313
+ result: error.message
314
+ });
315
+ throw error;
316
+ }
317
+ }
318
+ };
319
+ }
320
+ async function closeClientQuietly(client) {
321
+ if (!client)
322
+ return;
323
+ try {
324
+ await client.close();
325
+ } catch {
326
+ }
327
+ }
328
+ async function raceWithTimeout(task, timeoutMs, timeoutMessage) {
329
+ let timer;
330
+ try {
331
+ return await new Promise((resolvePromise, rejectPromise) => {
332
+ timer = setTimeout(() => rejectPromise(new Error(timeoutMessage)), timeoutMs);
333
+ task().then(resolvePromise, rejectPromise);
334
+ });
335
+ } finally {
336
+ if (timer)
337
+ clearTimeout(timer);
338
+ }
339
+ }
278
340
  async function raceWithTimeoutAndSignal(task, timeoutMs, timeoutMessage, signal) {
279
341
  if (signal?.aborted)
280
342
  throw new Error("MCP tool call aborted");
@@ -4,7 +4,7 @@ import {
4
4
  shell,
5
5
  spawn,
6
6
  writeFile
7
- } from "./chunk-FVIHGZQM.js";
7
+ } from "./chunk-O2XZLJMG.js";
8
8
 
9
9
  // src/presets/basic.ts
10
10
  var basicTools = { shell, readFile, writeFile, listFiles };
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-2EQT4EHD.js";
12
12
  import {
13
13
  connectMcpServers
14
- } from "./chunk-37GD7NL3.js";
14
+ } from "./chunk-DRAYZZ23.js";
15
15
  import {
16
16
  AgentAbortedError,
17
17
  AgentProviderError,
@@ -589,6 +589,7 @@ async function executeTurn(ctx, turn) {
589
589
  maxTokens: ctx.maxTokens ?? 16384,
590
590
  thinking: ctx.thinking,
591
591
  thinkingBudget: ctx.thinkingBudget,
592
+ cache: ctx.cache ?? true,
592
593
  signal: ctx.signal
593
594
  };
594
595
  const transformCtx = { messages: streamOptions.messages };
@@ -960,6 +961,8 @@ var HOOK_EVENT_NAMES = [
960
961
  "mcp:connect",
961
962
  "mcp:error",
962
963
  "mcp:close",
964
+ "mcp:bootstrap:start",
965
+ "mcp:bootstrap:end",
963
966
  "mcp:tool:gate",
964
967
  "mcp:tool:before",
965
968
  "mcp:tool:after",
@@ -989,10 +992,11 @@ function resolveBehavior(agentBehavior, runBehavior) {
989
992
  maxTurns: runBehavior?.maxTurns ?? agentBehavior?.maxTurns,
990
993
  maxTokens: runBehavior?.maxTokens ?? agentBehavior?.maxTokens,
991
994
  thinkingBudget: runBehavior?.thinkingBudget ?? agentBehavior?.thinkingBudget,
992
- schema: runBehavior?.schema ?? agentBehavior?.schema
995
+ schema: runBehavior?.schema ?? agentBehavior?.schema,
996
+ cache: runBehavior?.cache ?? agentBehavior?.cache ?? true
993
997
  };
994
998
  }
995
- function createAgent({ provider, name: agentName, system: agentSystem, tools: agentTools, toolAliases, behavior: agentBehavior, execution, mcpServers, session, skills: agentSkills, mcpConnector }) {
999
+ function createAgent({ provider, name: agentName, system: agentSystem, tools: agentTools, toolAliases, behavior: agentBehavior, execution, mcpServers, session, skills: agentSkills, mcpConnector, eager }) {
996
1000
  const hooks = createHooks();
997
1001
  const executionContext = execution ?? createProcessContext();
998
1002
  const sourceTools = agentTools ?? {};
@@ -1002,6 +1006,7 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
1002
1006
  let idlePromise;
1003
1007
  let executionHandle = null;
1004
1008
  let mcpConnection = null;
1009
+ let mcpWarmupPromise = null;
1005
1010
  const allMcpServers = mcpServers ?? [];
1006
1011
  const steeringQueue = [];
1007
1012
  const followUpQueue = [];
@@ -1076,11 +1081,7 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
1076
1081
  executionHandle = await executionContext.spawn();
1077
1082
  }
1078
1083
  if (allMcpServers.length > 0 && !mcpConnection) {
1079
- if (mcpConnector) {
1080
- mcpConnection = await mcpConnector(allMcpServers);
1081
- } else {
1082
- mcpConnection = await connectMcpServers(allMcpServers, void 0, hooks);
1083
- }
1084
+ await warmup();
1084
1085
  }
1085
1086
  if (!skillsDisabled && skillsConfig && !resolvedSkills) {
1086
1087
  resolvedSkills = await resolveSkills(skillsConfig);
@@ -1115,7 +1116,7 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
1115
1116
  }
1116
1117
  const thinking = options.thinking ?? "off";
1117
1118
  const model = options.model ?? provider.meta.defaultModel;
1118
- const { toolExecution, maxTurns, maxTokens, thinkingBudget, schema } = resolveBehavior(agentBehavior, options.behavior);
1119
+ const { toolExecution, maxTurns, maxTokens, thinkingBudget, schema, cache } = resolveBehavior(agentBehavior, options.behavior);
1119
1120
  let system = options.system || agentSystem || "You are a helpful assistant.";
1120
1121
  if (skillsCatalog) {
1121
1122
  system = `${system}
@@ -1249,6 +1250,7 @@ ${skillsCatalog}`;
1249
1250
  depth: runDepth,
1250
1251
  thinkingBudget,
1251
1252
  schema,
1253
+ cache,
1252
1254
  runStartMs
1253
1255
  });
1254
1256
  const finalStats = {
@@ -1364,10 +1366,39 @@ ${skillsCatalog}`;
1364
1366
  };
1365
1367
  }
1366
1368
  let destroyed = false;
1369
+ async function warmup() {
1370
+ if (destroyed)
1371
+ return;
1372
+ if (mcpConnection || allMcpServers.length === 0)
1373
+ return;
1374
+ if (mcpWarmupPromise)
1375
+ return mcpWarmupPromise;
1376
+ mcpWarmupPromise = (async () => {
1377
+ const connection = mcpConnector ? await mcpConnector(allMcpServers) : await connectMcpServers(allMcpServers, void 0, hooks);
1378
+ if (destroyed) {
1379
+ await connection.close().catch(() => {
1380
+ });
1381
+ return;
1382
+ }
1383
+ mcpConnection = connection;
1384
+ })();
1385
+ try {
1386
+ await mcpWarmupPromise;
1387
+ } catch (err) {
1388
+ mcpWarmupPromise = null;
1389
+ throw err;
1390
+ }
1391
+ }
1367
1392
  async function destroy() {
1368
1393
  if (destroyed)
1369
1394
  return;
1370
1395
  destroyed = true;
1396
+ if (mcpWarmupPromise) {
1397
+ try {
1398
+ await mcpWarmupPromise;
1399
+ } catch {
1400
+ }
1401
+ }
1371
1402
  if (mcpConnection) {
1372
1403
  await mcpConnection.close();
1373
1404
  mcpConnection = null;
@@ -1377,6 +1408,10 @@ ${skillsCatalog}`;
1377
1408
  executionHandle = null;
1378
1409
  }
1379
1410
  }
1411
+ if (eager && allMcpServers.length > 0) {
1412
+ void warmup().catch(() => {
1413
+ });
1414
+ }
1380
1415
  return {
1381
1416
  hooks,
1382
1417
  run,
@@ -1386,6 +1421,7 @@ ${skillsCatalog}`;
1386
1421
  waitForIdle,
1387
1422
  reset,
1388
1423
  destroy,
1424
+ warmup,
1389
1425
  activateSkill,
1390
1426
  deactivateSkill,
1391
1427
  get isRunning() {
@@ -5,7 +5,7 @@ import {
5
5
  toAnthropic,
6
6
  toolResultsMessage,
7
7
  userMessage
8
- } from "./chunk-S3FCOMRI.js";
8
+ } from "./chunk-CYWF2U62.js";
9
9
  import {
10
10
  matchesContextExceeded
11
11
  } from "./chunk-LNN5UTS2.js";
@@ -186,6 +186,52 @@ function mapStopReason(stopReason) {
186
186
  return "other";
187
187
  }
188
188
  }
189
+ var EPHEMERAL = { type: "ephemeral" };
190
+ function applyAnthropicCacheBreakpoints(params) {
191
+ if (typeof params.system === "string") {
192
+ if (params.system.length > 0) {
193
+ params.system = [{ type: "text", text: params.system, cache_control: EPHEMERAL }];
194
+ }
195
+ } else if (Array.isArray(params.system) && params.system.length > 0) {
196
+ const lastIdx = params.system.length - 1;
197
+ params.system = params.system.map(
198
+ (block, i) => i === lastIdx ? { ...block, cache_control: EPHEMERAL } : block
199
+ );
200
+ }
201
+ if (params.tools && params.tools.length > 0) {
202
+ const lastIdx = params.tools.length - 1;
203
+ params.tools = params.tools.map(
204
+ (tool, i) => i === lastIdx ? { ...tool, cache_control: EPHEMERAL } : tool
205
+ );
206
+ }
207
+ if (params.messages.length === 0)
208
+ return;
209
+ const lastMsgIdx = params.messages.length - 1;
210
+ const lastMsg = params.messages[lastMsgIdx];
211
+ if (typeof lastMsg.content === "string") {
212
+ if (lastMsg.content.length === 0)
213
+ return;
214
+ params.messages[lastMsgIdx] = {
215
+ ...lastMsg,
216
+ content: [{ type: "text", text: lastMsg.content, cache_control: EPHEMERAL }]
217
+ };
218
+ return;
219
+ }
220
+ if (!Array.isArray(lastMsg.content) || lastMsg.content.length === 0)
221
+ return;
222
+ const blocks = lastMsg.content;
223
+ let targetIdx = blocks.length - 1;
224
+ while (targetIdx >= 0 && isThinkingBlock(blocks[targetIdx]))
225
+ targetIdx -= 1;
226
+ if (targetIdx < 0)
227
+ return;
228
+ const nextBlocks = blocks.slice();
229
+ nextBlocks[targetIdx] = { ...nextBlocks[targetIdx], cache_control: EPHEMERAL };
230
+ params.messages[lastMsgIdx] = { ...lastMsg, content: nextBlocks };
231
+ }
232
+ function isThinkingBlock(block) {
233
+ return block.type === "thinking" || block.type === "redacted_thinking";
234
+ }
189
235
  function looksLikeAnthropicApiError(err) {
190
236
  if (!err || typeof err !== "object")
191
237
  return false;
@@ -345,6 +391,8 @@ function anthropic(anthropicParams) {
345
391
  messages: messages.map((m) => toAnthropic(m)),
346
392
  stream: true
347
393
  };
394
+ if (options.cache !== false)
395
+ applyAnthropicCacheBreakpoints(params);
348
396
  if (thinking !== "off") {
349
397
  const budgetTokens = options.thinkingBudget ?? THINKING_BUDGETS[thinking];
350
398
  params.thinking = {
@@ -698,7 +746,12 @@ function openrouter(params) {
698
746
  "HTTP-Referer": "https://github.com/Tahul/zidane",
699
747
  "X-Title": "zidane"
700
748
  },
701
- capabilities: params?.capabilities ?? { vision: true, imageInToolResult: false }
749
+ capabilities: params?.capabilities ?? { vision: true, imageInToolResult: false },
750
+ // OpenRouter honors `cache_control` markers for Anthropic + Gemini routes and
751
+ // silently ignores them for routes that cache automatically. Safe to turn on
752
+ // by default — the caller can still flip `behavior.cache = false` to opt out
753
+ // without needing to re-instantiate the provider.
754
+ cacheBreakpoints: true
702
755
  });
703
756
  }
704
757
 
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- import { d as AgentHooks } from './agent-IYYE8a3i.js';
2
- export { ab as ActivationVia, ac as ActiveSkill, A as Agent, a as AgentAbortedError, b as AgentBehavior, c as AgentContextExceededError, e as AgentOptions, f as AgentProviderError, g as AgentRunOptions, h as AgentStats, i as AgentToolNotAllowedError, j as AnthropicParams, C as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, k as CerebrasParams, m as ClassifiedError, n as ClassifiedErrorKind, o as CreateSessionOptions, ad as DeactivationReason, ae as FileMapAdapter, af as FileMapStoreOptions, I as ImageContent, M as McpConnection, p as McpServerConfig, q as McpToolHookContext, O as OAuthRefreshHookContext, ag as OpenAICompatAuthHeader, ah as OpenAICompatHttpError, ai as OpenAICompatParams, r as OpenAIParams, s as OpenRouterParams, P as PromptDocumentPart, t as PromptImagePart, u as PromptPart, v as PromptTextPart, w as Provider, x as ProviderCapabilities, R as RemoteStoreOptions, y as RunHookMap, S as Session, z as SessionContentBlock, B as SessionData, D as SessionEndStatus, E as SessionHookContext, F as SessionMessage, G as SessionRun, H as SessionStore, J as SessionTurn, aj as SkillActivationState, ak as SkillActivationStateOptions, K as SkillConfig, al as SkillDiagnostic, L as SkillResource, am as SkillSource, N as SkillsConfig, Q as SpawnHookContext, T as StreamCallbacks, U as StreamHookContext, V as StreamOptions, W as ThinkingLevel, X as ToolCall, Y as ToolContext, Z as ToolDef, _ as ToolExecutionMode, $ as ToolHookContext, a0 as ToolMap, a1 as ToolResult, a2 as ToolResultContent, a3 as ToolResultImageContent, a4 as ToolResultTextContent, a5 as ToolSpec, a6 as TurnFinishReason, a7 as TurnResult, a8 as TurnUsage, an as anthropic, ao as autoDetectAndConvert, ap as cerebras, aq as classifyOpenAICompatError, ar as connectMcpServers, as as createAgent, at as createFileMapStore, au as createMemoryStore, av as createRemoteStore, aw as createSession, ax as createSkillActivationState, ay as fromAnthropic, az as fromOpenAI, aA as loadSession, aB as mapOAIFinishReason, a9 as matchesContextExceeded, aC as normalizeMcpBlocks, aD as normalizeMcpServers, aE as openai, aF as openaiCompat, aG as openrouter, aH as resultToString, aI as toAnthropic, aJ as toOpenAI, aK as toTypedError, aa as toolResultToText } from './agent-IYYE8a3i.js';
1
+ import { d as AgentHooks } from './agent-CEO3IeZj.js';
2
+ export { ab as ActivationVia, ac as ActiveSkill, A as Agent, a as AgentAbortedError, b as AgentBehavior, c as AgentContextExceededError, e as AgentOptions, f as AgentProviderError, g as AgentRunOptions, h as AgentStats, i as AgentToolNotAllowedError, j as AnthropicParams, C as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, k as CerebrasParams, m as ClassifiedError, n as ClassifiedErrorKind, o as CreateSessionOptions, ad as DeactivationReason, ae as FileMapAdapter, af as FileMapStoreOptions, I as ImageContent, M as McpConnection, p as McpServerConfig, q as McpToolHookContext, O as OAuthRefreshHookContext, ag as OpenAICompatAuthHeader, ah as OpenAICompatHttpError, ai as OpenAICompatParams, r as OpenAIParams, s as OpenRouterParams, P as PromptDocumentPart, t as PromptImagePart, u as PromptPart, v as PromptTextPart, w as Provider, x as ProviderCapabilities, R as RemoteStoreOptions, y as RunHookMap, S as Session, z as SessionContentBlock, B as SessionData, D as SessionEndStatus, E as SessionHookContext, F as SessionMessage, G as SessionRun, H as SessionStore, J as SessionTurn, aj as SkillActivationState, ak as SkillActivationStateOptions, K as SkillConfig, al as SkillDiagnostic, L as SkillResource, am as SkillSource, N as SkillsConfig, Q as SpawnHookContext, T as StreamCallbacks, U as StreamHookContext, V as StreamOptions, W as ThinkingLevel, X as ToolCall, Y as ToolContext, Z as ToolDef, _ as ToolExecutionMode, $ as ToolHookContext, a0 as ToolMap, a1 as ToolResult, a2 as ToolResultContent, a3 as ToolResultImageContent, a4 as ToolResultTextContent, a5 as ToolSpec, a6 as TurnFinishReason, a7 as TurnResult, a8 as TurnUsage, an as anthropic, ao as autoDetectAndConvert, ap as cerebras, aq as classifyOpenAICompatError, ar as connectMcpServers, as as createAgent, at as createFileMapStore, au as createMemoryStore, av as createRemoteStore, aw as createSession, ax as createSkillActivationState, ay as fromAnthropic, az as fromOpenAI, aA as loadSession, aB as mapOAIFinishReason, a9 as matchesContextExceeded, aC as normalizeMcpBlocks, aD as normalizeMcpServers, aE as openai, aF as openaiCompat, aG as openrouter, aH as resultToString, aI as toAnthropic, aJ as toOpenAI, aK as toTypedError, aa as toolResultToText } from './agent-CEO3IeZj.js';
3
3
  export { createDockerContext, createProcessContext } from './contexts.js';
4
4
  export { S as SandboxProvider, c as createSandboxContext } from './sandbox-CW72eLDP.js';
5
5
  export { C as ContextCapabilities, a as ContextType, E as ExecResult, b as ExecutionContext, c as ExecutionHandle, S as SpawnConfig } from './types-BpvTmawk.js';
6
6
  export { Preset, basic, basicTools, definePreset } from './presets.js';
7
7
  export { IMPLICITLY_ALLOWED_SKILL_TOOLS, SkillValidationIssue, SkillValidationResult, SourcedScanPath, buildCatalog, defineSkill, discoverSkills, installAllowedToolsGate, interpolateShellCommands, isToolAllowedByUnion, matchesAllowedTool, parseAllowedToolPattern, parseSkillFile, resolveSkills, validateResourcePath, validateSkillForWrite, validateSkillName, writeSkillToDisk, writeSkillsToDisk } from './skills.js';
8
- export { S as SkillsReadToolOptions, a as SkillsRunScriptToolOptions, b as SkillsUseToolOptions, c as createSkillsReadTool, d as createSkillsRunScriptTool, e as createSkillsUseTool, g as glob } from './skills-use-Ca4mG8zs.js';
9
- export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, c as createInteractionTool, b as createSpawnTool, s as spawn } from './spawn-BVN9GdDw.js';
8
+ export { S as SkillsReadToolOptions, a as SkillsRunScriptToolOptions, b as SkillsUseToolOptions, c as createSkillsReadTool, d as createSkillsRunScriptTool, e as createSkillsUseTool, g as glob } from './skills-use-CvHmgpmO.js';
9
+ export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, c as createInteractionTool, b as createSpawnTool, s as spawn } from './spawn-BJhCzli9.js';
10
10
  import { Hookable } from 'hookable';
11
11
  import '@modelcontextprotocol/sdk/client/index.js';
12
12
 
package/dist/index.js CHANGED
@@ -9,12 +9,12 @@ import {
9
9
  cerebras,
10
10
  openai,
11
11
  openrouter
12
- } from "./chunk-CDRXC7A7.js";
12
+ } from "./chunk-ZSEMKVHP.js";
13
13
  import {
14
14
  basicTools,
15
15
  basic_default,
16
16
  definePreset
17
- } from "./chunk-ZQWLUBNC.js";
17
+ } from "./chunk-MDVZX6GM.js";
18
18
  import {
19
19
  createAgent,
20
20
  createInteractionTool,
@@ -24,7 +24,7 @@ import {
24
24
  createSpawnTool,
25
25
  glob,
26
26
  spawn
27
- } from "./chunk-FVIHGZQM.js";
27
+ } from "./chunk-O2XZLJMG.js";
28
28
  import {
29
29
  IMPLICITLY_ALLOWED_SKILL_TOOLS,
30
30
  buildCatalog,
@@ -53,7 +53,7 @@ import {
53
53
  normalizeMcpBlocks,
54
54
  normalizeMcpServers,
55
55
  resultToString
56
- } from "./chunk-37GD7NL3.js";
56
+ } from "./chunk-DRAYZZ23.js";
57
57
  import {
58
58
  createFileMapStore,
59
59
  createMemoryStore,
@@ -71,7 +71,7 @@ import {
71
71
  openaiCompat,
72
72
  toAnthropic,
73
73
  toOpenAI
74
- } from "./chunk-S3FCOMRI.js";
74
+ } from "./chunk-CYWF2U62.js";
75
75
  import {
76
76
  AgentAbortedError,
77
77
  AgentContextExceededError,
package/dist/mcp.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import 'hookable';
2
- export { M as McpConnection, p as McpServerConfig, ar as connectMcpServers, aC as normalizeMcpBlocks, aD as normalizeMcpServers, aH as resultToString } from './agent-IYYE8a3i.js';
2
+ export { M as McpConnection, p as McpServerConfig, ar as connectMcpServers, aC as normalizeMcpBlocks, aD as normalizeMcpServers, aH as resultToString } from './agent-CEO3IeZj.js';
3
3
  import '@modelcontextprotocol/sdk/client/index.js';
4
4
  import './types-BpvTmawk.js';
package/dist/mcp.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  normalizeMcpBlocks,
4
4
  normalizeMcpServers,
5
5
  resultToString
6
- } from "./chunk-37GD7NL3.js";
6
+ } from "./chunk-DRAYZZ23.js";
7
7
  export {
8
8
  connectMcpServers,
9
9
  normalizeMcpBlocks,
package/dist/presets.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Z as ToolDef, e as AgentOptions } from './agent-IYYE8a3i.js';
1
+ import { Z as ToolDef, e as AgentOptions } from './agent-CEO3IeZj.js';
2
2
  import 'hookable';
3
3
  import './types-BpvTmawk.js';
4
4
  import '@modelcontextprotocol/sdk/client/index.js';
package/dist/presets.js CHANGED
@@ -2,11 +2,11 @@ import {
2
2
  basicTools,
3
3
  basic_default,
4
4
  definePreset
5
- } from "./chunk-ZQWLUBNC.js";
6
- import "./chunk-FVIHGZQM.js";
5
+ } from "./chunk-MDVZX6GM.js";
6
+ import "./chunk-O2XZLJMG.js";
7
7
  import "./chunk-TPXPVEH6.js";
8
8
  import "./chunk-2EQT4EHD.js";
9
- import "./chunk-37GD7NL3.js";
9
+ import "./chunk-DRAYZZ23.js";
10
10
  import "./chunk-LNN5UTS2.js";
11
11
  export {
12
12
  basic_default as basic,
@@ -1,4 +1,4 @@
1
- export { j as AnthropicParams, k as CerebrasParams, ag as OpenAICompatAuthHeader, ah as OpenAICompatHttpError, ai as OpenAICompatParams, r as OpenAIParams, s as OpenRouterParams, w as Provider, x as ProviderCapabilities, T as StreamCallbacks, V as StreamOptions, X as ToolCall, a1 as ToolResult, a5 as ToolSpec, a7 as TurnResult, an as anthropic, ap as cerebras, aq as classifyOpenAICompatError, aB as mapOAIFinishReason, aE as openai, aF as openaiCompat, aG as openrouter } from './agent-IYYE8a3i.js';
1
+ export { j as AnthropicParams, k as CerebrasParams, ag as OpenAICompatAuthHeader, ah as OpenAICompatHttpError, ai as OpenAICompatParams, r as OpenAIParams, s as OpenRouterParams, w as Provider, x as ProviderCapabilities, T as StreamCallbacks, V as StreamOptions, X as ToolCall, a1 as ToolResult, a5 as ToolSpec, a7 as TurnResult, an as anthropic, ap as cerebras, aq as classifyOpenAICompatError, aB as mapOAIFinishReason, aE as openai, aF as openaiCompat, aG as openrouter } from './agent-CEO3IeZj.js';
2
2
  import 'hookable';
3
3
  import './types-BpvTmawk.js';
4
4
  import '@modelcontextprotocol/sdk/client/index.js';
package/dist/providers.js CHANGED
@@ -3,13 +3,13 @@ import {
3
3
  cerebras,
4
4
  openai,
5
5
  openrouter
6
- } from "./chunk-CDRXC7A7.js";
6
+ } from "./chunk-ZSEMKVHP.js";
7
7
  import {
8
8
  OpenAICompatHttpError,
9
9
  classifyOpenAICompatError,
10
10
  mapOAIFinishReason,
11
11
  openaiCompat
12
- } from "./chunk-S3FCOMRI.js";
12
+ } from "./chunk-CYWF2U62.js";
13
13
  import "./chunk-LNN5UTS2.js";
14
14
  export {
15
15
  OpenAICompatHttpError,
@@ -1,4 +1,4 @@
1
- import { H as SessionStore } from '../agent-IYYE8a3i.js';
1
+ import { H as SessionStore } from '../agent-CEO3IeZj.js';
2
2
  import 'hookable';
3
3
  import '../types-BpvTmawk.js';
4
4
  import '@modelcontextprotocol/sdk/client/index.js';
package/dist/session.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { o as CreateSessionOptions, ae as FileMapAdapter, af as FileMapStoreOptions, R as RemoteStoreOptions, S as Session, z as SessionContentBlock, B as SessionData, F as SessionMessage, G as SessionRun, H as SessionStore, J as SessionTurn, ao as autoDetectAndConvert, at as createFileMapStore, au as createMemoryStore, av as createRemoteStore, aw as createSession, ay as fromAnthropic, az as fromOpenAI, aA as loadSession, aI as toAnthropic, aJ as toOpenAI } from './agent-IYYE8a3i.js';
1
+ export { o as CreateSessionOptions, ae as FileMapAdapter, af as FileMapStoreOptions, R as RemoteStoreOptions, S as Session, z as SessionContentBlock, B as SessionData, F as SessionMessage, G as SessionRun, H as SessionStore, J as SessionTurn, ao as autoDetectAndConvert, at as createFileMapStore, au as createMemoryStore, av as createRemoteStore, aw as createSession, ay as fromAnthropic, az as fromOpenAI, aA as loadSession, aI as toAnthropic, aJ as toOpenAI } from './agent-CEO3IeZj.js';
2
2
  import 'hookable';
3
3
  import './types-BpvTmawk.js';
4
4
  import '@modelcontextprotocol/sdk/client/index.js';
package/dist/session.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  fromOpenAI,
12
12
  toAnthropic,
13
13
  toOpenAI
14
- } from "./chunk-S3FCOMRI.js";
14
+ } from "./chunk-CYWF2U62.js";
15
15
  import "./chunk-LNN5UTS2.js";
16
16
  export {
17
17
  autoDetectAndConvert,
@@ -1,4 +1,4 @@
1
- import { Z as ToolDef, K as SkillConfig, aj as SkillActivationState, d as AgentHooks } from './agent-IYYE8a3i.js';
1
+ import { Z as ToolDef, K as SkillConfig, aj as SkillActivationState, d as AgentHooks } from './agent-CEO3IeZj.js';
2
2
  import { Hookable } from 'hookable';
3
3
 
4
4
  declare const glob: ToolDef;
package/dist/skills.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { d as AgentHooks, aj as SkillActivationState, K as SkillConfig, am as SkillSource, al as SkillDiagnostic, N as SkillsConfig } from './agent-IYYE8a3i.js';
2
- export { ab as ActivationVia, ac as ActiveSkill, ad as DeactivationReason, ak as SkillActivationStateOptions, L as SkillResource, ax as createSkillActivationState } from './agent-IYYE8a3i.js';
1
+ import { d as AgentHooks, aj as SkillActivationState, K as SkillConfig, am as SkillSource, al as SkillDiagnostic, N as SkillsConfig } from './agent-CEO3IeZj.js';
2
+ export { ab as ActivationVia, ac as ActiveSkill, ad as DeactivationReason, ak as SkillActivationStateOptions, L as SkillResource, ax as createSkillActivationState } from './agent-CEO3IeZj.js';
3
3
  import { Hookable } from 'hookable';
4
4
  import { b as ExecutionContext, c as ExecutionHandle } from './types-BpvTmawk.js';
5
5
  import '@modelcontextprotocol/sdk/client/index.js';
@@ -1,4 +1,4 @@
1
- import { Y as ToolContext, Z as ToolDef, h as AgentStats, l as ChildRunStats } from './agent-IYYE8a3i.js';
1
+ import { Y as ToolContext, Z as ToolDef, h as AgentStats, l as ChildRunStats } from './agent-CEO3IeZj.js';
2
2
  import { Preset } from './presets.js';
3
3
 
4
4
  /**
package/dist/tools.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export { S as SkillsReadToolOptions, a as SkillsRunScriptToolOptions, b as SkillsUseToolOptions, c as createSkillsReadTool, d as createSkillsRunScriptTool, e as createSkillsUseTool, g as glob } from './skills-use-Ca4mG8zs.js';
2
- export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, c as createInteractionTool, b as createSpawnTool, s as spawn } from './spawn-BVN9GdDw.js';
3
- import { Z as ToolDef } from './agent-IYYE8a3i.js';
4
- export { Y as ToolContext, a0 as ToolMap } from './agent-IYYE8a3i.js';
1
+ export { S as SkillsReadToolOptions, a as SkillsRunScriptToolOptions, b as SkillsUseToolOptions, c as createSkillsReadTool, d as createSkillsRunScriptTool, e as createSkillsUseTool, g as glob } from './skills-use-CvHmgpmO.js';
2
+ export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, c as createInteractionTool, b as createSpawnTool, s as spawn } from './spawn-BJhCzli9.js';
3
+ import { Z as ToolDef } from './agent-CEO3IeZj.js';
4
+ export { Y as ToolContext, a0 as ToolMap } from './agent-CEO3IeZj.js';
5
5
  export { V as ValidationResult, v as validateToolArgs } from './validation-DOY_k7lW.js';
6
6
  import 'hookable';
7
7
  import './presets.js';
package/dist/tools.js CHANGED
@@ -11,10 +11,10 @@ import {
11
11
  spawn,
12
12
  validateToolArgs,
13
13
  writeFile
14
- } from "./chunk-FVIHGZQM.js";
14
+ } from "./chunk-O2XZLJMG.js";
15
15
  import "./chunk-TPXPVEH6.js";
16
16
  import "./chunk-2EQT4EHD.js";
17
- import "./chunk-37GD7NL3.js";
17
+ import "./chunk-DRAYZZ23.js";
18
18
  import "./chunk-LNN5UTS2.js";
19
19
  export {
20
20
  createInteractionTool,
package/dist/types.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- export { A as Agent, a as AgentAbortedError, b as AgentBehavior, c as AgentContextExceededError, d as AgentHooks, e as AgentOptions, f as AgentProviderError, g as AgentRunOptions, h as AgentStats, i as AgentToolNotAllowedError, j as AnthropicParams, C as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, k as CerebrasParams, l as ChildRunStats, m as ClassifiedError, n as ClassifiedErrorKind, o as CreateSessionOptions, I as ImageContent, M as McpConnection, p as McpServerConfig, q as McpToolHookContext, O as OAuthRefreshHookContext, r as OpenAIParams, s as OpenRouterParams, P as PromptDocumentPart, t as PromptImagePart, u as PromptPart, v as PromptTextPart, w as Provider, x as ProviderCapabilities, R as RemoteStoreOptions, y as RunHookMap, S as Session, z as SessionContentBlock, B as SessionData, D as SessionEndStatus, E as SessionHookContext, F as SessionMessage, G as SessionRun, H as SessionStore, J as SessionTurn, K as SkillConfig, L as SkillResource, N as SkillsConfig, Q as SpawnHookContext, T as StreamCallbacks, U as StreamHookContext, V as StreamOptions, W as ThinkingLevel, X as ToolCall, Y as ToolContext, Z as ToolDef, _ as ToolExecutionMode, $ as ToolHookContext, a0 as ToolMap, a1 as ToolResult, a2 as ToolResultContent, a3 as ToolResultImageContent, a4 as ToolResultTextContent, a5 as ToolSpec, a6 as TurnFinishReason, a7 as TurnResult, a8 as TurnUsage, a9 as matchesContextExceeded, aa as toolResultToText } from './agent-IYYE8a3i.js';
1
+ export { A as Agent, a as AgentAbortedError, b as AgentBehavior, c as AgentContextExceededError, d as AgentHooks, e as AgentOptions, f as AgentProviderError, g as AgentRunOptions, h as AgentStats, i as AgentToolNotAllowedError, j as AnthropicParams, C as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, k as CerebrasParams, l as ChildRunStats, m as ClassifiedError, n as ClassifiedErrorKind, o as CreateSessionOptions, I as ImageContent, M as McpConnection, p as McpServerConfig, q as McpToolHookContext, O as OAuthRefreshHookContext, r as OpenAIParams, s as OpenRouterParams, P as PromptDocumentPart, t as PromptImagePart, u as PromptPart, v as PromptTextPart, w as Provider, x as ProviderCapabilities, R as RemoteStoreOptions, y as RunHookMap, S as Session, z as SessionContentBlock, B as SessionData, D as SessionEndStatus, E as SessionHookContext, F as SessionMessage, G as SessionRun, H as SessionStore, J as SessionTurn, K as SkillConfig, L as SkillResource, N as SkillsConfig, Q as SpawnHookContext, T as StreamCallbacks, U as StreamHookContext, V as StreamOptions, W as ThinkingLevel, X as ToolCall, Y as ToolContext, Z as ToolDef, _ as ToolExecutionMode, $ as ToolHookContext, a0 as ToolMap, a1 as ToolResult, a2 as ToolResultContent, a3 as ToolResultImageContent, a4 as ToolResultTextContent, a5 as ToolSpec, a6 as TurnFinishReason, a7 as TurnResult, a8 as TurnUsage, a9 as matchesContextExceeded, aa as toolResultToText } from './agent-CEO3IeZj.js';
2
2
  export { C as ContextCapabilities, a as ContextType, E as ExecResult, b as ExecutionContext, c as ExecutionHandle, S as SpawnConfig } from './types-BpvTmawk.js';
3
3
  export { S as SandboxProvider } from './sandbox-CW72eLDP.js';
4
4
  export { Preset } from './presets.js';
5
- export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState } from './spawn-BVN9GdDw.js';
5
+ export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState } from './spawn-BJhCzli9.js';
6
6
  export { V as ValidationResult } from './validation-DOY_k7lW.js';
7
7
  import 'hookable';
8
8
  import '@modelcontextprotocol/sdk/client/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zidane",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "an agent that goes straight to the goal",
5
5
  "type": "module",
6
6
  "private": false,
@@ -73,7 +73,7 @@
73
73
  "dependencies": {
74
74
  "@yaelg/pi-ai": "^0.66.1",
75
75
  "chalk": "^5.6.2",
76
- "hookable": "^6.1.0",
76
+ "hookable": "^6.1.1",
77
77
  "md4x": "^0.0.25"
78
78
  },
79
79
  "peerDependencies": {
@@ -90,15 +90,15 @@
90
90
  }
91
91
  },
92
92
  "devDependencies": {
93
- "@antfu/eslint-config": "^8.1.1",
94
- "@anthropic-ai/sdk": "^0.88.0",
93
+ "@antfu/eslint-config": "^8.2.0",
94
+ "@anthropic-ai/sdk": "^0.90.0",
95
95
  "@modelcontextprotocol/sdk": "^1.29.0",
96
- "@types/bun": "^1.3.12",
96
+ "@types/bun": "^1.3.13",
97
97
  "@types/dockerode": "^4.0.1",
98
98
  "bumpp": "^11.0.1",
99
- "eslint": "^10.2.0",
99
+ "eslint": "^10.2.1",
100
100
  "jiti": "^2.6.1",
101
101
  "tsup": "^8.5.1",
102
- "typescript": "~6.0.2"
102
+ "typescript": "~6.0.3"
103
103
  }
104
104
  }