reasonix 0.37.0 → 0.39.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/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/dist/cli/{chat-7257YAPG.js → chat-QCY6CH7O.js} +17 -17
- package/dist/cli/{chunk-XQIFIB3U.js → chunk-4D662BWT.js} +2 -2
- package/dist/cli/{chunk-SEFXUF24.js → chunk-5ZCRXN7S.js} +160 -29
- package/dist/cli/chunk-5ZCRXN7S.js.map +1 -0
- package/dist/cli/{chunk-XOIDSPMQ.js → chunk-6DR4F3MC.js} +20 -6
- package/dist/cli/chunk-6DR4F3MC.js.map +1 -0
- package/dist/cli/{chunk-RFX7TYVV.js → chunk-7G3SESEU.js} +15 -2
- package/dist/cli/chunk-7G3SESEU.js.map +1 -0
- package/dist/cli/chunk-AFFZF3MW.js +36 -0
- package/dist/cli/chunk-AFFZF3MW.js.map +1 -0
- package/dist/cli/{chunk-GKZJXYMY.js → chunk-AJGLCSZS.js} +709 -21
- package/dist/cli/chunk-AJGLCSZS.js.map +1 -0
- package/dist/cli/{chunk-JGZKTAOH.js → chunk-AKDDHHE6.js} +2 -2
- package/dist/cli/{chunk-APPB3ZPQ.js → chunk-BQR5TTNY.js} +10 -7
- package/dist/cli/chunk-BQR5TTNY.js.map +1 -0
- package/dist/cli/{chunk-YER7WCHF.js → chunk-DDA76P44.js} +25 -11
- package/dist/cli/chunk-DDA76P44.js.map +1 -0
- package/dist/cli/{chunk-T52GAWPP.js → chunk-NLV2YORE.js} +2 -2
- package/dist/cli/{chunk-S4GF3HPO.js → chunk-NTVW2TWO.js} +6 -4
- package/dist/cli/chunk-NTVW2TWO.js.map +1 -0
- package/dist/cli/{chunk-UNMYFZPZ.js → chunk-SJNIIH5W.js} +112 -112
- package/dist/cli/chunk-SJNIIH5W.js.map +1 -0
- package/dist/cli/{chunk-ZJR4QLXB.js → chunk-SUZRC4NC.js} +2 -2
- package/dist/cli/{chunk-BHLHOS5Y.js → chunk-SWLIVNTP.js} +328 -6
- package/dist/cli/chunk-SWLIVNTP.js.map +1 -0
- package/dist/cli/{chunk-JULZ7JTO.js → chunk-TGO7X47P.js} +97 -16
- package/dist/cli/chunk-TGO7X47P.js.map +1 -0
- package/dist/cli/{chunk-VF57YX2M.js → chunk-TPDWAMG6.js} +29 -1
- package/dist/cli/chunk-TPDWAMG6.js.map +1 -0
- package/dist/cli/{chunk-MSKUP6PD.js → chunk-TPK2CHWR.js} +1320 -934
- package/dist/cli/chunk-TPK2CHWR.js.map +1 -0
- package/dist/cli/{chunk-4Q3GRJIU.js → chunk-V5D77TFD.js} +2 -2
- package/dist/cli/{code-64EG5IU2.js → code-3BBVXXY6.js} +28 -20
- package/dist/cli/code-3BBVXXY6.js.map +1 -0
- package/dist/cli/{commands-FE2UDFBC.js → commands-PJMHSP3Z.js} +3 -4
- package/dist/cli/{commands-FE2UDFBC.js.map → commands-PJMHSP3Z.js.map} +1 -1
- package/dist/cli/{commit-3IAGB22T.js → commit-R6SC44W5.js} +2 -3
- package/dist/cli/{commit-3IAGB22T.js.map → commit-R6SC44W5.js.map} +1 -1
- package/dist/cli/{diff-NTEHCSDW.js → diff-LXBBKOZA.js} +17 -9
- package/dist/cli/diff-LXBBKOZA.js.map +1 -0
- package/dist/cli/{doctor-BW5HSQDW.js → doctor-ZBUEBRXP.js} +9 -7
- package/dist/cli/index.js +57 -33
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{mcp-2RDEQST6.js → mcp-RABKZDX4.js} +12 -4
- package/dist/cli/mcp-RABKZDX4.js.map +1 -0
- package/dist/cli/{mcp-browse-VM5GLRBQ.js → mcp-browse-H6O73SHN.js} +2 -3
- package/dist/cli/{mcp-browse-VM5GLRBQ.js.map → mcp-browse-H6O73SHN.js.map} +1 -1
- package/dist/cli/{mcp-inspect-CWSVCZUQ.js → mcp-inspect-XWBO52H6.js} +9 -7
- package/dist/cli/mcp-inspect-XWBO52H6.js.map +1 -0
- package/dist/cli/{prompt-KGIUONO3.js → prompt-CZSOFYK6.js} +3 -3
- package/dist/cli/{replay-D7RT2DR7.js → replay-TWTUIUUB.js} +17 -13
- package/dist/cli/replay-TWTUIUUB.js.map +1 -0
- package/dist/cli/{run-RWCOA32G.js → run-RWBLIICY.js} +15 -15
- package/dist/cli/run-RWBLIICY.js.map +1 -0
- package/dist/cli/{server-6ZW4TQUP.js → server-EPU4QONU.js} +21 -19
- package/dist/cli/server-EPU4QONU.js.map +1 -0
- package/dist/cli/{sessions-5ISNWFMU.js → sessions-TWUFHOUX.js} +9 -10
- package/dist/cli/{sessions-5ISNWFMU.js.map → sessions-TWUFHOUX.js.map} +1 -1
- package/dist/cli/{setup-HJG23NKJ.js → setup-WHXXHIZV.js} +61 -16
- package/dist/cli/setup-WHXXHIZV.js.map +1 -0
- package/dist/cli/{version-BXAN7Q4V.js → version-RAMBOIYL.js} +9 -10
- package/dist/cli/{version-BXAN7Q4V.js.map → version-RAMBOIYL.js.map} +1 -1
- package/dist/index.d.ts +22 -2
- package/dist/index.js +927 -58
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
- package/dist/cli/chunk-APPB3ZPQ.js.map +0 -1
- package/dist/cli/chunk-BHLHOS5Y.js.map +0 -1
- package/dist/cli/chunk-GKZJXYMY.js.map +0 -1
- package/dist/cli/chunk-JULZ7JTO.js.map +0 -1
- package/dist/cli/chunk-MSKUP6PD.js.map +0 -1
- package/dist/cli/chunk-RFX7TYVV.js.map +0 -1
- package/dist/cli/chunk-S4GF3HPO.js.map +0 -1
- package/dist/cli/chunk-SEFXUF24.js.map +0 -1
- package/dist/cli/chunk-UNMYFZPZ.js.map +0 -1
- package/dist/cli/chunk-VF57YX2M.js.map +0 -1
- package/dist/cli/chunk-WUI3P4RA.js +0 -319
- package/dist/cli/chunk-WUI3P4RA.js.map +0 -1
- package/dist/cli/chunk-XOIDSPMQ.js.map +0 -1
- package/dist/cli/chunk-YER7WCHF.js.map +0 -1
- package/dist/cli/code-64EG5IU2.js.map +0 -1
- package/dist/cli/diff-NTEHCSDW.js.map +0 -1
- package/dist/cli/mcp-2RDEQST6.js.map +0 -1
- package/dist/cli/mcp-inspect-CWSVCZUQ.js.map +0 -1
- package/dist/cli/replay-D7RT2DR7.js.map +0 -1
- package/dist/cli/run-RWCOA32G.js.map +0 -1
- package/dist/cli/server-6ZW4TQUP.js.map +0 -1
- package/dist/cli/setup-HJG23NKJ.js.map +0 -1
- /package/dist/cli/{chat-7257YAPG.js.map → chat-QCY6CH7O.js.map} +0 -0
- /package/dist/cli/{chunk-XQIFIB3U.js.map → chunk-4D662BWT.js.map} +0 -0
- /package/dist/cli/{chunk-JGZKTAOH.js.map → chunk-AKDDHHE6.js.map} +0 -0
- /package/dist/cli/{chunk-T52GAWPP.js.map → chunk-NLV2YORE.js.map} +0 -0
- /package/dist/cli/{chunk-ZJR4QLXB.js.map → chunk-SUZRC4NC.js.map} +0 -0
- /package/dist/cli/{chunk-4Q3GRJIU.js.map → chunk-V5D77TFD.js.map} +0 -0
- /package/dist/cli/{doctor-BW5HSQDW.js.map → doctor-ZBUEBRXP.js.map} +0 -0
- /package/dist/cli/{prompt-KGIUONO3.js.map → prompt-CZSOFYK6.js.map} +0 -0
package/README.md
CHANGED
|
@@ -162,6 +162,7 @@ For live cache-hit rates, costs, and methodology, see [`benchmarks/`](./benchmar
|
|
|
162
162
|
## Documentation
|
|
163
163
|
|
|
164
164
|
- [**Architecture**](./docs/ARCHITECTURE.md) — three pillars: cache-first loop, tool-call repair, cost control
|
|
165
|
+
- [**CLI Reference**](./docs/CLI-REFERENCE.md) — every shell subcommand, every slash command, every keybinding
|
|
165
166
|
- [**Benchmarks**](./benchmarks/) — τ-bench-lite harness, transcripts, cost methodology
|
|
166
167
|
- [**Website**](https://esengine.github.io/DeepSeek-Reasonix/) — getting started, dashboard mockup, TUI mockup
|
|
167
168
|
- [**Contributing**](./CONTRIBUTING.md) — comment policy, error-handling rules, library-over-hand-rolled
|
package/README.zh-CN.md
CHANGED
|
@@ -157,6 +157,7 @@ npx reasonix code --dir /path/to/project
|
|
|
157
157
|
## 文档
|
|
158
158
|
|
|
159
159
|
- [**架构**](./docs/ARCHITECTURE.md) —— 四大支柱、缓存优先循环、思维提取、脚手架
|
|
160
|
+
- [**CLI 参考**](./docs/CLI-REFERENCE.md) —— 每个 shell 子命令、每个 slash 命令、每个快捷键
|
|
160
161
|
- [**基准测试**](./benchmarks/) —— τ-bench-lite harness、transcript、成本方法论
|
|
161
162
|
- [**官方网站**](https://esengine.github.io/DeepSeek-Reasonix/) —— 入门、Dashboard 设计稿、TUI 设计稿
|
|
162
163
|
- [**贡献指南**](./CONTRIBUTING.md) —— 注释规则、错误处理、用现成库不手写
|
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
chatCommand
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-TPK2CHWR.js";
|
|
5
5
|
import "./chunk-BQNUJJN7.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-7G3SESEU.js";
|
|
7
7
|
import "./chunk-MRLXEMZ7.js";
|
|
8
8
|
import "./chunk-CPOV2O73.js";
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-5ZCRXN7S.js";
|
|
10
|
+
import "./chunk-SJNIIH5W.js";
|
|
11
11
|
import "./chunk-XJLZ4HKU.js";
|
|
12
12
|
import "./chunk-XHQIK7B6.js";
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-DDA76P44.js";
|
|
14
|
+
import "./chunk-NLV2YORE.js";
|
|
15
|
+
import "./chunk-SUZRC4NC.js";
|
|
16
16
|
import "./chunk-MHDNZXJJ.js";
|
|
17
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-TGO7X47P.js";
|
|
18
|
+
import "./chunk-AFFZF3MW.js";
|
|
18
19
|
import "./chunk-DAEAAVDF.js";
|
|
19
20
|
import "./chunk-KMWKGPFZ.js";
|
|
20
21
|
import "./chunk-3Q3C4W66.js";
|
|
21
22
|
import "./chunk-4DCHFFEY.js";
|
|
22
23
|
import "./chunk-WJ3YX4PZ.js";
|
|
23
|
-
import "./chunk-
|
|
24
|
+
import "./chunk-TPDWAMG6.js";
|
|
24
25
|
import "./chunk-SOZE7V7V.js";
|
|
25
26
|
import "./chunk-6NMWJSES.js";
|
|
26
|
-
import "./chunk-
|
|
27
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-NTVW2TWO.js";
|
|
28
|
+
import "./chunk-6DR4F3MC.js";
|
|
28
29
|
import "./chunk-FM57FNPJ.js";
|
|
29
|
-
import "./chunk-
|
|
30
|
-
import "./chunk-
|
|
30
|
+
import "./chunk-4D662BWT.js";
|
|
31
|
+
import "./chunk-AKDDHHE6.js";
|
|
31
32
|
import "./chunk-5X7LZJDE.js";
|
|
32
33
|
import "./chunk-6CXT5JRM.js";
|
|
33
|
-
import "./chunk-
|
|
34
|
-
import "./chunk-
|
|
35
|
-
import "./chunk-WUI3P4RA.js";
|
|
34
|
+
import "./chunk-AJGLCSZS.js";
|
|
35
|
+
import "./chunk-SWLIVNTP.js";
|
|
36
36
|
import "./chunk-ZTLZO42A.js";
|
|
37
37
|
import "./chunk-ORM6PK57.js";
|
|
38
38
|
import "./chunk-CRPQUBP6.js";
|
|
39
39
|
export {
|
|
40
40
|
chatCommand
|
|
41
41
|
};
|
|
42
|
-
//# sourceMappingURL=chat-
|
|
42
|
+
//# sourceMappingURL=chat-QCY6CH7O.js.map
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
compileFilters,
|
|
8
8
|
defaultIndexConfig,
|
|
9
9
|
resolveSemanticEmbeddingConfig
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-SWLIVNTP.js";
|
|
11
11
|
|
|
12
12
|
// src/index/semantic/builder.ts
|
|
13
13
|
import { promises as fs3 } from "fs";
|
|
@@ -948,4 +948,4 @@ export {
|
|
|
948
948
|
startOllamaDaemon,
|
|
949
949
|
pullOllamaModel
|
|
950
950
|
};
|
|
951
|
-
//# sourceMappingURL=chunk-
|
|
951
|
+
//# sourceMappingURL=chunk-4D662BWT.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
MemoryStore,
|
|
4
4
|
sanitizeMemoryName
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-DDA76P44.js";
|
|
6
6
|
import {
|
|
7
7
|
countTokens,
|
|
8
8
|
estimateConversationTokens,
|
|
@@ -13,15 +13,15 @@ import {
|
|
|
13
13
|
} from "./chunk-KMWKGPFZ.js";
|
|
14
14
|
import {
|
|
15
15
|
pauseGate
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-NTVW2TWO.js";
|
|
17
17
|
import {
|
|
18
18
|
NEGATIVE_CLAIM_RULE,
|
|
19
19
|
TUI_FORMATTING_RULES
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-6DR4F3MC.js";
|
|
21
21
|
import {
|
|
22
22
|
formatHookOutcomeMessage,
|
|
23
23
|
runHooks
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-AKDDHHE6.js";
|
|
25
25
|
import {
|
|
26
26
|
ignoredByLayers,
|
|
27
27
|
loadGitignoreAt,
|
|
@@ -36,12 +36,12 @@ import {
|
|
|
36
36
|
} from "./chunk-6CXT5JRM.js";
|
|
37
37
|
import {
|
|
38
38
|
t
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-AJGLCSZS.js";
|
|
40
40
|
import {
|
|
41
41
|
DEFAULT_INDEX_EXCLUDES,
|
|
42
42
|
webSearchEndpoint,
|
|
43
43
|
webSearchEngine
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-SWLIVNTP.js";
|
|
45
45
|
import {
|
|
46
46
|
DEEPSEEK_CONTEXT_TOKENS,
|
|
47
47
|
DEFAULT_CONTEXT_TOKENS,
|
|
@@ -287,6 +287,8 @@ var ToolRegistry = class {
|
|
|
287
287
|
_interceptor = null;
|
|
288
288
|
_auditListener = null;
|
|
289
289
|
_resultAugmenter = null;
|
|
290
|
+
/** Per-tool fingerprint of the last call that failed schema validation. Cleared by any successful validation for that tool. */
|
|
291
|
+
_lastMalformed = /* @__PURE__ */ new Map();
|
|
290
292
|
constructor(opts = {}) {
|
|
291
293
|
this._autoFlatten = opts.autoFlatten !== false;
|
|
292
294
|
}
|
|
@@ -309,6 +311,10 @@ var ToolRegistry = class {
|
|
|
309
311
|
setResultAugmenter(fn) {
|
|
310
312
|
this._resultAugmenter = fn;
|
|
311
313
|
}
|
|
314
|
+
/** True when an augmenter is already wired — lets late-installing callers skip clobbering an earlier one. */
|
|
315
|
+
get hasResultAugmenter() {
|
|
316
|
+
return this._resultAugmenter !== null;
|
|
317
|
+
}
|
|
312
318
|
register(def) {
|
|
313
319
|
if (!def.name) throw new Error("tool requires a name");
|
|
314
320
|
const internal = { ...def };
|
|
@@ -357,17 +363,29 @@ var ToolRegistry = class {
|
|
|
357
363
|
if (!tool) {
|
|
358
364
|
return JSON.stringify({ error: `unknown tool: ${name}` });
|
|
359
365
|
}
|
|
366
|
+
const fingerprint = fingerprintArgs(argumentsRaw);
|
|
360
367
|
let args;
|
|
361
368
|
try {
|
|
362
369
|
args = typeof argumentsRaw === "string" ? argumentsRaw.trim() ? JSON.parse(argumentsRaw) ?? {} : {} : argumentsRaw ?? {};
|
|
363
370
|
} catch (err) {
|
|
364
|
-
return
|
|
365
|
-
|
|
366
|
-
|
|
371
|
+
return this._noteMalformed(
|
|
372
|
+
name,
|
|
373
|
+
fingerprint,
|
|
374
|
+
`invalid tool arguments JSON: ${err.message}`
|
|
375
|
+
);
|
|
367
376
|
}
|
|
368
377
|
if (tool.flatSchema && args && typeof args === "object" && hasDotKey(args)) {
|
|
369
378
|
args = nestArguments(args);
|
|
370
379
|
}
|
|
380
|
+
const missing = tool.parameters ? missingRequiredParam(tool.parameters, args) : null;
|
|
381
|
+
if (missing) {
|
|
382
|
+
return this._noteMalformed(
|
|
383
|
+
name,
|
|
384
|
+
fingerprint,
|
|
385
|
+
`missing required parameter "${missing}". Retry with all required parameters filled.`
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
this._lastMalformed.delete(name);
|
|
371
389
|
if (this._planMode && !isReadOnlyCall(tool, args)) {
|
|
372
390
|
return JSON.stringify({
|
|
373
391
|
error: `${name}: unavailable in plan mode \u2014 this is a read-only exploration phase. Use read_file / list_directory / search_files / directory_tree / web_search / allowlisted shell commands to investigate. Call submit_plan with your proposed plan when you're ready for the user's review.`,
|
|
@@ -423,6 +441,18 @@ var ToolRegistry = class {
|
|
|
423
441
|
}
|
|
424
442
|
return finalResult;
|
|
425
443
|
}
|
|
444
|
+
/** Records the failed call's fingerprint; on the 2nd consecutive identical malformed call to the same tool, returns a sharper error that tells the model to stop retrying. */
|
|
445
|
+
_noteMalformed(name, fingerprint, detail) {
|
|
446
|
+
const prev = this._lastMalformed.get(name);
|
|
447
|
+
this._lastMalformed.set(name, fingerprint);
|
|
448
|
+
if (prev === fingerprint) {
|
|
449
|
+
return JSON.stringify({
|
|
450
|
+
error: `${name}: same call just failed validation (${detail}) \u2014 DO NOT retry with identical args. Either fix the call (read the schema in the tool spec) or pick a different tool.`,
|
|
451
|
+
consecutiveMalformed: true
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
return JSON.stringify({ error: `${name}: ${detail}` });
|
|
455
|
+
}
|
|
426
456
|
};
|
|
427
457
|
function isReadOnlyCall(tool, args) {
|
|
428
458
|
if (tool.readOnlyCheck) {
|
|
@@ -440,6 +470,22 @@ function hasDotKey(obj) {
|
|
|
440
470
|
}
|
|
441
471
|
return false;
|
|
442
472
|
}
|
|
473
|
+
function fingerprintArgs(argumentsRaw) {
|
|
474
|
+
if (typeof argumentsRaw === "string") return argumentsRaw;
|
|
475
|
+
try {
|
|
476
|
+
return JSON.stringify(argumentsRaw);
|
|
477
|
+
} catch {
|
|
478
|
+
return "";
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
function missingRequiredParam(schema, args) {
|
|
482
|
+
const required = schema.required;
|
|
483
|
+
if (!required || required.length === 0) return null;
|
|
484
|
+
for (const key of required) {
|
|
485
|
+
if (args[key] === void 0) return key;
|
|
486
|
+
}
|
|
487
|
+
return null;
|
|
488
|
+
}
|
|
443
489
|
|
|
444
490
|
// src/memory/runtime.ts
|
|
445
491
|
import { createHash } from "crypto";
|
|
@@ -1375,6 +1421,7 @@ function signature(call) {
|
|
|
1375
1421
|
|
|
1376
1422
|
// src/loop.ts
|
|
1377
1423
|
var ESCALATION_MODEL = "deepseek-v4-pro";
|
|
1424
|
+
var PARENT_BUDGET_WARN_THRESHOLD = 5;
|
|
1378
1425
|
var CacheFirstLoop = class {
|
|
1379
1426
|
client;
|
|
1380
1427
|
prefix;
|
|
@@ -1411,6 +1458,7 @@ var CacheFirstLoop = class {
|
|
|
1411
1458
|
_turnFailures = new TurnFailureTracker();
|
|
1412
1459
|
_turnSelfCorrected = false;
|
|
1413
1460
|
_foldedThisTurn = false;
|
|
1461
|
+
_toolDispatchesThisStep = 0;
|
|
1414
1462
|
context;
|
|
1415
1463
|
/** Subscribe API so UI hooks can derive `running` from finally-guaranteed insertions. */
|
|
1416
1464
|
get inflight() {
|
|
@@ -1465,6 +1513,23 @@ var CacheFirstLoop = class {
|
|
|
1465
1513
|
stormThreshold: parsePositiveIntEnv(process.env.REASONIX_STORM_THRESHOLD),
|
|
1466
1514
|
stormWindow: parsePositiveIntEnv(process.env.REASONIX_STORM_WINDOW)
|
|
1467
1515
|
});
|
|
1516
|
+
if (!this.tools.hasResultAugmenter) {
|
|
1517
|
+
this.tools.setResultAugmenter((_name, _args, result) => {
|
|
1518
|
+
this._toolDispatchesThisStep++;
|
|
1519
|
+
const remaining = this.maxToolIters - this._toolDispatchesThisStep;
|
|
1520
|
+
if (remaining <= 0) {
|
|
1521
|
+
return `${result}
|
|
1522
|
+
|
|
1523
|
+
[budget: 0 of ${this.maxToolIters} tool calls left this turn \u2014 finalize NOW; the next iter forces a summary]`;
|
|
1524
|
+
}
|
|
1525
|
+
if (remaining <= PARENT_BUDGET_WARN_THRESHOLD) {
|
|
1526
|
+
return `${result}
|
|
1527
|
+
|
|
1528
|
+
[budget: ${remaining} of ${this.maxToolIters} tool calls left this turn \u2014 wrap up soon]`;
|
|
1529
|
+
}
|
|
1530
|
+
return result;
|
|
1531
|
+
});
|
|
1532
|
+
}
|
|
1468
1533
|
this.sessionName = opts.session ?? null;
|
|
1469
1534
|
if (this.sessionName) {
|
|
1470
1535
|
const prior = loadSessionMessages(this.sessionName);
|
|
@@ -1718,6 +1783,7 @@ ${reason}`
|
|
|
1718
1783
|
this._turnSelfCorrected = false;
|
|
1719
1784
|
this._escalateThisTurn = false;
|
|
1720
1785
|
this._foldedThisTurn = false;
|
|
1786
|
+
this._toolDispatchesThisStep = 0;
|
|
1721
1787
|
let armedConsumed = false;
|
|
1722
1788
|
if (this._proArmedForNextTurn) {
|
|
1723
1789
|
this._escalateThisTurn = true;
|
|
@@ -3129,6 +3195,74 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
3129
3195
|
return `moved ${displayRel4(rootDir, src)} \u2192 ${displayRel4(rootDir, dst)}`;
|
|
3130
3196
|
}
|
|
3131
3197
|
});
|
|
3198
|
+
registry.register({
|
|
3199
|
+
name: "delete_file",
|
|
3200
|
+
description: "Delete one file under the sandbox root. Refuses directories \u2014 use delete_directory for those. Errors if the path doesn't exist.",
|
|
3201
|
+
parameters: {
|
|
3202
|
+
type: "object",
|
|
3203
|
+
properties: { path: { type: "string" } },
|
|
3204
|
+
required: ["path"]
|
|
3205
|
+
},
|
|
3206
|
+
fn: async (args) => {
|
|
3207
|
+
const abs = safePath(args.path);
|
|
3208
|
+
const st = await fs4.lstat(abs);
|
|
3209
|
+
if (st.isDirectory()) {
|
|
3210
|
+
throw new Error(
|
|
3211
|
+
`delete_file: ${args.path} is a directory \u2014 use delete_directory to remove it`
|
|
3212
|
+
);
|
|
3213
|
+
}
|
|
3214
|
+
await fs4.unlink(abs);
|
|
3215
|
+
return `deleted ${displayRel4(rootDir, abs)}`;
|
|
3216
|
+
}
|
|
3217
|
+
});
|
|
3218
|
+
registry.register({
|
|
3219
|
+
name: "delete_directory",
|
|
3220
|
+
description: "Recursively delete a directory under the sandbox root. Pass `recursive:false` to refuse non-empty directories. Errors if the path doesn't exist.",
|
|
3221
|
+
parameters: {
|
|
3222
|
+
type: "object",
|
|
3223
|
+
properties: {
|
|
3224
|
+
path: { type: "string" },
|
|
3225
|
+
recursive: {
|
|
3226
|
+
type: "boolean",
|
|
3227
|
+
description: "When true (default) deletes the directory and all its contents. When false, only removes empty directories \u2014 non-empty refuses with an error."
|
|
3228
|
+
}
|
|
3229
|
+
},
|
|
3230
|
+
required: ["path"]
|
|
3231
|
+
},
|
|
3232
|
+
fn: async (args) => {
|
|
3233
|
+
const abs = safePath(args.path);
|
|
3234
|
+
const st = await fs4.lstat(abs);
|
|
3235
|
+
if (!st.isDirectory()) {
|
|
3236
|
+
throw new Error(`delete_directory: ${args.path} is a file \u2014 use delete_file to remove it`);
|
|
3237
|
+
}
|
|
3238
|
+
const recursive = args.recursive !== false;
|
|
3239
|
+
if (recursive) {
|
|
3240
|
+
await fs4.rm(abs, { recursive: true, force: false });
|
|
3241
|
+
} else {
|
|
3242
|
+
await fs4.rmdir(abs);
|
|
3243
|
+
}
|
|
3244
|
+
return `deleted ${displayRel4(rootDir, abs)}/${recursive ? " (recursive)" : ""}`;
|
|
3245
|
+
}
|
|
3246
|
+
});
|
|
3247
|
+
registry.register({
|
|
3248
|
+
name: "copy_file",
|
|
3249
|
+
description: "Copy a file or directory under the sandbox root. Both source and destination resolve under the sandbox. Parent directories of the destination are created as needed. Refuses to overwrite an existing destination \u2014 delete it first if you want to replace it.",
|
|
3250
|
+
parameters: {
|
|
3251
|
+
type: "object",
|
|
3252
|
+
properties: {
|
|
3253
|
+
source: { type: "string" },
|
|
3254
|
+
destination: { type: "string" }
|
|
3255
|
+
},
|
|
3256
|
+
required: ["source", "destination"]
|
|
3257
|
+
},
|
|
3258
|
+
fn: async (args) => {
|
|
3259
|
+
const src = safePath(args.source);
|
|
3260
|
+
const dst = safePath(args.destination);
|
|
3261
|
+
await fs4.mkdir(pathMod4.dirname(dst), { recursive: true });
|
|
3262
|
+
await fs4.cp(src, dst, { recursive: true, force: false, errorOnExist: true });
|
|
3263
|
+
return `copied ${displayRel4(rootDir, src)} \u2192 ${displayRel4(rootDir, dst)}`;
|
|
3264
|
+
}
|
|
3265
|
+
});
|
|
3132
3266
|
return registry;
|
|
3133
3267
|
}
|
|
3134
3268
|
|
|
@@ -3343,7 +3477,7 @@ function registerChoiceTool(registry, opts = {}) {
|
|
|
3343
3477
|
|
|
3344
3478
|
// src/tools/plan-core.ts
|
|
3345
3479
|
var SUBMIT_PLAN_DESCRIPTION = "Submit ONE concrete plan you've already decided on. Use this for tasks that warrant a review gate \u2014 multi-file refactors, architecture changes, anything that would be expensive or confusing to undo. Skip it for small fixes (one-line typo, obvious bug with a clear fix) \u2014 just make the change. The user will either approve (you then implement it), ask for refinement, or cancel. If the user has already enabled /plan mode, writes are blocked at dispatch and you MUST use this. CRITICAL: do NOT use submit_plan to present alternative routes (A/B/C, option 1/2/3) for the user to pick from \u2014 the picker only exposes approve/refine/cancel, so a menu plan strands the user with no way to choose. For branching decisions, call `ask_choice` instead; only call submit_plan once the user has picked a direction and you have a single actionable plan. Write the plan as markdown with a one-line summary, a bulleted list of files to touch and what will change, and any risks or open questions. STRONGLY PREFERRED: pass `steps` \u2014 an array of {id, title, action, risk?} \u2014 so the UI renders a structured step list above the approval picker and tracks per-step progress. Use risk='high' for steps that touch prod data / break public APIs / are hard to undo; 'med' for non-trivial but reversible (multi-file edits, schema tweaks); 'low' for safe local work. After each step, call `mark_step_complete` so the user sees progress ticks.";
|
|
3346
|
-
var MARK_STEP_COMPLETE_DESCRIPTION = "Mark one step of the approved plan as done.
|
|
3480
|
+
var MARK_STEP_COMPLETE_DESCRIPTION = "Mark one step of the approved plan as done. MANDATORY: call this exactly once after finishing each step, before starting the next one \u2014 skipping it leaves the user staring at `0/N done` on the resume banner even when the work is finished, and they have no way to know which steps actually ran. The TUI updates the plan card's progress in place; the count is persisted to disk so it survives session resume. After the FINAL step, write a brief reply summarizing what was done and end the turn. Pass the `stepId` from the plan's steps array, a short `result` (what you did), and optional `notes` for anything surprising (errors, scope changes, follow-ups). This tool doesn't change any files. Don't call it if the plan didn't include structured steps, and don't invent ids that weren't in the original plan. If you only realized at the end that you skipped marking steps, mark them then \u2014 late is still better than never.";
|
|
3347
3481
|
var REVISE_PLAN_DESCRIPTION = "Surgically replace the REMAINING steps of an in-flight plan. Call this when the user has given feedback at a checkpoint that warrants a structured plan change \u2014 skip a step, swap two steps, add a new step, change risk, etc. Pass: `reason` (one sentence why), `remainingSteps` (the new tail of the plan, replacing whatever steps haven't been done yet), and optional `summary` (updated one-line plan summary). Done steps are NEVER touched \u2014 keep them out of `remainingSteps`. The TUI shows a diff (removed in red, kept in gray, added in green) and the user accepts or rejects. Don't call this for trivial mid-step adjustments \u2014 just keep executing. Don't call submit_plan for revisions either \u2014 that resets the whole plan including completed steps. Use submit_plan only when the entire approach has changed; use revise_plan when the tail needs editing.";
|
|
3348
3482
|
var STEP_ITEM_SCHEMA = {
|
|
3349
3483
|
type: "object",
|
|
@@ -3667,16 +3801,19 @@ async function searchMojeek(query, opts = {}) {
|
|
|
3667
3801
|
signal: opts.signal,
|
|
3668
3802
|
redirect: "follow"
|
|
3669
3803
|
});
|
|
3670
|
-
if (!resp.ok) throw new Error(
|
|
3804
|
+
if (!resp.ok) throw new Error(t("webErrors.status", { status: resp.status }));
|
|
3671
3805
|
const html = await resp.text();
|
|
3672
3806
|
const results = parseMojeekResults(html).slice(0, topK);
|
|
3673
3807
|
if (results.length === 0) {
|
|
3674
3808
|
if (/no results found|did not match any documents/i.test(html)) return [];
|
|
3675
3809
|
if (/captcha|verify you are human|access denied|forbidden/i.test(html)) {
|
|
3676
|
-
throw new Error("
|
|
3810
|
+
throw new Error(t("webErrors.mojeekBlocked"));
|
|
3677
3811
|
}
|
|
3678
3812
|
throw new Error(
|
|
3679
|
-
|
|
3813
|
+
t("webErrors.mojeekNoResults", {
|
|
3814
|
+
chars: html.length,
|
|
3815
|
+
preview: html.slice(0, 120).replace(/\s+/g, " ")
|
|
3816
|
+
})
|
|
3680
3817
|
);
|
|
3681
3818
|
}
|
|
3682
3819
|
return results;
|
|
@@ -3686,10 +3823,10 @@ function normalizeSearxngEndpoint(raw) {
|
|
|
3686
3823
|
try {
|
|
3687
3824
|
url = new URL(raw.includes("://") ? raw : `http://${raw}`);
|
|
3688
3825
|
} catch {
|
|
3689
|
-
throw new Error(
|
|
3826
|
+
throw new Error(t("webErrors.invalidEndpoint", { endpoint: raw }));
|
|
3690
3827
|
}
|
|
3691
3828
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
3692
|
-
throw new Error(
|
|
3829
|
+
throw new Error(t("webErrors.endpointMustBeHttp", { protocol: url.protocol }));
|
|
3693
3830
|
}
|
|
3694
3831
|
return url.origin;
|
|
3695
3832
|
}
|
|
@@ -3709,19 +3846,17 @@ async function searchSearxng(query, opts = {}) {
|
|
|
3709
3846
|
} catch (err) {
|
|
3710
3847
|
if (err instanceof TypeError && err.message.includes("fetch")) {
|
|
3711
3848
|
throw new Error(
|
|
3712
|
-
|
|
3849
|
+
t("webErrors.cannotReach", { endpoint: opts.endpoint ?? "http://localhost:8080" })
|
|
3713
3850
|
);
|
|
3714
3851
|
}
|
|
3715
3852
|
throw err;
|
|
3716
3853
|
}
|
|
3717
|
-
if (!resp.ok) throw new Error(
|
|
3854
|
+
if (!resp.ok) throw new Error(t("webErrors.status", { status: resp.status }));
|
|
3718
3855
|
const html = await resp.text();
|
|
3719
3856
|
const results = parseSearxngHtmlResults(html).slice(0, topK);
|
|
3720
3857
|
if (results.length === 0) {
|
|
3721
3858
|
if (/no results found|did not match any documents/i.test(html)) return [];
|
|
3722
|
-
throw new Error(
|
|
3723
|
-
`web_search: 0 results but SearXNG response doesn't look like an empty results page (${html.length} chars)`
|
|
3724
|
-
);
|
|
3859
|
+
throw new Error(t("webErrors.searxngNoResults", { chars: html.length }));
|
|
3725
3860
|
}
|
|
3726
3861
|
return results;
|
|
3727
3862
|
}
|
|
@@ -3815,13 +3950,11 @@ async function webFetch(url, opts = {}) {
|
|
|
3815
3950
|
clearTimeout(timer);
|
|
3816
3951
|
opts.signal?.removeEventListener("abort", cancel);
|
|
3817
3952
|
}
|
|
3818
|
-
if (!resp.ok) throw new Error(
|
|
3953
|
+
if (!resp.ok) throw new Error(t("webErrors.fetchStatus", { status: resp.status, url }));
|
|
3819
3954
|
const contentType = resp.headers.get("content-type") ?? "";
|
|
3820
3955
|
const declaredLen = Number(resp.headers.get("content-length") ?? "");
|
|
3821
3956
|
if (Number.isFinite(declaredLen) && declaredLen > FETCH_MAX_BYTES) {
|
|
3822
|
-
throw new Error(
|
|
3823
|
-
`web_fetch refused: content-length ${declaredLen} bytes exceeds ${FETCH_MAX_BYTES}-byte cap (${url})`
|
|
3824
|
-
);
|
|
3957
|
+
throw new Error(t("webErrors.fetchTooLarge", { len: declaredLen, cap: FETCH_MAX_BYTES, url }));
|
|
3825
3958
|
}
|
|
3826
3959
|
const raw = await readBodyCapped(resp, FETCH_MAX_BYTES);
|
|
3827
3960
|
const title = extractTitle(raw);
|
|
@@ -3848,9 +3981,7 @@ async function readBodyCapped(resp, maxBytes) {
|
|
|
3848
3981
|
await reader.cancel();
|
|
3849
3982
|
} catch {
|
|
3850
3983
|
}
|
|
3851
|
-
throw new Error(
|
|
3852
|
-
`web_fetch refused: response body exceeded ${maxBytes}-byte cap (${total} bytes seen)`
|
|
3853
|
-
);
|
|
3984
|
+
throw new Error(t("webErrors.fetchBodyTooLarge", { cap: maxBytes, seen: total }));
|
|
3854
3985
|
}
|
|
3855
3986
|
out += decoder.decode(value, { stream: true });
|
|
3856
3987
|
}
|
|
@@ -3978,7 +4109,7 @@ function registerWebTools(registry, opts = {}) {
|
|
|
3978
4109
|
},
|
|
3979
4110
|
fn: async (args, ctx) => {
|
|
3980
4111
|
if (!/^https?:\/\//i.test(args.url)) {
|
|
3981
|
-
throw new Error("
|
|
4112
|
+
throw new Error(t("webErrors.fetchInvalidUrl"));
|
|
3982
4113
|
}
|
|
3983
4114
|
const page = await webFetch(args.url, { maxChars: maxFetchChars, signal: ctx?.signal });
|
|
3984
4115
|
const header = page.title ? `${page.title}
|
|
@@ -5077,4 +5208,4 @@ export {
|
|
|
5077
5208
|
snapshotBeforeEdits,
|
|
5078
5209
|
restoreSnapshots
|
|
5079
5210
|
};
|
|
5080
|
-
//# sourceMappingURL=chunk-
|
|
5211
|
+
//# sourceMappingURL=chunk-5ZCRXN7S.js.map
|