zidane 5.3.1 → 5.3.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 +2 -0
- package/dist/{agent-bKs7MRT2.d.ts → agent-BXRCCHeq.d.ts} +129 -2
- package/dist/agent-BXRCCHeq.d.ts.map +1 -0
- package/dist/chat.d.ts +4 -4
- package/dist/chat.js +1 -1
- package/dist/{index-BlMvPh9X.d.ts → index-BPk8-Slm.d.ts} +26 -2
- package/dist/index-BPk8-Slm.d.ts.map +1 -0
- package/dist/{index-CTmNaIDb.d.ts → index-CT5_p-3P.d.ts} +2 -2
- package/dist/{index-CTmNaIDb.d.ts.map → index-CT5_p-3P.d.ts.map} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +5 -5
- package/dist/{login-CNS9_8Ue.js → login-DrBZ15G7.js} +3 -3
- package/dist/{login-CNS9_8Ue.js.map → login-DrBZ15G7.js.map} +1 -1
- package/dist/{mcp-ZsSFo4Dp.js → mcp-DhmmJfxK.js} +15 -2
- package/dist/mcp-DhmmJfxK.js.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/{presets-h5i3kpOP.js → presets-0_IRJAYF.js} +2 -2
- package/dist/{presets-h5i3kpOP.js.map → presets-0_IRJAYF.js.map} +1 -1
- package/dist/presets.d.ts +2 -2
- package/dist/presets.js +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/skills.d.ts +2 -2
- package/dist/{tools-CWEDS2ZT.js → tools-CCsL5SCO.js} +148 -104
- package/dist/tools-CCsL5SCO.js.map +1 -0
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +2 -2
- package/dist/{transcript-anchors-DOUqyvXR.d.ts → transcript-anchors-DSk8LlWt.d.ts} +3 -3
- package/dist/{transcript-anchors-DOUqyvXR.d.ts.map → transcript-anchors-DSk8LlWt.d.ts.map} +1 -1
- package/dist/tui.d.ts +2 -2
- package/dist/tui.js +4 -4
- package/dist/{turn-operations-D9HvatsR.js → turn-operations-CutZin8X.js} +4 -4
- package/dist/{turn-operations-D9HvatsR.js.map → turn-operations-CutZin8X.js.map} +1 -1
- package/dist/types-IcokUOyC.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/docs/ARCHITECTURE.md +1 -1
- package/docs/SKILL.md +23 -1
- package/package.json +1 -1
- package/dist/agent-bKs7MRT2.d.ts.map +0 -1
- package/dist/index-BlMvPh9X.d.ts.map +0 -1
- package/dist/mcp-ZsSFo4Dp.js.map +0 -1
- package/dist/tools-CWEDS2ZT.js.map +0 -1
|
@@ -2,7 +2,7 @@ import { n as createProcessContext } from "./contexts-BwiHIr2w.js";
|
|
|
2
2
|
import { a as AgentToolPairingError, l as toTypedError, r as AgentProviderError, s as errorMessage, t as AgentAbortedError } from "./errors-Byb0F8B9.js";
|
|
3
3
|
import { t as toolOutputByteLength } from "./types-IcokUOyC.js";
|
|
4
4
|
import { a as detectTurnInterruption, n as SYNTHETIC_TOOL_RESULT_PLACEHOLDER, o as ensureToolResultPairing, s as filterUnresolvedToolUses } from "./messages-D0xT979U.js";
|
|
5
|
-
import { t as connectMcpServers } from "./mcp-
|
|
5
|
+
import { t as connectMcpServers } from "./mcp-DhmmJfxK.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-ERgZUxgg.js";
|
|
7
7
|
import { n as formatTokenUsage, t as flattenTurns } from "./stats-DgOvY7wd.js";
|
|
8
8
|
import { createHooks } from "hookable";
|
|
@@ -107,8 +107,14 @@ function rewriteMessagesToWire(messages, maps) {
|
|
|
107
107
|
const STATE = /* @__PURE__ */ new WeakMap();
|
|
108
108
|
/**
|
|
109
109
|
* Get or lazily create the per-session read-state map. Returns `undefined`
|
|
110
|
-
* when no session is provided
|
|
111
|
-
*
|
|
110
|
+
* when no session is provided.
|
|
111
|
+
*
|
|
112
|
+
* Most tool callers should prefer {@link resolveReadStateMap}, which
|
|
113
|
+
* additionally honors an explicit `ctx.readState` (the path
|
|
114
|
+
* `spawn`'s `shareReadState: true` uses to forward the parent's map
|
|
115
|
+
* into a sessionless child). Use this helper directly only when the
|
|
116
|
+
* Session-keyed map is exactly what you want and you don't need to
|
|
117
|
+
* accept an override.
|
|
112
118
|
*/
|
|
113
119
|
function getReadState(session) {
|
|
114
120
|
if (!session) return void 0;
|
|
@@ -119,19 +125,38 @@ function getReadState(session) {
|
|
|
119
125
|
}
|
|
120
126
|
return map;
|
|
121
127
|
}
|
|
122
|
-
const TOOL_DEDUP_STATE = /* @__PURE__ */ new WeakMap();
|
|
123
128
|
/**
|
|
124
|
-
*
|
|
125
|
-
*
|
|
129
|
+
* Resolve the active read-state map from a tool context. An explicit
|
|
130
|
+
* `ctx.readState` wins (used by `spawn`'s `shareReadState` opt-in to
|
|
131
|
+
* forward the parent's map into a sessionless child); otherwise the
|
|
132
|
+
* usual `Session`-keyed lookup applies.
|
|
133
|
+
*
|
|
134
|
+
* Tools should call this helper instead of `getReadState(ctx.session)`
|
|
135
|
+
* directly so the `shareReadState` plumbing is honored uniformly.
|
|
126
136
|
*/
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
137
|
+
function resolveReadStateMap(ctx) {
|
|
138
|
+
return ctx.readState ?? getReadState(ctx.session);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Canonical read-state key for a `(cwd, path)` pair.
|
|
142
|
+
*
|
|
143
|
+
* `ctx.execution.readFile(handle, path)` resolves the model-provided
|
|
144
|
+
* path against `handle.cwd` before touching disk — so `src/App.tsx`,
|
|
145
|
+
* `./src/App.tsx`, and `/abs/cwd/src/App.tsx` all read the **same**
|
|
146
|
+
* bytes. The read-state map MUST mirror that resolution: without it,
|
|
147
|
+
* a model that reads `src/App.tsx` and then edits `./src/App.tsx`
|
|
148
|
+
* trips the `requireReadBeforeEdit` gate for a file it demonstrably
|
|
149
|
+
* already saw (the gate's "has not been read in this session" message
|
|
150
|
+
* fires on a stale key).
|
|
151
|
+
*
|
|
152
|
+
* `node:path`'s `resolve(cwd, path)` short-circuits when `path` is
|
|
153
|
+
* already absolute, so absolute and relative shapes converge on the
|
|
154
|
+
* same canonical form. We don't `realpath()` symlinks — the file IS
|
|
155
|
+
* the path the model addressed, not the realpath behind it; the host's
|
|
156
|
+
* execution context decides how to dereference.
|
|
157
|
+
*/
|
|
158
|
+
function readStateKey(cwd, path) {
|
|
159
|
+
return resolve(cwd, path);
|
|
135
160
|
}
|
|
136
161
|
/**
|
|
137
162
|
* FNV-1a 32-bit hash, hex-encoded. Fast, non-cryptographic — we only need
|
|
@@ -147,6 +172,20 @@ function hashContent(text) {
|
|
|
147
172
|
}
|
|
148
173
|
return h.toString(16).padStart(8, "0");
|
|
149
174
|
}
|
|
175
|
+
const TOOL_DEDUP_STATE = /* @__PURE__ */ new WeakMap();
|
|
176
|
+
/**
|
|
177
|
+
* Get or lazily create the per-session tool-dedup map. Returns `undefined`
|
|
178
|
+
* when no session is provided — middleware should treat that as "no dedup".
|
|
179
|
+
*/
|
|
180
|
+
function getToolDedupState(session) {
|
|
181
|
+
if (!session) return void 0;
|
|
182
|
+
let map = TOOL_DEDUP_STATE.get(session);
|
|
183
|
+
if (!map) {
|
|
184
|
+
map = /* @__PURE__ */ new Map();
|
|
185
|
+
TOOL_DEDUP_STATE.set(session, map);
|
|
186
|
+
}
|
|
187
|
+
return map;
|
|
188
|
+
}
|
|
150
189
|
//#endregion
|
|
151
190
|
//#region src/dedup-tools.ts
|
|
152
191
|
/**
|
|
@@ -1067,19 +1106,21 @@ function applyStaleReadElision(messages) {
|
|
|
1067
1106
|
}
|
|
1068
1107
|
/**
|
|
1069
1108
|
* Drop read-state entries for paths whose reads got elided. Keys are
|
|
1070
|
-
*
|
|
1071
|
-
*
|
|
1072
|
-
*
|
|
1073
|
-
*
|
|
1074
|
-
*
|
|
1075
|
-
*
|
|
1109
|
+
* canonical absolute paths produced by `readStateKey(cwd, path)` (see
|
|
1110
|
+
* `src/tools/read-state.ts`); the loop has `ctx.handle.cwd` in scope,
|
|
1111
|
+
* so we re-derive each elided path's canonical key and delete by
|
|
1112
|
+
* direct lookup. No suffix matching, no cross-cwd ambiguity.
|
|
1113
|
+
*
|
|
1114
|
+
* Resolves the map via `resolveReadStateMap` so a child agent running
|
|
1115
|
+
* with a parent's shared map (via `shareReadState`) invalidates the
|
|
1116
|
+
* shared entries too — otherwise a child's `read → edit → re-read`
|
|
1117
|
+
* would dedup-hit on the now-stale parent entry.
|
|
1076
1118
|
*/
|
|
1077
|
-
function invalidateReadStateForElidedPaths(
|
|
1078
|
-
if (
|
|
1079
|
-
const readState =
|
|
1119
|
+
function invalidateReadStateForElidedPaths(ctx, cwd, elidedPaths) {
|
|
1120
|
+
if (elidedPaths.length === 0) return;
|
|
1121
|
+
const readState = resolveReadStateMap(ctx);
|
|
1080
1122
|
if (!readState || readState.size === 0) return;
|
|
1081
|
-
const
|
|
1082
|
-
for (const key of [...readState.keys()]) if (suffixes.some((s) => key.endsWith(s))) readState.delete(key);
|
|
1123
|
+
for (const p of elidedPaths) readState.delete(readStateKey(cwd, p));
|
|
1083
1124
|
}
|
|
1084
1125
|
/**
|
|
1085
1126
|
* Run {@link ensureToolResultPairing} with the loop's hook + strict-mode
|
|
@@ -1265,7 +1306,7 @@ async function executeTurn(ctx, turn) {
|
|
|
1265
1306
|
if (ctx.elideStaleReads === true) {
|
|
1266
1307
|
const elision = applyStaleReadElision(canonicalMessages);
|
|
1267
1308
|
canonicalMessages = elision.messages;
|
|
1268
|
-
invalidateReadStateForElidedPaths(ctx.
|
|
1309
|
+
invalidateReadStateForElidedPaths(ctx, ctx.handle.cwd, elision.elidedPaths);
|
|
1269
1310
|
}
|
|
1270
1311
|
const wireMessages = rewriteMessagesToWire(canonicalMessages, ctx.aliasMaps);
|
|
1271
1312
|
let sanitizedMessages = sanitizeStoredToolResults(ctx.provider, wireMessages);
|
|
@@ -1539,17 +1580,35 @@ function stripImagesForNonVision(provider, output) {
|
|
|
1539
1580
|
if (provider.meta.capabilities?.vision !== false) return output;
|
|
1540
1581
|
return output.map((b) => b.type === "image" ? IMAGE_OMITTED_MARKER : b.text).join("\n");
|
|
1541
1582
|
}
|
|
1583
|
+
/**
|
|
1584
|
+
* Build the per-call base for every `tool:*` hook ctx (and the
|
|
1585
|
+
* matching shape for `mcp:tool:*`). Centralized so the `runId` /
|
|
1586
|
+
* `parentRunId` / `depth` identity fields land uniformly on every
|
|
1587
|
+
* event the loop fires — without one helper they drift across ~14
|
|
1588
|
+
* inline construction sites. The returned object IS the
|
|
1589
|
+
* {@link ToolHookContext} canonical shape; specialized hook payloads
|
|
1590
|
+
* (`gateCtx`, `transformCtx`, etc.) spread it and append their own
|
|
1591
|
+
* fields.
|
|
1592
|
+
*/
|
|
1593
|
+
function buildToolHookBase(ctx, turnId, callId, name, displayName, input) {
|
|
1594
|
+
return {
|
|
1595
|
+
turnId,
|
|
1596
|
+
callId,
|
|
1597
|
+
name,
|
|
1598
|
+
displayName,
|
|
1599
|
+
input,
|
|
1600
|
+
...ctx.runId !== void 0 ? { runId: ctx.runId } : {},
|
|
1601
|
+
...ctx.parentRunId !== void 0 ? { parentRunId: ctx.parentRunId } : {},
|
|
1602
|
+
...typeof ctx.depth === "number" ? { depth: ctx.depth } : {}
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1542
1605
|
async function executeSingleTool(ctx, call, turnId) {
|
|
1543
1606
|
const toolDef = ctx.tools[call.name];
|
|
1544
1607
|
const callId = call.id;
|
|
1545
1608
|
const displayName = toWireName(call.name, ctx.aliasMaps);
|
|
1546
1609
|
const runToolCounts = Object.freeze({ ...ctx.runToolCounts });
|
|
1547
1610
|
const gateCtx = {
|
|
1548
|
-
turnId,
|
|
1549
|
-
callId,
|
|
1550
|
-
name: call.name,
|
|
1551
|
-
displayName,
|
|
1552
|
-
input: call.input,
|
|
1611
|
+
...buildToolHookBase(ctx, turnId, callId, call.name, displayName, call.input),
|
|
1553
1612
|
block: false,
|
|
1554
1613
|
reason: "Tool execution was blocked",
|
|
1555
1614
|
runToolCounts
|
|
@@ -1602,11 +1661,7 @@ async function executeSingleTool(ctx, call, turnId) {
|
|
|
1602
1661
|
let effectiveInput = gateCtx.input;
|
|
1603
1662
|
if (!toolDef) {
|
|
1604
1663
|
const unknownCtx = {
|
|
1605
|
-
turnId,
|
|
1606
|
-
callId,
|
|
1607
|
-
name: call.name,
|
|
1608
|
-
displayName,
|
|
1609
|
-
input: effectiveInput,
|
|
1664
|
+
...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),
|
|
1610
1665
|
suppressError: false
|
|
1611
1666
|
};
|
|
1612
1667
|
await ctx.hooks.callHook("tool:unknown", unknownCtx);
|
|
@@ -1615,11 +1670,7 @@ async function executeSingleTool(ctx, call, turnId) {
|
|
|
1615
1670
|
if (!unknownCtx.suppressError) {
|
|
1616
1671
|
const err = /* @__PURE__ */ new Error(`Unknown tool: ${call.name}`);
|
|
1617
1672
|
await ctx.hooks.callHook("tool:error", {
|
|
1618
|
-
turnId,
|
|
1619
|
-
callId,
|
|
1620
|
-
name: call.name,
|
|
1621
|
-
displayName,
|
|
1622
|
-
input: effectiveInput,
|
|
1673
|
+
...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),
|
|
1623
1674
|
error: err
|
|
1624
1675
|
});
|
|
1625
1676
|
}
|
|
@@ -1641,11 +1692,7 @@ async function executeSingleTool(ctx, call, turnId) {
|
|
|
1641
1692
|
const validation = validateToolArgs(effectiveInput, toolDef.spec.inputSchema);
|
|
1642
1693
|
if (!validation.valid) {
|
|
1643
1694
|
await ctx.hooks.callHook("validation:reject", {
|
|
1644
|
-
turnId,
|
|
1645
|
-
callId,
|
|
1646
|
-
name: call.name,
|
|
1647
|
-
displayName,
|
|
1648
|
-
input: effectiveInput,
|
|
1695
|
+
...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),
|
|
1649
1696
|
reason: validation.error ?? "invalid input",
|
|
1650
1697
|
schema: toolDef.spec.inputSchema
|
|
1651
1698
|
});
|
|
@@ -1667,11 +1714,7 @@ async function executeSingleTool(ctx, call, turnId) {
|
|
|
1667
1714
|
effectiveInput = validation.coercedInput ?? effectiveInput;
|
|
1668
1715
|
const coercions = validation.coercions && validation.coercions.length > 0 ? validation.coercions : void 0;
|
|
1669
1716
|
if (coercions) await ctx.hooks.callHook("validation:coerce", {
|
|
1670
|
-
turnId,
|
|
1671
|
-
callId,
|
|
1672
|
-
name: call.name,
|
|
1673
|
-
displayName,
|
|
1674
|
-
input: effectiveInput,
|
|
1717
|
+
...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),
|
|
1675
1718
|
coercions,
|
|
1676
1719
|
schema: toolDef.spec.inputSchema
|
|
1677
1720
|
});
|
|
@@ -1685,11 +1728,7 @@ async function executeSingleTool(ctx, call, turnId) {
|
|
|
1685
1728
|
runToolCounts
|
|
1686
1729
|
});
|
|
1687
1730
|
await ctx.hooks.callHook("tool:before", {
|
|
1688
|
-
turnId,
|
|
1689
|
-
callId,
|
|
1690
|
-
name: call.name,
|
|
1691
|
-
displayName,
|
|
1692
|
-
input: effectiveInput,
|
|
1731
|
+
...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),
|
|
1693
1732
|
runToolCounts,
|
|
1694
1733
|
...coercions ? { coercions } : {}
|
|
1695
1734
|
});
|
|
@@ -1712,18 +1751,16 @@ async function executeSingleTool(ctx, call, turnId) {
|
|
|
1712
1751
|
turnId,
|
|
1713
1752
|
callId,
|
|
1714
1753
|
runId: ctx.runId,
|
|
1754
|
+
...ctx.parentRunId !== void 0 ? { parentRunId: ctx.parentRunId } : {},
|
|
1715
1755
|
...ctx.session ? { session: ctx.session } : {},
|
|
1756
|
+
...ctx.readState ? { readState: ctx.readState } : {},
|
|
1716
1757
|
...typeof ctx.depth === "number" ? { depth: ctx.depth } : {}
|
|
1717
1758
|
};
|
|
1718
1759
|
output = await toolDef.execute(effectiveInput, toolCtx);
|
|
1719
1760
|
} catch (err) {
|
|
1720
1761
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
1721
1762
|
const errorCtx = {
|
|
1722
|
-
turnId,
|
|
1723
|
-
callId,
|
|
1724
|
-
name: call.name,
|
|
1725
|
-
displayName,
|
|
1726
|
-
input: effectiveInput,
|
|
1763
|
+
...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),
|
|
1727
1764
|
error
|
|
1728
1765
|
};
|
|
1729
1766
|
await ctx.hooks.callHook("tool:error", errorCtx);
|
|
@@ -1761,9 +1798,11 @@ async function executeSingleTool(ctx, call, turnId) {
|
|
|
1761
1798
|
* across five call sites.
|
|
1762
1799
|
*/
|
|
1763
1800
|
async function fireDispatched(ctx, params) {
|
|
1764
|
-
const { reason,
|
|
1801
|
+
const { turnId, callId, name, displayName, input, outcome, reason, runToolCounts } = params;
|
|
1765
1802
|
await ctx.hooks.callHook("tool:dispatched", {
|
|
1766
|
-
...
|
|
1803
|
+
...buildToolHookBase(ctx, turnId, callId, name, displayName, input),
|
|
1804
|
+
outcome,
|
|
1805
|
+
runToolCounts,
|
|
1767
1806
|
...reason !== void 0 ? { reason } : {}
|
|
1768
1807
|
});
|
|
1769
1808
|
}
|
|
@@ -1784,11 +1823,7 @@ async function emitToolResult(ctx, params) {
|
|
|
1784
1823
|
let output = params.output;
|
|
1785
1824
|
let isError = params.isError;
|
|
1786
1825
|
const transformCtx = {
|
|
1787
|
-
turnId,
|
|
1788
|
-
callId,
|
|
1789
|
-
name,
|
|
1790
|
-
displayName,
|
|
1791
|
-
input,
|
|
1826
|
+
...buildToolHookBase(ctx, turnId, callId, name, displayName, input),
|
|
1792
1827
|
result: output,
|
|
1793
1828
|
isError,
|
|
1794
1829
|
outputBytes: toolOutputByteLength(output),
|
|
@@ -1813,11 +1848,7 @@ async function emitToolResult(ctx, params) {
|
|
|
1813
1848
|
}
|
|
1814
1849
|
output = stripImagesForNonVision(ctx.provider, output);
|
|
1815
1850
|
await ctx.hooks.callHook("tool:after", {
|
|
1816
|
-
turnId,
|
|
1817
|
-
callId,
|
|
1818
|
-
name,
|
|
1819
|
-
displayName,
|
|
1820
|
-
input,
|
|
1851
|
+
...buildToolHookBase(ctx, turnId, callId, name, displayName, input),
|
|
1821
1852
|
result: output,
|
|
1822
1853
|
outputBytes: toolOutputByteLength(output),
|
|
1823
1854
|
runToolCounts,
|
|
@@ -2745,7 +2776,7 @@ function initialRunCounter(session) {
|
|
|
2745
2776
|
for (const t of session.turns) consider(t.runId);
|
|
2746
2777
|
return max;
|
|
2747
2778
|
}
|
|
2748
|
-
function createAgent({ provider, name: agentName, system: agentSystem, tools: agentTools, toolAliases, behavior: agentBehavior, execution, mcpServers, session, skills: agentSkills, mcpConnector, eager, hooks: initialHooks }) {
|
|
2779
|
+
function createAgent({ provider, name: agentName, system: agentSystem, tools: agentTools, toolAliases, behavior: agentBehavior, execution, mcpServers, session, readState: agentReadState, skills: agentSkills, mcpConnector, eager, hooks: initialHooks }) {
|
|
2749
2780
|
const hooks = createHooks();
|
|
2750
2781
|
const executionContext = execution ?? createProcessContext();
|
|
2751
2782
|
const sourceTools = agentTools ?? {};
|
|
@@ -3061,6 +3092,8 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
3061
3092
|
maxTurns,
|
|
3062
3093
|
maxTokens,
|
|
3063
3094
|
...session ? { session } : {},
|
|
3095
|
+
...agentReadState ? { readState: agentReadState } : {},
|
|
3096
|
+
...options.parentRunId ? { parentRunId: options.parentRunId } : {},
|
|
3064
3097
|
depth: runDepth,
|
|
3065
3098
|
thinkingBudget,
|
|
3066
3099
|
schema,
|
|
@@ -3624,12 +3657,14 @@ const edit = {
|
|
|
3624
3657
|
} catch {
|
|
3625
3658
|
return `Edit error: file not found: ${target}.${await suggestionFor(ctx.execution, ctx.handle, target)}`;
|
|
3626
3659
|
}
|
|
3627
|
-
if (ctx.behavior?.requireReadBeforeEdit
|
|
3628
|
-
const readState =
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3660
|
+
if (ctx.behavior?.requireReadBeforeEdit) {
|
|
3661
|
+
const readState = resolveReadStateMap(ctx);
|
|
3662
|
+
if (readState) {
|
|
3663
|
+
const absKey = readStateKey(ctx.handle.cwd, target);
|
|
3664
|
+
const prior = readState.get(absKey);
|
|
3665
|
+
if (!prior) return `Edit error: ${target} has not been read in this session. Call read_file first so the edit applies against the current contents. (Reads inside a \`spawn\` subagent with \`persist: false\` and without \`shareReadState: true\` do NOT propagate to the parent — re-read in the calling context.)`;
|
|
3666
|
+
if (prior.contentHash !== hashContent(original)) return `Edit error: ${target} has changed on disk since the last read. Re-read the file before editing.`;
|
|
3667
|
+
}
|
|
3633
3668
|
}
|
|
3634
3669
|
const match = resolveOldString(original, find);
|
|
3635
3670
|
if (!match) {
|
|
@@ -3642,11 +3677,11 @@ const edit = {
|
|
|
3642
3677
|
const updated = replaceAll ? original.split(actual).join(styledReplacement) : original.replace(actual, styledReplacement);
|
|
3643
3678
|
if (updated === original) return `Edit error: replacement produced no change in ${target}.`;
|
|
3644
3679
|
await ctx.execution.writeFile(ctx.handle, target, updated);
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
const absKey =
|
|
3648
|
-
const prior = readState
|
|
3649
|
-
if (
|
|
3680
|
+
const readState = resolveReadStateMap(ctx);
|
|
3681
|
+
if (readState) {
|
|
3682
|
+
const absKey = readStateKey(ctx.handle.cwd, target);
|
|
3683
|
+
const prior = readState.get(absKey);
|
|
3684
|
+
if (prior) readState.set(absKey, {
|
|
3650
3685
|
...prior,
|
|
3651
3686
|
contentHash: hashContent(updated),
|
|
3652
3687
|
mtimeMs: Date.now()
|
|
@@ -4085,12 +4120,14 @@ const multiEdit = {
|
|
|
4085
4120
|
} catch {
|
|
4086
4121
|
return `multi_edit error: file not found: ${target}.${await suggestionFor(ctx.execution, ctx.handle, target)}`;
|
|
4087
4122
|
}
|
|
4088
|
-
if (ctx.behavior?.requireReadBeforeEdit
|
|
4089
|
-
const readState =
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4123
|
+
if (ctx.behavior?.requireReadBeforeEdit) {
|
|
4124
|
+
const readState = resolveReadStateMap(ctx);
|
|
4125
|
+
if (readState) {
|
|
4126
|
+
const absKey = readStateKey(ctx.handle.cwd, target);
|
|
4127
|
+
const prior = readState.get(absKey);
|
|
4128
|
+
if (!prior) return `multi_edit error: ${target} has not been read in this session. Call read_file first so the edits apply against the current contents. (Reads inside a \`spawn\` subagent with \`persist: false\` and without \`shareReadState: true\` do NOT propagate to the parent — re-read in the calling context.)`;
|
|
4129
|
+
if (prior.contentHash !== hashContent(current)) return `multi_edit error: ${target} has changed on disk since the last read. Re-read the file before editing.`;
|
|
4130
|
+
}
|
|
4094
4131
|
}
|
|
4095
4132
|
let totalReplacements = 0;
|
|
4096
4133
|
for (let i = 0; i < steps.length; i++) {
|
|
@@ -4110,11 +4147,11 @@ const multiEdit = {
|
|
|
4110
4147
|
totalReplacements += occurrences;
|
|
4111
4148
|
}
|
|
4112
4149
|
await ctx.execution.writeFile(ctx.handle, target, current);
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
const absKey =
|
|
4116
|
-
const prior = readState
|
|
4117
|
-
if (
|
|
4150
|
+
const readState = resolveReadStateMap(ctx);
|
|
4151
|
+
if (readState) {
|
|
4152
|
+
const absKey = readStateKey(ctx.handle.cwd, target);
|
|
4153
|
+
const prior = readState.get(absKey);
|
|
4154
|
+
if (prior) readState.set(absKey, {
|
|
4118
4155
|
...prior,
|
|
4119
4156
|
contentHash: hashContent(current),
|
|
4120
4157
|
mtimeMs: Date.now()
|
|
@@ -4264,14 +4301,16 @@ const readFile$1 = {
|
|
|
4264
4301
|
return `File not found: ${path}.${await suggestionFor(ctx.execution, ctx.handle, path)}`;
|
|
4265
4302
|
}
|
|
4266
4303
|
const totalBytes = Buffer.byteLength(raw);
|
|
4267
|
-
const
|
|
4268
|
-
const
|
|
4304
|
+
const dedupEnabled = ctx.behavior?.dedupReads !== false;
|
|
4305
|
+
const gateEnabled = ctx.behavior?.requireReadBeforeEdit === true;
|
|
4306
|
+
const readState = dedupEnabled || gateEnabled ? resolveReadStateMap(ctx) : void 0;
|
|
4307
|
+
const absKey = readStateKey(ctx.handle.cwd, path);
|
|
4269
4308
|
const offsetForKey = normalizeInteger(offset, 1);
|
|
4270
4309
|
const limitForKey = normalizeInteger(limit, DEFAULT_LINE_LIMIT);
|
|
4271
4310
|
const maxBytesForKey = normalizeInteger(maxBytes, DEFAULT_BYTE_CAP);
|
|
4272
4311
|
const showLineNumbers = typeof lineNumbers === "boolean" ? lineNumbers : ctx.behavior?.readLineNumbers ?? true;
|
|
4273
4312
|
const currentHash = readState ? hashContent(raw) : "";
|
|
4274
|
-
if (readState) {
|
|
4313
|
+
if (dedupEnabled && readState) {
|
|
4275
4314
|
const prior = readState.get(absKey);
|
|
4276
4315
|
if (prior && prior.contentHash === currentHash && prior.offset === offsetForKey && prior.limit === limitForKey && prior.maxBytes === maxBytesForKey && prior.lineNumbers === showLineNumbers) return `File ${path} unchanged since the previous read in this session — the prior result is still current.`;
|
|
4277
4316
|
}
|
|
@@ -4717,18 +4756,23 @@ function createSpawnTool(options = {}) {
|
|
|
4717
4756
|
let result = "";
|
|
4718
4757
|
let unbubble;
|
|
4719
4758
|
try {
|
|
4720
|
-
const
|
|
4759
|
+
const parentPreset = {
|
|
4721
4760
|
...ctx.name !== void 0 ? { name: ctx.name } : {},
|
|
4722
4761
|
...ctx.system !== void 0 ? { system: ctx.system } : {},
|
|
4723
4762
|
tools: ctx.tools,
|
|
4724
4763
|
...ctx.toolAliases !== void 0 ? { toolAliases: ctx.toolAliases } : {},
|
|
4725
4764
|
...ctx.mcpServers !== void 0 ? { mcpServers: ctx.mcpServers } : {},
|
|
4726
4765
|
...ctx.skills !== void 0 ? { skills: ctx.skills } : {},
|
|
4727
|
-
...ctx.behavior !== void 0 ? { behavior: ctx.behavior } : {}
|
|
4766
|
+
...ctx.behavior !== void 0 ? { behavior: ctx.behavior } : {}
|
|
4767
|
+
};
|
|
4768
|
+
const sharedReadState = options.shareReadState ? resolveReadStateMap(ctx) : void 0;
|
|
4769
|
+
const agent = createAgent({
|
|
4770
|
+
...parentPreset,
|
|
4728
4771
|
...options.preset,
|
|
4729
4772
|
provider: ctx.provider,
|
|
4730
4773
|
execution: ctx.execution,
|
|
4731
|
-
...options.persist && ctx.session ? { session: ctx.session } : {}
|
|
4774
|
+
...options.persist && ctx.session ? { session: ctx.session } : {},
|
|
4775
|
+
...sharedReadState ? { readState: sharedReadState } : {}
|
|
4732
4776
|
});
|
|
4733
4777
|
if (forwardHooks) {
|
|
4734
4778
|
const unregisterEnricher = agent.hooks.hook("tool:before", async (toolCtx) => {
|
|
@@ -4903,6 +4947,6 @@ const writeFile$1 = {
|
|
|
4903
4947
|
}
|
|
4904
4948
|
};
|
|
4905
4949
|
//#endregion
|
|
4906
|
-
export { PERSISTENCE_PREVIEW_BYTES as C, resolvePersistDir as D, maybePersistToolResult as E, getReadState as O, PERSISTED_STUB_PREFIX as S, cleanupPersistedSession as T, createSkillsReadTool as _, multiEdit as a, TOOL_USE_SKIPPED_MESSAGE as b, grep as c, resolveOldString as d, styleReplacementForVia as f, createSkillsRunScriptTool as g, createSkillsUseTool as h, readFile$1 as i, glob as l, createToolSearchTool as m, createSpawnTool as n, listFiles as o, createAgent as p, shell as r, createInteractionTool as s, writeFile$1 as t, edit as u, INTERRUPT_MESSAGE_FOR_TOOL_USE as v, buildPersistedStub as w, validateToolArgs as x, TOOL_USE_AFTER_ERROR_MESSAGE as y };
|
|
4950
|
+
export { readStateKey as A, PERSISTENCE_PREVIEW_BYTES as C, resolvePersistDir as D, maybePersistToolResult as E, getReadState as O, PERSISTED_STUB_PREFIX as S, cleanupPersistedSession as T, createSkillsReadTool as _, multiEdit as a, TOOL_USE_SKIPPED_MESSAGE as b, grep as c, resolveOldString as d, styleReplacementForVia as f, createSkillsRunScriptTool as g, createSkillsUseTool as h, readFile$1 as i, resolveReadStateMap as j, hashContent as k, glob as l, createToolSearchTool as m, createSpawnTool as n, listFiles as o, createAgent as p, shell as r, createInteractionTool as s, writeFile$1 as t, edit as u, INTERRUPT_MESSAGE_FOR_TOOL_USE as v, buildPersistedStub as w, validateToolArgs as x, TOOL_USE_AFTER_ERROR_MESSAGE as y };
|
|
4907
4951
|
|
|
4908
|
-
//# sourceMappingURL=tools-
|
|
4952
|
+
//# sourceMappingURL=tools-CCsL5SCO.js.map
|