zidane 3.1.1 → 3.1.2
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 +110 -7
- package/dist/{agent-Cq009tbG.d.ts → agent-C9q5VMGa.d.ts} +260 -0
- package/dist/{chunk-EBSFBIP3.js → chunk-2AE3VM5O.js} +255 -13
- package/dist/{chunk-R74LQKAM.js → chunk-7H34OFDA.js} +26 -0
- package/dist/{chunk-3DUWP7YU.js → chunk-BRMURQA2.js} +6 -1
- package/dist/{chunk-ATMVSCGJ.js → chunk-BXO7CZHJ.js} +1 -1
- package/dist/{chunk-VF4A7HAC.js → chunk-YQ7LY6CL.js} +3 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +5 -5
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +3 -3
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +2 -2
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/session.js +1 -1
- package/dist/{skills-use-Bi6Dklye.d.ts → skills-use-DU0unNP4.d.ts} +1 -1
- package/dist/skills.d.ts +2 -2
- package/dist/tools.d.ts +4 -4
- package/dist/tools.js +2 -2
- package/dist/types.d.ts +2 -2
- package/dist/{validation-BeQD94ft.d.ts → validation-BKA33eqb.d.ts} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,10 +15,10 @@ Built to be embedded.
|
|
|
15
15
|
A small, hookable core with sensible defaults so most consumers don't write a single hook. Built around three principles: **token discipline by default** (cache, dedup, compaction, byte-accounting), **self-healing on the fault paths** (auto-coerce args, hallucinated-tool fallback, error rewriting), and **provider parity** (server-side features on Anthropic, client-side equivalents everywhere else).
|
|
16
16
|
|
|
17
17
|
- 🧠 **Multi-provider, multi-auth** — Anthropic, OpenAI Codex, OpenRouter, Cerebras, plus a generic `openaiCompat` factory (Baseten, Fireworks, Groq, local servers). OAuth + API key, auto-refreshing tokens. Anthropic accepts opt-in `extraBetas` and `contextManagement` for first-party features.
|
|
18
|
-
- 🪝 **Streaming, hookable turn loop** — text/thinking deltas, tool calls, MCP, sessions, skills, spawn, OAuth, validation, budgets — all observable (and most mutatable) via typed hook events.
|
|
19
|
-
- 🛠 **Tools first-class** — `shell`, `read_file`, `write_file`, `edit`, `multi_edit`, `glob`, `grep`, `spawn`, human-in-the-loop, plus any [MCP](https://modelcontextprotocol.io) server. Sequential or parallel, per-call gates (`tool:gate`), validation auto-coerce (`"true"` → `true`), hallucinated-tool fallback (`tool:unknown`), error rewriting (`tool:error` → `result`).
|
|
20
|
-
- ✂️ **Token-aware ergonomics** — paginated reads with a "how to page" footer, 8 KB tail-truncated `shell`, idempotent `write_file`; `outputBytes` surfaced on every tool/MCP hook. `behavior.toolOutputBudget` injects a "summarize" nudge when a turn's outputs exceed the cap.
|
|
21
|
-
- 🗜 **Context discipline** — auto-injected `cache_control` breakpoints (Anthropic + OpenRouter); server-side compaction via `context-management-2025-06-27` on Anthropic, `behavior.compactStrategy: 'tail'` on everyone else. Per-session `read_file` dedup + opt-in `requireReadBeforeEdit` guard kill stale-content edits.
|
|
18
|
+
- 🪝 **Streaming, hookable turn loop** — text/thinking deltas, tool calls, MCP, sessions, skills, spawn, OAuth, validation, budgets — all observable (and most mutatable) via typed hook events. Per-request `system:transform` hook for runtime-derived prompt sections.
|
|
19
|
+
- 🛠 **Tools first-class** — `shell`, `read_file`, `write_file`, `edit`, `multi_edit`, `glob`, `grep`, `spawn`, human-in-the-loop, plus any [MCP](https://modelcontextprotocol.io) server. Sequential or parallel, per-call gates (`tool:gate` with writable `block` / `result` / `runToolCounts`), validation auto-coerce (`"true"` → `true`), hallucinated-tool fallback (`tool:unknown`), error rewriting (`tool:error` → `result`).
|
|
20
|
+
- ✂️ **Token-aware ergonomics** — paginated reads with a "how to page" footer, 8 KB tail-truncated `shell`, idempotent `write_file`; `outputBytes` surfaced on every tool/MCP hook. `behavior.toolOutputBudget` injects a "summarize" nudge when a turn's outputs exceed the cap; `behavior.toolBudgets` caps per-tool call counts (`'steer'` or `'block'`); `behavior.thinkingDecay` tapers reasoning budget per turn.
|
|
21
|
+
- 🗜 **Context discipline** — auto-injected `cache_control` breakpoints (Anthropic + OpenRouter); server-side compaction via `context-management-2025-06-27` on Anthropic, `behavior.compactStrategy: 'tail'` on everyone else. Per-session `read_file` dedup + opt-in `requireReadBeforeEdit` guard kill stale-content edits; `behavior.dedupTools` generalizes the same pattern to arbitrary tools (`todowrite`, `execute_sql`, …).
|
|
22
22
|
- 🎯 **Reasoning + structured output** — thinking levels (`off` / `minimal` / `low` / `medium` / `high` / `adaptive`) with optional exact budgets; force the final answer to a JSON Schema (Zod v4 interop), no brittle parsing.
|
|
23
23
|
- 💾 **Sessions, skills, multimodal** — pluggable session stores (memory / SQLite / remote / file-map), incremental persistence; [Agent Skills](https://agentskills.io/specification) spec-aligned with `allowed-tools` enforcement + resume rehydration; images + documents via `PromptPart[]`, tools can return image blocks routed natively on vision providers or via companion messages elsewhere.
|
|
24
24
|
- 🧵 **Sub-agents + execution contexts** — delegate to child agents with inherited or overridden preset (child events bubble to the parent); run tools in-process, Docker, or any `SandboxProvider` (E2B / Rivet / custom). Parallel MCP bootstrap with `agent.warmup()` + `eager: true` to hide cold starts.
|
|
@@ -67,10 +67,13 @@ createAgent({
|
|
|
67
67
|
maxTurns: 50, // max loop iterations
|
|
68
68
|
maxTokens: 16384, // max tokens per LLM response
|
|
69
69
|
thinkingBudget: 10240, // exact thinking token budget
|
|
70
|
+
thinkingDecay: { afterTurn: 5, factor: 0.5, floor: 1024 }, // taper budget per run-relative turn
|
|
70
71
|
cache: true, // prompt-cache breakpoints on supported providers (default: true)
|
|
71
72
|
toolOutputBudget: 32768, // soft per-turn cap on tool-output bytes (off by default)
|
|
72
73
|
dedupReads: true, // dedup identical re-reads of the same file in `read_file` (default: true)
|
|
74
|
+
dedupTools: { todowrite: i => JSON.stringify(i.todos) }, // generic per-tool argument dedup
|
|
73
75
|
requireReadBeforeEdit: false, // refuse `edit` / `multi_edit` against unread or stale files (default: false)
|
|
76
|
+
toolBudgets: { todowrite: { max: 6, onExceed: 'steer' } }, // per-tool soft call caps
|
|
74
77
|
compactStrategy: 'off', // client-side tail compaction for non-Anthropic providers — 'off' | 'tail' (default: 'off')
|
|
75
78
|
compactThreshold: 131_072, // bytes threshold that triggers tail compaction (default: 128 KiB)
|
|
76
79
|
compactKeepTurns: 4, // trailing turns left intact during compaction (default: 4)
|
|
@@ -162,6 +165,18 @@ Fallback: `params.apiKey` > `params.access` > `ANTHROPIC_API_KEY` env > `.creden
|
|
|
162
165
|
|
|
163
166
|
`extraBetas` are merged with the OAuth defaults (`claude-code-20250219`, `oauth-2025-04-20`) and de-duped. `contextManagement` is sent on the request body as `context_management`; pair it with the `context-management-2025-06-27` beta. For non-Anthropic providers, see `behavior.compactStrategy: 'tail'` for the client-side fallback.
|
|
164
167
|
|
|
168
|
+
`extraBodyParams` is a generic forward-compat pass-through for un-typed Messages API fields. Spread into the request before the typed core, so explicit factory options always win on collision. Use it when Anthropic ships a new beta before zidane has a dedicated knob:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
anthropic({
|
|
172
|
+
apiKey: '...',
|
|
173
|
+
extraBetas: ['some-future-beta'],
|
|
174
|
+
extraBodyParams: { future_field: { /* ... */ } },
|
|
175
|
+
})
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`openaiCompat` accepts the same `extraBodyParams` for OpenAI-style endpoints (e.g. `reasoning_effort`, `metadata`, OpenRouter `provider` routing).
|
|
179
|
+
|
|
165
180
|
### OpenRouter
|
|
166
181
|
|
|
167
182
|
```ts
|
|
@@ -367,15 +382,19 @@ All tool hooks include `turnId` and `callId` for correlation. Typed via `ToolHoo
|
|
|
367
382
|
|
|
368
383
|
```ts
|
|
369
384
|
agent.hooks.hook('tool:gate', (ctx) => {
|
|
370
|
-
// ctx.turnId, ctx.callId, ctx.name, ctx.input
|
|
385
|
+
// ctx.turnId, ctx.callId, ctx.name, ctx.input, ctx.runToolCounts
|
|
371
386
|
if (ctx.name === 'shell' && String(ctx.input.command).includes('rm -rf')) {
|
|
372
387
|
ctx.block = true
|
|
373
388
|
ctx.reason = 'dangerous command'
|
|
374
389
|
}
|
|
390
|
+
// Substitute a successful result without running the tool — mirrors
|
|
391
|
+
// tool:unknown / tool:error. When both are set, `block` wins.
|
|
392
|
+
if (ctx.name === 'todowrite' && (ctx.runToolCounts.todowrite ?? 0) > 0)
|
|
393
|
+
ctx.result = 'Already recorded; no-op.'
|
|
375
394
|
})
|
|
376
395
|
|
|
377
|
-
agent.hooks.hook('tool:before', (ctx) => { /* ctx.turnId, ctx.callId, ctx.name, ctx.input, ctx.coercions? */ })
|
|
378
|
-
agent.hooks.hook('tool:after', (ctx) => { /* + ctx.result, ctx.outputBytes, ctx.coercions? */ })
|
|
396
|
+
agent.hooks.hook('tool:before', (ctx) => { /* ctx.turnId, ctx.callId, ctx.name, ctx.input, ctx.runToolCounts, ctx.coercions? */ })
|
|
397
|
+
agent.hooks.hook('tool:after', (ctx) => { /* + ctx.result, ctx.outputBytes, ctx.runToolCounts, ctx.coercions? */ })
|
|
379
398
|
agent.hooks.hook('tool:error', (ctx) => {
|
|
380
399
|
// + ctx.error. Mutate ctx.result to substitute the payload sent back to the
|
|
381
400
|
// model in place of the default `Tool error: <msg>` — useful for OSS-model
|
|
@@ -434,6 +453,20 @@ agent.hooks.hook('context:transform', (ctx) => {
|
|
|
434
453
|
})
|
|
435
454
|
```
|
|
436
455
|
|
|
456
|
+
### System transform
|
|
457
|
+
|
|
458
|
+
Mutate the system prompt per request — useful for runtime-derived sections (files already read in the session, live tool budgets, skill activation reminders). Fires after `context:transform`, before the request goes out. `messages` is read-only here.
|
|
459
|
+
|
|
460
|
+
```ts
|
|
461
|
+
agent.hooks.hook('system:transform', (ctx) => {
|
|
462
|
+
// ctx.system, ctx.messages (readonly), ctx.turn, ctx.turnId, ctx.session?
|
|
463
|
+
if (ctx.session && ctx.turn > 1)
|
|
464
|
+
ctx.system += `\n\n## Reminder: keep responses concise after turn ${ctx.turn}.`
|
|
465
|
+
})
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
Cache breakpoints land naturally inside the provider after this hook, so repeated turns with the same derived system text still hit the cache.
|
|
469
|
+
|
|
437
470
|
### Hook recipes
|
|
438
471
|
|
|
439
472
|
Three patterns that don't have a built-in default. Copy-paste and tune.
|
|
@@ -484,6 +517,12 @@ const agent = createAgent({
|
|
|
484
517
|
agent.hooks.hook('budget:exceeded', (ctx) => {
|
|
485
518
|
console.warn(`turn ${ctx.turn}: ${ctx.bytes} > ${ctx.budget} bytes`)
|
|
486
519
|
})
|
|
520
|
+
|
|
521
|
+
agent.hooks.hook('tool-budget:exceeded', (ctx) => {
|
|
522
|
+
// Per-tool counterpart, fires when `behavior.toolBudgets[ctx.tool]` trips.
|
|
523
|
+
// ctx.tool, ctx.count, ctx.max, ctx.turnId, ctx.mode ('steer' | 'block')
|
|
524
|
+
console.warn(`tool ${ctx.tool} hit cap (${ctx.count}/${ctx.max}, mode=${ctx.mode})`)
|
|
525
|
+
})
|
|
487
526
|
```
|
|
488
527
|
|
|
489
528
|
### Client-side context compaction (non-Anthropic)
|
|
@@ -510,6 +549,70 @@ Anthropic users should prefer the server-side `context-management-2025-06-27` be
|
|
|
510
549
|
|
|
511
550
|
`behavior.requireReadBeforeEdit` (off by default) — `edit` and `multi_edit` reject when the file hasn't been read in the session, or when its on-disk content has drifted since the last read. Eliminates the silent-corruption case where a model edits against bytes it "remembers" but no longer reflect reality. Recommended on for stricter eval-grade runs.
|
|
512
551
|
|
|
552
|
+
### Generic per-tool dedup
|
|
553
|
+
|
|
554
|
+
`behavior.dedupTools` extends the read-file pattern to arbitrary tools. Provide a hasher per tool keyed by canonical name; identical inputs replay the prior result without re-running the tool. Requires a session.
|
|
555
|
+
|
|
556
|
+
The hasher contract has **three return values, three meanings** — pick deliberately:
|
|
557
|
+
|
|
558
|
+
| Return | Meaning |
|
|
559
|
+
|---|---|
|
|
560
|
+
| non-empty string | Cache key for this call. Equal keys replay the prior result. |
|
|
561
|
+
| `undefined` | **Skip dedup for this call.** Tool runs normally; nothing recorded. |
|
|
562
|
+
| `''` or non-string | Treated as `undefined` (defensive). |
|
|
563
|
+
|
|
564
|
+
```ts
|
|
565
|
+
behavior: {
|
|
566
|
+
dedupTools: {
|
|
567
|
+
// Always cache by full input — every identical re-call dedups.
|
|
568
|
+
todowrite: input => JSON.stringify(input),
|
|
569
|
+
|
|
570
|
+
// Cache by a normalized subset; non-cacheable shapes opt out via `undefined`.
|
|
571
|
+
execute_sql: (input) => {
|
|
572
|
+
const q = typeof input.query === 'string' ? input.query.trim().toLowerCase() : undefined
|
|
573
|
+
if (!q || q.includes('now()') || q.includes('random()')) return undefined
|
|
574
|
+
return q
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
The `undefined` opt-out is **not** the same as `JSON.stringify(input)` — that would dedup against the verbatim input. Use `undefined` to mean "this specific call is not cacheable" (timestamps baked in, randomness, debug flags).
|
|
581
|
+
|
|
582
|
+
Tools with side effects or non-deterministic outputs (network, time, randomness) **must not** be listed — there is no safety net beyond the consumer's hasher. For MCP tools, key by the namespaced wire name (`mcp_<server>_<tool>`).
|
|
583
|
+
|
|
584
|
+
### Per-tool call budgets
|
|
585
|
+
|
|
586
|
+
`behavior.toolBudgets` caps per-tool calls per run. Two reactions:
|
|
587
|
+
|
|
588
|
+
- `'steer'` — let the call run, but emit a synthetic user message after the turn nudging the model to commit and finish. Fires once per tool per run.
|
|
589
|
+
- `'block'` — refuse subsequent calls with `Blocked: <reason>`.
|
|
590
|
+
|
|
591
|
+
```ts
|
|
592
|
+
behavior: {
|
|
593
|
+
toolBudgets: {
|
|
594
|
+
todowrite: { max: 6, onExceed: 'steer' },
|
|
595
|
+
execute_sql: { max: 3, onExceed: 'block' },
|
|
596
|
+
},
|
|
597
|
+
}
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
Pass a function for custom messages: `onExceed: ctx => ({ mode: 'steer', message: '...' })`. Subscribe to `tool-budget:exceeded` for telemetry. Counts include dedup hits — by design, since both eat against agent-loop sanity.
|
|
601
|
+
|
|
602
|
+
### Adaptive thinking budget
|
|
603
|
+
|
|
604
|
+
`behavior.thinkingDecay` tapers the thinking budget across turns. Late turns are usually checkpoint / cleanup work where reasoning rarely pays for itself.
|
|
605
|
+
|
|
606
|
+
```ts
|
|
607
|
+
behavior: {
|
|
608
|
+
thinkingBudget: 8192,
|
|
609
|
+
thinkingDecay: { afterTurn: 5, factor: 0.5, floor: 1024 },
|
|
610
|
+
// turn 1-5 → 8192, turn 6 → 4096, turn 7 → 2048, turn 8+ → 1024
|
|
611
|
+
}
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
Pass a function for arbitrary curves: `thinkingDecay: (turn, base) => base / Math.sqrt(turn)`. No-op when `thinkingBudget` is unset. Honored by every provider that respects `thinkingBudget`.
|
|
615
|
+
|
|
513
616
|
## Steering and Follow-up
|
|
514
617
|
|
|
515
618
|
### Steering
|
|
@@ -229,6 +229,126 @@ interface AgentBehavior {
|
|
|
229
229
|
* Default: `true`.
|
|
230
230
|
*/
|
|
231
231
|
dedupReads?: boolean;
|
|
232
|
+
/**
|
|
233
|
+
* Taper the thinking budget over the course of a run. Late turns are
|
|
234
|
+
* usually checkpoint / cleanup work where reasoning rarely pays for
|
|
235
|
+
* itself; early turns benefit most. Two forms:
|
|
236
|
+
*
|
|
237
|
+
* - **Struct** — geometric decay starting after `afterTurn`, multiplying by
|
|
238
|
+
* `factor` each subsequent turn, clamped to `floor`. Example
|
|
239
|
+
* `{ afterTurn: 5, factor: 0.5, floor: 1024 }` with a base budget of 8192:
|
|
240
|
+
* turns 1-5 = 8192, turn 6 = 4096, turn 7 = 2048, turn 8+ = 1024.
|
|
241
|
+
* - **Function** — `(runTurn, baseBudget) => number`. Arbitrary curves;
|
|
242
|
+
* `runTurn` is 1-indexed, run-relative (resumed sessions reset).
|
|
243
|
+
*
|
|
244
|
+
* No-op when `thinkingBudget` is unset. Honored by every provider that
|
|
245
|
+
* respects `thinkingBudget` (anthropic legacy enabled+budget path,
|
|
246
|
+
* adaptive `maxTokensCap`, openai-compat `max_tokens` padding).
|
|
247
|
+
*
|
|
248
|
+
* Default: `undefined` (no decay).
|
|
249
|
+
*/
|
|
250
|
+
thinkingDecay?: {
|
|
251
|
+
afterTurn: number;
|
|
252
|
+
factor: number;
|
|
253
|
+
floor: number;
|
|
254
|
+
} | ((runTurn: number, baseBudget: number) => number);
|
|
255
|
+
/**
|
|
256
|
+
* Per-tool soft call budget for this run. Keyed by **canonical** tool name.
|
|
257
|
+
* On the first call after the run-cumulative dispatched count for that tool
|
|
258
|
+
* reaches `max`, the framework fires `onExceed`:
|
|
259
|
+
*
|
|
260
|
+
* - `'steer'` (default) — let the call execute, but emit a synthetic user
|
|
261
|
+
* message after the turn that nudges the model away from re-calling the
|
|
262
|
+
* tool. Reuses the existing post-turn steer pathway used by
|
|
263
|
+
* `toolOutputBudget`. Fires `tool-budget:exceeded` with `mode: 'steer'`.
|
|
264
|
+
* - `'block'` — refuse the call via `tool:gate` `block`. The model sees a
|
|
265
|
+
* `Blocked: <reason>` tool result. Fires `tool-budget:exceeded` with
|
|
266
|
+
* `mode: 'block'`.
|
|
267
|
+
* - **Function** — `(ctx) => { mode, message }`. The consumer supplies the
|
|
268
|
+
* steering / refusal text and chooses the mode dynamically.
|
|
269
|
+
*
|
|
270
|
+
* Counts include both real dispatches and dedup substitutes (Z19 hits).
|
|
271
|
+
* Excludes calls already blocked by an earlier gate (skill allow-list,
|
|
272
|
+
* consumer hook). Tool dispatched by spawned subagents has its own per-run
|
|
273
|
+
* counter — child counts never charge the parent.
|
|
274
|
+
*
|
|
275
|
+
* For MCP tools, key by the namespaced wire name (`mcp_<server>_<tool>`).
|
|
276
|
+
*
|
|
277
|
+
* Atomic in parallel mode: the middleware tracks its own per-tool
|
|
278
|
+
* approval counter, incremented synchronously at gate-time. A
|
|
279
|
+
* 4-call parallel batch against `max: 2` will let the first 2 through
|
|
280
|
+
* and refuse the rest, even though the loop's `runToolCounts` only
|
|
281
|
+
* propagates between calls (not within a single batch's gate fan-out).
|
|
282
|
+
*
|
|
283
|
+
* Default: `undefined` (no budget enforcement).
|
|
284
|
+
*/
|
|
285
|
+
toolBudgets?: Record<string, {
|
|
286
|
+
max: number;
|
|
287
|
+
onExceed?: 'steer' | 'block' | ((ctx: {
|
|
288
|
+
tool: string;
|
|
289
|
+
count: number;
|
|
290
|
+
max: number;
|
|
291
|
+
}) => {
|
|
292
|
+
mode: 'steer' | 'block';
|
|
293
|
+
message: string;
|
|
294
|
+
});
|
|
295
|
+
}>;
|
|
296
|
+
/**
|
|
297
|
+
* Generic per-tool argument deduplication. Keyed by the tool's **canonical**
|
|
298
|
+
* name (alias-stable). Each entry is a hasher: `(input) => string | undefined`.
|
|
299
|
+
*
|
|
300
|
+
* **Hasher contract** — three return values, three meanings:
|
|
301
|
+
*
|
|
302
|
+
* | Return | Meaning |
|
|
303
|
+
* |-------------------------|------------------------------------------------------------------------|
|
|
304
|
+
* | a non-empty string | Cache key for this call. Equal keys (most-recent-only, this session) |
|
|
305
|
+
* | | replay the prior recorded result without re-dispatching the tool. |
|
|
306
|
+
* | `undefined` | **Skip dedup for this call.** The tool runs normally; nothing recorded.|
|
|
307
|
+
* | `''` / non-string | Treated identically to `undefined` (defensive: no dedup, no error). |
|
|
308
|
+
*
|
|
309
|
+
* The `undefined` opt-out is the way to say *"this specific call is not
|
|
310
|
+
* cacheable"* (timestamps in input, randomness baked in, debug flags). It
|
|
311
|
+
* is **not** the same as `JSON.stringify(input)` — that would dedup against
|
|
312
|
+
* the verbatim input. Pick one explicitly:
|
|
313
|
+
*
|
|
314
|
+
* ```ts
|
|
315
|
+
* // Always cache by full input — every identical re-call dedups.
|
|
316
|
+
* dedupTools: { todowrite: input => JSON.stringify(input) }
|
|
317
|
+
*
|
|
318
|
+
* // Cache by a normalized subset; non-cacheable shapes opt out.
|
|
319
|
+
* dedupTools: {
|
|
320
|
+
* execute_sql: (input) => {
|
|
321
|
+
* const q = typeof input.query === 'string' ? input.query.trim().toLowerCase() : undefined
|
|
322
|
+
* if (!q || q.includes('now()') || q.includes('random()')) return undefined
|
|
323
|
+
* return q
|
|
324
|
+
* },
|
|
325
|
+
* }
|
|
326
|
+
* ```
|
|
327
|
+
*
|
|
328
|
+
* On a hit, the previously-recorded result is replayed as the tool_result
|
|
329
|
+
* without dispatching the tool. The substitution flows through `tool:gate`
|
|
330
|
+
* `result` (Z20), so `tool:after` and `tool:transform` still fire.
|
|
331
|
+
*
|
|
332
|
+
* Requires a session (`createSession()`); without one, the map is a silent
|
|
333
|
+
* no-op since per-session state has nowhere to live. Tools with side
|
|
334
|
+
* effects or non-deterministic outputs (network, time, randomness) MUST
|
|
335
|
+
* NOT be listed — there is no safety net beyond the consumer's hasher.
|
|
336
|
+
*
|
|
337
|
+
* For MCP tools, key by the namespaced wire name (`mcp_<server>_<tool>`).
|
|
338
|
+
* Parallel mode (`toolExecution: 'parallel'`, the default) sees calls in
|
|
339
|
+
* the SAME assistant turn race against each other — none can dedup against
|
|
340
|
+
* a sibling that started in the same batch. Sequential mode honors order
|
|
341
|
+
* within a turn.
|
|
342
|
+
*
|
|
343
|
+
* **Cache policy**: only the most recent `(hash, result)` per tool is
|
|
344
|
+
* retained. Interleaved patterns (input A, input B, input A) miss on the
|
|
345
|
+
* second A because B overwrote it. Sufficient for the common spam-the-
|
|
346
|
+
* same-call loop; consumers needing a richer cache should hook
|
|
347
|
+
* `tool:gate` directly.
|
|
348
|
+
*
|
|
349
|
+
* Default: `undefined` (no per-tool dedup).
|
|
350
|
+
*/
|
|
351
|
+
dedupTools?: Record<string, (input: Record<string, unknown>) => string | undefined>;
|
|
232
352
|
/**
|
|
233
353
|
* Require `read_file` before `edit` / `multi_edit` on the same path, and
|
|
234
354
|
* reject edits when the file has changed on disk since the last read in
|
|
@@ -674,6 +794,18 @@ interface AnthropicParams {
|
|
|
674
794
|
* ```
|
|
675
795
|
*/
|
|
676
796
|
contextManagement?: AnthropicContextManagement;
|
|
797
|
+
/**
|
|
798
|
+
* Generic pass-through for fields on the Messages API request body that the
|
|
799
|
+
* SDK does not yet type. Spread into the request before the typed fields,
|
|
800
|
+
* so explicit options ({@link AnthropicParams.contextManagement} and the
|
|
801
|
+
* built-in fields like `model` / `tools` / `messages`) win on collision.
|
|
802
|
+
*
|
|
803
|
+
* Forward-compat escape hatch for new Anthropic betas — when a future flag
|
|
804
|
+
* ships before zidane has a dedicated typed knob, set it here without
|
|
805
|
+
* waiting on a release. Most fields will still need the matching beta in
|
|
806
|
+
* {@link AnthropicParams.extraBetas}.
|
|
807
|
+
*/
|
|
808
|
+
extraBodyParams?: Record<string, unknown>;
|
|
677
809
|
}
|
|
678
810
|
declare function anthropic(anthropicParams?: AnthropicParams): Provider;
|
|
679
811
|
|
|
@@ -796,6 +928,17 @@ interface OpenAICompatParams {
|
|
|
796
928
|
* Default: `false`. The `openrouter` wrapper sets this to `true`.
|
|
797
929
|
*/
|
|
798
930
|
cacheBreakpoints?: boolean;
|
|
931
|
+
/**
|
|
932
|
+
* Generic pass-through for fields on the Chat Completions request body that
|
|
933
|
+
* zidane does not yet type. Spread into the request before the typed core
|
|
934
|
+
* (model / messages / tools / max_tokens / stream / tool_choice), so
|
|
935
|
+
* explicit options always win on collision.
|
|
936
|
+
*
|
|
937
|
+
* Forward-compat escape hatch for endpoints that ship one-off fields ahead
|
|
938
|
+
* of zidane (e.g. OpenAI `reasoning_effort`, OpenRouter `provider` routing,
|
|
939
|
+
* vendor-specific `safety_level` knobs).
|
|
940
|
+
*/
|
|
941
|
+
extraBodyParams?: Record<string, unknown>;
|
|
799
942
|
}
|
|
800
943
|
/**
|
|
801
944
|
* Factory for any OpenAI-compatible HTTP endpoint.
|
|
@@ -1557,11 +1700,34 @@ interface AgentHooks {
|
|
|
1557
1700
|
turnId: string;
|
|
1558
1701
|
options: StreamOptions;
|
|
1559
1702
|
}) => void;
|
|
1703
|
+
/**
|
|
1704
|
+
* Fires after each assistant turn (before its tool-result follow-up
|
|
1705
|
+
* dispatches; the loop iterates back to a fresh `turn:before` once the
|
|
1706
|
+
* tool results are produced).
|
|
1707
|
+
*
|
|
1708
|
+
* `toolCounts.turn` — calls **emitted** by the model in this assistant
|
|
1709
|
+
* turn, keyed by canonical tool name. Reflects what the model asked for,
|
|
1710
|
+
* regardless of downstream gate outcome. Most useful for spotting per-turn
|
|
1711
|
+
* spikes ("the model called todowrite 4 times in one turn").
|
|
1712
|
+
*
|
|
1713
|
+
* `toolCounts.run` — cumulative running counter of **dispatched** calls
|
|
1714
|
+
* scoped to this `runId`, captured at fire time. Excludes calls that were
|
|
1715
|
+
* `block`ed by `tool:gate` handlers. Includes calls short-circuited via
|
|
1716
|
+
* `tool:gate` `result` substitution (the model still asked, the framework
|
|
1717
|
+
* just answered without the tool running). Resumed sessions start a fresh
|
|
1718
|
+
* run with empty counts.
|
|
1719
|
+
*
|
|
1720
|
+
* Both fields are frozen snapshots; mutate-safe.
|
|
1721
|
+
*/
|
|
1560
1722
|
'turn:after': (ctx: {
|
|
1561
1723
|
turn: number;
|
|
1562
1724
|
turnId: string;
|
|
1563
1725
|
usage: TurnUsage;
|
|
1564
1726
|
message: SessionTurn;
|
|
1727
|
+
toolCounts: {
|
|
1728
|
+
turn: Readonly<Record<string, number>>;
|
|
1729
|
+
run: Readonly<Record<string, number>>;
|
|
1730
|
+
};
|
|
1565
1731
|
}) => void;
|
|
1566
1732
|
'stream:text': (ctx: StreamHookContext & {
|
|
1567
1733
|
delta: string;
|
|
@@ -1575,17 +1741,53 @@ interface AgentHooks {
|
|
|
1575
1741
|
thinking: string;
|
|
1576
1742
|
}) => void;
|
|
1577
1743
|
'oauth:refresh': (ctx: OAuthRefreshHookContext) => void;
|
|
1744
|
+
/**
|
|
1745
|
+
* Fires before validation, `tool:before`, and `execute`. Two ways to
|
|
1746
|
+
* intercept:
|
|
1747
|
+
*
|
|
1748
|
+
* - Set `block = true` (with a `reason`) to refuse the call. The model
|
|
1749
|
+
* sees a `Blocked: <reason>` tool result; `tool:before` / `tool:after`
|
|
1750
|
+
* do **not** fire.
|
|
1751
|
+
* - Set `result` to substitute a successful tool_result and skip
|
|
1752
|
+
* execution. The model sees the substitute as a normal tool_result;
|
|
1753
|
+
* `tool:before` does not fire, but `tool:after` and `tool:transform`
|
|
1754
|
+
* do — so byte budgets, telemetry, and post-mutation hooks see the
|
|
1755
|
+
* substitute. Useful for cache hits, dedup, idempotency guards,
|
|
1756
|
+
* plan-mode synthetic acks.
|
|
1757
|
+
*
|
|
1758
|
+
* If multiple handlers along the chain set both `block` and `result`,
|
|
1759
|
+
* `block` wins — refusal beats substitution, so a policy gate
|
|
1760
|
+
* (skills allow-list, custom security) can always override an upstream
|
|
1761
|
+
* consumer's cache substitute. Mirrors the writable-`result` shape on
|
|
1762
|
+
* `tool:unknown` and `tool:error` so consumers learn one pattern.
|
|
1763
|
+
*
|
|
1764
|
+
* `runToolCounts` — frozen pre-call snapshot of per-tool dispatched
|
|
1765
|
+
* counts in this run. Use it to self-throttle, drive observability, or
|
|
1766
|
+
* implement budget guards. Counts every call that passed gate, including
|
|
1767
|
+
* dedup substitutes (Z19); excludes `block`ed calls.
|
|
1768
|
+
*
|
|
1769
|
+
* **Parallel mode** (`toolExecution: 'parallel'`, the default): the
|
|
1770
|
+
* snapshot is taken before any dispatches in the batch, so consumer
|
|
1771
|
+
* hooks reading `runToolCounts` see the pre-batch view. Built-in
|
|
1772
|
+
* budget / dedup middleware uses internal per-call reservation, so
|
|
1773
|
+
* `behavior.toolBudgets` enforces atomically even within a parallel
|
|
1774
|
+
* batch.
|
|
1775
|
+
*/
|
|
1578
1776
|
'tool:gate': (ctx: ToolHookContext & {
|
|
1579
1777
|
block: boolean;
|
|
1580
1778
|
reason: string;
|
|
1779
|
+
result?: string | ToolResultContent[];
|
|
1780
|
+
runToolCounts: Readonly<Record<string, number>>;
|
|
1581
1781
|
}) => void;
|
|
1582
1782
|
'tool:before': (ctx: ToolHookContext & {
|
|
1583
1783
|
coercions?: readonly string[];
|
|
1784
|
+
runToolCounts: Readonly<Record<string, number>>;
|
|
1584
1785
|
}) => void;
|
|
1585
1786
|
'tool:after': (ctx: ToolHookContext & {
|
|
1586
1787
|
result: string | ToolResultContent[];
|
|
1587
1788
|
outputBytes: number;
|
|
1588
1789
|
coercions?: readonly string[];
|
|
1790
|
+
runToolCounts: Readonly<Record<string, number>>;
|
|
1589
1791
|
}) => void;
|
|
1590
1792
|
/**
|
|
1591
1793
|
* Fires when a tool throws during execution. Mutate `result` to substitute a
|
|
@@ -1646,6 +1848,27 @@ interface AgentHooks {
|
|
|
1646
1848
|
'context:transform': (ctx: {
|
|
1647
1849
|
messages: SessionMessage[];
|
|
1648
1850
|
}) => void;
|
|
1851
|
+
/**
|
|
1852
|
+
* Fires per request, after `context:transform` and before the request goes
|
|
1853
|
+
* out. Mutating `ctx.system` updates the system prompt the provider sends
|
|
1854
|
+
* for this turn — useful for runtime-derived sections (e.g. listing files
|
|
1855
|
+
* already read in the session, surfacing live tool budgets, injecting
|
|
1856
|
+
* skill activation reminders).
|
|
1857
|
+
*
|
|
1858
|
+
* Cache breakpoints are applied inside the provider after this hook, so
|
|
1859
|
+
* mutations land in the cache key naturally — repeated turns with the
|
|
1860
|
+
* same derived system text still hit the cache.
|
|
1861
|
+
*
|
|
1862
|
+
* `messages` is read-only here; use `context:transform` for message
|
|
1863
|
+
* surgery. `session` is `undefined` when the run is sessionless.
|
|
1864
|
+
*/
|
|
1865
|
+
'system:transform': (ctx: {
|
|
1866
|
+
system: string;
|
|
1867
|
+
messages: readonly SessionMessage[];
|
|
1868
|
+
turn: number;
|
|
1869
|
+
turnId: string;
|
|
1870
|
+
session?: Session;
|
|
1871
|
+
}) => void;
|
|
1649
1872
|
'steer:inject': (ctx: {
|
|
1650
1873
|
message: string;
|
|
1651
1874
|
}) => void;
|
|
@@ -1673,6 +1896,7 @@ interface AgentHooks {
|
|
|
1673
1896
|
}) => void;
|
|
1674
1897
|
'child:tool:before': (ctx: ToolHookContext & {
|
|
1675
1898
|
coercions?: readonly string[];
|
|
1899
|
+
runToolCounts: Readonly<Record<string, number>>;
|
|
1676
1900
|
childId: string;
|
|
1677
1901
|
depth: number;
|
|
1678
1902
|
}) => void;
|
|
@@ -1680,6 +1904,7 @@ interface AgentHooks {
|
|
|
1680
1904
|
result: string | ToolResultContent[];
|
|
1681
1905
|
outputBytes: number;
|
|
1682
1906
|
coercions?: readonly string[];
|
|
1907
|
+
runToolCounts: Readonly<Record<string, number>>;
|
|
1683
1908
|
childId: string;
|
|
1684
1909
|
depth: number;
|
|
1685
1910
|
}) => void;
|
|
@@ -1693,6 +1918,10 @@ interface AgentHooks {
|
|
|
1693
1918
|
turnId: string;
|
|
1694
1919
|
usage: TurnUsage;
|
|
1695
1920
|
message: SessionTurn;
|
|
1921
|
+
toolCounts: {
|
|
1922
|
+
turn: Readonly<Record<string, number>>;
|
|
1923
|
+
run: Readonly<Record<string, number>>;
|
|
1924
|
+
};
|
|
1696
1925
|
childId: string;
|
|
1697
1926
|
depth: number;
|
|
1698
1927
|
}) => void;
|
|
@@ -1732,9 +1961,22 @@ interface AgentHooks {
|
|
|
1732
1961
|
ok: false;
|
|
1733
1962
|
error: Error;
|
|
1734
1963
|
})) => void;
|
|
1964
|
+
/**
|
|
1965
|
+
* MCP-side counterpart of `tool:gate`. Same shape: set `block` to refuse,
|
|
1966
|
+
* set `result` to substitute a successful payload and skip the upstream
|
|
1967
|
+
* MCP `callTool`. When both are set across the handler chain, `block` wins.
|
|
1968
|
+
*
|
|
1969
|
+
* Fires INSIDE the MCP wrapper's `execute`, after the loop's `tool:gate`
|
|
1970
|
+
* already ran. Does **not** carry `runToolCounts` — those are loop-level
|
|
1971
|
+
* and already exposed on `tool:gate` for MCP tools (which are registered
|
|
1972
|
+
* as agent tools under their namespaced name `mcp_<server>_<tool>`). Use
|
|
1973
|
+
* `tool:gate` for budget / dedup logic; reserve `mcp:tool:gate` for
|
|
1974
|
+
* MCP-specific concerns (per-server routing, transport-aware refusals).
|
|
1975
|
+
*/
|
|
1735
1976
|
'mcp:tool:gate': (ctx: McpToolHookContext & {
|
|
1736
1977
|
block: boolean;
|
|
1737
1978
|
reason: string;
|
|
1979
|
+
result?: string | ToolResultContent[];
|
|
1738
1980
|
}) => void;
|
|
1739
1981
|
'mcp:tool:before': (ctx: McpToolHookContext) => void;
|
|
1740
1982
|
'mcp:tool:after': (ctx: McpToolHookContext & {
|
|
@@ -1785,6 +2027,24 @@ interface AgentHooks {
|
|
|
1785
2027
|
bytes: number;
|
|
1786
2028
|
budget: number;
|
|
1787
2029
|
}) => void;
|
|
2030
|
+
/**
|
|
2031
|
+
* Fires when a per-tool budget configured via `behavior.toolBudgets` is
|
|
2032
|
+
* exceeded for a specific tool. `mode` reflects how the framework reacted:
|
|
2033
|
+
* `'steer'` lets the call run and queues a post-turn nudge; `'block'`
|
|
2034
|
+
* refuses the call outright with `Blocked: <message>`.
|
|
2035
|
+
*
|
|
2036
|
+
* `count` is the run-cumulative dispatched count just before this call.
|
|
2037
|
+
* Use `turnId` to correlate with `turn:after` if you need the integer turn
|
|
2038
|
+
* index. Distinct from `budget:exceeded` (byte-level) so consumers can
|
|
2039
|
+
* subscribe specifically; both can fire in the same turn.
|
|
2040
|
+
*/
|
|
2041
|
+
'tool-budget:exceeded': (ctx: {
|
|
2042
|
+
tool: string;
|
|
2043
|
+
count: number;
|
|
2044
|
+
max: number;
|
|
2045
|
+
turnId: string;
|
|
2046
|
+
mode: 'steer' | 'block';
|
|
2047
|
+
}) => void;
|
|
1788
2048
|
'agent:abort': (ctx: object) => void;
|
|
1789
2049
|
'agent:done': (ctx: AgentStats) => void;
|
|
1790
2050
|
'session:start': (ctx: SessionHookContext & {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from "./chunk-IUBBVF53.js";
|
|
12
12
|
import {
|
|
13
13
|
connectMcpServers
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-7H34OFDA.js";
|
|
15
15
|
import {
|
|
16
16
|
toolOutputByteLength
|
|
17
17
|
} from "./chunk-JH6IAAFA.js";
|
|
@@ -197,6 +197,17 @@ function getReadState(session) {
|
|
|
197
197
|
}
|
|
198
198
|
return map;
|
|
199
199
|
}
|
|
200
|
+
var TOOL_DEDUP_STATE = /* @__PURE__ */ new WeakMap();
|
|
201
|
+
function getToolDedupState(session) {
|
|
202
|
+
if (!session)
|
|
203
|
+
return void 0;
|
|
204
|
+
let map = TOOL_DEDUP_STATE.get(session);
|
|
205
|
+
if (!map) {
|
|
206
|
+
map = /* @__PURE__ */ new Map();
|
|
207
|
+
TOOL_DEDUP_STATE.set(session, map);
|
|
208
|
+
}
|
|
209
|
+
return map;
|
|
210
|
+
}
|
|
200
211
|
function hashContent(text) {
|
|
201
212
|
let h = 2166136261;
|
|
202
213
|
for (let i = 0; i < text.length; i++) {
|
|
@@ -1279,6 +1290,59 @@ function rewriteMessagesToWire(messages, maps) {
|
|
|
1279
1290
|
return messages.map((msg) => ({ ...msg, content: rewriteContentToWire(msg.content, maps) }));
|
|
1280
1291
|
}
|
|
1281
1292
|
|
|
1293
|
+
// src/dedup-tools.ts
|
|
1294
|
+
function installDedupToolsGate(hooks, getDedupTools, getSession) {
|
|
1295
|
+
const pending = /* @__PURE__ */ new Map();
|
|
1296
|
+
function pendingKey(callId, name) {
|
|
1297
|
+
return `${callId}::${name}`;
|
|
1298
|
+
}
|
|
1299
|
+
function gateHandler(ctx) {
|
|
1300
|
+
if (ctx.block || ctx.result !== void 0)
|
|
1301
|
+
return;
|
|
1302
|
+
const dedupTools = getDedupTools();
|
|
1303
|
+
const hasher = dedupTools?.[ctx.name];
|
|
1304
|
+
if (!hasher)
|
|
1305
|
+
return;
|
|
1306
|
+
const session = getSession();
|
|
1307
|
+
const state = getToolDedupState(session);
|
|
1308
|
+
if (!state)
|
|
1309
|
+
return;
|
|
1310
|
+
let hash;
|
|
1311
|
+
try {
|
|
1312
|
+
hash = hasher(ctx.input);
|
|
1313
|
+
} catch {
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
if (typeof hash !== "string" || hash.length === 0)
|
|
1317
|
+
return;
|
|
1318
|
+
const prior = state.get(ctx.name);
|
|
1319
|
+
if (prior && prior.hash === hash) {
|
|
1320
|
+
ctx.result = prior.result;
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
pending.set(pendingKey(ctx.callId, ctx.name), hash);
|
|
1324
|
+
}
|
|
1325
|
+
function afterHandler(ctx) {
|
|
1326
|
+
const key = pendingKey(ctx.callId, ctx.name);
|
|
1327
|
+
const hash = pending.get(key);
|
|
1328
|
+
if (hash === void 0)
|
|
1329
|
+
return;
|
|
1330
|
+
pending.delete(key);
|
|
1331
|
+
const session = getSession();
|
|
1332
|
+
const state = getToolDedupState(session);
|
|
1333
|
+
if (!state)
|
|
1334
|
+
return;
|
|
1335
|
+
state.set(ctx.name, { hash, result: ctx.result });
|
|
1336
|
+
}
|
|
1337
|
+
const unregisterGate = hooks.hook("tool:gate", gateHandler);
|
|
1338
|
+
const unregisterAfter = hooks.hook("tool:after", afterHandler);
|
|
1339
|
+
return function uninstall() {
|
|
1340
|
+
unregisterGate();
|
|
1341
|
+
unregisterAfter();
|
|
1342
|
+
pending.clear();
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1282
1346
|
// src/tools/validation.ts
|
|
1283
1347
|
var TRUE_STRINGS = /* @__PURE__ */ new Set(["true", "True", "TRUE", "1", "yes", "Yes", "YES"]);
|
|
1284
1348
|
var FALSE_STRINGS = /* @__PURE__ */ new Set(["false", "False", "FALSE", "0", "no", "No", "NO"]);
|
|
@@ -1434,6 +1498,24 @@ function formatValue(value) {
|
|
|
1434
1498
|
|
|
1435
1499
|
// src/loop.ts
|
|
1436
1500
|
var IMAGE_OMITTED_MARKER = "[image omitted \u2014 model does not support vision]";
|
|
1501
|
+
function applyThinkingDecay(baseBudget, decay, turn) {
|
|
1502
|
+
if (typeof baseBudget !== "number" || baseBudget <= 0)
|
|
1503
|
+
return baseBudget;
|
|
1504
|
+
if (!decay)
|
|
1505
|
+
return baseBudget;
|
|
1506
|
+
let raw;
|
|
1507
|
+
if (typeof decay === "function") {
|
|
1508
|
+
raw = decay(turn, baseBudget);
|
|
1509
|
+
} else {
|
|
1510
|
+
if (turn <= decay.afterTurn)
|
|
1511
|
+
return baseBudget;
|
|
1512
|
+
const k = turn - decay.afterTurn;
|
|
1513
|
+
raw = Math.max(decay.floor, baseBudget * decay.factor ** k);
|
|
1514
|
+
}
|
|
1515
|
+
if (Number.isNaN(raw) || raw <= 0)
|
|
1516
|
+
return 0;
|
|
1517
|
+
return Math.round(Math.min(baseBudget, raw));
|
|
1518
|
+
}
|
|
1437
1519
|
function turnsToMessages(turns) {
|
|
1438
1520
|
return turns.filter((t) => t.role !== "system").map((t) => ({ role: t.role, content: t.content }));
|
|
1439
1521
|
}
|
|
@@ -1589,6 +1671,7 @@ async function executeTurn(ctx, turn) {
|
|
|
1589
1671
|
const keep = typeof ctx.compactKeepTurns === "number" && ctx.compactKeepTurns >= 0 ? ctx.compactKeepTurns : 4;
|
|
1590
1672
|
sanitizedMessages = applyTailCompaction(sanitizedMessages, threshold, keep);
|
|
1591
1673
|
}
|
|
1674
|
+
const effectiveThinkingBudget = applyThinkingDecay(ctx.thinkingBudget, ctx.thinkingDecay, turn);
|
|
1592
1675
|
const streamOptions = {
|
|
1593
1676
|
model: ctx.model,
|
|
1594
1677
|
system: ctx.system,
|
|
@@ -1596,13 +1679,22 @@ async function executeTurn(ctx, turn) {
|
|
|
1596
1679
|
messages: sanitizedMessages,
|
|
1597
1680
|
maxTokens: ctx.maxTokens ?? 16384,
|
|
1598
1681
|
thinking: ctx.thinking,
|
|
1599
|
-
thinkingBudget:
|
|
1682
|
+
thinkingBudget: effectiveThinkingBudget,
|
|
1600
1683
|
cache: ctx.cache ?? true,
|
|
1601
1684
|
signal: ctx.signal
|
|
1602
1685
|
};
|
|
1603
1686
|
const transformCtx = { messages: streamOptions.messages };
|
|
1604
1687
|
await ctx.hooks.callHook("context:transform", transformCtx);
|
|
1605
1688
|
streamOptions.messages = transformCtx.messages;
|
|
1689
|
+
const systemCtx = {
|
|
1690
|
+
system: streamOptions.system,
|
|
1691
|
+
messages: streamOptions.messages,
|
|
1692
|
+
turn,
|
|
1693
|
+
turnId,
|
|
1694
|
+
...ctx.session ? { session: ctx.session } : {}
|
|
1695
|
+
};
|
|
1696
|
+
await ctx.hooks.callHook("system:transform", systemCtx);
|
|
1697
|
+
streamOptions.system = systemCtx.system;
|
|
1606
1698
|
await ctx.hooks.callHook("turn:before", { turn, turnId, options: streamOptions });
|
|
1607
1699
|
let currentText = "";
|
|
1608
1700
|
let currentThinking = "";
|
|
@@ -1635,7 +1727,13 @@ async function executeTurn(ctx, turn) {
|
|
|
1635
1727
|
createdAt: Date.now()
|
|
1636
1728
|
};
|
|
1637
1729
|
ctx.turns.push(errorTurn);
|
|
1638
|
-
await ctx.hooks.callHook("turn:after", {
|
|
1730
|
+
await ctx.hooks.callHook("turn:after", {
|
|
1731
|
+
turn,
|
|
1732
|
+
turnId,
|
|
1733
|
+
usage: errorUsage,
|
|
1734
|
+
message: errorTurn,
|
|
1735
|
+
toolCounts: { turn: Object.freeze({}), run: Object.freeze({ ...ctx.runToolCounts }) }
|
|
1736
|
+
});
|
|
1639
1737
|
throw wrapProviderError(err, ctx);
|
|
1640
1738
|
}
|
|
1641
1739
|
if (currentText) {
|
|
@@ -1658,7 +1756,16 @@ async function executeTurn(ctx, turn) {
|
|
|
1658
1756
|
createdAt: Date.now()
|
|
1659
1757
|
};
|
|
1660
1758
|
ctx.turns.push(assistantTurn);
|
|
1661
|
-
|
|
1759
|
+
const turnCounts = {};
|
|
1760
|
+
for (const tc of canonicalToolCalls)
|
|
1761
|
+
turnCounts[tc.name] = (turnCounts[tc.name] ?? 0) + 1;
|
|
1762
|
+
await ctx.hooks.callHook("turn:after", {
|
|
1763
|
+
turn,
|
|
1764
|
+
turnId,
|
|
1765
|
+
usage: result.usage,
|
|
1766
|
+
message: assistantTurn,
|
|
1767
|
+
toolCounts: { turn: Object.freeze(turnCounts), run: Object.freeze({ ...ctx.runToolCounts }) }
|
|
1768
|
+
});
|
|
1662
1769
|
if (result.done) {
|
|
1663
1770
|
if (ctx.schema && !ctx.signal.aborted) {
|
|
1664
1771
|
const outputSpec = {
|
|
@@ -1771,6 +1878,7 @@ async function executeSingleTool(ctx, call, turnId) {
|
|
|
1771
1878
|
const toolDef = ctx.tools[call.name];
|
|
1772
1879
|
const callId = call.id;
|
|
1773
1880
|
const displayName = toWireName(call.name, ctx.aliasMaps);
|
|
1881
|
+
const runToolCounts = Object.freeze({ ...ctx.runToolCounts });
|
|
1774
1882
|
const gateCtx = {
|
|
1775
1883
|
turnId,
|
|
1776
1884
|
callId,
|
|
@@ -1778,12 +1886,27 @@ async function executeSingleTool(ctx, call, turnId) {
|
|
|
1778
1886
|
displayName,
|
|
1779
1887
|
input: call.input,
|
|
1780
1888
|
block: false,
|
|
1781
|
-
reason: "Tool execution was blocked"
|
|
1889
|
+
reason: "Tool execution was blocked",
|
|
1890
|
+
runToolCounts
|
|
1782
1891
|
};
|
|
1783
1892
|
await ctx.hooks.callHook("tool:gate", gateCtx);
|
|
1784
1893
|
if (gateCtx.block) {
|
|
1785
1894
|
return { result: { id: callId, content: `Blocked: ${gateCtx.reason}` } };
|
|
1786
1895
|
}
|
|
1896
|
+
ctx.runToolCounts[call.name] = (ctx.runToolCounts[call.name] ?? 0) + 1;
|
|
1897
|
+
if (gateCtx.result !== void 0) {
|
|
1898
|
+
const substitute = await emitToolResult(ctx, {
|
|
1899
|
+
turnId,
|
|
1900
|
+
callId,
|
|
1901
|
+
name: call.name,
|
|
1902
|
+
displayName,
|
|
1903
|
+
input: gateCtx.input,
|
|
1904
|
+
output: gateCtx.result,
|
|
1905
|
+
isError: false,
|
|
1906
|
+
runToolCounts
|
|
1907
|
+
});
|
|
1908
|
+
return { result: { id: callId, content: substitute } };
|
|
1909
|
+
}
|
|
1787
1910
|
let effectiveInput = gateCtx.input;
|
|
1788
1911
|
if (!toolDef) {
|
|
1789
1912
|
const unknownCtx = {
|
|
@@ -1841,6 +1964,7 @@ async function executeSingleTool(ctx, call, turnId) {
|
|
|
1841
1964
|
name: call.name,
|
|
1842
1965
|
displayName,
|
|
1843
1966
|
input: effectiveInput,
|
|
1967
|
+
runToolCounts,
|
|
1844
1968
|
...coercions ? { coercions } : {}
|
|
1845
1969
|
});
|
|
1846
1970
|
let output;
|
|
@@ -1880,12 +2004,29 @@ async function executeSingleTool(ctx, call, turnId) {
|
|
|
1880
2004
|
output = errorCtx.result ?? `Tool error: ${error.message}`;
|
|
1881
2005
|
isError = true;
|
|
1882
2006
|
}
|
|
1883
|
-
const
|
|
2007
|
+
const finalOutput = await emitToolResult(ctx, {
|
|
1884
2008
|
turnId,
|
|
1885
2009
|
callId,
|
|
1886
2010
|
name: call.name,
|
|
1887
2011
|
displayName,
|
|
1888
2012
|
input: effectiveInput,
|
|
2013
|
+
output,
|
|
2014
|
+
isError,
|
|
2015
|
+
runToolCounts,
|
|
2016
|
+
...coercions ? { coercions } : {}
|
|
2017
|
+
});
|
|
2018
|
+
return { result: { id: callId, content: finalOutput } };
|
|
2019
|
+
}
|
|
2020
|
+
async function emitToolResult(ctx, params) {
|
|
2021
|
+
const { turnId, callId, name, displayName, input, runToolCounts, coercions } = params;
|
|
2022
|
+
let output = params.output;
|
|
2023
|
+
let isError = params.isError;
|
|
2024
|
+
const transformCtx = {
|
|
2025
|
+
turnId,
|
|
2026
|
+
callId,
|
|
2027
|
+
name,
|
|
2028
|
+
displayName,
|
|
2029
|
+
input,
|
|
1889
2030
|
result: output,
|
|
1890
2031
|
isError,
|
|
1891
2032
|
outputBytes: toolOutputByteLength(output),
|
|
@@ -1898,14 +2039,15 @@ async function executeSingleTool(ctx, call, turnId) {
|
|
|
1898
2039
|
await ctx.hooks.callHook("tool:after", {
|
|
1899
2040
|
turnId,
|
|
1900
2041
|
callId,
|
|
1901
|
-
name
|
|
2042
|
+
name,
|
|
1902
2043
|
displayName,
|
|
1903
|
-
input
|
|
2044
|
+
input,
|
|
1904
2045
|
result: output,
|
|
1905
2046
|
outputBytes: toolOutputByteLength(output),
|
|
2047
|
+
runToolCounts,
|
|
1906
2048
|
...coercions ? { coercions } : {}
|
|
1907
2049
|
});
|
|
1908
|
-
return
|
|
2050
|
+
return output;
|
|
1909
2051
|
}
|
|
1910
2052
|
async function executeToolsSequential(ctx, toolCalls, turnId) {
|
|
1911
2053
|
const results = [];
|
|
@@ -2014,6 +2156,81 @@ function buildPromptMessage(provider, parts) {
|
|
|
2014
2156
|
return defaultPromptMessage(parts);
|
|
2015
2157
|
}
|
|
2016
2158
|
|
|
2159
|
+
// src/tool-budgets.ts
|
|
2160
|
+
function installToolBudgetsGate(hooks, getToolBudgets, enqueueSteer) {
|
|
2161
|
+
const steeredOnce = /* @__PURE__ */ new Set();
|
|
2162
|
+
const approvedCounts = {};
|
|
2163
|
+
async function gateHandler(ctx) {
|
|
2164
|
+
if (ctx.block || ctx.result !== void 0)
|
|
2165
|
+
return;
|
|
2166
|
+
const toolBudgets = getToolBudgets();
|
|
2167
|
+
const budget = toolBudgets?.[ctx.name];
|
|
2168
|
+
if (!budget)
|
|
2169
|
+
return;
|
|
2170
|
+
const max = budget.max;
|
|
2171
|
+
if (typeof max !== "number" || max <= 0)
|
|
2172
|
+
return;
|
|
2173
|
+
const count = approvedCounts[ctx.name] ?? 0;
|
|
2174
|
+
if (count < max) {
|
|
2175
|
+
approvedCounts[ctx.name] = count + 1;
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
2178
|
+
const onExceed = budget.onExceed ?? "steer";
|
|
2179
|
+
let mode;
|
|
2180
|
+
let message;
|
|
2181
|
+
if (typeof onExceed === "function") {
|
|
2182
|
+
try {
|
|
2183
|
+
const out = onExceed({ tool: ctx.name, count, max });
|
|
2184
|
+
mode = out.mode;
|
|
2185
|
+
message = out.message;
|
|
2186
|
+
} catch {
|
|
2187
|
+
mode = "steer";
|
|
2188
|
+
message = defaultSteerMessage(ctx.name, count, max);
|
|
2189
|
+
}
|
|
2190
|
+
} else if (onExceed === "block") {
|
|
2191
|
+
mode = "block";
|
|
2192
|
+
message = defaultBlockMessage(ctx.name, max);
|
|
2193
|
+
} else {
|
|
2194
|
+
mode = "steer";
|
|
2195
|
+
message = defaultSteerMessage(ctx.name, count, max);
|
|
2196
|
+
}
|
|
2197
|
+
if (mode === "block") {
|
|
2198
|
+
ctx.block = true;
|
|
2199
|
+
ctx.reason = message;
|
|
2200
|
+
await hooks.callHook("tool-budget:exceeded", {
|
|
2201
|
+
tool: ctx.name,
|
|
2202
|
+
count,
|
|
2203
|
+
max,
|
|
2204
|
+
turnId: ctx.turnId,
|
|
2205
|
+
mode: "block"
|
|
2206
|
+
});
|
|
2207
|
+
return;
|
|
2208
|
+
}
|
|
2209
|
+
if (!steeredOnce.has(ctx.name)) {
|
|
2210
|
+
steeredOnce.add(ctx.name);
|
|
2211
|
+
enqueueSteer(message);
|
|
2212
|
+
await hooks.callHook("tool-budget:exceeded", {
|
|
2213
|
+
tool: ctx.name,
|
|
2214
|
+
count,
|
|
2215
|
+
max,
|
|
2216
|
+
turnId: ctx.turnId,
|
|
2217
|
+
mode: "steer"
|
|
2218
|
+
});
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
const unregister = hooks.hook("tool:gate", gateHandler);
|
|
2222
|
+
return function uninstall() {
|
|
2223
|
+
unregister();
|
|
2224
|
+
steeredOnce.clear();
|
|
2225
|
+
};
|
|
2226
|
+
}
|
|
2227
|
+
function defaultSteerMessage(tool, count, max) {
|
|
2228
|
+
return `[Tool budget reached: '${tool}' has been called ${count} times this run (cap: ${max}). Avoid calling it again unless strictly necessary; commit to a result and move on.]`;
|
|
2229
|
+
}
|
|
2230
|
+
function defaultBlockMessage(tool, max) {
|
|
2231
|
+
return `Tool '${tool}' has reached its per-run budget of ${max} calls; further invocations are refused.`;
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2017
2234
|
// src/agent.ts
|
|
2018
2235
|
var HOOK_EVENT_NAMES = [
|
|
2019
2236
|
"system:before",
|
|
@@ -2032,6 +2249,7 @@ var HOOK_EVENT_NAMES = [
|
|
|
2032
2249
|
"validation:reject",
|
|
2033
2250
|
"validation:coerce",
|
|
2034
2251
|
"context:transform",
|
|
2252
|
+
"system:transform",
|
|
2035
2253
|
"steer:inject",
|
|
2036
2254
|
"spawn:before",
|
|
2037
2255
|
"spawn:complete",
|
|
@@ -2060,6 +2278,7 @@ var HOOK_EVENT_NAMES = [
|
|
|
2060
2278
|
"usage",
|
|
2061
2279
|
"output",
|
|
2062
2280
|
"budget:exceeded",
|
|
2281
|
+
"tool-budget:exceeded",
|
|
2063
2282
|
"agent:abort",
|
|
2064
2283
|
"agent:done",
|
|
2065
2284
|
"session:start",
|
|
@@ -2083,7 +2302,12 @@ function resolveBehavior(agentBehavior, runBehavior) {
|
|
|
2083
2302
|
toolOutputBudget: runBehavior?.toolOutputBudget ?? agentBehavior?.toolOutputBudget,
|
|
2084
2303
|
compactStrategy: runBehavior?.compactStrategy ?? agentBehavior?.compactStrategy ?? "off",
|
|
2085
2304
|
compactThreshold: runBehavior?.compactThreshold ?? agentBehavior?.compactThreshold,
|
|
2086
|
-
compactKeepTurns: runBehavior?.compactKeepTurns ?? agentBehavior?.compactKeepTurns
|
|
2305
|
+
compactKeepTurns: runBehavior?.compactKeepTurns ?? agentBehavior?.compactKeepTurns,
|
|
2306
|
+
thinkingDecay: runBehavior?.thinkingDecay ?? agentBehavior?.thinkingDecay,
|
|
2307
|
+
dedupReads: runBehavior?.dedupReads ?? agentBehavior?.dedupReads,
|
|
2308
|
+
dedupTools: runBehavior?.dedupTools ?? agentBehavior?.dedupTools,
|
|
2309
|
+
requireReadBeforeEdit: runBehavior?.requireReadBeforeEdit ?? agentBehavior?.requireReadBeforeEdit,
|
|
2310
|
+
toolBudgets: runBehavior?.toolBudgets ?? agentBehavior?.toolBudgets
|
|
2087
2311
|
};
|
|
2088
2312
|
}
|
|
2089
2313
|
function createAgent({ provider, name: agentName, system: agentSystem, tools: agentTools, toolAliases, behavior: agentBehavior, execution, mcpServers, session, skills: agentSkills, mcpConnector, eager }) {
|
|
@@ -2206,7 +2430,8 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
2206
2430
|
}
|
|
2207
2431
|
const thinking = options.thinking ?? "off";
|
|
2208
2432
|
const model = options.model ?? provider.meta.defaultModel;
|
|
2209
|
-
const
|
|
2433
|
+
const resolvedBehavior = resolveBehavior(agentBehavior, options.behavior);
|
|
2434
|
+
const { toolExecution, maxTurns, maxTokens, thinkingBudget, schema, cache, toolOutputBudget, compactStrategy, compactThreshold, compactKeepTurns, thinkingDecay, dedupTools, toolBudgets } = resolvedBehavior;
|
|
2210
2435
|
let system = options.system || agentSystem || "You are a helpful assistant.";
|
|
2211
2436
|
if (skillsCatalog) {
|
|
2212
2437
|
system = `${system}
|
|
@@ -2306,6 +2531,16 @@ ${skillsCatalog}`;
|
|
|
2306
2531
|
await hooks.callHook("session:end", { sessionId: session.id, runId, status, turnRange: [runTurnStart, turns.length - 1] });
|
|
2307
2532
|
}
|
|
2308
2533
|
const uninstallAllowedToolsGate = installAllowedToolsGate(hooks, skillActivationState);
|
|
2534
|
+
const uninstallToolBudgets = installToolBudgetsGate(
|
|
2535
|
+
hooks,
|
|
2536
|
+
() => toolBudgets,
|
|
2537
|
+
(msg) => steeringQueue.push(msg)
|
|
2538
|
+
);
|
|
2539
|
+
const uninstallDedupTools = installDedupToolsGate(
|
|
2540
|
+
hooks,
|
|
2541
|
+
() => dedupTools,
|
|
2542
|
+
() => session ?? void 0
|
|
2543
|
+
);
|
|
2309
2544
|
const runStartMs = Date.now();
|
|
2310
2545
|
const runDepth = typeof options.depth === "number" ? options.depth : 0;
|
|
2311
2546
|
try {
|
|
@@ -2318,7 +2553,10 @@ ${skillsCatalog}`;
|
|
|
2318
2553
|
agentToolAliases: toolAliases,
|
|
2319
2554
|
agentMcpServers: mcpServers,
|
|
2320
2555
|
agentSkills,
|
|
2321
|
-
|
|
2556
|
+
// Forward the resolved view (agent + run merged) so per-run overrides
|
|
2557
|
+
// of `dedupReads` / `requireReadBeforeEdit` / etc. are visible to
|
|
2558
|
+
// tools via `ToolContext.behavior`.
|
|
2559
|
+
agentBehavior: resolvedBehavior,
|
|
2322
2560
|
tools,
|
|
2323
2561
|
formattedTools,
|
|
2324
2562
|
aliasMaps,
|
|
@@ -2345,7 +2583,9 @@ ${skillsCatalog}`;
|
|
|
2345
2583
|
compactStrategy,
|
|
2346
2584
|
compactThreshold,
|
|
2347
2585
|
compactKeepTurns,
|
|
2348
|
-
|
|
2586
|
+
...thinkingDecay !== void 0 ? { thinkingDecay } : {},
|
|
2587
|
+
runStartMs,
|
|
2588
|
+
runToolCounts: {}
|
|
2349
2589
|
});
|
|
2350
2590
|
const finalStats = {
|
|
2351
2591
|
...stats,
|
|
@@ -2387,6 +2627,8 @@ ${skillsCatalog}`;
|
|
|
2387
2627
|
} finally {
|
|
2388
2628
|
await deactivateAllSkills();
|
|
2389
2629
|
uninstallAllowedToolsGate();
|
|
2630
|
+
uninstallDedupTools();
|
|
2631
|
+
uninstallToolBudgets();
|
|
2390
2632
|
unregisterSpawnHook();
|
|
2391
2633
|
unregisterSessionSync?.();
|
|
2392
2634
|
for (const unregister of perRunUnregisters)
|
|
@@ -259,6 +259,32 @@ function buildMcpToolDef(config, client, tool, namespacedName, hooks) {
|
|
|
259
259
|
if (gateCtx.block)
|
|
260
260
|
return `Blocked: ${gateCtx.reason}`;
|
|
261
261
|
const effectiveInput = gateCtx.input;
|
|
262
|
+
if (gateCtx.result !== void 0) {
|
|
263
|
+
let substitute = gateCtx.result;
|
|
264
|
+
const transformCtx = {
|
|
265
|
+
turnId,
|
|
266
|
+
callId,
|
|
267
|
+
server: config.name,
|
|
268
|
+
tool: tool.name,
|
|
269
|
+
displayName,
|
|
270
|
+
input: effectiveInput,
|
|
271
|
+
result: substitute,
|
|
272
|
+
outputBytes: toolOutputByteLength(substitute)
|
|
273
|
+
};
|
|
274
|
+
await hooks?.callHook("mcp:tool:transform", transformCtx);
|
|
275
|
+
substitute = transformCtx.result;
|
|
276
|
+
await hooks?.callHook("mcp:tool:after", {
|
|
277
|
+
turnId,
|
|
278
|
+
callId,
|
|
279
|
+
server: config.name,
|
|
280
|
+
tool: tool.name,
|
|
281
|
+
displayName,
|
|
282
|
+
input: effectiveInput,
|
|
283
|
+
result: substitute,
|
|
284
|
+
outputBytes: toolOutputByteLength(substitute)
|
|
285
|
+
});
|
|
286
|
+
return substitute;
|
|
287
|
+
}
|
|
262
288
|
await hooks?.callHook("mcp:tool:before", {
|
|
263
289
|
turnId,
|
|
264
290
|
callId,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
toAnthropic,
|
|
6
6
|
toolResultsMessage,
|
|
7
7
|
userMessage
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-YQ7LY6CL.js";
|
|
9
9
|
import {
|
|
10
10
|
matchesContextExceeded
|
|
11
11
|
} from "./chunk-LNN5UTS2.js";
|
|
@@ -437,6 +437,11 @@ function anthropic(anthropicParams) {
|
|
|
437
437
|
const thinking = options.thinking ?? "off";
|
|
438
438
|
const modelId = options.model;
|
|
439
439
|
const params = {
|
|
440
|
+
// Forward-compat escape hatch for un-typed beta fields. Spread first so
|
|
441
|
+
// the typed core (model / max_tokens / system / tools / messages /
|
|
442
|
+
// stream) and the explicit `context_management` below override on
|
|
443
|
+
// collision — explicit always wins.
|
|
444
|
+
...anthropicParams?.extraBodyParams ?? {},
|
|
440
445
|
model: modelId,
|
|
441
446
|
max_tokens: options.maxTokens,
|
|
442
447
|
system,
|
|
@@ -393,6 +393,9 @@ function openaiCompat(params) {
|
|
|
393
393
|
}
|
|
394
394
|
const maxTokens = options.thinkingBudget ? options.thinkingBudget + options.maxTokens : options.maxTokens;
|
|
395
395
|
const body = {
|
|
396
|
+
// Spread first so the typed core below wins on collision — explicit
|
|
397
|
+
// always overrides generic.
|
|
398
|
+
...params.extraBodyParams ?? {},
|
|
396
399
|
model: modelId,
|
|
397
400
|
messages,
|
|
398
401
|
max_tokens: maxTokens,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { d as AgentHooks } from './agent-
|
|
2
|
-
export { ac as ActivationVia, ad 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, ae as DeactivationReason, af as FileMapAdapter, ag as FileMapStoreOptions, I as ImageContent, M as McpConnection, p as McpServerConfig, q as McpToolHookContext, O as OAuthRefreshHookContext, ah as OpenAICompatAuthHeader, ai as OpenAICompatHttpError, aj 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, ak as SkillActivationState, al as SkillActivationStateOptions, K as SkillConfig, am as SkillDiagnostic, L as SkillResource, an 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, ao as anthropic, ap as autoDetectAndConvert, aq as cerebras, ar as classifyOpenAICompatError, as as connectMcpServers, at as createAgent, au as createFileMapStore, av as createMemoryStore, aw as createRemoteStore, ax as createSession, ay as createSkillActivationState, az as fromAnthropic, aA as fromOpenAI, aB as loadSession, aC as mapOAIFinishReason, a9 as matchesContextExceeded, aD as normalizeMcpBlocks, aE as normalizeMcpServers, aF as openai, aG as openaiCompat, aH as openrouter, aI as resultToString, aJ as toAnthropic, aK as toOpenAI, aL as toTypedError, aa as toolOutputByteLength, ab as toolResultToText } from './agent-
|
|
1
|
+
import { d as AgentHooks } from './agent-C9q5VMGa.js';
|
|
2
|
+
export { ac as ActivationVia, ad 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, ae as DeactivationReason, af as FileMapAdapter, ag as FileMapStoreOptions, I as ImageContent, M as McpConnection, p as McpServerConfig, q as McpToolHookContext, O as OAuthRefreshHookContext, ah as OpenAICompatAuthHeader, ai as OpenAICompatHttpError, aj 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, ak as SkillActivationState, al as SkillActivationStateOptions, K as SkillConfig, am as SkillDiagnostic, L as SkillResource, an 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, ao as anthropic, ap as autoDetectAndConvert, aq as cerebras, ar as classifyOpenAICompatError, as as connectMcpServers, at as createAgent, au as createFileMapStore, av as createMemoryStore, aw as createRemoteStore, ax as createSession, ay as createSkillActivationState, az as fromAnthropic, aA as fromOpenAI, aB as loadSession, aC as mapOAIFinishReason, a9 as matchesContextExceeded, aD as normalizeMcpBlocks, aE as normalizeMcpServers, aF as openai, aG as openaiCompat, aH as openrouter, aI as resultToString, aJ as toAnthropic, aK as toOpenAI, aL as toTypedError, aa as toolOutputByteLength, ab as toolResultToText } from './agent-C9q5VMGa.js';
|
|
3
3
|
export { createDockerContext, createProcessContext } from './contexts.js';
|
|
4
4
|
export { S as SandboxProvider, c as createSandboxContext } from './sandbox-CLghrTLi.js';
|
|
5
5
|
export { C as ContextCapabilities, a as ContextType, E as ExecResult, b as ExecutionContext, c as ExecutionHandle, S as SpawnConfig } from './types-vA1a_ZX7.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, f as edit, g as glob, h as grep, m as multiEdit } from './skills-use-
|
|
9
|
-
export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, V as ValidationResult, c as createInteractionTool, b as createSpawnTool, s as spawn, v as validateToolArgs } from './validation-
|
|
8
|
+
export { S as SkillsReadToolOptions, a as SkillsRunScriptToolOptions, b as SkillsUseToolOptions, c as createSkillsReadTool, d as createSkillsRunScriptTool, e as createSkillsUseTool, f as edit, g as glob, h as grep, m as multiEdit } from './skills-use-DU0unNP4.js';
|
|
9
|
+
export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, V as ValidationResult, c as createInteractionTool, b as createSpawnTool, s as spawn, v as validateToolArgs } from './validation-BKA33eqb.js';
|
|
10
10
|
import { Hookable } from 'hookable';
|
|
11
11
|
import '@modelcontextprotocol/sdk/client/index.js';
|
|
12
12
|
|
package/dist/index.js
CHANGED
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
cerebras,
|
|
7
7
|
openai,
|
|
8
8
|
openrouter
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-BRMURQA2.js";
|
|
10
10
|
import {
|
|
11
11
|
basicTools,
|
|
12
12
|
basic_default,
|
|
13
13
|
definePreset
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-BXO7CZHJ.js";
|
|
15
15
|
import {
|
|
16
16
|
createAgent,
|
|
17
17
|
createInteractionTool,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
multiEdit,
|
|
26
26
|
spawn,
|
|
27
27
|
validateToolArgs
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-2AE3VM5O.js";
|
|
29
29
|
import {
|
|
30
30
|
IMPLICITLY_ALLOWED_SKILL_TOOLS,
|
|
31
31
|
buildCatalog,
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
normalizeMcpBlocks,
|
|
55
55
|
normalizeMcpServers,
|
|
56
56
|
resultToString
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-7H34OFDA.js";
|
|
58
58
|
import {
|
|
59
59
|
toolOutputByteLength,
|
|
60
60
|
toolResultToText
|
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
openaiCompat,
|
|
77
77
|
toAnthropic,
|
|
78
78
|
toOpenAI
|
|
79
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-YQ7LY6CL.js";
|
|
80
80
|
import {
|
|
81
81
|
AgentAbortedError,
|
|
82
82
|
AgentContextExceededError,
|
package/dist/mcp.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import 'hookable';
|
|
2
|
-
export { M as McpConnection, p as McpServerConfig, as as connectMcpServers, aD as normalizeMcpBlocks, aE as normalizeMcpServers, aI as resultToString } from './agent-
|
|
2
|
+
export { M as McpConnection, p as McpServerConfig, as as connectMcpServers, aD as normalizeMcpBlocks, aE as normalizeMcpServers, aI as resultToString } from './agent-C9q5VMGa.js';
|
|
3
3
|
import '@modelcontextprotocol/sdk/client/index.js';
|
|
4
4
|
import './types-vA1a_ZX7.js';
|
package/dist/mcp.js
CHANGED
package/dist/presets.d.ts
CHANGED
package/dist/presets.js
CHANGED
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
basicTools,
|
|
3
3
|
basic_default,
|
|
4
4
|
definePreset
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-BXO7CZHJ.js";
|
|
6
|
+
import "./chunk-2AE3VM5O.js";
|
|
7
7
|
import "./chunk-TPXPVEH6.js";
|
|
8
8
|
import "./chunk-IUBBVF53.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-7H34OFDA.js";
|
|
10
10
|
import "./chunk-JH6IAAFA.js";
|
|
11
11
|
import "./chunk-LNN5UTS2.js";
|
|
12
12
|
export {
|
package/dist/providers.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { j as AnthropicParams, k as CerebrasParams, ah as OpenAICompatAuthHeader, ai as OpenAICompatHttpError, aj 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, ao as anthropic, aq as cerebras, ar as classifyOpenAICompatError, aC as mapOAIFinishReason, aF as openai, aG as openaiCompat, aH as openrouter } from './agent-
|
|
1
|
+
export { j as AnthropicParams, k as CerebrasParams, ah as OpenAICompatAuthHeader, ai as OpenAICompatHttpError, aj 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, ao as anthropic, aq as cerebras, ar as classifyOpenAICompatError, aC as mapOAIFinishReason, aF as openai, aG as openaiCompat, aH as openrouter } from './agent-C9q5VMGa.js';
|
|
2
2
|
import 'hookable';
|
|
3
3
|
import './types-vA1a_ZX7.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-
|
|
6
|
+
} from "./chunk-BRMURQA2.js";
|
|
7
7
|
import {
|
|
8
8
|
OpenAICompatHttpError,
|
|
9
9
|
classifyOpenAICompatError,
|
|
10
10
|
mapOAIFinishReason,
|
|
11
11
|
openaiCompat
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-YQ7LY6CL.js";
|
|
13
13
|
import "./chunk-LNN5UTS2.js";
|
|
14
14
|
export {
|
|
15
15
|
OpenAICompatHttpError,
|
package/dist/session/sqlite.d.ts
CHANGED
package/dist/session.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { o as CreateSessionOptions, af as FileMapAdapter, ag 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, ap as autoDetectAndConvert, au as createFileMapStore, av as createMemoryStore, aw as createRemoteStore, ax as createSession, az as fromAnthropic, aA as fromOpenAI, aB as loadSession, aJ as toAnthropic, aK as toOpenAI } from './agent-
|
|
1
|
+
export { o as CreateSessionOptions, af as FileMapAdapter, ag 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, ap as autoDetectAndConvert, au as createFileMapStore, av as createMemoryStore, aw as createRemoteStore, ax as createSession, az as fromAnthropic, aA as fromOpenAI, aB as loadSession, aJ as toAnthropic, aK as toOpenAI } from './agent-C9q5VMGa.js';
|
|
2
2
|
import 'hookable';
|
|
3
3
|
import './types-vA1a_ZX7.js';
|
|
4
4
|
import '@modelcontextprotocol/sdk/client/index.js';
|
package/dist/session.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Z as ToolDef, K as SkillConfig, ak as SkillActivationState, d as AgentHooks } from './agent-
|
|
1
|
+
import { Z as ToolDef, K as SkillConfig, ak as SkillActivationState, d as AgentHooks } from './agent-C9q5VMGa.js';
|
|
2
2
|
import { Hookable } from 'hookable';
|
|
3
3
|
|
|
4
4
|
/**
|
package/dist/skills.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as AgentHooks, ak as SkillActivationState, K as SkillConfig, an as SkillSource, am as SkillDiagnostic, N as SkillsConfig } from './agent-
|
|
2
|
-
export { ac as ActivationVia, ad as ActiveSkill, ae as DeactivationReason, al as SkillActivationStateOptions, L as SkillResource, ay as createSkillActivationState } from './agent-
|
|
1
|
+
import { d as AgentHooks, ak as SkillActivationState, K as SkillConfig, an as SkillSource, am as SkillDiagnostic, N as SkillsConfig } from './agent-C9q5VMGa.js';
|
|
2
|
+
export { ac as ActivationVia, ad as ActiveSkill, ae as DeactivationReason, al as SkillActivationStateOptions, L as SkillResource, ay as createSkillActivationState } from './agent-C9q5VMGa.js';
|
|
3
3
|
import { Hookable } from 'hookable';
|
|
4
4
|
import { b as ExecutionContext, c as ExecutionHandle } from './types-vA1a_ZX7.js';
|
|
5
5
|
import '@modelcontextprotocol/sdk/client/index.js';
|
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, f as edit, g as glob, h as grep, m as multiEdit } from './skills-use-
|
|
2
|
-
export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, V as ValidationResult, c as createInteractionTool, b as createSpawnTool, s as spawn, v as validateToolArgs } from './validation-
|
|
3
|
-
import { Z as ToolDef } from './agent-
|
|
4
|
-
export { Y as ToolContext, a0 as ToolMap } from './agent-
|
|
1
|
+
export { S as SkillsReadToolOptions, a as SkillsRunScriptToolOptions, b as SkillsUseToolOptions, c as createSkillsReadTool, d as createSkillsRunScriptTool, e as createSkillsUseTool, f as edit, g as glob, h as grep, m as multiEdit } from './skills-use-DU0unNP4.js';
|
|
2
|
+
export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, V as ValidationResult, c as createInteractionTool, b as createSpawnTool, s as spawn, v as validateToolArgs } from './validation-BKA33eqb.js';
|
|
3
|
+
import { Z as ToolDef } from './agent-C9q5VMGa.js';
|
|
4
|
+
export { Y as ToolContext, a0 as ToolMap } from './agent-C9q5VMGa.js';
|
|
5
5
|
import 'hookable';
|
|
6
6
|
import './presets.js';
|
|
7
7
|
import './types-vA1a_ZX7.js';
|
package/dist/tools.js
CHANGED
|
@@ -14,10 +14,10 @@ import {
|
|
|
14
14
|
spawn,
|
|
15
15
|
validateToolArgs,
|
|
16
16
|
writeFile
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-2AE3VM5O.js";
|
|
18
18
|
import "./chunk-TPXPVEH6.js";
|
|
19
19
|
import "./chunk-IUBBVF53.js";
|
|
20
|
-
import "./chunk-
|
|
20
|
+
import "./chunk-7H34OFDA.js";
|
|
21
21
|
import "./chunk-JH6IAAFA.js";
|
|
22
22
|
import "./chunk-LNN5UTS2.js";
|
|
23
23
|
export {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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 toolOutputByteLength, ab as toolResultToText } from './agent-
|
|
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 toolOutputByteLength, ab as toolResultToText } from './agent-C9q5VMGa.js';
|
|
2
2
|
export { C as ContextCapabilities, a as ContextType, E as ExecResult, b as ExecutionContext, c as ExecutionHandle, S as SpawnConfig } from './types-vA1a_ZX7.js';
|
|
3
3
|
export { S as SandboxProvider } from './sandbox-CLghrTLi.js';
|
|
4
4
|
export { Preset } from './presets.js';
|
|
5
|
-
export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, V as ValidationResult } from './validation-
|
|
5
|
+
export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, V as ValidationResult } from './validation-BKA33eqb.js';
|
|
6
6
|
import 'hookable';
|
|
7
7
|
import '@modelcontextprotocol/sdk/client/index.js';
|