zidane 5.6.11 → 5.6.13
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 +19 -2
- package/dist/{agent-C9AKTU_V.d.ts → agent-ClkpElCZ.d.ts} +540 -55
- package/dist/agent-ClkpElCZ.d.ts.map +1 -0
- package/dist/chat.d.ts +47 -17
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +3 -3
- package/dist/{index-6f4T7Gc0.d.ts → index-CTDMMdIy.d.ts} +348 -3
- package/dist/index-CTDMMdIy.d.ts.map +1 -0
- package/dist/{index-DPN7TcXK.d.ts → index-v3Tzobqr.d.ts} +2 -2
- package/dist/{index-DPN7TcXK.d.ts.map → index-v3Tzobqr.d.ts.map} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +169 -8
- package/dist/index.js.map +1 -1
- package/dist/{login-BindcfKi.js → login-DS3sf6b5.js} +4 -4
- package/dist/{login-BindcfKi.js.map → login-DS3sf6b5.js.map} +1 -1
- package/dist/{mcp-0jRkIV0g.js → mcp-DGeB7-3D.js} +13 -2
- package/dist/mcp-DGeB7-3D.js.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/{messages-BfmXLDT4.js → messages-Dym8S_YH.js} +303 -8
- package/dist/messages-Dym8S_YH.js.map +1 -0
- package/dist/{presets-CmzMeWg2.js → presets-CZXS_87d.js} +2 -2
- package/dist/{presets-CmzMeWg2.js.map → presets-CZXS_87d.js.map} +1 -1
- package/dist/presets.d.ts +2 -2
- package/dist/presets.js +1 -1
- package/dist/{providers-C_ahnRBS.js → providers-beXyD9W9.js} +137 -21
- package/dist/providers-beXyD9W9.js.map +1 -0
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +3 -3
- package/dist/restate.d.ts +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/{session-PUzXZlG6.js → session-BRIsmBSY.js} +5 -2
- package/dist/session-BRIsmBSY.js.map +1 -0
- package/dist/session.d.ts +2 -2
- package/dist/session.js +3 -3
- package/dist/skills.d.ts +2 -2
- package/dist/{tools-CxOfTt3R.js → tools-DE9pR_NG.js} +515 -116
- package/dist/tools-DE9pR_NG.js.map +1 -0
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-DDCHSDdX.d.ts → transcript-anchors-D0TR6djV.d.ts} +4 -4
- package/dist/transcript-anchors-D0TR6djV.d.ts.map +1 -0
- package/dist/tui.d.ts +2 -2
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +12 -8
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-CxE8BBau.js → turn-operations-6Yls2HuG.js} +907 -42
- package/dist/turn-operations-6Yls2HuG.js.map +1 -0
- package/dist/types-oKPBdCmL.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/docs/ARCHITECTURE.md +101 -20
- package/docs/CHAT.md +27 -5
- package/docs/RESTATE.md +1 -1
- package/docs/SKILL.md +39 -3
- package/package.json +5 -2
- package/dist/agent-C9AKTU_V.d.ts.map +0 -1
- package/dist/index-6f4T7Gc0.d.ts.map +0 -1
- package/dist/mcp-0jRkIV0g.js.map +0 -1
- package/dist/messages-BfmXLDT4.js.map +0 -1
- package/dist/providers-C_ahnRBS.js.map +0 -1
- package/dist/session-PUzXZlG6.js.map +0 -1
- package/dist/tools-CxOfTt3R.js.map +0 -1
- package/dist/transcript-anchors-DDCHSDdX.d.ts.map +0 -1
- package/dist/turn-operations-CxE8BBau.js.map +0 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { n as createProcessContext } from "./contexts-BOtMvzli.js";
|
|
2
2
|
import { c as errorMessage, i as AgentProviderError, n as AgentBudgetExceededError, o as AgentToolPairingError, t as AgentAbortedError, u as toTypedError } from "./errors-DdZXnyXE.js";
|
|
3
3
|
import { n as toolOutputByteLength, t as DEFAULT_AGENT_CLOCK } from "./types-oKPBdCmL.js";
|
|
4
|
-
import { a as detectTurnInterruption, c as filterUnresolvedToolUses, n as SYNTHETIC_TOOL_RESULT_PLACEHOLDER, o as ensureEndsWithUserMessage, s as ensureToolResultPairing } from "./messages-
|
|
5
|
-
import { t as connectMcpServers } from "./mcp-
|
|
4
|
+
import { E as appendStaticSection, a as detectTurnInterruption, c as filterUnresolvedToolUses, n as SYNTHETIC_TOOL_RESULT_PLACEHOLDER, o as ensureEndsWithUserMessage, s as ensureToolResultPairing } from "./messages-Dym8S_YH.js";
|
|
5
|
+
import { t as connectMcpServers } from "./mcp-DGeB7-3D.js";
|
|
6
6
|
import { _ as validateResourcePath, b as createSkillActivationState, d as escapeXml, n as resolveSkills, p as installAllowedToolsGate, t as interpolateShellCommands, u as buildCatalog } from "./interpolate-DM1UcKeQ.js";
|
|
7
7
|
import { n as formatTokenUsage, t as flattenTurns } from "./stats-Lc3zL3RM.js";
|
|
8
8
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
9
9
|
import { createHooks } from "hookable";
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
|
-
import { mkdir, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
11
|
+
import { glob, mkdir, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
12
12
|
import { Buffer } from "node:buffer";
|
|
13
13
|
//#region src/aliasing.ts
|
|
14
14
|
/**
|
|
@@ -60,6 +60,45 @@ function toCanonicalName(wire, maps) {
|
|
|
60
60
|
return maps.canonicalByAlias.get(wire) ?? wire;
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
|
+
* Augment {@link AliasMaps} with INBOUND-ONLY aliases for the Claude Code
|
|
64
|
+
* `mcp__server__tool` double-underscore naming convention. For every MCP
|
|
65
|
+
* tool registered with the canonical `mcp_<server>_<tool>` form, add a
|
|
66
|
+
* `canonicalByAlias` entry mapping the double-underscore variant to the
|
|
67
|
+
* same canonical name. Outbound (`aliasByCanonical`) is left untouched —
|
|
68
|
+
* the model still sees the single-underscore canonical on the wire, so
|
|
69
|
+
* the tools-array byte count (and the provider prompt cache) is
|
|
70
|
+
* unaffected.
|
|
71
|
+
*
|
|
72
|
+
* Why: SDK consumers and tool descriptions across the ecosystem
|
|
73
|
+
* inconsistently reference one form or the other (Anthropic's docs use
|
|
74
|
+
* double, zidane uses single). A Claude-Code-trained model emitting
|
|
75
|
+
* `mcp__supabase__apply_migration` against a server zidane registered as
|
|
76
|
+
* `mcp_supabase_apply_migration` would otherwise trip the `tool:unknown`
|
|
77
|
+
* path and waste a turn on the correction.
|
|
78
|
+
*
|
|
79
|
+
* Idempotent: a canonical that already has a double-underscore alias
|
|
80
|
+
* mapped (host's explicit `toolAliases` got there first) is left alone.
|
|
81
|
+
* Tools whose canonical name DOESN'T start with `mcp_` (or that contain
|
|
82
|
+
* no inner separator) are skipped — we don't want to invent aliases for
|
|
83
|
+
* non-MCP tools or malformed names.
|
|
84
|
+
*
|
|
85
|
+
* Mutates `maps.canonicalByAlias` in place and returns the same object
|
|
86
|
+
* for chaining.
|
|
87
|
+
*/
|
|
88
|
+
function augmentMcpDoubleUnderscoreAliases(maps, canonicalNames) {
|
|
89
|
+
for (const canonical of canonicalNames) {
|
|
90
|
+
if (!canonical.startsWith("mcp_")) continue;
|
|
91
|
+
const tail = canonical.slice(4);
|
|
92
|
+
const sep = tail.indexOf("_");
|
|
93
|
+
if (sep <= 0 || sep >= tail.length - 1) continue;
|
|
94
|
+
const doubleForm = `mcp__${tail.slice(0, sep)}__${tail.slice(sep + 1)}`;
|
|
95
|
+
if (doubleForm === canonical) continue;
|
|
96
|
+
if (maps.canonicalByAlias.has(doubleForm)) continue;
|
|
97
|
+
maps.canonicalByAlias.set(doubleForm, canonical);
|
|
98
|
+
}
|
|
99
|
+
return maps;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
63
102
|
* Rewrite `tool_call` block names in a content array from canonical → wire for outbound
|
|
64
103
|
* messages sent to the provider. Mutation is non-destructive (returns a new array).
|
|
65
104
|
*/
|
|
@@ -326,36 +365,86 @@ function installDedupToolsGate(hooks, getDedupTools, getSession) {
|
|
|
326
365
|
function pendingKey(callId, name) {
|
|
327
366
|
return `${callId}::${name}`;
|
|
328
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* Resolve the legacy hasher-only form vs the new config-object form to
|
|
370
|
+
* the same internal shape. Centralised so the gate/after handlers stay
|
|
371
|
+
* single-branch. Returns `null` when the tool has no dedup config.
|
|
372
|
+
*/
|
|
373
|
+
function resolveConfig(name) {
|
|
374
|
+
const raw = getDedupTools()?.[name];
|
|
375
|
+
if (!raw) return null;
|
|
376
|
+
if (typeof raw === "function") return {
|
|
377
|
+
hasher: raw,
|
|
378
|
+
mode: "replay",
|
|
379
|
+
threshold: Infinity,
|
|
380
|
+
reason: void 0
|
|
381
|
+
};
|
|
382
|
+
const threshold = (typeof raw.threshold === "number" && Number.isFinite(raw.threshold) ? Math.max(2, Math.floor(raw.threshold)) : void 0) ?? (raw.mode === "block-after" ? 4 : Infinity);
|
|
383
|
+
return {
|
|
384
|
+
hasher: raw.hasher,
|
|
385
|
+
mode: raw.mode ?? "replay",
|
|
386
|
+
threshold,
|
|
387
|
+
reason: raw.reason
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
function formatReason(reason, toolName, input, count) {
|
|
391
|
+
if (typeof reason === "string") return reason;
|
|
392
|
+
if (typeof reason === "function") try {
|
|
393
|
+
const out = reason(input, count);
|
|
394
|
+
if (typeof out === "string" && out.length > 0) return out;
|
|
395
|
+
} catch {}
|
|
396
|
+
return `Identical \`${toolName}\` call repeated ${count} times — break the loop by changing your approach or moving on to a different step.`;
|
|
397
|
+
}
|
|
329
398
|
function gateHandler(ctx) {
|
|
330
399
|
if (ctx.block || ctx.result !== void 0) return;
|
|
331
|
-
const
|
|
332
|
-
if (!
|
|
400
|
+
const config = resolveConfig(ctx.name);
|
|
401
|
+
if (!config) return;
|
|
333
402
|
const state = getToolDedupState(getSession());
|
|
334
403
|
if (!state) return;
|
|
335
404
|
let hash;
|
|
336
405
|
try {
|
|
337
|
-
hash = hasher(ctx.input);
|
|
406
|
+
hash = config.hasher(ctx.input);
|
|
338
407
|
} catch {
|
|
339
408
|
return;
|
|
340
409
|
}
|
|
341
410
|
if (typeof hash !== "string" || hash.length === 0) return;
|
|
342
411
|
const prior = state.get(ctx.name);
|
|
343
412
|
if (prior && prior.hash === hash) {
|
|
413
|
+
const priorRepeats = prior.repeats ?? 0;
|
|
414
|
+
const count = priorRepeats + 2;
|
|
415
|
+
if (config.mode === "block-after" && count >= config.threshold) {
|
|
416
|
+
ctx.block = true;
|
|
417
|
+
ctx.reason = formatReason(config.reason, ctx.name, ctx.input, count);
|
|
418
|
+
state.set(ctx.name, {
|
|
419
|
+
hash,
|
|
420
|
+
result: prior.result,
|
|
421
|
+
repeats: priorRepeats + 1
|
|
422
|
+
});
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
344
425
|
ctx.result = prior.result;
|
|
426
|
+
pending.set(pendingKey(ctx.callId, ctx.name), {
|
|
427
|
+
hash,
|
|
428
|
+
repeats: priorRepeats + 1
|
|
429
|
+
});
|
|
345
430
|
return;
|
|
346
431
|
}
|
|
347
|
-
pending.set(pendingKey(ctx.callId, ctx.name),
|
|
432
|
+
pending.set(pendingKey(ctx.callId, ctx.name), {
|
|
433
|
+
hash,
|
|
434
|
+
repeats: 0
|
|
435
|
+
});
|
|
348
436
|
}
|
|
349
437
|
function afterHandler(ctx) {
|
|
350
438
|
const key = pendingKey(ctx.callId, ctx.name);
|
|
351
|
-
const
|
|
352
|
-
if (
|
|
439
|
+
const entry = pending.get(key);
|
|
440
|
+
if (entry === void 0) return;
|
|
353
441
|
pending.delete(key);
|
|
354
442
|
const state = getToolDedupState(getSession());
|
|
355
443
|
if (!state) return;
|
|
356
444
|
state.set(ctx.name, {
|
|
357
|
-
hash,
|
|
358
|
-
result: ctx.result
|
|
445
|
+
hash: entry.hash,
|
|
446
|
+
result: ctx.result,
|
|
447
|
+
repeats: entry.repeats
|
|
359
448
|
});
|
|
360
449
|
}
|
|
361
450
|
const unregisterGate = hooks.hook("tool:gate", gateHandler);
|
|
@@ -1412,6 +1501,8 @@ async function runLoop(ctx) {
|
|
|
1412
1501
|
const startTime = Date.now();
|
|
1413
1502
|
const maxTurns = ctx.maxTurns ?? Number.POSITIVE_INFINITY;
|
|
1414
1503
|
let turnsCompleted = 0;
|
|
1504
|
+
const pauseCap = ctx.maxConsecutivePauseTurns ?? 5;
|
|
1505
|
+
let consecutiveEmptyPauseTurns = 0;
|
|
1415
1506
|
const ttft = { mark: void 0 };
|
|
1416
1507
|
const markTtft = () => {
|
|
1417
1508
|
if (ttft.mark === void 0) ttft.mark = Date.now() - ctx.runStartMs;
|
|
@@ -1446,6 +1537,10 @@ async function runLoop(ctx) {
|
|
|
1446
1537
|
totalIn,
|
|
1447
1538
|
totalOut
|
|
1448
1539
|
});
|
|
1540
|
+
if (result.pauseEmpty) {
|
|
1541
|
+
consecutiveEmptyPauseTurns += 1;
|
|
1542
|
+
if (pauseCap > 0 && consecutiveEmptyPauseTurns >= pauseCap) break;
|
|
1543
|
+
} else consecutiveEmptyPauseTurns = 0;
|
|
1449
1544
|
if (ctx.signal.aborted) {
|
|
1450
1545
|
await ctx.hooks.callHook("agent:abort", {});
|
|
1451
1546
|
break;
|
|
@@ -1621,6 +1716,106 @@ function extractStreamErrorMeta(err) {
|
|
|
1621
1716
|
}
|
|
1622
1717
|
return out;
|
|
1623
1718
|
}
|
|
1719
|
+
/** Defaults applied when `behavior.retry` is absent or has missing fields. */
|
|
1720
|
+
const RETRY_DEFAULTS = {
|
|
1721
|
+
maxAttempts: 3,
|
|
1722
|
+
initialDelayMs: 1e3,
|
|
1723
|
+
maxDelayMs: 3e4
|
|
1724
|
+
};
|
|
1725
|
+
/**
|
|
1726
|
+
* Normalize a user-supplied `RetryConfig` (any field may be missing or invalid)
|
|
1727
|
+
* into a fully-populated config the retry loop can use without per-field guards.
|
|
1728
|
+
*
|
|
1729
|
+
* Invalid values (non-finite, < 1 for `maxAttempts`, < 0 for delays) fall back
|
|
1730
|
+
* to defaults rather than throwing — this is a behavior knob, not a validation
|
|
1731
|
+
* boundary, and a bad value here shouldn't crash a run.
|
|
1732
|
+
*/
|
|
1733
|
+
function resolveRetryConfig(cfg) {
|
|
1734
|
+
return {
|
|
1735
|
+
maxAttempts: Number.isFinite(cfg?.maxAttempts) && cfg.maxAttempts >= 1 ? Math.floor(cfg.maxAttempts) : RETRY_DEFAULTS.maxAttempts,
|
|
1736
|
+
initialDelayMs: Number.isFinite(cfg?.initialDelayMs) && cfg.initialDelayMs >= 0 ? cfg.initialDelayMs : RETRY_DEFAULTS.initialDelayMs,
|
|
1737
|
+
maxDelayMs: Number.isFinite(cfg?.maxDelayMs) && cfg.maxDelayMs >= 0 ? cfg.maxDelayMs : RETRY_DEFAULTS.maxDelayMs
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
/**
|
|
1741
|
+
* Compute the backoff delay for the upcoming retry.
|
|
1742
|
+
*
|
|
1743
|
+
* Strategy:
|
|
1744
|
+
* - If the server returned `retry-after` / `retry-after-ms`, honor it (capped at `maxDelayMs`).
|
|
1745
|
+
* - Otherwise: `initialDelayMs * 2^(attempt-1)`, capped at `maxDelayMs`, then "full jitter"
|
|
1746
|
+
* (`Math.random() * computed`). Full jitter scatters retries from concurrent clients
|
|
1747
|
+
* across the whole window — empirically better than fixed exponential under thundering-herd
|
|
1748
|
+
* (per AWS Architecture Blog's analysis of EBO+jitter strategies).
|
|
1749
|
+
*
|
|
1750
|
+
* `attempt` is the 1-indexed number of the attempt that just *failed*, so the first
|
|
1751
|
+
* post-failure delay uses `attempt=1` → `initialDelayMs * 1` before jitter.
|
|
1752
|
+
*/
|
|
1753
|
+
function computeRetryDelayMs(attempt, cfg, retryAfterMs) {
|
|
1754
|
+
if (retryAfterMs !== void 0 && retryAfterMs >= 0) return Math.min(retryAfterMs, cfg.maxDelayMs);
|
|
1755
|
+
const exponential = cfg.initialDelayMs * 2 ** (attempt - 1);
|
|
1756
|
+
const capped = Math.min(exponential, cfg.maxDelayMs);
|
|
1757
|
+
return Math.floor(Math.random() * capped);
|
|
1758
|
+
}
|
|
1759
|
+
/**
|
|
1760
|
+
* Extract a `retry-after` value (in milliseconds) from an error's `.headers`, if any.
|
|
1761
|
+
*
|
|
1762
|
+
* Supports both `retry-after-ms` (non-standard but Stainless-emitted; already in ms,
|
|
1763
|
+
* always integer) and the standard `retry-after` header (integer seconds, RFC 7231).
|
|
1764
|
+
* Returns `undefined` when neither is present, non-numeric, or negative.
|
|
1765
|
+
*
|
|
1766
|
+
* `parseInt` over `parseFloat` here matches the actual contract — Stainless emits
|
|
1767
|
+
* `retry-after-ms` as an integer and RFC 7231 specifies a non-negative integer for
|
|
1768
|
+
* the seconds form. The HTTP-date form of `retry-after` is deliberately unsupported
|
|
1769
|
+
* (Anthropic + OpenAI both emit numeric seconds; supporting dates invites clock-skew
|
|
1770
|
+
* concerns for negligible benefit).
|
|
1771
|
+
*/
|
|
1772
|
+
function extractRetryAfterMs(err) {
|
|
1773
|
+
if (!err || typeof err !== "object") return void 0;
|
|
1774
|
+
const headers = err.headers;
|
|
1775
|
+
if (!headers || typeof headers !== "object") return void 0;
|
|
1776
|
+
const get = (key) => {
|
|
1777
|
+
const h = headers;
|
|
1778
|
+
if (typeof h.get === "function") {
|
|
1779
|
+
const v = h.get(key);
|
|
1780
|
+
return typeof v === "string" ? v : void 0;
|
|
1781
|
+
}
|
|
1782
|
+
const v = h[key];
|
|
1783
|
+
return typeof v === "string" ? v : void 0;
|
|
1784
|
+
};
|
|
1785
|
+
const ms = get("retry-after-ms");
|
|
1786
|
+
if (ms !== void 0) {
|
|
1787
|
+
const parsed = Number.parseInt(ms, 10);
|
|
1788
|
+
if (Number.isFinite(parsed) && parsed >= 0) return parsed;
|
|
1789
|
+
}
|
|
1790
|
+
const seconds = get("retry-after");
|
|
1791
|
+
if (seconds !== void 0) {
|
|
1792
|
+
const parsed = Number.parseInt(seconds, 10);
|
|
1793
|
+
if (Number.isFinite(parsed) && parsed >= 0) return parsed * 1e3;
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
/**
|
|
1797
|
+
* `setTimeout` that rejects if the given signal aborts before the timer fires.
|
|
1798
|
+
*
|
|
1799
|
+
* Resolves with `undefined` on normal completion. Rejects with the signal's
|
|
1800
|
+
* `reason` (or a generic AbortError when no reason is set) on abort. Cleans
|
|
1801
|
+
* up its `abort` listener in both paths so callers don't leak handlers.
|
|
1802
|
+
*/
|
|
1803
|
+
function abortableSleep(ms, signal) {
|
|
1804
|
+
if (signal.aborted) return Promise.reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
|
|
1805
|
+
return new Promise((resolve, reject) => {
|
|
1806
|
+
let timer;
|
|
1807
|
+
const onAbort = () => {
|
|
1808
|
+
clearTimeout(timer);
|
|
1809
|
+
signal.removeEventListener("abort", onAbort);
|
|
1810
|
+
reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
|
|
1811
|
+
};
|
|
1812
|
+
timer = setTimeout(() => {
|
|
1813
|
+
signal.removeEventListener("abort", onAbort);
|
|
1814
|
+
resolve();
|
|
1815
|
+
}, ms);
|
|
1816
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1817
|
+
});
|
|
1818
|
+
}
|
|
1624
1819
|
async function executeTurn(ctx, turn, priorUsage) {
|
|
1625
1820
|
const turnId = await ctx.generateTurnId();
|
|
1626
1821
|
let canonicalMessages = turnsToMessages(applyCompactSummaryCutoff(ctx.turns));
|
|
@@ -1635,6 +1830,21 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
1635
1830
|
const threshold = typeof ctx.compactThreshold === "number" && ctx.compactThreshold > 0 ? ctx.compactThreshold : 131072;
|
|
1636
1831
|
const keep = typeof ctx.compactKeepTurns === "number" && ctx.compactKeepTurns >= 0 ? ctx.compactKeepTurns : 4;
|
|
1637
1832
|
sanitizedMessages = applyTailCompaction(sanitizedMessages, threshold, keep);
|
|
1833
|
+
} else if (typeof ctx.compactStrategy === "function") {
|
|
1834
|
+
const threshold = typeof ctx.compactThreshold === "number" && ctx.compactThreshold > 0 ? ctx.compactThreshold : 131072;
|
|
1835
|
+
const keep = typeof ctx.compactKeepTurns === "number" && ctx.compactKeepTurns >= 0 ? ctx.compactKeepTurns : 4;
|
|
1836
|
+
let totalBytes = 0;
|
|
1837
|
+
for (const msg of sanitizedMessages) for (const block of msg.content) if (block.type === "tool_result") totalBytes += toolOutputByteLength(block.output);
|
|
1838
|
+
try {
|
|
1839
|
+
const compacted = await ctx.compactStrategy(sanitizedMessages, {
|
|
1840
|
+
threshold,
|
|
1841
|
+
keepTurns: keep,
|
|
1842
|
+
totalBytes
|
|
1843
|
+
});
|
|
1844
|
+
if (Array.isArray(compacted)) sanitizedMessages = compacted;
|
|
1845
|
+
} catch (err) {
|
|
1846
|
+
console.error("[zidane] compactStrategy function threw:", err);
|
|
1847
|
+
}
|
|
1638
1848
|
}
|
|
1639
1849
|
const effectiveThinkingBudget = applyThinkingDecay(ctx.thinkingBudget, ctx.thinkingDecay, turn);
|
|
1640
1850
|
const formattedTools = ctx.rebuildFormattedTools ? ctx.rebuildFormattedTools() : ctx.formattedTools;
|
|
@@ -1668,6 +1878,8 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
1668
1878
|
turnId,
|
|
1669
1879
|
options: streamOptions
|
|
1670
1880
|
});
|
|
1881
|
+
streamOptions.messages = applyPairingRepair(ctx, streamOptions.messages, turnId);
|
|
1882
|
+
streamOptions.messages = ensureEndsWithUserMessage(streamOptions.messages, ctx.provider);
|
|
1671
1883
|
let currentText = "";
|
|
1672
1884
|
let currentThinking = "";
|
|
1673
1885
|
const streamStartedAt = Date.now();
|
|
@@ -1679,74 +1891,104 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
1679
1891
|
turnId,
|
|
1680
1892
|
startedAt: streamStartedAt
|
|
1681
1893
|
});
|
|
1894
|
+
const retryCfg = resolveRetryConfig(ctx.retry);
|
|
1682
1895
|
let result;
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1896
|
+
let attempt = 0;
|
|
1897
|
+
while (true) {
|
|
1898
|
+
attempt += 1;
|
|
1899
|
+
try {
|
|
1900
|
+
result = await ctx.provider.stream(streamOptions, {
|
|
1901
|
+
onText(delta) {
|
|
1902
|
+
markTurnTtft();
|
|
1903
|
+
currentText += delta;
|
|
1904
|
+
ctx.hooks.callHook("stream:text", {
|
|
1905
|
+
delta,
|
|
1906
|
+
text: currentText,
|
|
1907
|
+
turnId
|
|
1908
|
+
});
|
|
1909
|
+
},
|
|
1910
|
+
onThinking(delta) {
|
|
1911
|
+
markTurnTtft();
|
|
1912
|
+
currentThinking += delta;
|
|
1913
|
+
ctx.hooks.callHook("stream:thinking", {
|
|
1914
|
+
delta,
|
|
1915
|
+
thinking: currentThinking,
|
|
1916
|
+
turnId
|
|
1917
|
+
});
|
|
1918
|
+
},
|
|
1919
|
+
onOAuthRefresh(refreshCtx) {
|
|
1920
|
+
return ctx.hooks.callHook("oauth:refresh", refreshCtx);
|
|
1921
|
+
}
|
|
1922
|
+
});
|
|
1923
|
+
break;
|
|
1924
|
+
} catch (caught) {
|
|
1925
|
+
let terminalErr = caught;
|
|
1926
|
+
let wasAborted = ctx.signal.aborted || caught instanceof Error && caught.name === "AbortError";
|
|
1927
|
+
const classified = !wasAborted ? ctx.provider.classifyError?.(caught) : null;
|
|
1928
|
+
const isRetryable = classified?.kind === "provider_error" && classified.retryable === true;
|
|
1929
|
+
if (!wasAborted && isRetryable && currentText === "" && currentThinking === "" && attempt < retryCfg.maxAttempts) {
|
|
1930
|
+
const meta = extractStreamErrorMeta(caught);
|
|
1931
|
+
const delayMs = computeRetryDelayMs(attempt, retryCfg, extractRetryAfterMs(caught));
|
|
1932
|
+
await ctx.hooks.callHook("stream:retry", {
|
|
1933
|
+
turnId,
|
|
1934
|
+
attempt,
|
|
1935
|
+
nextAttempt: attempt + 1,
|
|
1936
|
+
delayMs,
|
|
1937
|
+
err: caught,
|
|
1938
|
+
...meta
|
|
1692
1939
|
});
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1940
|
+
try {
|
|
1941
|
+
await abortableSleep(delayMs, ctx.signal);
|
|
1942
|
+
continue;
|
|
1943
|
+
} catch {
|
|
1944
|
+
const abortErr = /* @__PURE__ */ new Error("Agent run aborted");
|
|
1945
|
+
abortErr.name = "AbortError";
|
|
1946
|
+
terminalErr = abortErr;
|
|
1947
|
+
wasAborted = true;
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
const errorUsage = {
|
|
1951
|
+
input: 0,
|
|
1952
|
+
output: 0
|
|
1953
|
+
};
|
|
1954
|
+
const placeholderText = wasAborted ? "[⏹ Streaming was aborted.]" : buildStreamErrorPlaceholder(terminalErr);
|
|
1955
|
+
const errorContent = currentText ? [{
|
|
1956
|
+
type: "text",
|
|
1957
|
+
text: currentText
|
|
1958
|
+
}] : [{
|
|
1959
|
+
type: "text",
|
|
1960
|
+
text: placeholderText
|
|
1961
|
+
}];
|
|
1962
|
+
const errorTurn = {
|
|
1963
|
+
id: turnId,
|
|
1964
|
+
runId: ctx.runId,
|
|
1965
|
+
role: "assistant",
|
|
1966
|
+
content: errorContent,
|
|
1967
|
+
usage: errorUsage,
|
|
1968
|
+
createdAt: await ctx.clock.now()
|
|
1969
|
+
};
|
|
1970
|
+
ctx.turns.push(errorTurn);
|
|
1971
|
+
if (!wasAborted) {
|
|
1972
|
+
const meta = extractStreamErrorMeta(terminalErr);
|
|
1973
|
+
await ctx.hooks.callHook("stream:error", {
|
|
1974
|
+
err: terminalErr,
|
|
1975
|
+
turnId,
|
|
1976
|
+
...meta
|
|
1701
1977
|
});
|
|
1702
|
-
},
|
|
1703
|
-
onOAuthRefresh(refreshCtx) {
|
|
1704
|
-
return ctx.hooks.callHook("oauth:refresh", refreshCtx);
|
|
1705
1978
|
}
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
const wasAborted = ctx.signal.aborted || err instanceof Error && err.name === "AbortError";
|
|
1709
|
-
const errorUsage = {
|
|
1710
|
-
input: 0,
|
|
1711
|
-
output: 0
|
|
1712
|
-
};
|
|
1713
|
-
const placeholderText = wasAborted ? "[⏹ Streaming was aborted.]" : buildStreamErrorPlaceholder(err);
|
|
1714
|
-
const errorContent = currentText ? [{
|
|
1715
|
-
type: "text",
|
|
1716
|
-
text: currentText
|
|
1717
|
-
}] : [{
|
|
1718
|
-
type: "text",
|
|
1719
|
-
text: placeholderText
|
|
1720
|
-
}];
|
|
1721
|
-
const errorTurn = {
|
|
1722
|
-
id: turnId,
|
|
1723
|
-
runId: ctx.runId,
|
|
1724
|
-
role: "assistant",
|
|
1725
|
-
content: errorContent,
|
|
1726
|
-
usage: errorUsage,
|
|
1727
|
-
createdAt: await ctx.clock.now()
|
|
1728
|
-
};
|
|
1729
|
-
ctx.turns.push(errorTurn);
|
|
1730
|
-
if (!wasAborted) {
|
|
1731
|
-
const meta = extractStreamErrorMeta(err);
|
|
1732
|
-
await ctx.hooks.callHook("stream:error", {
|
|
1733
|
-
err,
|
|
1979
|
+
await ctx.hooks.callHook("turn:after", {
|
|
1980
|
+
turn,
|
|
1734
1981
|
turnId,
|
|
1735
|
-
|
|
1982
|
+
usage: errorUsage,
|
|
1983
|
+
message: errorTurn,
|
|
1984
|
+
toolCounts: {
|
|
1985
|
+
turn: Object.freeze({}),
|
|
1986
|
+
run: Object.freeze({ ...ctx.runToolCounts })
|
|
1987
|
+
},
|
|
1988
|
+
cumulativeUsage: buildCumulativeUsage(priorUsage, errorUsage)
|
|
1736
1989
|
});
|
|
1990
|
+
throw wrapProviderError(terminalErr, ctx);
|
|
1737
1991
|
}
|
|
1738
|
-
await ctx.hooks.callHook("turn:after", {
|
|
1739
|
-
turn,
|
|
1740
|
-
turnId,
|
|
1741
|
-
usage: errorUsage,
|
|
1742
|
-
message: errorTurn,
|
|
1743
|
-
toolCounts: {
|
|
1744
|
-
turn: Object.freeze({}),
|
|
1745
|
-
run: Object.freeze({ ...ctx.runToolCounts })
|
|
1746
|
-
},
|
|
1747
|
-
cumulativeUsage: buildCumulativeUsage(priorUsage, errorUsage)
|
|
1748
|
-
});
|
|
1749
|
-
throw wrapProviderError(err, ctx);
|
|
1750
1992
|
}
|
|
1751
1993
|
if (currentText) await ctx.hooks.callHook("stream:end", {
|
|
1752
1994
|
text: currentText,
|
|
@@ -1844,6 +2086,7 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
1844
2086
|
usage: result.usage
|
|
1845
2087
|
};
|
|
1846
2088
|
}
|
|
2089
|
+
const finishedEmptyPause = canonicalToolCalls.length === 0 && result.usage.finishReason === "pause" && currentText.length === 0 && currentThinking.length === 0;
|
|
1847
2090
|
if (canonicalToolCalls.length === 0 && result.usage.finishReason === "pause") {
|
|
1848
2091
|
const continueMsg = ctx.provider.userMessage("Please continue.");
|
|
1849
2092
|
ctx.turns.push({
|
|
@@ -1856,7 +2099,8 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
1856
2099
|
return {
|
|
1857
2100
|
ended: false,
|
|
1858
2101
|
turnId,
|
|
1859
|
-
usage: result.usage
|
|
2102
|
+
usage: result.usage,
|
|
2103
|
+
...finishedEmptyPause ? { pauseEmpty: true } : {}
|
|
1860
2104
|
};
|
|
1861
2105
|
}
|
|
1862
2106
|
const toolResults = await executeToolBatch(ctx, canonicalToolCalls, turnId);
|
|
@@ -2032,6 +2276,11 @@ async function runSingleToolDispatch(ctx, call, turnId, fixed) {
|
|
|
2032
2276
|
}
|
|
2033
2277
|
let effectiveInput = gateCtx.input;
|
|
2034
2278
|
if (!toolDef) {
|
|
2279
|
+
await ctx.hooks.callHook("tool:before", {
|
|
2280
|
+
...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),
|
|
2281
|
+
runToolCounts,
|
|
2282
|
+
unknown: true
|
|
2283
|
+
});
|
|
2035
2284
|
const unknownCtx = {
|
|
2036
2285
|
...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),
|
|
2037
2286
|
suppressError: false
|
|
@@ -3431,9 +3680,12 @@ function selectToolSearchMatches(catalog, input, defaultLimit = DEFAULT_LIMIT$1)
|
|
|
3431
3680
|
* normal "tool not callable" error on its next attempt, which is the
|
|
3432
3681
|
* correct response when a tool genuinely no longer exists.
|
|
3433
3682
|
*/
|
|
3434
|
-
function applyToolSearchToUnlocked(catalog, input, unlocked, defaultLimit) {
|
|
3683
|
+
function applyToolSearchToUnlocked(catalog, input, unlocked, defaultLimit, addUnlock) {
|
|
3435
3684
|
const { shown } = selectToolSearchMatches(catalog, input, defaultLimit ?? DEFAULT_LIMIT$1);
|
|
3436
|
-
for (const entry of shown)
|
|
3685
|
+
for (const entry of shown) {
|
|
3686
|
+
unlocked.add(entry.canonicalName);
|
|
3687
|
+
addUnlock?.(entry.canonicalName);
|
|
3688
|
+
}
|
|
3437
3689
|
}
|
|
3438
3690
|
/**
|
|
3439
3691
|
* Factory for `tool_search`. Auto-injected by the agent when
|
|
@@ -3476,7 +3728,10 @@ function createToolSearchTool(options) {
|
|
|
3476
3728
|
if (ctx.signal?.aborted) return "<tool_search_results matches=\"0\" aborted=\"true\">Run aborted.</tool_search_results>";
|
|
3477
3729
|
if (options.catalog.length === 0) return "<tool_search_results matches=\"0\">No lazy tools registered for this run.</tool_search_results>";
|
|
3478
3730
|
const { shown, total, truncated, misses, query, server } = selectToolSearchMatches(options.catalog, input, defaultLimit);
|
|
3479
|
-
for (const entry of shown)
|
|
3731
|
+
for (const entry of shown) {
|
|
3732
|
+
options.unlocked.add(entry.canonicalName);
|
|
3733
|
+
options.addUnlock?.(entry.canonicalName);
|
|
3734
|
+
}
|
|
3480
3735
|
const parts = [];
|
|
3481
3736
|
const queryAttr = query ? ` query="${escapeXml(query)}"` : "";
|
|
3482
3737
|
const serverAttr = server ? ` server="${escapeXml(server)}"` : "";
|
|
@@ -3540,6 +3795,7 @@ const HOOK_EVENT_SET = new Set([
|
|
|
3540
3795
|
"stream:end",
|
|
3541
3796
|
"stream:thinking",
|
|
3542
3797
|
"stream:error",
|
|
3798
|
+
"stream:retry",
|
|
3543
3799
|
"oauth:refresh",
|
|
3544
3800
|
"tool:gate",
|
|
3545
3801
|
"tool:dispatched",
|
|
@@ -3673,6 +3929,7 @@ function resolveBehavior(agentBehavior, runBehavior) {
|
|
|
3673
3929
|
maxConcurrentTools: runBehavior?.maxConcurrentTools ?? agentBehavior?.maxConcurrentTools,
|
|
3674
3930
|
maxTurns: runBehavior?.maxTurns ?? agentBehavior?.maxTurns,
|
|
3675
3931
|
maxCostUsd: runBehavior?.maxCostUsd ?? agentBehavior?.maxCostUsd,
|
|
3932
|
+
retry: runBehavior?.retry ?? agentBehavior?.retry,
|
|
3676
3933
|
maxTotalTokens: runBehavior?.maxTotalTokens ?? agentBehavior?.maxTotalTokens,
|
|
3677
3934
|
maxTokens: runBehavior?.maxTokens ?? agentBehavior?.maxTokens,
|
|
3678
3935
|
thinkingBudget: runBehavior?.thinkingBudget ?? agentBehavior?.thinkingBudget,
|
|
@@ -3692,13 +3949,15 @@ function resolveBehavior(agentBehavior, runBehavior) {
|
|
|
3692
3949
|
elideStaleReads: runBehavior?.elideStaleReads ?? agentBehavior?.elideStaleReads,
|
|
3693
3950
|
toolDisclosure: runBehavior?.toolDisclosure ?? agentBehavior?.toolDisclosure ?? "eager",
|
|
3694
3951
|
toolSearch: runBehavior?.toolSearch ?? agentBehavior?.toolSearch,
|
|
3952
|
+
surfaceMcpInstructions: runBehavior?.surfaceMcpInstructions ?? agentBehavior?.surfaceMcpInstructions ?? true,
|
|
3695
3953
|
persistThreshold: runBehavior?.persistThreshold ?? agentBehavior?.persistThreshold,
|
|
3696
3954
|
persistExcludeTools: runBehavior?.persistExcludeTools ?? agentBehavior?.persistExcludeTools,
|
|
3697
3955
|
persistDir: runBehavior?.persistDir ?? agentBehavior?.persistDir,
|
|
3698
3956
|
persistMaxBytes: runBehavior?.persistMaxBytes ?? agentBehavior?.persistMaxBytes,
|
|
3699
3957
|
tasksDir: runBehavior?.tasksDir ?? agentBehavior?.tasksDir,
|
|
3700
3958
|
disableBackgroundTasks: runBehavior?.disableBackgroundTasks ?? agentBehavior?.disableBackgroundTasks,
|
|
3701
|
-
strictToolPairing: runBehavior?.strictToolPairing ?? agentBehavior?.strictToolPairing ?? false
|
|
3959
|
+
strictToolPairing: runBehavior?.strictToolPairing ?? agentBehavior?.strictToolPairing ?? false,
|
|
3960
|
+
maxConsecutivePauseTurns: runBehavior?.maxConsecutivePauseTurns ?? agentBehavior?.maxConsecutivePauseTurns
|
|
3702
3961
|
};
|
|
3703
3962
|
}
|
|
3704
3963
|
/**
|
|
@@ -3821,6 +4080,40 @@ function installLazyDisclosureGate(hooks, lazyCanonicalNames, unlocked, discover
|
|
|
3821
4080
|
});
|
|
3822
4081
|
}
|
|
3823
4082
|
/**
|
|
4083
|
+
* Render the per-server MCP `instructions` payloads into a single
|
|
4084
|
+
* `# MCP Server Instructions` section. Matches the shape the Claude Code
|
|
4085
|
+
* SDK emits so eval traces stay comparable.
|
|
4086
|
+
*
|
|
4087
|
+
* Empty / whitespace-only entries are filtered out upstream (see
|
|
4088
|
+
* `bootstrapServer`); this function only renders what survived. Callers
|
|
4089
|
+
* that pass an empty map get an empty string back — no stub heading.
|
|
4090
|
+
*
|
|
4091
|
+
* Output shape:
|
|
4092
|
+
*
|
|
4093
|
+
* # MCP Server Instructions
|
|
4094
|
+
*
|
|
4095
|
+
* ## supabase
|
|
4096
|
+
* The project is provisioned. Use `apply_migration` directly.
|
|
4097
|
+
*
|
|
4098
|
+
* ## linear
|
|
4099
|
+
* …
|
|
4100
|
+
*
|
|
4101
|
+
* Server names are emitted in Map iteration order (config order), which
|
|
4102
|
+
* is byte-stable across runs.
|
|
4103
|
+
*/
|
|
4104
|
+
function renderMcpInstructionsSection(instructions) {
|
|
4105
|
+
if (instructions.size === 0) return "";
|
|
4106
|
+
const parts = ["# MCP Server Instructions", ""];
|
|
4107
|
+
let first = true;
|
|
4108
|
+
for (const [name, body] of instructions) {
|
|
4109
|
+
if (!first) parts.push("");
|
|
4110
|
+
first = false;
|
|
4111
|
+
parts.push(`## ${name}`);
|
|
4112
|
+
parts.push(body.trim());
|
|
4113
|
+
}
|
|
4114
|
+
return parts.join("\n");
|
|
4115
|
+
}
|
|
4116
|
+
/**
|
|
3824
4117
|
* Pick the next safe value for `runCounter` so `run_${++counter}` mints
|
|
3825
4118
|
* an id that doesn't collide with any runId already referenced by the
|
|
3826
4119
|
* session — whether the runId lives in `session.runs` or only in
|
|
@@ -4007,9 +4300,9 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
4007
4300
|
const thinking = options.thinking ?? "off";
|
|
4008
4301
|
const model = options.model ?? provider.meta.defaultModel;
|
|
4009
4302
|
const resolvedBehavior = resolveBehavior(agentBehavior, options.behavior);
|
|
4010
|
-
const { maxConcurrentTools, maxTurns, maxCostUsd, maxTotalTokens, maxTokens, thinkingBudget, schema, cache, toolOutputBudget, toolOutputBudgetExcludeTools, compactStrategy, compactThreshold, compactKeepTurns, thinkingDecay, dedupTools, toolBudgets, elideStaleReads, toolDisclosure, toolSearch, persistThreshold, persistExcludeTools, persistDir, persistMaxBytes, strictToolPairing } = resolvedBehavior;
|
|
4303
|
+
const { maxConcurrentTools, maxTurns, maxCostUsd, maxTotalTokens, maxTokens, retry, thinkingBudget, schema, cache, toolOutputBudget, toolOutputBudgetExcludeTools, compactStrategy, compactThreshold, compactKeepTurns, thinkingDecay, dedupTools, toolBudgets, elideStaleReads, toolDisclosure, toolSearch, surfaceMcpInstructions, persistThreshold, persistExcludeTools, persistDir, persistMaxBytes, strictToolPairing, maxConsecutivePauseTurns } = resolvedBehavior;
|
|
4011
4304
|
let system = options.system || agentSystem || "You are a helpful assistant.";
|
|
4012
|
-
if (skillsCatalog) system =
|
|
4305
|
+
if (skillsCatalog) system = appendStaticSection(system, skillsCatalog);
|
|
4013
4306
|
const runBaseTools = options.tools !== void 0 ? options.tools : mcpConnection ? {
|
|
4014
4307
|
...sourceTools,
|
|
4015
4308
|
...mcpConnection.tools
|
|
@@ -4041,6 +4334,16 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
4041
4334
|
});
|
|
4042
4335
|
const disclosure = partitionToolDisclosure(toolsPreSearch, mcpToolNames, mcpServers, toolDisclosure, toolAliases);
|
|
4043
4336
|
const unlocked = new Set(disclosure.eagerCanonicalNames);
|
|
4337
|
+
const initialUnlocked = new Set(disclosure.eagerCanonicalNames);
|
|
4338
|
+
const dynamicUnlockOrder = [];
|
|
4339
|
+
const dynamicUnlockSeen = /* @__PURE__ */ new Set();
|
|
4340
|
+
function recordDynamicUnlock(canonical) {
|
|
4341
|
+
if (initialUnlocked.has(canonical)) return;
|
|
4342
|
+
if (dynamicUnlockSeen.has(canonical)) return;
|
|
4343
|
+
dynamicUnlockSeen.add(canonical);
|
|
4344
|
+
unlocked.add(canonical);
|
|
4345
|
+
dynamicUnlockOrder.push(canonical);
|
|
4346
|
+
}
|
|
4044
4347
|
const hostDefinedToolSearch = !!toolsPreSearch.tool_search;
|
|
4045
4348
|
const shouldInjectToolSearch = disclosure.lazyEntries.length > 0 && toolSearch?.tool !== false && !hostDefinedToolSearch;
|
|
4046
4349
|
let tools = toolsPreSearch;
|
|
@@ -4048,6 +4351,7 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
4048
4351
|
const toolSearchTool = createToolSearchTool({
|
|
4049
4352
|
catalog: disclosure.lazyEntries,
|
|
4050
4353
|
unlocked,
|
|
4354
|
+
addUnlock: recordDynamicUnlock,
|
|
4051
4355
|
...toolSearch?.limit !== void 0 ? { defaultLimit: toolSearch.limit } : {}
|
|
4052
4356
|
});
|
|
4053
4357
|
tools = {
|
|
@@ -4055,14 +4359,29 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
4055
4359
|
[toolSearchTool.spec.name]: toolSearchTool
|
|
4056
4360
|
};
|
|
4057
4361
|
unlocked.add(toolSearchTool.spec.name);
|
|
4362
|
+
initialUnlocked.add(toolSearchTool.spec.name);
|
|
4058
4363
|
}
|
|
4059
4364
|
const discoveryToolName = shouldInjectToolSearch ? "tool_search" : hostDefinedToolSearch ? toolAliases?.tool_search ?? "tool_search" : null;
|
|
4060
|
-
if (disclosure.lazyEntries.length > 0) system =
|
|
4365
|
+
if (disclosure.lazyEntries.length > 0) system = appendStaticSection(system, buildSearchableCatalog(disclosure.lazyEntries, { discoveryToolName }));
|
|
4366
|
+
if (surfaceMcpInstructions && mcpConnection?.instructions && mcpConnection.instructions.size > 0) {
|
|
4367
|
+
const section = renderMcpInstructionsSection(mcpConnection.instructions);
|
|
4368
|
+
if (section.length > 0) system = appendStaticSection(system, section);
|
|
4369
|
+
}
|
|
4061
4370
|
const aliasMaps = buildAliasMaps(toolAliases, Object.keys(tools));
|
|
4371
|
+
augmentMcpDoubleUnderscoreAliases(aliasMaps, Object.keys(tools));
|
|
4062
4372
|
function buildFormattedTools() {
|
|
4063
4373
|
const specs = [];
|
|
4064
4374
|
for (const t of Object.values(tools)) {
|
|
4065
|
-
if (!
|
|
4375
|
+
if (!initialUnlocked.has(t.spec.name)) continue;
|
|
4376
|
+
specs.push({
|
|
4377
|
+
name: aliasMaps.aliasByCanonical.get(t.spec.name) ?? t.spec.name,
|
|
4378
|
+
description: t.spec.description || "",
|
|
4379
|
+
inputSchema: t.spec.inputSchema
|
|
4380
|
+
});
|
|
4381
|
+
}
|
|
4382
|
+
for (const canonical of dynamicUnlockOrder) {
|
|
4383
|
+
const t = tools[canonical];
|
|
4384
|
+
if (!t) continue;
|
|
4066
4385
|
specs.push({
|
|
4067
4386
|
name: aliasMaps.aliasByCanonical.get(t.spec.name) ?? t.spec.name,
|
|
4068
4387
|
description: t.spec.description || "",
|
|
@@ -4085,7 +4404,7 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
4085
4404
|
if (block.type !== "tool_call") continue;
|
|
4086
4405
|
if (block.name !== "tool_search") continue;
|
|
4087
4406
|
if (!resolvedCallIds.has(block.id)) continue;
|
|
4088
|
-
applyToolSearchToUnlocked(disclosure.lazyEntries, block.input, unlocked, toolSearch?.limit);
|
|
4407
|
+
applyToolSearchToUnlocked(disclosure.lazyEntries, block.input, unlocked, toolSearch?.limit, recordDynamicUnlock);
|
|
4089
4408
|
}
|
|
4090
4409
|
}
|
|
4091
4410
|
}
|
|
@@ -4206,6 +4525,7 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
4206
4525
|
maxTurns,
|
|
4207
4526
|
...maxCostUsd !== void 0 ? { maxCostUsd } : {},
|
|
4208
4527
|
...maxTotalTokens !== void 0 ? { maxTotalTokens } : {},
|
|
4528
|
+
...retry !== void 0 ? { retry } : {},
|
|
4209
4529
|
maxTokens,
|
|
4210
4530
|
...session ? { session } : {},
|
|
4211
4531
|
...agentReadState ? { readState: agentReadState } : {},
|
|
@@ -4226,6 +4546,7 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
4226
4546
|
...persistDir !== void 0 ? { persistDir } : {},
|
|
4227
4547
|
...persistMaxBytes !== void 0 ? { persistMaxBytes } : {},
|
|
4228
4548
|
...strictToolPairing ? { strictToolPairing: true } : {},
|
|
4549
|
+
...maxConsecutivePauseTurns !== void 0 ? { maxConsecutivePauseTurns } : {},
|
|
4229
4550
|
providerName: provider.name,
|
|
4230
4551
|
runStartMs,
|
|
4231
4552
|
runToolCounts: {},
|
|
@@ -4523,7 +4844,8 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
4523
4844
|
get activeSkills() {
|
|
4524
4845
|
return skillActivationState.active();
|
|
4525
4846
|
},
|
|
4526
|
-
meta: Object.freeze({ ...provider.meta })
|
|
4847
|
+
meta: Object.freeze({ ...provider.meta }),
|
|
4848
|
+
[Symbol.asyncDispose]: destroy
|
|
4527
4849
|
};
|
|
4528
4850
|
}
|
|
4529
4851
|
//#endregion
|
|
@@ -4799,7 +5121,7 @@ const edit = {
|
|
|
4799
5121
|
properties: {
|
|
4800
5122
|
path: {
|
|
4801
5123
|
type: "string",
|
|
4802
|
-
description: "
|
|
5124
|
+
description: "File path (relative to the execution-context cwd, or absolute)."
|
|
4803
5125
|
},
|
|
4804
5126
|
old_string: {
|
|
4805
5127
|
type: "string",
|
|
@@ -4904,12 +5226,19 @@ function sharedPrefixLength(a, b) {
|
|
|
4904
5226
|
/**
|
|
4905
5227
|
* Glob-pattern file matching.
|
|
4906
5228
|
*
|
|
4907
|
-
* Uses
|
|
4908
|
-
* context.
|
|
4909
|
-
*
|
|
4910
|
-
*
|
|
5229
|
+
* Uses the Node `fs/promises` `glob` API in the in-process execution
|
|
5230
|
+
* context (Bun ≥1.3 re-implements the same module-level entry, so the
|
|
5231
|
+
* same code path serves both runtimes). For non-process contexts
|
|
5232
|
+
* (docker, sandbox), falls back to running the pattern through a shell
|
|
5233
|
+
* `find` invocation so the match is executed wherever the context lives.
|
|
5234
|
+
*
|
|
5235
|
+
* Behavioral note: Node's `fs.glob` yields directories alongside files
|
|
5236
|
+
* and Bun's port doesn't yet accept `withFileTypes`, so we post-filter
|
|
5237
|
+
* with `stat` to keep the historical files-only contract.
|
|
4911
5238
|
*
|
|
4912
|
-
* Results are capped at 1000 entries to keep model input bounded.
|
|
5239
|
+
* Results are capped at 1000 entries to keep model input bounded. The
|
|
5240
|
+
* cap applies after the directory filter, so dirs don't consume the
|
|
5241
|
+
* file budget.
|
|
4913
5242
|
*
|
|
4914
5243
|
* By default each row carries `<path>\t<size>\t<mtime>` metadata so the
|
|
4915
5244
|
* model can rank "what changed recently" without a follow-up `read_file`.
|
|
@@ -4921,10 +5250,14 @@ function sharedPrefixLength(a, b) {
|
|
|
4921
5250
|
const DEFAULT_LIMIT = 1e3;
|
|
4922
5251
|
const SAFE_GLOB_PATTERN_RE = /^[\w./*?[\]{}!,^@+-]+$/;
|
|
4923
5252
|
async function globInProcess(pattern, cwd, limit) {
|
|
4924
|
-
const glob = new Bun.Glob(pattern);
|
|
4925
5253
|
const results = [];
|
|
4926
|
-
for await (const
|
|
4927
|
-
|
|
5254
|
+
for await (const rel of glob(pattern, { cwd })) {
|
|
5255
|
+
try {
|
|
5256
|
+
if (!(await stat(resolve(cwd, rel))).isFile()) continue;
|
|
5257
|
+
} catch {
|
|
5258
|
+
continue;
|
|
5259
|
+
}
|
|
5260
|
+
results.push(rel);
|
|
4928
5261
|
if (results.length >= limit) break;
|
|
4929
5262
|
}
|
|
4930
5263
|
return results.sort();
|
|
@@ -4936,7 +5269,7 @@ async function globViaShell(pattern, ctx, limit) {
|
|
|
4936
5269
|
if (result.exitCode !== 0 && !result.stdout) return [];
|
|
4937
5270
|
return result.stdout.split("\n").filter((line) => line.length > 0);
|
|
4938
5271
|
}
|
|
4939
|
-
const glob = {
|
|
5272
|
+
const glob$1 = {
|
|
4940
5273
|
isConcurrencySafe: true,
|
|
4941
5274
|
spec: {
|
|
4942
5275
|
name: "glob",
|
|
@@ -4986,10 +5319,10 @@ const glob = {
|
|
|
4986
5319
|
/**
|
|
4987
5320
|
* Search file contents by regex.
|
|
4988
5321
|
*
|
|
4989
|
-
* Wraps ripgrep (`rg`) when available, falls back to an in-process
|
|
4990
|
-
* regex implementation when running in the
|
|
4991
|
-
* non-process contexts without `rg`,
|
|
4992
|
-
* doing nothing.
|
|
5322
|
+
* Wraps ripgrep (`rg`) when available, falls back to an in-process
|
|
5323
|
+
* `fs/promises` `glob` + regex implementation when running in the
|
|
5324
|
+
* in-process execution context. For non-process contexts without `rg`,
|
|
5325
|
+
* returns a clear hint rather than silently doing nothing.
|
|
4993
5326
|
*
|
|
4994
5327
|
* The tool surface mirrors Claude Code's `Grep` so models authored against the
|
|
4995
5328
|
* Anthropic tool surface need no relearning. Output modes:
|
|
@@ -5006,7 +5339,7 @@ const grep = {
|
|
|
5006
5339
|
isConcurrencySafe: true,
|
|
5007
5340
|
spec: {
|
|
5008
5341
|
name: "grep",
|
|
5009
|
-
description: "Search file contents by regex. Returns matching paths (default), match content, or per-file counts. Backed by ripgrep when available with
|
|
5342
|
+
description: "Search file contents by regex. Returns matching paths (default), match content, or per-file counts. Backed by ripgrep when available with an in-process glob fallback for in-process runs.",
|
|
5010
5343
|
inputSchema: {
|
|
5011
5344
|
type: "object",
|
|
5012
5345
|
properties: {
|
|
@@ -5190,13 +5523,12 @@ async function enumerateFiles(input, ctx) {
|
|
|
5190
5523
|
if ((await ctx.execution.exec(ctx.handle, `test -f ${shellQuote(input.path)} && echo file || echo dir`)).stdout.trim() === "file") return [input.path];
|
|
5191
5524
|
} catch {}
|
|
5192
5525
|
const pattern = input.glob ?? "**/*";
|
|
5193
|
-
const glob = new Bun.Glob(pattern);
|
|
5194
|
-
const out = [];
|
|
5195
5526
|
const scanRoot = root === "." ? cwd : `${cwd.replace(/\/$/, "")}/${root.replace(/^\.\//, "")}`;
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5527
|
+
const prefix = root === "." ? "" : `${root.replace(/\/$/, "")}/`;
|
|
5528
|
+
const out = [];
|
|
5529
|
+
for await (const rel of glob(pattern, { cwd: scanRoot })) try {
|
|
5530
|
+
if ((await stat(resolve(scanRoot, rel))).isFile()) out.push(prefix ? `${prefix}${rel}` : rel);
|
|
5531
|
+
} catch {}
|
|
5200
5532
|
return out.sort();
|
|
5201
5533
|
}
|
|
5202
5534
|
function formatPaginated(text, input) {
|
|
@@ -5242,12 +5574,12 @@ const listFiles = {
|
|
|
5242
5574
|
isConcurrencySafe: true,
|
|
5243
5575
|
spec: {
|
|
5244
5576
|
name: "list_files",
|
|
5245
|
-
description: "List files and
|
|
5577
|
+
description: "List the immediate entries (files and subdirectories) at `path`. Returns a newline-separated list, or `(empty directory)` when the directory exists but is empty. Returns `Directory not found: <path>` for a missing path. Non-recursive — use `glob` for pattern matching across nested directories.",
|
|
5246
5578
|
inputSchema: {
|
|
5247
5579
|
type: "object",
|
|
5248
5580
|
properties: { path: {
|
|
5249
5581
|
type: "string",
|
|
5250
|
-
description: "
|
|
5582
|
+
description: "Directory path (relative to the execution-context cwd, or absolute). Defaults to `.`."
|
|
5251
5583
|
} },
|
|
5252
5584
|
required: []
|
|
5253
5585
|
}
|
|
@@ -5294,7 +5626,7 @@ const multiEdit = {
|
|
|
5294
5626
|
properties: {
|
|
5295
5627
|
path: {
|
|
5296
5628
|
type: "string",
|
|
5297
|
-
description: "
|
|
5629
|
+
description: "File path (relative to the execution-context cwd, or absolute)."
|
|
5298
5630
|
},
|
|
5299
5631
|
edits: {
|
|
5300
5632
|
type: "array",
|
|
@@ -5504,7 +5836,7 @@ const readFile$1 = {
|
|
|
5504
5836
|
properties: {
|
|
5505
5837
|
path: {
|
|
5506
5838
|
type: "string",
|
|
5507
|
-
description: "
|
|
5839
|
+
description: "File path (relative to the execution-context cwd, or absolute)."
|
|
5508
5840
|
},
|
|
5509
5841
|
offset: {
|
|
5510
5842
|
type: "integer",
|
|
@@ -5720,6 +6052,62 @@ function extractText(message) {
|
|
|
5720
6052
|
return "";
|
|
5721
6053
|
}
|
|
5722
6054
|
/**
|
|
6055
|
+
* Read-only tool whitelist applied when a subagent preset has
|
|
6056
|
+
* `readonly: true` and no explicit `tools` list. Intentionally narrow —
|
|
6057
|
+
* only obviously non-mutating built-ins. Hosts wanting a different
|
|
6058
|
+
* read-only profile (e.g. include `glob` for a code-search agent) should
|
|
6059
|
+
* pass an explicit `tools` array on the subagent def.
|
|
6060
|
+
*/
|
|
6061
|
+
const READONLY_TOOL_DEFAULTS = [
|
|
6062
|
+
"read_file",
|
|
6063
|
+
"grep",
|
|
6064
|
+
"glob",
|
|
6065
|
+
"list_files"
|
|
6066
|
+
];
|
|
6067
|
+
/**
|
|
6068
|
+
* Apply a subagent preset's tool filter to the parent's tool registry.
|
|
6069
|
+
* Always a strict subset of the input — the child agent never gains
|
|
6070
|
+
* tools the parent doesn't have. Names that don't match a parent tool
|
|
6071
|
+
* are silently dropped (matches MCP's lenient `enabledTools` behavior).
|
|
6072
|
+
*
|
|
6073
|
+
* Precedence: `def.tools` (explicit list) > `def.readonly: true`
|
|
6074
|
+
* (built-in read-only set) > unfiltered.
|
|
6075
|
+
*/
|
|
6076
|
+
function filterToolsForSubagent(parentTools, def) {
|
|
6077
|
+
if (!parentTools) return parentTools;
|
|
6078
|
+
const explicit = def.tools;
|
|
6079
|
+
if (explicit && explicit.length > 0) {
|
|
6080
|
+
const wanted = new Set(explicit);
|
|
6081
|
+
const filtered = {};
|
|
6082
|
+
for (const [registryKey, t] of Object.entries(parentTools)) if (wanted.has(t.spec.name)) filtered[registryKey] = t;
|
|
6083
|
+
return filtered;
|
|
6084
|
+
}
|
|
6085
|
+
if (def.readonly) {
|
|
6086
|
+
const wanted = new Set(READONLY_TOOL_DEFAULTS);
|
|
6087
|
+
const filtered = {};
|
|
6088
|
+
for (const [registryKey, t] of Object.entries(parentTools)) if (wanted.has(t.spec.name)) filtered[registryKey] = t;
|
|
6089
|
+
return filtered;
|
|
6090
|
+
}
|
|
6091
|
+
return parentTools;
|
|
6092
|
+
}
|
|
6093
|
+
/**
|
|
6094
|
+
* Render the per-type descriptions into a single schema-field
|
|
6095
|
+
* description string the model reads when choosing a `subagent_type`.
|
|
6096
|
+
* Falls back to a generic line when the host didn't supply any per-type
|
|
6097
|
+
* descriptions.
|
|
6098
|
+
*/
|
|
6099
|
+
function buildSubagentTypeDescription(registry) {
|
|
6100
|
+
const lines = [];
|
|
6101
|
+
let hasAny = false;
|
|
6102
|
+
for (const [key, def] of Object.entries(registry)) if (def.description) {
|
|
6103
|
+
lines.push(`- "${key}": ${def.description}`);
|
|
6104
|
+
hasAny = true;
|
|
6105
|
+
} else lines.push(`- "${key}"`);
|
|
6106
|
+
lines.push("- \"general-purpose\": no specialization; uses the spawn tool's default config.");
|
|
6107
|
+
if (!hasAny) return `Optional subagent preset. One of: ${lines.map((l) => l.replace(/^- /, "").replace(/:.*$/, "")).join(", ")}.`;
|
|
6108
|
+
return `Optional subagent preset that overlays the spawn tool's defaults.\n${lines.join("\n")}`;
|
|
6109
|
+
}
|
|
6110
|
+
/**
|
|
5723
6111
|
* Race `task` (an already-running child `agent.run()` promise) against a
|
|
5724
6112
|
* timer. Does NOT race against the parent abort signal — the child agent
|
|
5725
6113
|
* already observes the same signal internally and handles its own aborted
|
|
@@ -5856,6 +6244,8 @@ function createSpawnTool(options = {}) {
|
|
|
5856
6244
|
turns: 0,
|
|
5857
6245
|
elapsed: 0
|
|
5858
6246
|
};
|
|
6247
|
+
const subagentRegistry = options.subagents;
|
|
6248
|
+
const subagentTypeKeys = !!subagentRegistry && Object.keys(subagentRegistry).length > 0 ? [...new Set([...Object.keys(subagentRegistry), "general-purpose"])] : [];
|
|
5859
6249
|
return {
|
|
5860
6250
|
get children() {
|
|
5861
6251
|
return localChildren;
|
|
@@ -5877,7 +6267,12 @@ function createSpawnTool(options = {}) {
|
|
|
5877
6267
|
system: {
|
|
5878
6268
|
type: "string",
|
|
5879
6269
|
description: "Optional system prompt override for this specific sub-agent."
|
|
5880
|
-
}
|
|
6270
|
+
},
|
|
6271
|
+
...subagentTypeKeys.length > 0 ? { subagent_type: {
|
|
6272
|
+
type: "string",
|
|
6273
|
+
enum: subagentTypeKeys,
|
|
6274
|
+
description: buildSubagentTypeDescription(subagentRegistry)
|
|
6275
|
+
} } : {}
|
|
5881
6276
|
},
|
|
5882
6277
|
required: ["task"]
|
|
5883
6278
|
}
|
|
@@ -5885,6 +6280,8 @@ function createSpawnTool(options = {}) {
|
|
|
5885
6280
|
async execute(input, ctx) {
|
|
5886
6281
|
const task = input.task;
|
|
5887
6282
|
const systemOverride = input.system;
|
|
6283
|
+
const requestedSubagentType = typeof input.subagent_type === "string" ? input.subagent_type : void 0;
|
|
6284
|
+
const subagentDef = requestedSubagentType && subagentRegistry ? subagentRegistry[requestedSubagentType] ?? void 0 : void 0;
|
|
5888
6285
|
const parentDepth = ctx.depth ?? 0;
|
|
5889
6286
|
const childDepth = parentDepth + 1;
|
|
5890
6287
|
if (childDepth > maxDepth) return `Cannot spawn: maxDepth=${maxDepth} reached (parent depth=${parentDepth}). Deepen the cap with createSpawnTool({ maxDepth }).`;
|
|
@@ -5905,10 +6302,11 @@ function createSpawnTool(options = {}) {
|
|
|
5905
6302
|
let result = "";
|
|
5906
6303
|
let unbubble;
|
|
5907
6304
|
try {
|
|
6305
|
+
const filteredTools = subagentDef ? filterToolsForSubagent(ctx.tools, subagentDef) : ctx.tools;
|
|
5908
6306
|
const parentPreset = {
|
|
5909
6307
|
...ctx.name !== void 0 ? { name: ctx.name } : {},
|
|
5910
6308
|
...ctx.system !== void 0 ? { system: ctx.system } : {},
|
|
5911
|
-
tools:
|
|
6309
|
+
tools: filteredTools,
|
|
5912
6310
|
...ctx.toolAliases !== void 0 ? { toolAliases: ctx.toolAliases } : {},
|
|
5913
6311
|
...ctx.mcpServers !== void 0 ? { mcpServers: ctx.mcpServers } : {},
|
|
5914
6312
|
...ctx.skills !== void 0 ? { skills: ctx.skills } : {},
|
|
@@ -5948,10 +6346,11 @@ function createSpawnTool(options = {}) {
|
|
|
5948
6346
|
};
|
|
5949
6347
|
await ctx.hooks.callHook("spawn:before", spawnHookCtx);
|
|
5950
6348
|
const propagatedTracing = Object.keys(spawnHookCtx.tracingContext).length > 0 ? Object.freeze({ ...spawnHookCtx.tracingContext }) : void 0;
|
|
6349
|
+
const effectiveSystem = systemOverride ?? subagentDef?.system ?? options.system;
|
|
5951
6350
|
const runPromise = agent.run({
|
|
5952
6351
|
prompt: task,
|
|
5953
6352
|
model: options.model,
|
|
5954
|
-
system:
|
|
6353
|
+
system: effectiveSystem,
|
|
5955
6354
|
thinking: options.thinking,
|
|
5956
6355
|
signal: ctx.signal,
|
|
5957
6356
|
depth: childDepth,
|
|
@@ -6088,17 +6487,17 @@ function createSpawnTool(options = {}) {
|
|
|
6088
6487
|
const writeFile$1 = {
|
|
6089
6488
|
spec: {
|
|
6090
6489
|
name: "write_file",
|
|
6091
|
-
description: "Write content to
|
|
6490
|
+
description: "Write `content` to `path`, creating any missing parent directories. Overwrites existing files in full; prefer `edit` / `multi_edit` for surgical changes when you only want to alter part of a file. Returns one of: `Created <path> (N bytes)` (file did not exist), `Updated <path> (N bytes)` (content differed), or `No change needed: <path> already at target state (N bytes)` — so the model can detect no-ops without a separate `read_file`.",
|
|
6092
6491
|
inputSchema: {
|
|
6093
6492
|
type: "object",
|
|
6094
6493
|
properties: {
|
|
6095
6494
|
path: {
|
|
6096
6495
|
type: "string",
|
|
6097
|
-
description: "
|
|
6496
|
+
description: "File path (relative to the execution-context cwd, or absolute)."
|
|
6098
6497
|
},
|
|
6099
6498
|
content: {
|
|
6100
6499
|
type: "string",
|
|
6101
|
-
description: "
|
|
6500
|
+
description: "Complete file content. Overwrites any existing file at `path`."
|
|
6102
6501
|
}
|
|
6103
6502
|
},
|
|
6104
6503
|
required: ["path", "content"]
|
|
@@ -6118,6 +6517,6 @@ const writeFile$1 = {
|
|
|
6118
6517
|
}
|
|
6119
6518
|
};
|
|
6120
6519
|
//#endregion
|
|
6121
|
-
export { resolvePersistDir as A, formatTaskStatus as B, TOOL_USE_SKIPPED_MESSAGE as C, buildPersistedStub as D, PERSISTENCE_PREVIEW_BYTES as E, resolveReadStateMap as F, previewLine as H, ageString as I, compactPath as L, getReadState as M, hashContent as N, cleanupPersistedSession as O, readStateKey as P, fmtTokens as R, TOOL_USE_CANCELLED_MESSAGE as S, PERSISTED_STUB_PREFIX as T, shortId as U, formatTaskSummary as V, createSkillsReadTool as _, multiEdit as a, INTERRUPT_MESSAGE_FOR_TOOL_USE as b, grep as c, resolveOldString as d, styleReplacementForVia as f, createSkillsRunScriptTool as g, createSkillsUseTool as h, readFile$1 as i, resolveTasksDir as j, maybePersistToolResult as k, glob as l, createToolSearchTool as m, createSpawnTool as n, listFiles as o, createAgent as p, shellKill as r, createInteractionTool as s, writeFile$1 as t, edit as u, createShellTool as v, validateToolArgs as w, SHELL_CASCADE_CANCEL_MESSAGE as x, shell as y, formatDuration as z };
|
|
6520
|
+
export { resolvePersistDir as A, formatTaskStatus as B, TOOL_USE_SKIPPED_MESSAGE as C, buildPersistedStub as D, PERSISTENCE_PREVIEW_BYTES as E, resolveReadStateMap as F, previewLine as H, ageString as I, compactPath as L, getReadState as M, hashContent as N, cleanupPersistedSession as O, readStateKey as P, fmtTokens as R, TOOL_USE_CANCELLED_MESSAGE as S, PERSISTED_STUB_PREFIX as T, shortId as U, formatTaskSummary as V, createSkillsReadTool as _, multiEdit as a, INTERRUPT_MESSAGE_FOR_TOOL_USE as b, grep as c, resolveOldString as d, styleReplacementForVia as f, createSkillsRunScriptTool as g, createSkillsUseTool as h, readFile$1 as i, resolveTasksDir as j, maybePersistToolResult as k, glob$1 as l, createToolSearchTool as m, createSpawnTool as n, listFiles as o, createAgent as p, shellKill as r, createInteractionTool as s, writeFile$1 as t, edit as u, createShellTool as v, validateToolArgs as w, SHELL_CASCADE_CANCEL_MESSAGE as x, shell as y, formatDuration as z };
|
|
6122
6521
|
|
|
6123
|
-
//# sourceMappingURL=tools-
|
|
6522
|
+
//# sourceMappingURL=tools-DE9pR_NG.js.map
|