zidane 2.2.3 → 3.0.1
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 +120 -16
- package/dist/{agent-CEO3IeZj.d.ts → agent-4zeSbdXy.d.ts} +97 -3
- package/dist/{chunk-MDVZX6GM.js → chunk-2VM47IBI.js} +5 -3
- package/dist/{chunk-ZSEMKVHP.js → chunk-HQD5ICI6.js} +28 -14
- package/dist/chunk-JH6IAAFA.js +28 -0
- package/dist/{chunk-O2XZLJMG.js → chunk-QFHGWKK3.js} +746 -34
- package/dist/{chunk-DRAYZZ23.js → chunk-R74LQKAM.js} +11 -3
- package/dist/index.d.ts +4 -4
- package/dist/index.js +18 -8
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +2 -1
- package/dist/presets.d.ts +12 -2
- package/dist/presets.js +4 -3
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/{skills-use-CvHmgpmO.d.ts → skills-use-DhxQaluD.d.ts} +16 -2
- package/dist/skills.d.ts +2 -2
- package/dist/tools.d.ts +19 -5
- package/dist/tools.js +9 -2
- package/dist/types.d.ts +2 -3
- package/dist/types.js +3 -1
- package/dist/{spawn-BJhCzli9.d.ts → validation-CYISGVTn.d.ts} +35 -2
- package/package.json +1 -1
- package/dist/chunk-MYWDHD7C.js +0 -14
- package/dist/validation-DOY_k7lW.d.ts +0 -11
package/README.md
CHANGED
|
@@ -14,7 +14,11 @@ Built to be embedded.
|
|
|
14
14
|
|
|
15
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
16
|
- 🔁 **Streaming turn loop** — stream text + thinking deltas, tool calls, and tool results with hookable events at every step.
|
|
17
|
-
- 🛠 **Tools first-class** — shell
|
|
17
|
+
- 🛠 **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 execution, per-call gates, typed hooks. Built-in tools ship with sensible truncation and idempotency defaults so consumers don't have to polyfill them.
|
|
18
|
+
- ✂️ **Token-aware tool ergonomics** — `read_file` line-paginates with a footer that documents how to read the rest, `shell` tail-truncates combined output at 8 KB, `write_file` returns `No change needed` on idempotent writes. `outputBytes` surfaced on every tool/mcp hook.
|
|
19
|
+
- 🧰 **Self-healing tool args** — `validateToolArgs` auto-coerces small/OSS-model mistakes (`"true"` → `true`, `"42"` → `42`, JSON-encoded arrays) before reaching `execute`. `validation:reject` fires only on irrecoverable mismatches.
|
|
20
|
+
- 🪤 **Hallucinated tool names** handled — `tool:unknown` fires before the default error so consumers can substitute a friendly response.
|
|
21
|
+
- 📉 **Per-turn output budget** — `behavior.toolOutputBudget` injects a "summarize before continuing" message when a turn's tool outputs exceed the cap. Off by default.
|
|
18
22
|
- 🧩 **[Agent Skills](https://agentskills.io/specification) spec-aligned** — discover, activate, and run skills with `allowed-tools` enforcement and session-resume rehydration.
|
|
19
23
|
- 💾 **Pluggable sessions** — in-memory, SQLite, remote HTTP, or a file-map adapter. Turns persist incrementally — a crash leaves valid partial history.
|
|
20
24
|
- 🖼 **Multimodal** — images + documents via `PromptPart[]`; tools can return image blocks (screenshots, diagrams) routed natively on vision providers and via companion messages elsewhere.
|
|
@@ -25,8 +29,10 @@ Built to be embedded.
|
|
|
25
29
|
- 🧵 **Sub-agent spawning** — delegate to child agents with inherited or overridden preset; child stream/tool events bubble to the parent.
|
|
26
30
|
- 🧭 **Typed errors** — `AgentContextExceededError` / `AgentProviderError` / `AgentAbortedError` instead of sniffing error strings.
|
|
27
31
|
- 🔌 **Execution contexts** — run tools in-process, in Docker, or in a remote sandbox (E2B / Rivet / any `SandboxProvider`).
|
|
28
|
-
- 🪝 **Hookable everything** —
|
|
29
|
-
- 🧪 **
|
|
32
|
+
- 🪝 **Hookable everything** — typed hook events covering turn, stream, tool, MCP, session, skills, spawn, OAuth refresh, bootstrap timing, validation rejection / coercion, and budget overflow.
|
|
33
|
+
- 🧪 **1000+ tests, zero API keys** — mock providers + mock execution contexts; suite runs in under 2 seconds.
|
|
34
|
+
|
|
35
|
+
> Upgrading from 2.x? See [`docs/migrate-from-v2.md`](./docs/migrate-from-v2.md) for the full list of behavior changes.
|
|
30
36
|
|
|
31
37
|
## Quickstart
|
|
32
38
|
|
|
@@ -70,6 +76,7 @@ createAgent({
|
|
|
70
76
|
maxTokens: 16384, // max tokens per LLM response
|
|
71
77
|
thinkingBudget: 10240, // exact thinking token budget
|
|
72
78
|
cache: true, // prompt-cache breakpoints on supported providers (default: true)
|
|
79
|
+
toolOutputBudget: 32768, // soft per-turn cap on tool-output bytes (off by default)
|
|
73
80
|
},
|
|
74
81
|
execution: createProcessContext(), // where tools run
|
|
75
82
|
mcpServers: [], // MCP tool servers
|
|
@@ -213,13 +220,23 @@ The `basic` preset bundles:
|
|
|
213
220
|
|
|
214
221
|
| Tool | Description |
|
|
215
222
|
|---|---|
|
|
216
|
-
| `shell` | Execute shell commands |
|
|
217
|
-
| `readFile` | Read file
|
|
218
|
-
| `writeFile` | Write/
|
|
223
|
+
| `shell` | Execute shell commands. Combined stdout+stderr tail-truncated at 8 KB by default; `maxOutputBytes: 0` disables |
|
|
224
|
+
| `readFile` | Read a file by line range. Default: lines 1..2000, byte cap 64 KB. Truncation footer documents how to page; binary files return a marker instead of mojibake |
|
|
225
|
+
| `writeFile` | Write a file. Returns `Created` / `Updated` / `No change needed: …` so the model can detect no-ops without a separate read |
|
|
226
|
+
| `edit` | Surgical replace of `old_string` → `new_string`. Fails clearly on non-unique matches (unless `replace_all`) and on not-found (with a nearest-match preview) |
|
|
227
|
+
| `multiEdit` | Atomic list of edits to one file. All-or-nothing: any failed edit prevents the write |
|
|
219
228
|
| `listFiles` | List directory contents |
|
|
220
229
|
| `spawn` | Spawn a sub-agent |
|
|
221
230
|
|
|
222
|
-
|
|
231
|
+
Opt-in tools available via `import { glob, grep, createInteractionTool } from 'zidane'`:
|
|
232
|
+
|
|
233
|
+
| Tool | Description |
|
|
234
|
+
|---|---|
|
|
235
|
+
| `glob` | Bun.Glob-backed pattern matching (in-process); shells out in docker/sandbox |
|
|
236
|
+
| `grep` | ripgrep-backed regex search (with a Bun.Glob fallback). `output_mode`, `-i / -n / -A / -B / -C`, `multiline`, `head_limit`, `offset` — Claude Code Grep semantics |
|
|
237
|
+
| `createInteractionTool` | Human-in-the-loop factory |
|
|
238
|
+
|
|
239
|
+
The three `skills_use` / `skills_read` / `skills_run_script` tools auto-inject when the skills catalog is non-empty.
|
|
223
240
|
|
|
224
241
|
Define a custom preset:
|
|
225
242
|
|
|
@@ -333,26 +350,51 @@ agent.hooks.hook('tool:gate', (ctx) => {
|
|
|
333
350
|
}
|
|
334
351
|
})
|
|
335
352
|
|
|
336
|
-
agent.hooks.hook('tool:before', (ctx) => { /* ctx.turnId, ctx.callId, ctx.name, ctx.input */ })
|
|
337
|
-
agent.hooks.hook('tool:after', (ctx) => { /* + ctx.result */ })
|
|
353
|
+
agent.hooks.hook('tool:before', (ctx) => { /* ctx.turnId, ctx.callId, ctx.name, ctx.input, ctx.coercions? */ })
|
|
354
|
+
agent.hooks.hook('tool:after', (ctx) => { /* + ctx.result, ctx.outputBytes, ctx.coercions? */ })
|
|
338
355
|
agent.hooks.hook('tool:error', (ctx) => { /* + ctx.error */ })
|
|
339
356
|
agent.hooks.hook('tool:transform', (ctx) => {
|
|
340
|
-
// + ctx.result, ctx.isError — mutate to modify
|
|
341
|
-
|
|
342
|
-
|
|
357
|
+
// + ctx.result, ctx.isError, ctx.outputBytes (pre-mutation), ctx.coercions? — mutate result/isError to modify.
|
|
358
|
+
// Built-in tools already truncate; use this hook for consumer concerns the framework can't infer,
|
|
359
|
+
// e.g. redacting secrets in tool output before they reach the model.
|
|
360
|
+
if (typeof ctx.result === 'string')
|
|
361
|
+
ctx.result = ctx.result.replace(/\b(API_KEY|TOKEN|PASSWORD)\s*=\s*\S+/gi, '$1=<redacted>')
|
|
362
|
+
})
|
|
363
|
+
agent.hooks.hook('tool:unknown', (ctx) => {
|
|
364
|
+
// Fires when the model invents a tool name (or calls one no longer registered).
|
|
365
|
+
// Mutate ctx.result to substitute a friendly response, set ctx.suppressError = true
|
|
366
|
+
// to skip the companion `tool:error`.
|
|
367
|
+
if (ctx.name === 'EnterPlanMode') {
|
|
368
|
+
ctx.result = 'EnterPlanMode is not available — use shell to draft a plan as comments.'
|
|
369
|
+
ctx.suppressError = true
|
|
370
|
+
}
|
|
371
|
+
})
|
|
372
|
+
agent.hooks.hook('validation:reject', (ctx) => {
|
|
373
|
+
// Fires when arg validation rejects the input even after auto-coercion attempts.
|
|
374
|
+
// Observational — the model still receives `Validation error: …` for the retry.
|
|
375
|
+
// ctx.reason, ctx.schema
|
|
376
|
+
})
|
|
377
|
+
agent.hooks.hook('validation:coerce', (ctx) => {
|
|
378
|
+
// Fires when validation auto-healed at least one field. Never fires on
|
|
379
|
+
// perfectly-typed inputs. ctx.coercions lists the field names that were changed.
|
|
380
|
+
// Symmetric counterpart to `validation:reject` — useful for "model wrongness rate".
|
|
343
381
|
})
|
|
344
382
|
```
|
|
345
383
|
|
|
384
|
+
`ctx.coercions` (when present) is the same `readonly string[]` exposed via `validation:coerce`. The field is **omitted** from `tool:before` / `tool:after` / `tool:transform` ctx when no coercion happened, so it never noises up the happy path. Listeners can `if (ctx.coercions)` guard.
|
|
385
|
+
|
|
346
386
|
MCP tool hooks mirror the same pattern with `server` and `tool` fields. Typed via `McpToolHookContext`.
|
|
347
387
|
|
|
348
388
|
```ts
|
|
349
389
|
agent.hooks.hook('mcp:tool:gate', (ctx) => { /* ctx.turnId, ctx.callId, ctx.server, ctx.tool, ctx.input, ctx.block, ctx.reason */ })
|
|
350
390
|
agent.hooks.hook('mcp:tool:before', (ctx) => { /* ctx.turnId, ctx.callId, ctx.server, ctx.tool, ctx.input */ })
|
|
351
|
-
agent.hooks.hook('mcp:tool:after', (ctx) => { /* + ctx.result */ })
|
|
352
|
-
agent.hooks.hook('mcp:tool:transform', (ctx) => { /* + ctx.result — mutate to modify */ })
|
|
391
|
+
agent.hooks.hook('mcp:tool:after', (ctx) => { /* + ctx.result, ctx.outputBytes */ })
|
|
392
|
+
agent.hooks.hook('mcp:tool:transform', (ctx) => { /* + ctx.result, ctx.outputBytes — mutate to modify */ })
|
|
353
393
|
agent.hooks.hook('mcp:tool:error', (ctx) => { /* + ctx.error */ })
|
|
354
394
|
```
|
|
355
395
|
|
|
396
|
+
`outputBytes` measures the wire size of the tool's result. On `*:transform` it's the **pre-mutation** size (a truncation handler can size-budget); on `*:after` it's the **post-mutation** size that goes to the model. `toolOutputByteLength(content)` exported from `zidane` reproduces the formula.
|
|
397
|
+
|
|
356
398
|
### Context transform
|
|
357
399
|
|
|
358
400
|
Prune messages before each LLM call:
|
|
@@ -364,6 +406,58 @@ agent.hooks.hook('context:transform', (ctx) => {
|
|
|
364
406
|
})
|
|
365
407
|
```
|
|
366
408
|
|
|
409
|
+
### Hook recipes
|
|
410
|
+
|
|
411
|
+
Three patterns that don't have a built-in default. Copy-paste and tune.
|
|
412
|
+
|
|
413
|
+
```ts
|
|
414
|
+
// 1. Truncate MCP tool results.
|
|
415
|
+
// Built-in tools (shell, read_file) already tail-truncate; MCP server outputs
|
|
416
|
+
// don't, since their sizes vary wildly and zidane can't pick a sane default
|
|
417
|
+
// on their behalf. Apply the same shape to mcp:tool:transform.
|
|
418
|
+
agent.hooks.hook('mcp:tool:transform', (ctx) => {
|
|
419
|
+
if (ctx.outputBytes <= 8192 || typeof ctx.result !== 'string')
|
|
420
|
+
return
|
|
421
|
+
const tail = ctx.result.slice(-4096)
|
|
422
|
+
ctx.result = `…(${ctx.outputBytes - tail.length} bytes truncated from head)…\n${tail}`
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
// 2. Substitute a friendly response when the model invents a tool name.
|
|
426
|
+
agent.hooks.hook('tool:unknown', (ctx) => {
|
|
427
|
+
if (ctx.name === 'EnterPlanMode') {
|
|
428
|
+
ctx.result = 'EnterPlanMode is not available — use shell to draft a plan as comments.'
|
|
429
|
+
ctx.suppressError = true
|
|
430
|
+
}
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
// 3. Drop old turns once the conversation grows past a soft cap.
|
|
434
|
+
agent.hooks.hook('context:transform', (ctx) => {
|
|
435
|
+
const KEEP_RECENT = 30
|
|
436
|
+
if (ctx.messages.length > KEEP_RECENT) {
|
|
437
|
+
const trimmed = [ctx.messages[0], ...ctx.messages.slice(-KEEP_RECENT + 1)]
|
|
438
|
+
ctx.messages.splice(0, ctx.messages.length, ...trimmed)
|
|
439
|
+
}
|
|
440
|
+
})
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
`mcp:tool:transform`, `tool:unknown`, and `context:transform` are the highest-leverage entries on the surface for the cases v3 doesn't auto-handle. Most production agents end up with one of each.
|
|
444
|
+
|
|
445
|
+
### Per-turn output budget
|
|
446
|
+
|
|
447
|
+
When working with OSS models that return large tool outputs, set `behavior.toolOutputBudget` to inject a "summarize before continuing" message after any turn whose combined post-`tool:transform` tool-output bytes exceed the cap. Off by default.
|
|
448
|
+
|
|
449
|
+
```ts
|
|
450
|
+
const agent = createAgent({
|
|
451
|
+
...basic,
|
|
452
|
+
provider,
|
|
453
|
+
behavior: { toolOutputBudget: 32768 },
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
agent.hooks.hook('budget:exceeded', (ctx) => {
|
|
457
|
+
console.warn(`turn ${ctx.turn}: ${ctx.bytes} > ${ctx.budget} bytes`)
|
|
458
|
+
})
|
|
459
|
+
```
|
|
460
|
+
|
|
367
461
|
## Steering and Follow-up
|
|
368
462
|
|
|
369
463
|
### Steering
|
|
@@ -751,19 +845,29 @@ stats.timeTillFirstTokenMs // ms from run() start to the first stream/tool
|
|
|
751
845
|
All types are available from `zidane/types`:
|
|
752
846
|
|
|
753
847
|
```ts
|
|
754
|
-
import type { Agent, SessionTurn, TurnUsage, Provider, ToolDef } from 'zidane/types'
|
|
848
|
+
import type { Agent, SessionTurn, TurnUsage, Provider, ToolDef, ValidationResult } from 'zidane/types'
|
|
755
849
|
|
|
756
850
|
// Hook context types for typed event handlers
|
|
757
851
|
import type { ToolHookContext, McpToolHookContext, SessionHookContext, StreamHookContext } from 'zidane/types'
|
|
758
852
|
```
|
|
759
853
|
|
|
854
|
+
Helpers (re-exported from the main entry):
|
|
855
|
+
|
|
856
|
+
```ts
|
|
857
|
+
import { toolResultToText, toolOutputByteLength, validateToolArgs } from 'zidane'
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
- `toolResultToText(content)` — flatten `string | ToolResultContent[]` to a string for logging.
|
|
861
|
+
- `toolOutputByteLength(content)` — same formula the loop uses for `outputBytes`.
|
|
862
|
+
- `validateToolArgs(input, schema)` — the validator the loop runs between `tool:gate` and `tool:before`. Useful for unit tests of consumer tool definitions.
|
|
863
|
+
|
|
760
864
|
## Testing
|
|
761
865
|
|
|
762
866
|
```bash
|
|
763
867
|
bun test
|
|
764
868
|
```
|
|
765
869
|
|
|
766
|
-
|
|
870
|
+
1000+ tests with mock provider and execution context. No API keys or Docker needed; the suite runs in under 2 seconds.
|
|
767
871
|
|
|
768
872
|
## Benchmarks
|
|
769
873
|
|
|
@@ -121,7 +121,18 @@ declare function toTypedError(classification: ClassifiedError, provider: string,
|
|
|
121
121
|
* Shared types for the agent system.
|
|
122
122
|
*/
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Thinking / extended-reasoning configuration.
|
|
126
|
+
*
|
|
127
|
+
* - `'off'` — no thinking.
|
|
128
|
+
* - `'minimal' | 'low' | 'medium' | 'high'` — explicit token budget. Maps to
|
|
129
|
+
* provider-specific reasoning controls (Anthropic `thinking.type='enabled'`
|
|
130
|
+
* with a budget; OpenAI `reasoning_effort`).
|
|
131
|
+
* - `'adaptive'` — let the model decide per-turn whether and how much to think.
|
|
132
|
+
* Anthropic-only (`thinking.type='adaptive'`). Other providers fall back to
|
|
133
|
+
* no reasoning when this value is supplied.
|
|
134
|
+
*/
|
|
135
|
+
type ThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'adaptive';
|
|
125
136
|
interface McpServerConfig {
|
|
126
137
|
/** Display name (used for tool namespacing) */
|
|
127
138
|
name: string;
|
|
@@ -194,6 +205,17 @@ interface AgentBehavior {
|
|
|
194
205
|
* Default: `true`.
|
|
195
206
|
*/
|
|
196
207
|
cache?: boolean;
|
|
208
|
+
/**
|
|
209
|
+
* Soft per-turn cap on total tool-output bytes. When the sum of `outputBytes`
|
|
210
|
+
* across a turn's tool results exceeds this value, the loop injects a
|
|
211
|
+
* synthetic user message instructing the model to summarize before calling
|
|
212
|
+
* more tools, and fires the `budget:exceeded` hook.
|
|
213
|
+
*
|
|
214
|
+
* Measured **post-`tool:transform`** so consumer truncation counts toward the
|
|
215
|
+
* budget. Off by default (undefined / `0` disables the check). A reasonable
|
|
216
|
+
* starting value for OSS-model integrations is `32768`.
|
|
217
|
+
*/
|
|
218
|
+
toolOutputBudget?: number;
|
|
197
219
|
}
|
|
198
220
|
interface ImageContent {
|
|
199
221
|
type: 'image';
|
|
@@ -270,6 +292,19 @@ interface ToolResultImageContent {
|
|
|
270
292
|
* structured content should route the array through without flattening.
|
|
271
293
|
*/
|
|
272
294
|
declare function toolResultToText(content: string | ToolResultContent[]): string;
|
|
295
|
+
/**
|
|
296
|
+
* Approximate byte length of a tool output as it goes back to the model.
|
|
297
|
+
*
|
|
298
|
+
* - Plain text: UTF-8 byte length.
|
|
299
|
+
* - Structured content: text blocks contribute their UTF-8 byte length; image
|
|
300
|
+
* blocks contribute their **base64 character length**, since that is what
|
|
301
|
+
* the model tokenizes (the wire-encoded payload, not the decoded image).
|
|
302
|
+
*
|
|
303
|
+
* Used by the agent loop to populate `outputBytes` on `tool:after`,
|
|
304
|
+
* `tool:transform`, `mcp:tool:after`, and `mcp:tool:transform` hooks so
|
|
305
|
+
* consumers can size-budget tool output without re-counting bytes themselves.
|
|
306
|
+
*/
|
|
307
|
+
declare function toolOutputByteLength(content: string | ToolResultContent[]): number;
|
|
273
308
|
type SessionContentBlock = {
|
|
274
309
|
type: 'text';
|
|
275
310
|
text: string;
|
|
@@ -1423,9 +1458,13 @@ interface AgentHooks {
|
|
|
1423
1458
|
block: boolean;
|
|
1424
1459
|
reason: string;
|
|
1425
1460
|
}) => void;
|
|
1426
|
-
'tool:before': (ctx: ToolHookContext
|
|
1461
|
+
'tool:before': (ctx: ToolHookContext & {
|
|
1462
|
+
coercions?: readonly string[];
|
|
1463
|
+
}) => void;
|
|
1427
1464
|
'tool:after': (ctx: ToolHookContext & {
|
|
1428
1465
|
result: string | ToolResultContent[];
|
|
1466
|
+
outputBytes: number;
|
|
1467
|
+
coercions?: readonly string[];
|
|
1429
1468
|
}) => void;
|
|
1430
1469
|
'tool:error': (ctx: ToolHookContext & {
|
|
1431
1470
|
error: Error;
|
|
@@ -1433,6 +1472,45 @@ interface AgentHooks {
|
|
|
1433
1472
|
'tool:transform': (ctx: ToolHookContext & {
|
|
1434
1473
|
result: string | ToolResultContent[];
|
|
1435
1474
|
isError: boolean;
|
|
1475
|
+
outputBytes: number;
|
|
1476
|
+
coercions?: readonly string[];
|
|
1477
|
+
}) => void;
|
|
1478
|
+
/**
|
|
1479
|
+
* Fires before the generic "Unknown tool" error when the model invokes a tool
|
|
1480
|
+
* that isn't registered (hallucinated names, dropped MCP servers, dangling
|
|
1481
|
+
* aliases). Mutate `result` to substitute a friendly response or set
|
|
1482
|
+
* `suppressError: true` to skip the companion `tool:error` emission.
|
|
1483
|
+
*
|
|
1484
|
+
* Fires for any unknown tool name — including hallucinated MCP-style names
|
|
1485
|
+
* (`mcp_supabase_xxx`); branch on `name.startsWith('mcp_')` to differentiate.
|
|
1486
|
+
*/
|
|
1487
|
+
'tool:unknown': (ctx: ToolHookContext & {
|
|
1488
|
+
result?: string | ToolResultContent[];
|
|
1489
|
+
suppressError: boolean;
|
|
1490
|
+
}) => void;
|
|
1491
|
+
/**
|
|
1492
|
+
* Fires when `validateToolArgs` rejects an input that could not be auto-coerced
|
|
1493
|
+
* to satisfy the tool's `inputSchema`. Observational — the tool call still
|
|
1494
|
+
* surfaces a `Validation error: …` string back to the model. Useful for
|
|
1495
|
+
* counting validation failures separately from runtime tool errors.
|
|
1496
|
+
*/
|
|
1497
|
+
'validation:reject': (ctx: ToolHookContext & {
|
|
1498
|
+
reason: string;
|
|
1499
|
+
schema: Record<string, unknown>;
|
|
1500
|
+
}) => void;
|
|
1501
|
+
/**
|
|
1502
|
+
* Fires when `validateToolArgs` successfully auto-coerced one or more input
|
|
1503
|
+
* fields to satisfy the tool's `inputSchema`. **Only fires when at least one
|
|
1504
|
+
* coercion happened** — never on perfectly-shaped inputs. Useful for counting
|
|
1505
|
+
* model "wrongness rate" without re-running validation downstream.
|
|
1506
|
+
*
|
|
1507
|
+
* `coercions` lists the field names that were coerced. The values landed in
|
|
1508
|
+
* the input that the tool actually received; consumers wanting before/after
|
|
1509
|
+
* comparison can re-run `validateToolArgs(ctx.input, ctx.schema)`.
|
|
1510
|
+
*/
|
|
1511
|
+
'validation:coerce': (ctx: ToolHookContext & {
|
|
1512
|
+
coercions: readonly string[];
|
|
1513
|
+
schema: Record<string, unknown>;
|
|
1436
1514
|
}) => void;
|
|
1437
1515
|
'context:transform': (ctx: {
|
|
1438
1516
|
messages: SessionMessage[];
|
|
@@ -1463,11 +1541,14 @@ interface AgentHooks {
|
|
|
1463
1541
|
depth: number;
|
|
1464
1542
|
}) => void;
|
|
1465
1543
|
'child:tool:before': (ctx: ToolHookContext & {
|
|
1544
|
+
coercions?: readonly string[];
|
|
1466
1545
|
childId: string;
|
|
1467
1546
|
depth: number;
|
|
1468
1547
|
}) => void;
|
|
1469
1548
|
'child:tool:after': (ctx: ToolHookContext & {
|
|
1470
1549
|
result: string | ToolResultContent[];
|
|
1550
|
+
outputBytes: number;
|
|
1551
|
+
coercions?: readonly string[];
|
|
1471
1552
|
childId: string;
|
|
1472
1553
|
depth: number;
|
|
1473
1554
|
}) => void;
|
|
@@ -1527,9 +1608,11 @@ interface AgentHooks {
|
|
|
1527
1608
|
'mcp:tool:before': (ctx: McpToolHookContext) => void;
|
|
1528
1609
|
'mcp:tool:after': (ctx: McpToolHookContext & {
|
|
1529
1610
|
result: string | ToolResultContent[];
|
|
1611
|
+
outputBytes: number;
|
|
1530
1612
|
}) => void;
|
|
1531
1613
|
'mcp:tool:transform': (ctx: McpToolHookContext & {
|
|
1532
1614
|
result: string | ToolResultContent[];
|
|
1615
|
+
outputBytes: number;
|
|
1533
1616
|
}) => void;
|
|
1534
1617
|
'mcp:tool:error': (ctx: McpToolHookContext & {
|
|
1535
1618
|
error: Error;
|
|
@@ -1560,6 +1643,17 @@ interface AgentHooks {
|
|
|
1560
1643
|
output: Record<string, unknown>;
|
|
1561
1644
|
schema: Record<string, unknown>;
|
|
1562
1645
|
}) => void;
|
|
1646
|
+
/**
|
|
1647
|
+
* Fires when a turn's total tool-output bytes exceed `behavior.toolOutputBudget`.
|
|
1648
|
+
* Measured post-`tool:transform`. Loop injects a synthetic user message after
|
|
1649
|
+
* the tool-results turn instructing the model to summarize.
|
|
1650
|
+
*/
|
|
1651
|
+
'budget:exceeded': (ctx: {
|
|
1652
|
+
turn: number;
|
|
1653
|
+
turnId: string;
|
|
1654
|
+
bytes: number;
|
|
1655
|
+
budget: number;
|
|
1656
|
+
}) => void;
|
|
1563
1657
|
'agent:abort': (ctx: object) => void;
|
|
1564
1658
|
'agent:done': (ctx: AgentStats) => void;
|
|
1565
1659
|
'session:start': (ctx: SessionHookContext & {
|
|
@@ -1675,4 +1769,4 @@ interface Agent {
|
|
|
1675
1769
|
}
|
|
1676
1770
|
declare function createAgent({ provider, name: agentName, system: agentSystem, tools: agentTools, toolAliases, behavior: agentBehavior, execution, mcpServers, session, skills: agentSkills, mcpConnector, eager }: AgentOptions): Agent;
|
|
1677
1771
|
|
|
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,
|
|
1772
|
+
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, fromOpenAI as aA, loadSession as aB, mapOAIFinishReason as aC, normalizeMcpBlocks as aD, normalizeMcpServers as aE, openai as aF, openaiCompat as aG, openrouter as aH, resultToString as aI, toAnthropic as aJ, toOpenAI as aK, toTypedError as aL, toolOutputByteLength as aa, toolResultToText as ab, type ActivationVia as ac, type ActiveSkill as ad, type DeactivationReason as ae, type FileMapAdapter as af, type FileMapStoreOptions as ag, type OpenAICompatAuthHeader as ah, OpenAICompatHttpError as ai, type OpenAICompatParams as aj, type SkillActivationState as ak, type SkillActivationStateOptions as al, type SkillDiagnostic as am, type SkillSource as an, anthropic as ao, autoDetectAndConvert as ap, cerebras as aq, classifyOpenAICompatError as ar, connectMcpServers as as, createAgent as at, createFileMapStore as au, createMemoryStore as av, createRemoteStore as aw, createSession as ax, createSkillActivationState as ay, fromAnthropic 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 };
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
+
edit,
|
|
2
3
|
listFiles,
|
|
4
|
+
multiEdit,
|
|
3
5
|
readFile,
|
|
4
6
|
shell,
|
|
5
7
|
spawn,
|
|
6
8
|
writeFile
|
|
7
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-QFHGWKK3.js";
|
|
8
10
|
|
|
9
11
|
// src/presets/basic.ts
|
|
10
|
-
var basicTools = { shell, readFile, writeFile, listFiles };
|
|
12
|
+
var basicTools = { shell, readFile, writeFile, listFiles, edit, multiEdit };
|
|
11
13
|
var basic_default = definePreset({
|
|
12
14
|
name: "basic",
|
|
13
|
-
system: "You are a helpful assistant with access to shell, file reading, file writing, directory listing, and sub-agent spawning
|
|
15
|
+
system: "You are a helpful assistant with access to shell, file reading, file writing, surgical and multi-edit tools, directory listing, and sub-agent spawning. Prefer `edit` / `multi_edit` for in-place changes and `write_file` for full file overwrites. Use them to accomplish tasks in the project directory.",
|
|
14
16
|
tools: { ...basicTools, spawn }
|
|
15
17
|
});
|
|
16
18
|
|
|
@@ -161,12 +161,22 @@ function createClient(SDK, apiKey, isOAuth, baseURL) {
|
|
|
161
161
|
} : { apiKey, ...base }
|
|
162
162
|
);
|
|
163
163
|
}
|
|
164
|
-
var
|
|
165
|
-
minimal:
|
|
166
|
-
low:
|
|
167
|
-
medium:
|
|
168
|
-
high:
|
|
164
|
+
var EFFORT_FOR_LEVEL = {
|
|
165
|
+
minimal: "low",
|
|
166
|
+
low: "low",
|
|
167
|
+
medium: "medium",
|
|
168
|
+
high: "high"
|
|
169
169
|
};
|
|
170
|
+
function planAnthropicThinking(level, customBudget) {
|
|
171
|
+
if (level === "off")
|
|
172
|
+
return null;
|
|
173
|
+
if (level === "adaptive")
|
|
174
|
+
return { kind: "adaptive" };
|
|
175
|
+
if (customBudget !== void 0) {
|
|
176
|
+
return { kind: "enabled", budgetTokens: customBudget, maxTokensBump: customBudget };
|
|
177
|
+
}
|
|
178
|
+
return { kind: "adaptive", effort: EFFORT_FOR_LEVEL[level] };
|
|
179
|
+
}
|
|
170
180
|
function mapStopReason(stopReason) {
|
|
171
181
|
if (!stopReason)
|
|
172
182
|
return void 0;
|
|
@@ -393,13 +403,16 @@ function anthropic(anthropicParams) {
|
|
|
393
403
|
};
|
|
394
404
|
if (options.cache !== false)
|
|
395
405
|
applyAnthropicCacheBreakpoints(params);
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
type: "enabled",
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
|
|
406
|
+
const plan = planAnthropicThinking(thinking, options.thinkingBudget);
|
|
407
|
+
if (plan) {
|
|
408
|
+
if (plan.kind === "enabled") {
|
|
409
|
+
params.thinking = { type: "enabled", budget_tokens: plan.budgetTokens };
|
|
410
|
+
params.max_tokens = plan.maxTokensBump + params.max_tokens;
|
|
411
|
+
} else {
|
|
412
|
+
params.thinking = { type: "adaptive" };
|
|
413
|
+
if (plan.effort)
|
|
414
|
+
params.output_config = { effort: plan.effort };
|
|
415
|
+
}
|
|
403
416
|
params.temperature = 1;
|
|
404
417
|
}
|
|
405
418
|
if (options.toolChoice) {
|
|
@@ -679,13 +692,14 @@ function openai(params) {
|
|
|
679
692
|
messages: toPiMessages(options.messages, modelId),
|
|
680
693
|
tools: options.tools
|
|
681
694
|
};
|
|
695
|
+
const reasoningLevel = options.thinking && options.thinking !== "off" && options.thinking !== "adaptive" ? options.thinking : void 0;
|
|
682
696
|
const stream = streamOpenAICodexResponses(model, context, {
|
|
683
697
|
apiKey,
|
|
684
698
|
maxTokens: options.maxTokens,
|
|
685
699
|
signal: options.signal,
|
|
686
700
|
transport: params?.transport,
|
|
687
|
-
reasoningEffort:
|
|
688
|
-
reasoningSummary:
|
|
701
|
+
reasoningEffort: reasoningLevel,
|
|
702
|
+
reasoningSummary: reasoningLevel ? "auto" : void 0,
|
|
689
703
|
onPayload: (payload) => applyPayloadOverrides(payload, options)
|
|
690
704
|
});
|
|
691
705
|
let finalMessage;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
import { Buffer } from "buffer";
|
|
3
|
+
function toolResultToText(content) {
|
|
4
|
+
if (typeof content === "string")
|
|
5
|
+
return content;
|
|
6
|
+
return content.map((block) => {
|
|
7
|
+
if (block.type === "text")
|
|
8
|
+
return block.text;
|
|
9
|
+
return `[image: ${block.mediaType} \u2014 ${block.data.length} b64 bytes]`;
|
|
10
|
+
}).join("\n");
|
|
11
|
+
}
|
|
12
|
+
function toolOutputByteLength(content) {
|
|
13
|
+
if (typeof content === "string")
|
|
14
|
+
return Buffer.byteLength(content);
|
|
15
|
+
let total = 0;
|
|
16
|
+
for (const block of content) {
|
|
17
|
+
if (block.type === "text")
|
|
18
|
+
total += Buffer.byteLength(block.text);
|
|
19
|
+
else
|
|
20
|
+
total += block.data.length;
|
|
21
|
+
}
|
|
22
|
+
return total;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
toolResultToText,
|
|
27
|
+
toolOutputByteLength
|
|
28
|
+
};
|