@wrongstack/core 0.257.2 → 0.264.0
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/dist/{agent-bridge-BrxWHEOm.d.ts → agent-bridge-D8sa1vtv.d.ts} +1 -1
- package/dist/{agent-subagent-runner-US741uBH.d.ts → agent-subagent-runner-c9DLkaas.d.ts} +31 -9
- package/dist/{brain-TjEEwSpw.d.ts → brain-O1IdKPaK.d.ts} +59 -2
- package/dist/{compactor-C5sT4U7I.d.ts → compactor-BBy0rCtB.d.ts} +1 -1
- package/dist/{config-DuAu23zm.d.ts → config-Dz2F3H2K.d.ts} +7 -1
- package/dist/{context-CGdgA0q6.d.ts → context-BGSpZNSE.d.ts} +33 -0
- package/dist/coordination/index.d.ts +1681 -15
- package/dist/coordination/index.js +2826 -405
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +25 -25
- package/dist/defaults/index.js +2258 -1433
- package/dist/defaults/index.js.map +1 -1
- package/dist/dispatcher-types.d-BBeXBQgS.d.ts +66 -0
- package/dist/execution/index.d.ts +15 -15
- package/dist/execution/index.js +502 -398
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/prompt-enhancer.d.ts +2 -2
- package/dist/execution/prompt-enhancer.js +7 -1
- package/dist/execution/prompt-enhancer.js.map +1 -1
- package/dist/extension/index.d.ts +6 -6
- package/dist/extension/index.js.map +1 -1
- package/dist/{goal-preamble-CznHTZqP.d.ts → goal-preamble-DzjFuN3p.d.ts} +21 -9
- package/dist/{goal-store-CV9Yz2X_.d.ts → goal-store-CxWmCGbH.d.ts} +4 -2
- package/dist/{index-CC0Mcm05.d.ts → index-CYIQrXVF.d.ts} +8 -8
- package/dist/{index-CitPrI3a.d.ts → index-CbLSI66_.d.ts} +5 -5
- package/dist/index.d.ts +50 -94
- package/dist/index.js +16009 -12406
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +6 -6
- package/dist/kernel/index.d.ts +9 -9
- package/dist/kernel/index.js +6 -1
- package/dist/kernel/index.js.map +1 -1
- package/dist/{llm-selector-CJ4SyAFE.d.ts → llm-selector-DzxuZnNz.d.ts} +2 -2
- package/dist/{mcp-servers-D8YnLaEp.d.ts → mcp-servers-DC4QRPUI.d.ts} +3 -3
- package/dist/models/index.d.ts +5 -5
- package/dist/models/index.js +6 -1
- package/dist/models/index.js.map +1 -1
- package/dist/{models-registry-ByZCdFuQ.d.ts → models-registry-B_siPxqN.d.ts} +1 -1
- package/dist/{multi-agent-coordinator-DqTUEAeC.d.ts → multi-agent-coordinator-CK5Jdj9K.d.ts} +2 -2
- package/dist/{null-fleet-bus-B5mfTJXT.d.ts → null-fleet-bus-DgvD4SCO.d.ts} +13 -8
- package/dist/observability/index.d.ts +2 -2
- package/dist/observability/index.js +8 -3
- package/dist/observability/index.js.map +1 -1
- package/dist/{parallel-eternal-engine-C0juOszP.d.ts → parallel-eternal-engine-bK0JQBR_.d.ts} +13 -9
- package/dist/{path-resolver-CbkT-RMU.d.ts → path-resolver-BPEDlN38.d.ts} +3 -3
- package/dist/{permission-CwBBpCoF.d.ts → permission-4yvGmMRB.d.ts} +1 -1
- package/dist/{permission-policy-B8rSu908.d.ts → permission-policy-C6XpsBOy.d.ts} +3 -2
- package/dist/{pipeline-JG8XoudC.d.ts → pipeline-CXCeMz8J.d.ts} +58 -3
- package/dist/{plan-templates-DPiQMkBz.d.ts → plan-templates-BvzRBkJc.d.ts} +32 -11
- package/dist/{provider-runner-hM7EXlLI.d.ts → provider-runner-C5aQpDWE.d.ts} +3 -3
- package/dist/{retry-policy-Tg7LXkoK.d.ts → retry-policy-CFhdtRzz.d.ts} +1 -1
- package/dist/sdd/index.d.ts +8 -8
- package/dist/sdd/index.js +59 -31
- package/dist/sdd/index.js.map +1 -1
- package/dist/{secret-vault-gxtFZYBt.d.ts → secret-vault-CxiVLbt1.d.ts} +1 -1
- package/dist/security/index.d.ts +4 -4
- package/dist/security/index.js +238 -204
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-DWsqVjGf.d.ts → selector-gIuhRTkN.d.ts} +1 -1
- package/dist/{session-event-bridge-BAFWdgQ3.d.ts → session-event-bridge-DkvvrpDt.d.ts} +8 -2
- package/dist/{session-reader-CqRvaL5v.d.ts → session-reader-KdfVwkKP.d.ts} +1 -1
- package/dist/skills/index.js +67 -64
- package/dist/skills/index.js.map +1 -1
- package/dist/storage/index.d.ts +50 -22
- package/dist/storage/index.js +1654 -525
- package/dist/storage/index.js.map +1 -1
- package/dist/tools/index.d.ts +57 -0
- package/dist/tools/index.js +411 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types/index.d.ts +19 -19
- package/dist/types/index.js +711 -694
- package/dist/types/index.js.map +1 -1
- package/dist/utils/error.d.ts +7 -0
- package/dist/utils/error.js +8 -0
- package/dist/utils/error.js.map +1 -0
- package/dist/utils/index.d.ts +7 -67
- package/dist/utils/index.js +17 -5
- package/dist/utils/index.js.map +1 -1
- package/package.json +5 -1
- package/skills/output-standards/SKILL.md +14 -9
- package/skills/output-standards/SKILL.save.md +3 -2
- package/dist/package-outdated-watcher-BSgR_kK-.d.ts +0 -581
package/dist/types/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomBytes, createCipheriv, createDecipheriv, randomUUID } from 'crypto';
|
|
2
|
-
import * as fs2 from 'fs';
|
|
3
2
|
import * as fs from 'fs/promises';
|
|
4
3
|
import * as path4 from 'path';
|
|
4
|
+
import * as fs2 from 'fs';
|
|
5
5
|
import * as os from 'os';
|
|
6
6
|
|
|
7
7
|
// src/types/blocks.ts
|
|
@@ -14,20 +14,663 @@ function isToolUseBlock(b) {
|
|
|
14
14
|
function isToolResultBlock(b) {
|
|
15
15
|
return b.type === "tool_result";
|
|
16
16
|
}
|
|
17
|
-
function isImageBlock(b) {
|
|
18
|
-
return b.type === "image";
|
|
17
|
+
function isImageBlock(b) {
|
|
18
|
+
return b.type === "image";
|
|
19
|
+
}
|
|
20
|
+
function isThinkingBlock(b) {
|
|
21
|
+
return b.type === "thinking";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/types/messages.ts
|
|
25
|
+
function asBlocks(content) {
|
|
26
|
+
return typeof content === "string" ? [{ type: "text", text: content }] : content;
|
|
27
|
+
}
|
|
28
|
+
function asText(content) {
|
|
29
|
+
if (typeof content === "string") return content;
|
|
30
|
+
return content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
31
|
+
}
|
|
32
|
+
async function atomicWrite(targetPath, content, opts = {}) {
|
|
33
|
+
const dir = path4.dirname(targetPath);
|
|
34
|
+
await fs.mkdir(dir, { recursive: true });
|
|
35
|
+
const tmp = path4.join(dir, `.${path4.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
36
|
+
try {
|
|
37
|
+
if (typeof content === "string") {
|
|
38
|
+
await fs.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
|
|
39
|
+
} else {
|
|
40
|
+
await fs.writeFile(tmp, content, { flag: "wx" });
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const fh = await fs.open(tmp, "r+");
|
|
44
|
+
try {
|
|
45
|
+
await fh.sync();
|
|
46
|
+
} finally {
|
|
47
|
+
await fh.close();
|
|
48
|
+
}
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
let mode;
|
|
52
|
+
try {
|
|
53
|
+
const stat2 = await fs.stat(targetPath);
|
|
54
|
+
mode = stat2.mode & 511;
|
|
55
|
+
} catch {
|
|
56
|
+
mode = opts.mode;
|
|
57
|
+
}
|
|
58
|
+
if (mode !== void 0) {
|
|
59
|
+
await fs.chmod(tmp, mode);
|
|
60
|
+
}
|
|
61
|
+
await renameWithRetry(tmp, targetPath);
|
|
62
|
+
} catch (err) {
|
|
63
|
+
try {
|
|
64
|
+
await fs.unlink(tmp);
|
|
65
|
+
} catch {
|
|
66
|
+
}
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
|
|
71
|
+
async function renameWithRetry(from, to) {
|
|
72
|
+
if (process.platform !== "win32") {
|
|
73
|
+
await fs.rename(from, to);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const delays = [10, 25, 60, 120, 250];
|
|
77
|
+
let lastErr;
|
|
78
|
+
for (let i = 0; i <= delays.length; i++) {
|
|
79
|
+
try {
|
|
80
|
+
await fs.rename(from, to);
|
|
81
|
+
return;
|
|
82
|
+
} catch (err) {
|
|
83
|
+
lastErr = err;
|
|
84
|
+
const code = err?.code;
|
|
85
|
+
if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
await new Promise((resolve4) => setTimeout(resolve4, delays[i]));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
throw lastErr;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/utils/error.ts
|
|
95
|
+
function toErrorMessage(err) {
|
|
96
|
+
return err instanceof Error ? err.message : String(err);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/utils/term.ts
|
|
100
|
+
var hasStdout = () => typeof process !== "undefined" && !!process.stdout;
|
|
101
|
+
function isStdoutTTY() {
|
|
102
|
+
return hasStdout() && Boolean(process.stdout.isTTY);
|
|
103
|
+
}
|
|
104
|
+
function writeTo(s, stream) {
|
|
105
|
+
if (!stream || typeof stream.write !== "function") return false;
|
|
106
|
+
{
|
|
107
|
+
stream.write(s);
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function writeErr(s, stream = process.stderr) {
|
|
112
|
+
return writeTo(s, stream);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/utils/color.ts
|
|
116
|
+
var isColorTty = () => {
|
|
117
|
+
if (envFlag(process.env.NO_COLOR)) return false;
|
|
118
|
+
if (envFlag(process.env.FORCE_COLOR)) return true;
|
|
119
|
+
return isStdoutTTY();
|
|
120
|
+
};
|
|
121
|
+
function envFlag(value) {
|
|
122
|
+
if (value === void 0) return false;
|
|
123
|
+
if (value.trim() === "") return false;
|
|
124
|
+
return !/^(0|false|no|off)$/i.test(value.trim());
|
|
125
|
+
}
|
|
126
|
+
var COLOR = isColorTty();
|
|
127
|
+
var wrap = (open2, close) => (s) => COLOR ? `\x1B[${open2}m${s}\x1B[${close}m` : s;
|
|
128
|
+
var color = {
|
|
129
|
+
reset: wrap("0", "0"),
|
|
130
|
+
bold: wrap("1", "22"),
|
|
131
|
+
dim: wrap("2", "22"),
|
|
132
|
+
italic: wrap("3", "23"),
|
|
133
|
+
underline: wrap("4", "24"),
|
|
134
|
+
red: wrap("31", "39"),
|
|
135
|
+
green: wrap("32", "39"),
|
|
136
|
+
yellow: wrap("33", "39"),
|
|
137
|
+
blue: wrap("34", "39"),
|
|
138
|
+
magenta: wrap("35", "39"),
|
|
139
|
+
cyan: wrap("36", "39"),
|
|
140
|
+
gray: wrap("90", "39"),
|
|
141
|
+
amber: wrap("38;5;214", "39"),
|
|
142
|
+
pink: wrap("38;5;205", "39"),
|
|
143
|
+
bgRed: wrap("41", "49"),
|
|
144
|
+
bgGreen: wrap("42", "49")
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// src/utils/string.ts
|
|
148
|
+
function truncate(s, max) {
|
|
149
|
+
return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/utils/expect-defined.ts
|
|
153
|
+
function expectDefined(value, label) {
|
|
154
|
+
if (value === null || value === void 0) {
|
|
155
|
+
const err = new Error("Expected value to be defined");
|
|
156
|
+
err.name = "ExpectDefinedError";
|
|
157
|
+
throw err;
|
|
158
|
+
}
|
|
159
|
+
return value;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/utils/deep-merge.ts
|
|
163
|
+
var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
|
|
164
|
+
"__proto__",
|
|
165
|
+
"constructor",
|
|
166
|
+
"prototype",
|
|
167
|
+
"__defineGetter__",
|
|
168
|
+
"__defineSetter__",
|
|
169
|
+
"__lookupGetter__",
|
|
170
|
+
"__lookupSetter__"
|
|
171
|
+
]);
|
|
172
|
+
function isPrimitiveArray(a) {
|
|
173
|
+
return a.every((v) => v === null || typeof v !== "object" && typeof v !== "function");
|
|
174
|
+
}
|
|
175
|
+
function deepMerge(base, patch, options = {}) {
|
|
176
|
+
const {
|
|
177
|
+
conflictResolution = "prefer-patch",
|
|
178
|
+
arrayMode = "replace",
|
|
179
|
+
protectProto = true,
|
|
180
|
+
onNonPrimitiveArrayReplace
|
|
181
|
+
} = options;
|
|
182
|
+
if (typeof base !== "object" || base === null) {
|
|
183
|
+
return conflictResolution === "prefer-patch" ? patch : base;
|
|
184
|
+
}
|
|
185
|
+
if (typeof patch !== "object" || patch === null) {
|
|
186
|
+
return conflictResolution === "prefer-patch" ? patch : base;
|
|
187
|
+
}
|
|
188
|
+
if (Array.isArray(base) && Array.isArray(patch)) {
|
|
189
|
+
if (arrayMode === "concat-primitives" && isPrimitiveArray(base) && isPrimitiveArray(patch)) {
|
|
190
|
+
return [.../* @__PURE__ */ new Set([...base, ...patch])];
|
|
191
|
+
}
|
|
192
|
+
return conflictResolution === "prefer-patch" ? patch : base;
|
|
193
|
+
}
|
|
194
|
+
if (Array.isArray(base) || Array.isArray(patch)) {
|
|
195
|
+
return conflictResolution === "prefer-patch" ? patch : base;
|
|
196
|
+
}
|
|
197
|
+
const baseObj = base;
|
|
198
|
+
const patchObj = patch;
|
|
199
|
+
const out = { ...baseObj };
|
|
200
|
+
for (const [k, v] of Object.entries(patchObj)) {
|
|
201
|
+
if (protectProto && FORBIDDEN_PROTO_KEYS.has(k)) continue;
|
|
202
|
+
const existing = out[k];
|
|
203
|
+
if (v !== null && typeof v === "object" && !Array.isArray(v) && existing !== null && typeof existing === "object" && !Array.isArray(existing)) {
|
|
204
|
+
out[k] = deepMerge(existing, v, options);
|
|
205
|
+
} else if (Array.isArray(v) && Array.isArray(existing)) {
|
|
206
|
+
if (onNonPrimitiveArrayReplace && !isPrimitiveArray(v)) {
|
|
207
|
+
onNonPrimitiveArrayReplace(k, existing.length, v.length);
|
|
208
|
+
}
|
|
209
|
+
out[k] = deepMerge(existing, v, options);
|
|
210
|
+
} else if (v !== void 0) {
|
|
211
|
+
if (onNonPrimitiveArrayReplace && Array.isArray(v) && !isPrimitiveArray(v)) {
|
|
212
|
+
const existingLen = Array.isArray(existing) ? existing.length : 0;
|
|
213
|
+
onNonPrimitiveArrayReplace(k, existingLen, v.length);
|
|
214
|
+
}
|
|
215
|
+
out[k] = v;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return out;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/utils/tool-output-serializer.ts
|
|
222
|
+
function createToolOutputSerializer(opts = {}) {
|
|
223
|
+
const capBytes = opts.perIterationOutputCapBytes ?? 1e5;
|
|
224
|
+
function serialize(value) {
|
|
225
|
+
if (typeof value === "string") return value;
|
|
226
|
+
if (value === null || value === void 0) return "";
|
|
227
|
+
if (typeof value === "object") {
|
|
228
|
+
if (Array.isArray(value)) return value.map(serialize).join("\n");
|
|
229
|
+
if ("text" in value) {
|
|
230
|
+
const t = value.text;
|
|
231
|
+
return typeof t === "string" ? t : JSON.stringify(value, null, 2);
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
return JSON.stringify(value, null, 2);
|
|
235
|
+
} catch {
|
|
236
|
+
return String(value);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return String(value);
|
|
240
|
+
}
|
|
241
|
+
function enforceCap(text, remainingBudget) {
|
|
242
|
+
if (remainingBudget <= 0) {
|
|
243
|
+
return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
|
|
244
|
+
}
|
|
245
|
+
const textBytes = Buffer.byteLength(text, "utf8");
|
|
246
|
+
if (textBytes <= remainingBudget) {
|
|
247
|
+
return { text, newBudget: remainingBudget - textBytes };
|
|
248
|
+
}
|
|
249
|
+
const marker = `
|
|
250
|
+
\u2026[truncated ${textBytes - remainingBudget} bytes]\u2026
|
|
251
|
+
`;
|
|
252
|
+
const markerBytes = Buffer.byteLength(marker, "utf8");
|
|
253
|
+
const available = remainingBudget - markerBytes;
|
|
254
|
+
if (available <= 0) {
|
|
255
|
+
return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
|
|
256
|
+
}
|
|
257
|
+
const half = Math.floor(available / 2);
|
|
258
|
+
const first = text.slice(0, half);
|
|
259
|
+
const second = text.slice(text.length - half);
|
|
260
|
+
return { text: `${first}${marker}${second}`, newBudget: 0 };
|
|
261
|
+
}
|
|
262
|
+
return { serialize, enforceCap, capBytes };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// src/utils/token-estimate.ts
|
|
266
|
+
var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
|
|
267
|
+
var CALIBRATION_GLOBAL_KEY = "__global__";
|
|
268
|
+
var _cals = /* @__PURE__ */ new Map();
|
|
269
|
+
function calState(key) {
|
|
270
|
+
let state = _cals.get(key);
|
|
271
|
+
if (!state) {
|
|
272
|
+
state = { ratio: 1, count: 0, prevEst: 0 };
|
|
273
|
+
_cals.set(key, state);
|
|
274
|
+
}
|
|
275
|
+
return state;
|
|
276
|
+
}
|
|
277
|
+
var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
|
|
278
|
+
var ESTIMATE_CACHE_MAX_SIZE = 1e4;
|
|
279
|
+
function getCachedEstimate(key, compute) {
|
|
280
|
+
const existing = ESTIMATE_CACHE.get(key);
|
|
281
|
+
if (existing !== void 0) return existing;
|
|
282
|
+
if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {
|
|
283
|
+
let evicted = 0;
|
|
284
|
+
const maxEvict = Math.floor(ESTIMATE_CACHE_MAX_SIZE / 4);
|
|
285
|
+
for (const k of ESTIMATE_CACHE.keys()) {
|
|
286
|
+
if (evicted >= maxEvict) break;
|
|
287
|
+
ESTIMATE_CACHE.delete(k);
|
|
288
|
+
evicted++;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const estimate = compute(key);
|
|
292
|
+
ESTIMATE_CACHE.set(key, estimate);
|
|
293
|
+
return estimate;
|
|
294
|
+
}
|
|
295
|
+
function estimateToolInputTokens(input) {
|
|
296
|
+
if (typeof input === "string") return RoughTokenEstimate(input);
|
|
297
|
+
if (input === null || typeof input !== "object") {
|
|
298
|
+
return RoughTokenEstimate(String(input));
|
|
299
|
+
}
|
|
300
|
+
return getCachedEstimate(JSON.stringify(input), (key) => RoughTokenEstimate(key));
|
|
301
|
+
}
|
|
302
|
+
function estimateToolResultTokens(content) {
|
|
303
|
+
if (typeof content === "string") return RoughTokenEstimate(content);
|
|
304
|
+
return getCachedEstimate(JSON.stringify(content), (key) => RoughTokenEstimate(key));
|
|
305
|
+
}
|
|
306
|
+
function estimateTextTokens(text) {
|
|
307
|
+
return RoughTokenEstimate(text);
|
|
308
|
+
}
|
|
309
|
+
function computeMessageTokens(msg) {
|
|
310
|
+
if (typeof msg.content === "string") return estimateTextTokens(msg.content);
|
|
311
|
+
let total = 0;
|
|
312
|
+
for (const b of msg.content) {
|
|
313
|
+
if (b.type === "text") total += estimateTextTokens(b.text);
|
|
314
|
+
else if (b.type === "tool_use") total += estimateToolInputTokens(b.input);
|
|
315
|
+
else if (b.type === "tool_result") total += estimateToolResultTokens(b.content);
|
|
316
|
+
else total += RoughTokenEstimate(JSON.stringify(b));
|
|
317
|
+
}
|
|
318
|
+
return total;
|
|
319
|
+
}
|
|
320
|
+
function estimateMessageTokens(messages) {
|
|
321
|
+
let total = 0;
|
|
322
|
+
for (const m of messages) {
|
|
323
|
+
if (typeof m._estTokens === "number" && m._estTokens > 0) {
|
|
324
|
+
total += m._estTokens;
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
total += computeMessageTokens(m);
|
|
328
|
+
}
|
|
329
|
+
return total;
|
|
330
|
+
}
|
|
331
|
+
function estimateToolDefTokens(tool) {
|
|
332
|
+
const cached = tool._estDefTokens;
|
|
333
|
+
if (typeof cached === "number" && cached > 0) return cached;
|
|
334
|
+
return RoughTokenEstimate(tool.name) + RoughTokenEstimate(tool.description ?? "") + RoughTokenEstimate(JSON.stringify(tool.inputSchema));
|
|
335
|
+
}
|
|
336
|
+
function estimateRequestTokens(messages, systemPrompt, tools, calibrationKey = CALIBRATION_GLOBAL_KEY) {
|
|
337
|
+
let messagesTokens = 0;
|
|
338
|
+
if (typeof messages === "string") {
|
|
339
|
+
messagesTokens = RoughTokenEstimate(messages);
|
|
340
|
+
} else if (Array.isArray(messages)) {
|
|
341
|
+
for (const m of messages) {
|
|
342
|
+
if (typeof m === "object" && m !== null && "content" in m) {
|
|
343
|
+
const cached = m._estTokens;
|
|
344
|
+
if (typeof cached === "number" && cached > 0) {
|
|
345
|
+
messagesTokens += cached;
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
const content = m.content;
|
|
349
|
+
if (typeof content === "string") {
|
|
350
|
+
messagesTokens += RoughTokenEstimate(content);
|
|
351
|
+
} else if (Array.isArray(content)) {
|
|
352
|
+
for (const b of content) {
|
|
353
|
+
if (typeof b === "object" && b !== null) {
|
|
354
|
+
if (b.type === "text") {
|
|
355
|
+
messagesTokens += RoughTokenEstimate(b.text);
|
|
356
|
+
} else {
|
|
357
|
+
messagesTokens += RoughTokenEstimate(JSON.stringify(b));
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
let systemTokens = 0;
|
|
366
|
+
if (typeof systemPrompt === "string") {
|
|
367
|
+
systemTokens = RoughTokenEstimate(systemPrompt);
|
|
368
|
+
} else if (Array.isArray(systemPrompt)) {
|
|
369
|
+
for (const b of systemPrompt) {
|
|
370
|
+
if (typeof b === "object" && b !== null && b.type === "text") {
|
|
371
|
+
systemTokens += RoughTokenEstimate(b.text);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
let toolsTokens = 0;
|
|
376
|
+
for (const t of tools) {
|
|
377
|
+
toolsTokens += estimateToolDefTokens(t);
|
|
378
|
+
}
|
|
379
|
+
const total = messagesTokens + systemTokens + toolsTokens;
|
|
380
|
+
calState(calibrationKey).prevEst = total;
|
|
381
|
+
return {
|
|
382
|
+
messages: messagesTokens,
|
|
383
|
+
systemPrompt: systemTokens,
|
|
384
|
+
tools: toolsTokens,
|
|
385
|
+
total
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// src/utils/message-invariants.ts
|
|
390
|
+
function repairToolUseAdjacency(messages) {
|
|
391
|
+
const removedToolUses = [];
|
|
392
|
+
const removedToolResults = [];
|
|
393
|
+
let removedMessages = 0;
|
|
394
|
+
let changed = false;
|
|
395
|
+
const out = [];
|
|
396
|
+
for (let i = 0; i < messages.length; i++) {
|
|
397
|
+
const original = expectDefined(messages[i]);
|
|
398
|
+
let msg = original;
|
|
399
|
+
if (hasToolUse(msg)) {
|
|
400
|
+
const nextIds = toolResultIds(messages[i + 1]);
|
|
401
|
+
const filtered = mapContent(msg, (blocks) => {
|
|
402
|
+
const next = [];
|
|
403
|
+
for (const block of blocks) {
|
|
404
|
+
if (block.type === "tool_use" && !nextIds.has(block.id)) {
|
|
405
|
+
removedToolUses.push(block.id);
|
|
406
|
+
changed = true;
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
next.push(block);
|
|
410
|
+
}
|
|
411
|
+
return next;
|
|
412
|
+
});
|
|
413
|
+
msg = filtered ?? msg;
|
|
414
|
+
}
|
|
415
|
+
if (hasToolResult(msg)) {
|
|
416
|
+
const allowed = toolUseIds(out[out.length - 1]);
|
|
417
|
+
const filtered = mapContent(msg, (blocks) => {
|
|
418
|
+
const next = [];
|
|
419
|
+
for (const block of blocks) {
|
|
420
|
+
if (block.type === "tool_result" && !allowed.has(block.tool_use_id)) {
|
|
421
|
+
removedToolResults.push(block.tool_use_id);
|
|
422
|
+
changed = true;
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
next.push(block);
|
|
426
|
+
}
|
|
427
|
+
return next;
|
|
428
|
+
});
|
|
429
|
+
msg = filtered ?? msg;
|
|
430
|
+
}
|
|
431
|
+
if (isEmptyMessage(msg)) {
|
|
432
|
+
removedMessages++;
|
|
433
|
+
changed = true;
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
out.push(msg);
|
|
437
|
+
}
|
|
438
|
+
return {
|
|
439
|
+
messages: changed ? out : messages,
|
|
440
|
+
report: { changed, removedToolUses, removedToolResults, removedMessages }
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function hasToolUse(msg) {
|
|
444
|
+
return contentBlocks(msg).some((b) => b.type === "tool_use");
|
|
445
|
+
}
|
|
446
|
+
function hasToolResult(msg) {
|
|
447
|
+
return contentBlocks(msg).some((b) => b.type === "tool_result");
|
|
448
|
+
}
|
|
449
|
+
function toolUseIds(msg) {
|
|
450
|
+
const ids = /* @__PURE__ */ new Set();
|
|
451
|
+
if (!msg || msg.role !== "assistant") return ids;
|
|
452
|
+
for (const block of contentBlocks(msg)) {
|
|
453
|
+
if (block.type === "tool_use") ids.add(block.id);
|
|
454
|
+
}
|
|
455
|
+
return ids;
|
|
456
|
+
}
|
|
457
|
+
function toolResultIds(msg) {
|
|
458
|
+
const ids = /* @__PURE__ */ new Set();
|
|
459
|
+
if (!msg || msg.role !== "user") return ids;
|
|
460
|
+
for (const block of contentBlocks(msg)) {
|
|
461
|
+
if (block.type === "tool_result") ids.add(block.tool_use_id);
|
|
462
|
+
}
|
|
463
|
+
return ids;
|
|
464
|
+
}
|
|
465
|
+
function contentBlocks(msg) {
|
|
466
|
+
return msg && Array.isArray(msg.content) ? msg.content : [];
|
|
467
|
+
}
|
|
468
|
+
function mapContent(msg, fn) {
|
|
469
|
+
if (!Array.isArray(msg.content)) return msg;
|
|
470
|
+
const next = fn(msg.content);
|
|
471
|
+
if (next.length === msg.content.length && next.every((b, idx) => b === msg.content[idx])) {
|
|
472
|
+
return msg;
|
|
473
|
+
}
|
|
474
|
+
return { ...msg, content: next };
|
|
475
|
+
}
|
|
476
|
+
function isEmptyMessage(msg) {
|
|
477
|
+
if (typeof msg.content === "string") return msg.content.trim().length === 0;
|
|
478
|
+
return msg.content.length === 0;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// src/utils/json-schema-validate.ts
|
|
482
|
+
function validateAgainstSchema(value, schema) {
|
|
483
|
+
const errors = [];
|
|
484
|
+
walk(value, schema, "", errors);
|
|
485
|
+
return { ok: errors.length === 0, errors };
|
|
486
|
+
}
|
|
487
|
+
function walk(value, schema, path7, errors) {
|
|
488
|
+
if (schema.enum !== void 0) {
|
|
489
|
+
if (!schema.enum.some((e) => deepEqual(e, value))) {
|
|
490
|
+
errors.push({
|
|
491
|
+
path: path7 || "<root>",
|
|
492
|
+
message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
|
|
493
|
+
});
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (typeof schema.type === "string") {
|
|
498
|
+
if (!checkType(value, schema.type)) {
|
|
499
|
+
errors.push({
|
|
500
|
+
path: path7 || "<root>",
|
|
501
|
+
message: `expected ${schema.type}, got ${describeType(value)}`
|
|
502
|
+
});
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
if (schema.type === "object" && isPlainObject(value)) {
|
|
507
|
+
const obj = value;
|
|
508
|
+
for (const req of schema.required ?? []) {
|
|
509
|
+
if (!(req in obj)) {
|
|
510
|
+
errors.push({ path: joinPath(path7, req), message: "required property missing" });
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
if (schema.properties) {
|
|
514
|
+
for (const [key, subSchema] of Object.entries(schema.properties)) {
|
|
515
|
+
if (key in obj) {
|
|
516
|
+
walk(obj[key], subSchema, joinPath(path7, key), errors);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (schema.type === "array" && Array.isArray(value) && schema.items) {
|
|
522
|
+
for (let i = 0; i < value.length; i++) {
|
|
523
|
+
walk(value[i], schema.items, `${path7}[${i}]`, errors);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
function checkType(value, type) {
|
|
528
|
+
switch (type) {
|
|
529
|
+
case "string":
|
|
530
|
+
return typeof value === "string";
|
|
531
|
+
case "number":
|
|
532
|
+
return typeof value === "number" && !Number.isNaN(value);
|
|
533
|
+
case "integer":
|
|
534
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
535
|
+
case "boolean":
|
|
536
|
+
return typeof value === "boolean";
|
|
537
|
+
case "null":
|
|
538
|
+
return value === null;
|
|
539
|
+
case "array":
|
|
540
|
+
return Array.isArray(value);
|
|
541
|
+
case "object":
|
|
542
|
+
return isPlainObject(value);
|
|
543
|
+
default:
|
|
544
|
+
return true;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
function isPlainObject(v) {
|
|
548
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
549
|
+
}
|
|
550
|
+
function describeType(v) {
|
|
551
|
+
if (v === null) return "null";
|
|
552
|
+
if (Array.isArray(v)) return "array";
|
|
553
|
+
return typeof v;
|
|
554
|
+
}
|
|
555
|
+
function joinPath(parent, key) {
|
|
556
|
+
if (!parent) return key;
|
|
557
|
+
return `${parent}.${key}`;
|
|
558
|
+
}
|
|
559
|
+
function deepEqual(a, b) {
|
|
560
|
+
if (a === b) return true;
|
|
561
|
+
if (typeof a !== typeof b) return false;
|
|
562
|
+
if (a === null || b === null) return a === b;
|
|
563
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
564
|
+
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
565
|
+
}
|
|
566
|
+
if (typeof a === "object" && typeof b === "object") {
|
|
567
|
+
const ak = Object.keys(a);
|
|
568
|
+
const bk = Object.keys(b);
|
|
569
|
+
if (ak.length !== bk.length) return false;
|
|
570
|
+
return ak.every(
|
|
571
|
+
(k) => deepEqual(a[k], b[k])
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
return false;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// src/utils/regex-guard.ts
|
|
578
|
+
var MAX_PATTERN_LEN = 512;
|
|
579
|
+
var DANGEROUS_PATTERNS = [
|
|
580
|
+
/(\([^)]*[+*][^)]*\))[+*]/,
|
|
581
|
+
// (a+)+, (.*)+, etc
|
|
582
|
+
/(\(\?:[^)]*[+*][^)]*\))[+*]/
|
|
583
|
+
// same, with non-capturing group
|
|
584
|
+
];
|
|
585
|
+
function compileUserRegex(pattern, flags) {
|
|
586
|
+
if (typeof pattern !== "string") {
|
|
587
|
+
return { ok: false, reason: "pattern must be a string" };
|
|
588
|
+
}
|
|
589
|
+
if (pattern.length === 0) {
|
|
590
|
+
return { ok: false, reason: "pattern is empty" };
|
|
591
|
+
}
|
|
592
|
+
if (pattern.length > MAX_PATTERN_LEN) {
|
|
593
|
+
return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };
|
|
594
|
+
}
|
|
595
|
+
for (const rx of DANGEROUS_PATTERNS) {
|
|
596
|
+
if (rx.test(pattern)) {
|
|
597
|
+
return {
|
|
598
|
+
ok: false,
|
|
599
|
+
reason: "pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers"
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
try {
|
|
604
|
+
return { ok: true, regex: new RegExp(pattern, flags) };
|
|
605
|
+
} catch (err) {
|
|
606
|
+
return {
|
|
607
|
+
ok: false,
|
|
608
|
+
reason: err instanceof Error ? err.message : "invalid regex"
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// src/utils/merge-models-payload.ts
|
|
614
|
+
function mergeModelsPayload(base, overlay) {
|
|
615
|
+
const out = {};
|
|
616
|
+
for (const [id, provider] of Object.entries(base)) {
|
|
617
|
+
out[id] = cloneProvider(provider);
|
|
618
|
+
}
|
|
619
|
+
for (const [id, ovProvider] of Object.entries(overlay)) {
|
|
620
|
+
const existing = out[id];
|
|
621
|
+
out[id] = existing ? mergeProvider(existing, ovProvider) : cloneProvider(ovProvider);
|
|
622
|
+
}
|
|
623
|
+
return out;
|
|
624
|
+
}
|
|
625
|
+
function mergeProvider(base, overlay) {
|
|
626
|
+
const models = {};
|
|
627
|
+
for (const [mid, m] of Object.entries(base.models ?? {})) {
|
|
628
|
+
models[mid] = { ...m };
|
|
629
|
+
}
|
|
630
|
+
for (const [mid, ovModel] of Object.entries(overlay.models ?? {})) {
|
|
631
|
+
const existing = models[mid];
|
|
632
|
+
models[mid] = existing ? mergeModel(existing, ovModel) : { ...ovModel };
|
|
633
|
+
}
|
|
634
|
+
return {
|
|
635
|
+
...base,
|
|
636
|
+
// Overlay scalar fields win when explicitly provided; otherwise keep base.
|
|
637
|
+
...stripUndefined({
|
|
638
|
+
id: overlay.id,
|
|
639
|
+
name: overlay.name,
|
|
640
|
+
npm: overlay.npm,
|
|
641
|
+
api: overlay.api,
|
|
642
|
+
env: overlay.env,
|
|
643
|
+
doc: overlay.doc
|
|
644
|
+
}),
|
|
645
|
+
models
|
|
646
|
+
};
|
|
19
647
|
}
|
|
20
|
-
function
|
|
21
|
-
|
|
648
|
+
function mergeModel(base, overlay) {
|
|
649
|
+
const merged = { ...base, ...overlay };
|
|
650
|
+
if (base.limit || overlay.limit) {
|
|
651
|
+
merged.limit = { ...base.limit, ...overlay.limit };
|
|
652
|
+
}
|
|
653
|
+
if (base.cost || overlay.cost) {
|
|
654
|
+
merged.cost = { ...base.cost, ...overlay.cost };
|
|
655
|
+
}
|
|
656
|
+
if (base.modalities || overlay.modalities) {
|
|
657
|
+
merged.modalities = { ...base.modalities, ...overlay.modalities };
|
|
658
|
+
}
|
|
659
|
+
return merged;
|
|
22
660
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
661
|
+
function cloneProvider(p) {
|
|
662
|
+
const models = {};
|
|
663
|
+
for (const [mid, m] of Object.entries(p.models ?? {})) {
|
|
664
|
+
models[mid] = { ...m };
|
|
665
|
+
}
|
|
666
|
+
return { ...p, models };
|
|
27
667
|
}
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
668
|
+
function stripUndefined(obj) {
|
|
669
|
+
const out = {};
|
|
670
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
671
|
+
if (v !== void 0) out[k] = v;
|
|
672
|
+
}
|
|
673
|
+
return out;
|
|
31
674
|
}
|
|
32
675
|
|
|
33
676
|
// src/types/errors.ts
|
|
@@ -175,7 +818,7 @@ var AgentError = class extends WrongStackError {
|
|
|
175
818
|
};
|
|
176
819
|
function toWrongStackError(err, code = ERROR_CODES.AGENT_RUN_FAILED) {
|
|
177
820
|
if (err instanceof WrongStackError) return err;
|
|
178
|
-
const message =
|
|
821
|
+
const message = toErrorMessage(err);
|
|
179
822
|
return new AgentError({
|
|
180
823
|
message,
|
|
181
824
|
code: code === "UNKNOWN" ? ERROR_CODES.AGENT_RUN_FAILED : code,
|
|
@@ -253,11 +896,6 @@ function isSddError(err) {
|
|
|
253
896
|
return err instanceof SddError;
|
|
254
897
|
}
|
|
255
898
|
|
|
256
|
-
// src/utils/string.ts
|
|
257
|
-
function truncate(s, max) {
|
|
258
|
-
return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
899
|
// src/types/provider.ts
|
|
262
900
|
var ProviderError = class extends WrongStackError {
|
|
263
901
|
status;
|
|
@@ -388,126 +1026,6 @@ var DEFAULT_SESSION_PRUNE_DAYS = 30;
|
|
|
388
1026
|
|
|
389
1027
|
// src/types/secret-vault.ts
|
|
390
1028
|
var ENCRYPTED_PREFIX = "enc:v1:";
|
|
391
|
-
async function atomicWrite(targetPath, content, opts = {}) {
|
|
392
|
-
const dir = path4.dirname(targetPath);
|
|
393
|
-
await fs.mkdir(dir, { recursive: true });
|
|
394
|
-
const tmp = path4.join(dir, `.${path4.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
395
|
-
try {
|
|
396
|
-
if (typeof content === "string") {
|
|
397
|
-
await fs.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
|
|
398
|
-
} else {
|
|
399
|
-
await fs.writeFile(tmp, content, { flag: "wx" });
|
|
400
|
-
}
|
|
401
|
-
try {
|
|
402
|
-
const fh = await fs.open(tmp, "r+");
|
|
403
|
-
try {
|
|
404
|
-
await fh.sync();
|
|
405
|
-
} finally {
|
|
406
|
-
await fh.close();
|
|
407
|
-
}
|
|
408
|
-
} catch {
|
|
409
|
-
}
|
|
410
|
-
let mode;
|
|
411
|
-
try {
|
|
412
|
-
const stat2 = await fs.stat(targetPath);
|
|
413
|
-
mode = stat2.mode & 511;
|
|
414
|
-
} catch {
|
|
415
|
-
mode = opts.mode;
|
|
416
|
-
}
|
|
417
|
-
if (mode !== void 0) {
|
|
418
|
-
await fs.chmod(tmp, mode);
|
|
419
|
-
}
|
|
420
|
-
await renameWithRetry(tmp, targetPath);
|
|
421
|
-
} catch (err) {
|
|
422
|
-
try {
|
|
423
|
-
await fs.unlink(tmp);
|
|
424
|
-
} catch {
|
|
425
|
-
}
|
|
426
|
-
throw err;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
|
|
430
|
-
async function renameWithRetry(from, to) {
|
|
431
|
-
if (process.platform !== "win32") {
|
|
432
|
-
await fs.rename(from, to);
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
const delays = [10, 25, 60, 120, 250];
|
|
436
|
-
let lastErr;
|
|
437
|
-
for (let i = 0; i <= delays.length; i++) {
|
|
438
|
-
try {
|
|
439
|
-
await fs.rename(from, to);
|
|
440
|
-
return;
|
|
441
|
-
} catch (err) {
|
|
442
|
-
lastErr = err;
|
|
443
|
-
const code = err?.code;
|
|
444
|
-
if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
|
|
445
|
-
throw err;
|
|
446
|
-
}
|
|
447
|
-
await new Promise((resolve4) => setTimeout(resolve4, delays[i]));
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
throw lastErr;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
// src/utils/deep-merge.ts
|
|
454
|
-
var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
|
|
455
|
-
"__proto__",
|
|
456
|
-
"constructor",
|
|
457
|
-
"prototype",
|
|
458
|
-
"__defineGetter__",
|
|
459
|
-
"__defineSetter__",
|
|
460
|
-
"__lookupGetter__",
|
|
461
|
-
"__lookupSetter__"
|
|
462
|
-
]);
|
|
463
|
-
function isPrimitiveArray(a) {
|
|
464
|
-
return a.every((v) => v === null || typeof v !== "object" && typeof v !== "function");
|
|
465
|
-
}
|
|
466
|
-
function deepMerge(base, patch, options = {}) {
|
|
467
|
-
const {
|
|
468
|
-
conflictResolution = "prefer-patch",
|
|
469
|
-
arrayMode = "replace",
|
|
470
|
-
protectProto = true,
|
|
471
|
-
onNonPrimitiveArrayReplace
|
|
472
|
-
} = options;
|
|
473
|
-
if (typeof base !== "object" || base === null) {
|
|
474
|
-
return conflictResolution === "prefer-patch" ? patch : base;
|
|
475
|
-
}
|
|
476
|
-
if (typeof patch !== "object" || patch === null) {
|
|
477
|
-
return conflictResolution === "prefer-patch" ? patch : base;
|
|
478
|
-
}
|
|
479
|
-
if (Array.isArray(base) && Array.isArray(patch)) {
|
|
480
|
-
if (arrayMode === "concat-primitives" && isPrimitiveArray(base) && isPrimitiveArray(patch)) {
|
|
481
|
-
return [.../* @__PURE__ */ new Set([...base, ...patch])];
|
|
482
|
-
}
|
|
483
|
-
return conflictResolution === "prefer-patch" ? patch : base;
|
|
484
|
-
}
|
|
485
|
-
if (Array.isArray(base) || Array.isArray(patch)) {
|
|
486
|
-
return conflictResolution === "prefer-patch" ? patch : base;
|
|
487
|
-
}
|
|
488
|
-
const baseObj = base;
|
|
489
|
-
const patchObj = patch;
|
|
490
|
-
const out = { ...baseObj };
|
|
491
|
-
for (const [k, v] of Object.entries(patchObj)) {
|
|
492
|
-
if (protectProto && FORBIDDEN_PROTO_KEYS.has(k)) continue;
|
|
493
|
-
const existing = out[k];
|
|
494
|
-
if (v !== null && typeof v === "object" && !Array.isArray(v) && existing !== null && typeof existing === "object" && !Array.isArray(existing)) {
|
|
495
|
-
out[k] = deepMerge(existing, v, options);
|
|
496
|
-
} else if (Array.isArray(v) && Array.isArray(existing)) {
|
|
497
|
-
if (onNonPrimitiveArrayReplace && !isPrimitiveArray(v)) {
|
|
498
|
-
onNonPrimitiveArrayReplace(k, existing.length, v.length);
|
|
499
|
-
}
|
|
500
|
-
out[k] = deepMerge(existing, v, options);
|
|
501
|
-
} else if (v !== void 0) {
|
|
502
|
-
if (onNonPrimitiveArrayReplace && Array.isArray(v) && !isPrimitiveArray(v)) {
|
|
503
|
-
const existingLen = Array.isArray(existing) ? existing.length : 0;
|
|
504
|
-
onNonPrimitiveArrayReplace(k, existingLen, v.length);
|
|
505
|
-
}
|
|
506
|
-
out[k] = v;
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
return out;
|
|
510
|
-
}
|
|
511
1029
|
|
|
512
1030
|
// src/security/secret-vault.ts
|
|
513
1031
|
var KEY_BYTES = 32;
|
|
@@ -624,7 +1142,7 @@ var DefaultSecretVault = class {
|
|
|
624
1142
|
};
|
|
625
1143
|
function decryptConfigSecrets(cfg, vault, opts) {
|
|
626
1144
|
const warn = opts?.warn ?? ((msg) => console.warn(msg));
|
|
627
|
-
return
|
|
1145
|
+
return walk2(cfg, vault, (v, key) => {
|
|
628
1146
|
try {
|
|
629
1147
|
return vault.decrypt(v);
|
|
630
1148
|
} catch (err) {
|
|
@@ -636,20 +1154,20 @@ function decryptConfigSecrets(cfg, vault, opts) {
|
|
|
636
1154
|
});
|
|
637
1155
|
}
|
|
638
1156
|
function encryptConfigSecrets(cfg, vault, _opts) {
|
|
639
|
-
return
|
|
1157
|
+
return walk2(cfg, vault, (v) => vault.encrypt(v));
|
|
640
1158
|
}
|
|
641
|
-
function
|
|
1159
|
+
function walk2(node, vault, transform) {
|
|
642
1160
|
if (node === null || node === void 0) return node;
|
|
643
1161
|
if (typeof node !== "object") return node;
|
|
644
1162
|
if (Array.isArray(node)) {
|
|
645
|
-
return node.map((item) =>
|
|
1163
|
+
return node.map((item) => walk2(item, vault, transform));
|
|
646
1164
|
}
|
|
647
1165
|
const out = /* @__PURE__ */ Object.create(null);
|
|
648
1166
|
for (const [k, v] of Object.entries(node)) {
|
|
649
1167
|
if (typeof v === "string" && isSecretField(k)) {
|
|
650
1168
|
out[k] = transform(v, k);
|
|
651
1169
|
} else if (typeof v === "object" && v !== null) {
|
|
652
|
-
out[k] =
|
|
1170
|
+
out[k] = walk2(v, vault, transform);
|
|
653
1171
|
} else {
|
|
654
1172
|
out[k] = v;
|
|
655
1173
|
}
|
|
@@ -734,74 +1252,24 @@ function windowsAccountName() {
|
|
|
734
1252
|
return username;
|
|
735
1253
|
}
|
|
736
1254
|
function walkCount(node, vault, counter) {
|
|
737
|
-
if (node === null || node === void 0) return node;
|
|
738
|
-
if (typeof node !== "object") return node;
|
|
739
|
-
if (Array.isArray(node)) {
|
|
740
|
-
return node.map((item) => walkCount(item, vault, counter));
|
|
741
|
-
}
|
|
742
|
-
const out = /* @__PURE__ */ Object.create(null);
|
|
743
|
-
for (const [k, v] of Object.entries(node)) {
|
|
744
|
-
if (typeof v === "string" && isSecretField(k) && !vault.isEncrypted(v) && v.length > 0) {
|
|
745
|
-
out[k] = vault.encrypt(v);
|
|
746
|
-
counter.n++;
|
|
747
|
-
} else if (typeof v === "object" && v !== null) {
|
|
748
|
-
out[k] = walkCount(v, vault, counter);
|
|
749
|
-
} else {
|
|
750
|
-
out[k] = v;
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
return out;
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
// src/utils/term.ts
|
|
757
|
-
var hasStdout = () => typeof process !== "undefined" && !!process.stdout;
|
|
758
|
-
function isStdoutTTY() {
|
|
759
|
-
return hasStdout() && Boolean(process.stdout.isTTY);
|
|
760
|
-
}
|
|
761
|
-
function writeTo(s, stream) {
|
|
762
|
-
if (!stream || typeof stream.write !== "function") return false;
|
|
763
|
-
{
|
|
764
|
-
stream.write(s);
|
|
765
|
-
return true;
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
function writeErr(s, stream = process.stderr) {
|
|
769
|
-
return writeTo(s, stream);
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
// src/utils/color.ts
|
|
773
|
-
var isColorTty = () => {
|
|
774
|
-
if (envFlag(process.env.NO_COLOR)) return false;
|
|
775
|
-
if (envFlag(process.env.FORCE_COLOR)) return true;
|
|
776
|
-
return isStdoutTTY();
|
|
777
|
-
};
|
|
778
|
-
function envFlag(value) {
|
|
779
|
-
if (value === void 0) return false;
|
|
780
|
-
if (value.trim() === "") return false;
|
|
781
|
-
return !/^(0|false|no|off)$/i.test(value.trim());
|
|
782
|
-
}
|
|
783
|
-
var COLOR = isColorTty();
|
|
784
|
-
var wrap = (open2, close) => (s) => COLOR ? `\x1B[${open2}m${s}\x1B[${close}m` : s;
|
|
785
|
-
var color = {
|
|
786
|
-
reset: wrap("0", "0"),
|
|
787
|
-
bold: wrap("1", "22"),
|
|
788
|
-
dim: wrap("2", "22"),
|
|
789
|
-
italic: wrap("3", "23"),
|
|
790
|
-
underline: wrap("4", "24"),
|
|
791
|
-
red: wrap("31", "39"),
|
|
792
|
-
green: wrap("32", "39"),
|
|
793
|
-
yellow: wrap("33", "39"),
|
|
794
|
-
blue: wrap("34", "39"),
|
|
795
|
-
magenta: wrap("35", "39"),
|
|
796
|
-
cyan: wrap("36", "39"),
|
|
797
|
-
gray: wrap("90", "39"),
|
|
798
|
-
amber: wrap("38;5;214", "39"),
|
|
799
|
-
pink: wrap("38;5;205", "39"),
|
|
800
|
-
bgRed: wrap("41", "49"),
|
|
801
|
-
bgGreen: wrap("42", "49")
|
|
802
|
-
};
|
|
803
|
-
|
|
804
|
-
// src/infrastructure/logger.ts
|
|
1255
|
+
if (node === null || node === void 0) return node;
|
|
1256
|
+
if (typeof node !== "object") return node;
|
|
1257
|
+
if (Array.isArray(node)) {
|
|
1258
|
+
return node.map((item) => walkCount(item, vault, counter));
|
|
1259
|
+
}
|
|
1260
|
+
const out = /* @__PURE__ */ Object.create(null);
|
|
1261
|
+
for (const [k, v] of Object.entries(node)) {
|
|
1262
|
+
if (typeof v === "string" && isSecretField(k) && !vault.isEncrypted(v) && v.length > 0) {
|
|
1263
|
+
out[k] = vault.encrypt(v);
|
|
1264
|
+
counter.n++;
|
|
1265
|
+
} else if (typeof v === "object" && v !== null) {
|
|
1266
|
+
out[k] = walkCount(v, vault, counter);
|
|
1267
|
+
} else {
|
|
1268
|
+
out[k] = v;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
return out;
|
|
1272
|
+
}
|
|
805
1273
|
var LEVEL_RANK = {
|
|
806
1274
|
error: 0,
|
|
807
1275
|
warn: 1,
|
|
@@ -1080,250 +1548,24 @@ function priceFromModel(m) {
|
|
|
1080
1548
|
return {
|
|
1081
1549
|
input: m.cost?.input,
|
|
1082
1550
|
output: m.cost?.output,
|
|
1083
|
-
cacheRead: m.cost?.cache_read,
|
|
1084
|
-
cacheWrite: m.cost?.cache_write
|
|
1085
|
-
};
|
|
1086
|
-
}
|
|
1087
|
-
function round4(n) {
|
|
1088
|
-
return Math.round(n * 1e4) / 1e4;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
// src/types/memory.ts
|
|
1092
|
-
var MEMORY_TYPE_LABELS = {
|
|
1093
|
-
fact: "Fact",
|
|
1094
|
-
decision: "Decision",
|
|
1095
|
-
convention: "Convention",
|
|
1096
|
-
preference: "Preference",
|
|
1097
|
-
reference: "Reference",
|
|
1098
|
-
anti_pattern: "Anti-pattern"
|
|
1099
|
-
};
|
|
1100
|
-
|
|
1101
|
-
// src/utils/token-estimate.ts
|
|
1102
|
-
var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
|
|
1103
|
-
var CALIBRATION_GLOBAL_KEY = "__global__";
|
|
1104
|
-
var _cals = /* @__PURE__ */ new Map();
|
|
1105
|
-
function calState(key) {
|
|
1106
|
-
let state = _cals.get(key);
|
|
1107
|
-
if (!state) {
|
|
1108
|
-
state = { ratio: 1, count: 0, prevEst: 0 };
|
|
1109
|
-
_cals.set(key, state);
|
|
1110
|
-
}
|
|
1111
|
-
return state;
|
|
1112
|
-
}
|
|
1113
|
-
var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
|
|
1114
|
-
var ESTIMATE_CACHE_MAX_SIZE = 1e4;
|
|
1115
|
-
function getCachedEstimate(key, compute) {
|
|
1116
|
-
const existing = ESTIMATE_CACHE.get(key);
|
|
1117
|
-
if (existing !== void 0) return existing;
|
|
1118
|
-
if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {
|
|
1119
|
-
let evicted = 0;
|
|
1120
|
-
const maxEvict = Math.floor(ESTIMATE_CACHE_MAX_SIZE / 4);
|
|
1121
|
-
for (const k of ESTIMATE_CACHE.keys()) {
|
|
1122
|
-
if (evicted >= maxEvict) break;
|
|
1123
|
-
ESTIMATE_CACHE.delete(k);
|
|
1124
|
-
evicted++;
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
const estimate = compute(key);
|
|
1128
|
-
ESTIMATE_CACHE.set(key, estimate);
|
|
1129
|
-
return estimate;
|
|
1130
|
-
}
|
|
1131
|
-
function estimateToolInputTokens(input) {
|
|
1132
|
-
if (typeof input === "string") return RoughTokenEstimate(input);
|
|
1133
|
-
if (input === null || typeof input !== "object") {
|
|
1134
|
-
return RoughTokenEstimate(String(input));
|
|
1135
|
-
}
|
|
1136
|
-
return getCachedEstimate(JSON.stringify(input), (key) => RoughTokenEstimate(key));
|
|
1137
|
-
}
|
|
1138
|
-
function estimateToolResultTokens(content) {
|
|
1139
|
-
if (typeof content === "string") return RoughTokenEstimate(content);
|
|
1140
|
-
return getCachedEstimate(JSON.stringify(content), (key) => RoughTokenEstimate(key));
|
|
1141
|
-
}
|
|
1142
|
-
function estimateTextTokens(text) {
|
|
1143
|
-
return RoughTokenEstimate(text);
|
|
1144
|
-
}
|
|
1145
|
-
function computeMessageTokens(msg) {
|
|
1146
|
-
if (typeof msg.content === "string") return estimateTextTokens(msg.content);
|
|
1147
|
-
let total = 0;
|
|
1148
|
-
for (const b of msg.content) {
|
|
1149
|
-
if (b.type === "text") total += estimateTextTokens(b.text);
|
|
1150
|
-
else if (b.type === "tool_use") total += estimateToolInputTokens(b.input);
|
|
1151
|
-
else if (b.type === "tool_result") total += estimateToolResultTokens(b.content);
|
|
1152
|
-
else total += RoughTokenEstimate(JSON.stringify(b));
|
|
1153
|
-
}
|
|
1154
|
-
return total;
|
|
1155
|
-
}
|
|
1156
|
-
function estimateMessageTokens(messages) {
|
|
1157
|
-
let total = 0;
|
|
1158
|
-
for (const m of messages) {
|
|
1159
|
-
if (typeof m._estTokens === "number" && m._estTokens > 0) {
|
|
1160
|
-
total += m._estTokens;
|
|
1161
|
-
continue;
|
|
1162
|
-
}
|
|
1163
|
-
total += computeMessageTokens(m);
|
|
1164
|
-
}
|
|
1165
|
-
return total;
|
|
1166
|
-
}
|
|
1167
|
-
function estimateToolDefTokens(tool) {
|
|
1168
|
-
const cached = tool._estDefTokens;
|
|
1169
|
-
if (typeof cached === "number" && cached > 0) return cached;
|
|
1170
|
-
return RoughTokenEstimate(tool.name) + RoughTokenEstimate(tool.description ?? "") + RoughTokenEstimate(JSON.stringify(tool.inputSchema));
|
|
1171
|
-
}
|
|
1172
|
-
function estimateRequestTokens(messages, systemPrompt, tools, calibrationKey = CALIBRATION_GLOBAL_KEY) {
|
|
1173
|
-
let messagesTokens = 0;
|
|
1174
|
-
if (typeof messages === "string") {
|
|
1175
|
-
messagesTokens = RoughTokenEstimate(messages);
|
|
1176
|
-
} else if (Array.isArray(messages)) {
|
|
1177
|
-
for (const m of messages) {
|
|
1178
|
-
if (typeof m === "object" && m !== null && "content" in m) {
|
|
1179
|
-
const cached = m._estTokens;
|
|
1180
|
-
if (typeof cached === "number" && cached > 0) {
|
|
1181
|
-
messagesTokens += cached;
|
|
1182
|
-
continue;
|
|
1183
|
-
}
|
|
1184
|
-
const content = m.content;
|
|
1185
|
-
if (typeof content === "string") {
|
|
1186
|
-
messagesTokens += RoughTokenEstimate(content);
|
|
1187
|
-
} else if (Array.isArray(content)) {
|
|
1188
|
-
for (const b of content) {
|
|
1189
|
-
if (typeof b === "object" && b !== null) {
|
|
1190
|
-
if (b.type === "text") {
|
|
1191
|
-
messagesTokens += RoughTokenEstimate(b.text);
|
|
1192
|
-
} else {
|
|
1193
|
-
messagesTokens += RoughTokenEstimate(JSON.stringify(b));
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
let systemTokens = 0;
|
|
1202
|
-
if (typeof systemPrompt === "string") {
|
|
1203
|
-
systemTokens = RoughTokenEstimate(systemPrompt);
|
|
1204
|
-
} else if (Array.isArray(systemPrompt)) {
|
|
1205
|
-
for (const b of systemPrompt) {
|
|
1206
|
-
if (typeof b === "object" && b !== null && b.type === "text") {
|
|
1207
|
-
systemTokens += RoughTokenEstimate(b.text);
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
let toolsTokens = 0;
|
|
1212
|
-
for (const t of tools) {
|
|
1213
|
-
toolsTokens += estimateToolDefTokens(t);
|
|
1214
|
-
}
|
|
1215
|
-
const total = messagesTokens + systemTokens + toolsTokens;
|
|
1216
|
-
calState(calibrationKey).prevEst = total;
|
|
1217
|
-
return {
|
|
1218
|
-
messages: messagesTokens,
|
|
1219
|
-
systemPrompt: systemTokens,
|
|
1220
|
-
tools: toolsTokens,
|
|
1221
|
-
total
|
|
1222
|
-
};
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
// src/utils/expect-defined.ts
|
|
1226
|
-
function expectDefined(value, label) {
|
|
1227
|
-
if (value === null || value === void 0) {
|
|
1228
|
-
const err = new Error("Expected value to be defined");
|
|
1229
|
-
err.name = "ExpectDefinedError";
|
|
1230
|
-
throw err;
|
|
1231
|
-
}
|
|
1232
|
-
return value;
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1235
|
-
// src/utils/message-invariants.ts
|
|
1236
|
-
function repairToolUseAdjacency(messages) {
|
|
1237
|
-
const removedToolUses = [];
|
|
1238
|
-
const removedToolResults = [];
|
|
1239
|
-
let removedMessages = 0;
|
|
1240
|
-
let changed = false;
|
|
1241
|
-
const out = [];
|
|
1242
|
-
for (let i = 0; i < messages.length; i++) {
|
|
1243
|
-
const original = expectDefined(messages[i]);
|
|
1244
|
-
let msg = original;
|
|
1245
|
-
if (hasToolUse(msg)) {
|
|
1246
|
-
const nextIds = toolResultIds(messages[i + 1]);
|
|
1247
|
-
const filtered = mapContent(msg, (blocks) => {
|
|
1248
|
-
const next = [];
|
|
1249
|
-
for (const block of blocks) {
|
|
1250
|
-
if (block.type === "tool_use" && !nextIds.has(block.id)) {
|
|
1251
|
-
removedToolUses.push(block.id);
|
|
1252
|
-
changed = true;
|
|
1253
|
-
continue;
|
|
1254
|
-
}
|
|
1255
|
-
next.push(block);
|
|
1256
|
-
}
|
|
1257
|
-
return next;
|
|
1258
|
-
});
|
|
1259
|
-
msg = filtered ?? msg;
|
|
1260
|
-
}
|
|
1261
|
-
if (hasToolResult(msg)) {
|
|
1262
|
-
const allowed = toolUseIds(out[out.length - 1]);
|
|
1263
|
-
const filtered = mapContent(msg, (blocks) => {
|
|
1264
|
-
const next = [];
|
|
1265
|
-
for (const block of blocks) {
|
|
1266
|
-
if (block.type === "tool_result" && !allowed.has(block.tool_use_id)) {
|
|
1267
|
-
removedToolResults.push(block.tool_use_id);
|
|
1268
|
-
changed = true;
|
|
1269
|
-
continue;
|
|
1270
|
-
}
|
|
1271
|
-
next.push(block);
|
|
1272
|
-
}
|
|
1273
|
-
return next;
|
|
1274
|
-
});
|
|
1275
|
-
msg = filtered ?? msg;
|
|
1276
|
-
}
|
|
1277
|
-
if (isEmptyMessage(msg)) {
|
|
1278
|
-
removedMessages++;
|
|
1279
|
-
changed = true;
|
|
1280
|
-
continue;
|
|
1281
|
-
}
|
|
1282
|
-
out.push(msg);
|
|
1283
|
-
}
|
|
1284
|
-
return {
|
|
1285
|
-
messages: changed ? out : messages,
|
|
1286
|
-
report: { changed, removedToolUses, removedToolResults, removedMessages }
|
|
1287
|
-
};
|
|
1288
|
-
}
|
|
1289
|
-
function hasToolUse(msg) {
|
|
1290
|
-
return contentBlocks(msg).some((b) => b.type === "tool_use");
|
|
1291
|
-
}
|
|
1292
|
-
function hasToolResult(msg) {
|
|
1293
|
-
return contentBlocks(msg).some((b) => b.type === "tool_result");
|
|
1294
|
-
}
|
|
1295
|
-
function toolUseIds(msg) {
|
|
1296
|
-
const ids = /* @__PURE__ */ new Set();
|
|
1297
|
-
if (!msg || msg.role !== "assistant") return ids;
|
|
1298
|
-
for (const block of contentBlocks(msg)) {
|
|
1299
|
-
if (block.type === "tool_use") ids.add(block.id);
|
|
1300
|
-
}
|
|
1301
|
-
return ids;
|
|
1302
|
-
}
|
|
1303
|
-
function toolResultIds(msg) {
|
|
1304
|
-
const ids = /* @__PURE__ */ new Set();
|
|
1305
|
-
if (!msg || msg.role !== "user") return ids;
|
|
1306
|
-
for (const block of contentBlocks(msg)) {
|
|
1307
|
-
if (block.type === "tool_result") ids.add(block.tool_use_id);
|
|
1308
|
-
}
|
|
1309
|
-
return ids;
|
|
1310
|
-
}
|
|
1311
|
-
function contentBlocks(msg) {
|
|
1312
|
-
return msg && Array.isArray(msg.content) ? msg.content : [];
|
|
1313
|
-
}
|
|
1314
|
-
function mapContent(msg, fn) {
|
|
1315
|
-
if (!Array.isArray(msg.content)) return msg;
|
|
1316
|
-
const next = fn(msg.content);
|
|
1317
|
-
if (next.length === msg.content.length && next.every((b, idx) => b === msg.content[idx])) {
|
|
1318
|
-
return msg;
|
|
1319
|
-
}
|
|
1320
|
-
return { ...msg, content: next };
|
|
1551
|
+
cacheRead: m.cost?.cache_read,
|
|
1552
|
+
cacheWrite: m.cost?.cache_write
|
|
1553
|
+
};
|
|
1321
1554
|
}
|
|
1322
|
-
function
|
|
1323
|
-
|
|
1324
|
-
return msg.content.length === 0;
|
|
1555
|
+
function round4(n) {
|
|
1556
|
+
return Math.round(n * 1e4) / 1e4;
|
|
1325
1557
|
}
|
|
1326
1558
|
|
|
1559
|
+
// src/types/memory.ts
|
|
1560
|
+
var MEMORY_TYPE_LABELS = {
|
|
1561
|
+
fact: "Fact",
|
|
1562
|
+
decision: "Decision",
|
|
1563
|
+
convention: "Convention",
|
|
1564
|
+
preference: "Preference",
|
|
1565
|
+
reference: "Reference",
|
|
1566
|
+
anti_pattern: "Anti-pattern"
|
|
1567
|
+
};
|
|
1568
|
+
|
|
1327
1569
|
// src/execution/compaction-core.ts
|
|
1328
1570
|
function emitCompactionMetrics(event, metrics) {
|
|
1329
1571
|
console.log(
|
|
@@ -2091,71 +2333,6 @@ var DefaultSecretScrubber = class {
|
|
|
2091
2333
|
return visit(obj);
|
|
2092
2334
|
}
|
|
2093
2335
|
};
|
|
2094
|
-
|
|
2095
|
-
// src/utils/merge-models-payload.ts
|
|
2096
|
-
function mergeModelsPayload(base, overlay) {
|
|
2097
|
-
const out = {};
|
|
2098
|
-
for (const [id, provider] of Object.entries(base)) {
|
|
2099
|
-
out[id] = cloneProvider(provider);
|
|
2100
|
-
}
|
|
2101
|
-
for (const [id, ovProvider] of Object.entries(overlay)) {
|
|
2102
|
-
const existing = out[id];
|
|
2103
|
-
out[id] = existing ? mergeProvider(existing, ovProvider) : cloneProvider(ovProvider);
|
|
2104
|
-
}
|
|
2105
|
-
return out;
|
|
2106
|
-
}
|
|
2107
|
-
function mergeProvider(base, overlay) {
|
|
2108
|
-
const models = {};
|
|
2109
|
-
for (const [mid, m] of Object.entries(base.models ?? {})) {
|
|
2110
|
-
models[mid] = { ...m };
|
|
2111
|
-
}
|
|
2112
|
-
for (const [mid, ovModel] of Object.entries(overlay.models ?? {})) {
|
|
2113
|
-
const existing = models[mid];
|
|
2114
|
-
models[mid] = existing ? mergeModel(existing, ovModel) : { ...ovModel };
|
|
2115
|
-
}
|
|
2116
|
-
return {
|
|
2117
|
-
...base,
|
|
2118
|
-
// Overlay scalar fields win when explicitly provided; otherwise keep base.
|
|
2119
|
-
...stripUndefined({
|
|
2120
|
-
id: overlay.id,
|
|
2121
|
-
name: overlay.name,
|
|
2122
|
-
npm: overlay.npm,
|
|
2123
|
-
api: overlay.api,
|
|
2124
|
-
env: overlay.env,
|
|
2125
|
-
doc: overlay.doc
|
|
2126
|
-
}),
|
|
2127
|
-
models
|
|
2128
|
-
};
|
|
2129
|
-
}
|
|
2130
|
-
function mergeModel(base, overlay) {
|
|
2131
|
-
const merged = { ...base, ...overlay };
|
|
2132
|
-
if (base.limit || overlay.limit) {
|
|
2133
|
-
merged.limit = { ...base.limit, ...overlay.limit };
|
|
2134
|
-
}
|
|
2135
|
-
if (base.cost || overlay.cost) {
|
|
2136
|
-
merged.cost = { ...base.cost, ...overlay.cost };
|
|
2137
|
-
}
|
|
2138
|
-
if (base.modalities || overlay.modalities) {
|
|
2139
|
-
merged.modalities = { ...base.modalities, ...overlay.modalities };
|
|
2140
|
-
}
|
|
2141
|
-
return merged;
|
|
2142
|
-
}
|
|
2143
|
-
function cloneProvider(p) {
|
|
2144
|
-
const models = {};
|
|
2145
|
-
for (const [mid, m] of Object.entries(p.models ?? {})) {
|
|
2146
|
-
models[mid] = { ...m };
|
|
2147
|
-
}
|
|
2148
|
-
return { ...p, models };
|
|
2149
|
-
}
|
|
2150
|
-
function stripUndefined(obj) {
|
|
2151
|
-
const out = {};
|
|
2152
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
2153
|
-
if (v !== void 0) out[k] = v;
|
|
2154
|
-
}
|
|
2155
|
-
return out;
|
|
2156
|
-
}
|
|
2157
|
-
|
|
2158
|
-
// src/models/models-registry.ts
|
|
2159
2336
|
var DEFAULT_URL = "https://models.dev/api.json";
|
|
2160
2337
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
2161
2338
|
var DEFAULT_REFRESH_TIMEOUT_MS = 15e3;
|
|
@@ -2251,7 +2428,7 @@ var DefaultModelsRegistry = class {
|
|
|
2251
2428
|
}
|
|
2252
2429
|
if (overlayAvailable) {
|
|
2253
2430
|
console.warn(
|
|
2254
|
-
`ModelsRegistry: models.dev unavailable (${
|
|
2431
|
+
`ModelsRegistry: models.dev unavailable (${toErrorMessage(err)}); serving curated overlay only.`
|
|
2255
2432
|
);
|
|
2256
2433
|
return {};
|
|
2257
2434
|
}
|
|
@@ -3135,144 +3312,6 @@ function getDangerousCapabilities(toolOrCaps) {
|
|
|
3135
3312
|
);
|
|
3136
3313
|
}
|
|
3137
3314
|
|
|
3138
|
-
// src/utils/json-schema-validate.ts
|
|
3139
|
-
function validateAgainstSchema(value, schema) {
|
|
3140
|
-
const errors = [];
|
|
3141
|
-
walk2(value, schema, "", errors);
|
|
3142
|
-
return { ok: errors.length === 0, errors };
|
|
3143
|
-
}
|
|
3144
|
-
function walk2(value, schema, path7, errors) {
|
|
3145
|
-
if (schema.enum !== void 0) {
|
|
3146
|
-
if (!schema.enum.some((e) => deepEqual(e, value))) {
|
|
3147
|
-
errors.push({
|
|
3148
|
-
path: path7 || "<root>",
|
|
3149
|
-
message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
|
|
3150
|
-
});
|
|
3151
|
-
return;
|
|
3152
|
-
}
|
|
3153
|
-
}
|
|
3154
|
-
if (typeof schema.type === "string") {
|
|
3155
|
-
if (!checkType(value, schema.type)) {
|
|
3156
|
-
errors.push({
|
|
3157
|
-
path: path7 || "<root>",
|
|
3158
|
-
message: `expected ${schema.type}, got ${describeType(value)}`
|
|
3159
|
-
});
|
|
3160
|
-
return;
|
|
3161
|
-
}
|
|
3162
|
-
}
|
|
3163
|
-
if (schema.type === "object" && isPlainObject(value)) {
|
|
3164
|
-
const obj = value;
|
|
3165
|
-
for (const req of schema.required ?? []) {
|
|
3166
|
-
if (!(req in obj)) {
|
|
3167
|
-
errors.push({ path: joinPath(path7, req), message: "required property missing" });
|
|
3168
|
-
}
|
|
3169
|
-
}
|
|
3170
|
-
if (schema.properties) {
|
|
3171
|
-
for (const [key, subSchema] of Object.entries(schema.properties)) {
|
|
3172
|
-
if (key in obj) {
|
|
3173
|
-
walk2(obj[key], subSchema, joinPath(path7, key), errors);
|
|
3174
|
-
}
|
|
3175
|
-
}
|
|
3176
|
-
}
|
|
3177
|
-
}
|
|
3178
|
-
if (schema.type === "array" && Array.isArray(value) && schema.items) {
|
|
3179
|
-
value.forEach((item, i) => walk2(item, schema.items, `${path7}[${i}]`, errors));
|
|
3180
|
-
}
|
|
3181
|
-
}
|
|
3182
|
-
function checkType(value, type) {
|
|
3183
|
-
switch (type) {
|
|
3184
|
-
case "string":
|
|
3185
|
-
return typeof value === "string";
|
|
3186
|
-
case "number":
|
|
3187
|
-
return typeof value === "number" && !Number.isNaN(value);
|
|
3188
|
-
case "integer":
|
|
3189
|
-
return typeof value === "number" && Number.isInteger(value);
|
|
3190
|
-
case "boolean":
|
|
3191
|
-
return typeof value === "boolean";
|
|
3192
|
-
case "null":
|
|
3193
|
-
return value === null;
|
|
3194
|
-
case "array":
|
|
3195
|
-
return Array.isArray(value);
|
|
3196
|
-
case "object":
|
|
3197
|
-
return isPlainObject(value);
|
|
3198
|
-
default:
|
|
3199
|
-
return true;
|
|
3200
|
-
}
|
|
3201
|
-
}
|
|
3202
|
-
function isPlainObject(v) {
|
|
3203
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3204
|
-
}
|
|
3205
|
-
function describeType(v) {
|
|
3206
|
-
if (v === null) return "null";
|
|
3207
|
-
if (Array.isArray(v)) return "array";
|
|
3208
|
-
return typeof v;
|
|
3209
|
-
}
|
|
3210
|
-
function joinPath(parent, key) {
|
|
3211
|
-
if (!parent) return key;
|
|
3212
|
-
return `${parent}.${key}`;
|
|
3213
|
-
}
|
|
3214
|
-
function deepEqual(a, b) {
|
|
3215
|
-
if (a === b) return true;
|
|
3216
|
-
if (typeof a !== typeof b) return false;
|
|
3217
|
-
if (a === null || b === null) return a === b;
|
|
3218
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
3219
|
-
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
3220
|
-
}
|
|
3221
|
-
if (typeof a === "object" && typeof b === "object") {
|
|
3222
|
-
const ak = Object.keys(a);
|
|
3223
|
-
const bk = Object.keys(b);
|
|
3224
|
-
if (ak.length !== bk.length) return false;
|
|
3225
|
-
return ak.every(
|
|
3226
|
-
(k) => deepEqual(a[k], b[k])
|
|
3227
|
-
);
|
|
3228
|
-
}
|
|
3229
|
-
return false;
|
|
3230
|
-
}
|
|
3231
|
-
|
|
3232
|
-
// src/utils/tool-output-serializer.ts
|
|
3233
|
-
function createToolOutputSerializer(opts = {}) {
|
|
3234
|
-
const capBytes = opts.perIterationOutputCapBytes ?? 1e5;
|
|
3235
|
-
function serialize(value) {
|
|
3236
|
-
if (typeof value === "string") return value;
|
|
3237
|
-
if (value === null || value === void 0) return "";
|
|
3238
|
-
if (typeof value === "object") {
|
|
3239
|
-
if (Array.isArray(value)) return value.map(serialize).join("\n");
|
|
3240
|
-
if ("text" in value) {
|
|
3241
|
-
const t = value.text;
|
|
3242
|
-
return typeof t === "string" ? t : JSON.stringify(value, null, 2);
|
|
3243
|
-
}
|
|
3244
|
-
try {
|
|
3245
|
-
return JSON.stringify(value, null, 2);
|
|
3246
|
-
} catch {
|
|
3247
|
-
return String(value);
|
|
3248
|
-
}
|
|
3249
|
-
}
|
|
3250
|
-
return String(value);
|
|
3251
|
-
}
|
|
3252
|
-
function enforceCap(text, remainingBudget) {
|
|
3253
|
-
if (remainingBudget <= 0) {
|
|
3254
|
-
return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
|
|
3255
|
-
}
|
|
3256
|
-
const textBytes = Buffer.byteLength(text, "utf8");
|
|
3257
|
-
if (textBytes <= remainingBudget) {
|
|
3258
|
-
return { text, newBudget: remainingBudget - textBytes };
|
|
3259
|
-
}
|
|
3260
|
-
const marker = `
|
|
3261
|
-
\u2026[truncated ${textBytes - remainingBudget} bytes]\u2026
|
|
3262
|
-
`;
|
|
3263
|
-
const markerBytes = Buffer.byteLength(marker, "utf8");
|
|
3264
|
-
const available = remainingBudget - markerBytes;
|
|
3265
|
-
if (available <= 0) {
|
|
3266
|
-
return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
|
|
3267
|
-
}
|
|
3268
|
-
const half = Math.floor(available / 2);
|
|
3269
|
-
const first = text.slice(0, half);
|
|
3270
|
-
const second = text.slice(text.length - half);
|
|
3271
|
-
return { text: `${first}${marker}${second}`, newBudget: 0 };
|
|
3272
|
-
}
|
|
3273
|
-
return { serialize, enforceCap, capBytes };
|
|
3274
|
-
}
|
|
3275
|
-
|
|
3276
3315
|
// src/execution/tool-executor.ts
|
|
3277
3316
|
var ToolExecutor = class _ToolExecutor {
|
|
3278
3317
|
constructor(registry, opts) {
|
|
@@ -3436,7 +3475,7 @@ ${post.additionalContext}`;
|
|
|
3436
3475
|
);
|
|
3437
3476
|
return { result, tool, durationMs: Date.now() - start };
|
|
3438
3477
|
} catch (err) {
|
|
3439
|
-
const msg =
|
|
3478
|
+
const msg = toErrorMessage(err);
|
|
3440
3479
|
const scrubbed = this.opts.secretScrubber.scrub(msg);
|
|
3441
3480
|
this.opts.renderer?.writeToolResult(tool.name, scrubbed, true);
|
|
3442
3481
|
const result = {
|
|
@@ -3457,7 +3496,7 @@ ${post.additionalContext}`;
|
|
|
3457
3496
|
try {
|
|
3458
3497
|
return await runOne(use);
|
|
3459
3498
|
} catch (err) {
|
|
3460
|
-
const msg =
|
|
3499
|
+
const msg = toErrorMessage(err);
|
|
3461
3500
|
const scrubbed = this.opts.secretScrubber.scrub(msg);
|
|
3462
3501
|
const result = {
|
|
3463
3502
|
type: "tool_result",
|
|
@@ -3873,6 +3912,17 @@ var Context = class {
|
|
|
3873
3912
|
agentId;
|
|
3874
3913
|
/** Human-readable agent name. */
|
|
3875
3914
|
agentName;
|
|
3915
|
+
/**
|
|
3916
|
+
* Session-level trace ID for correlating storage events with agent
|
|
3917
|
+
* iterations. Stored here and also propagated to `session.traceId`
|
|
3918
|
+
* so storage operations can include it in `storage.*` events.
|
|
3919
|
+
*/
|
|
3920
|
+
traceId;
|
|
3921
|
+
/**
|
|
3922
|
+
* When true, tools can access any path on the filesystem.
|
|
3923
|
+
* When false or undefined, tools are restricted to the project root.
|
|
3924
|
+
*/
|
|
3925
|
+
allowOutsideProjectRoot;
|
|
3876
3926
|
/** Callbacks fired when `setWorkingDir()` changes the working directory. */
|
|
3877
3927
|
_onWorkingDirChanged = [];
|
|
3878
3928
|
/**
|
|
@@ -3908,6 +3958,9 @@ var Context = class {
|
|
|
3908
3958
|
this.tools = init.tools ?? [];
|
|
3909
3959
|
this.agentId = init.agentId ?? "unknown";
|
|
3910
3960
|
this.agentName = init.agentName ?? "Unknown Agent";
|
|
3961
|
+
this.traceId = init.traceId;
|
|
3962
|
+
this.allowOutsideProjectRoot = init.allowOutsideProjectRoot ?? true;
|
|
3963
|
+
this.session.traceId = init.traceId;
|
|
3911
3964
|
}
|
|
3912
3965
|
/**
|
|
3913
3966
|
* Observable wrapper over the mutable conversation state. Lazy so
|
|
@@ -4007,42 +4060,6 @@ var Context = class {
|
|
|
4007
4060
|
}
|
|
4008
4061
|
};
|
|
4009
4062
|
|
|
4010
|
-
// src/utils/regex-guard.ts
|
|
4011
|
-
var MAX_PATTERN_LEN = 512;
|
|
4012
|
-
var DANGEROUS_PATTERNS = [
|
|
4013
|
-
/(\([^)]*[+*][^)]*\))[+*]/,
|
|
4014
|
-
// (a+)+, (.*)+, etc
|
|
4015
|
-
/(\(\?:[^)]*[+*][^)]*\))[+*]/
|
|
4016
|
-
// same, with non-capturing group
|
|
4017
|
-
];
|
|
4018
|
-
function compileUserRegex(pattern, flags) {
|
|
4019
|
-
if (typeof pattern !== "string") {
|
|
4020
|
-
return { ok: false, reason: "pattern must be a string" };
|
|
4021
|
-
}
|
|
4022
|
-
if (pattern.length === 0) {
|
|
4023
|
-
return { ok: false, reason: "pattern is empty" };
|
|
4024
|
-
}
|
|
4025
|
-
if (pattern.length > MAX_PATTERN_LEN) {
|
|
4026
|
-
return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };
|
|
4027
|
-
}
|
|
4028
|
-
for (const rx of DANGEROUS_PATTERNS) {
|
|
4029
|
-
if (rx.test(pattern)) {
|
|
4030
|
-
return {
|
|
4031
|
-
ok: false,
|
|
4032
|
-
reason: "pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers"
|
|
4033
|
-
};
|
|
4034
|
-
}
|
|
4035
|
-
}
|
|
4036
|
-
try {
|
|
4037
|
-
return { ok: true, regex: new RegExp(pattern, flags) };
|
|
4038
|
-
} catch (err) {
|
|
4039
|
-
return {
|
|
4040
|
-
ok: false,
|
|
4041
|
-
reason: err instanceof Error ? err.message : "invalid regex"
|
|
4042
|
-
};
|
|
4043
|
-
}
|
|
4044
|
-
}
|
|
4045
|
-
|
|
4046
4063
|
// src/storage/session-reader.ts
|
|
4047
4064
|
var DefaultSessionReader = class {
|
|
4048
4065
|
store;
|