zames_pro 2.93.0 → 2.94.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/agent-loop.js +76 -3
- package/dist/index.js +14 -0
- package/dist/run-task.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.94.1] - 2026-11-02
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **dev:** dump an unparsed call in the watchdog branch too
|
|
15
|
+
|
|
16
|
+
## [2.94.0] - 2026-11-02
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **dev:** dump unrecognized tool calls and hot-reload the parser
|
|
21
|
+
|
|
10
22
|
## [2.93.0] - 2026-11-02
|
|
11
23
|
|
|
12
24
|
### Fixed
|
package/dist/agent-loop.js
CHANGED
|
@@ -13,7 +13,7 @@ import { shouldRunDiagnostics, runDiagnostics, } from './diagnostics.js';
|
|
|
13
13
|
// The tools that WRITE/EDIT a file (and take a `path`). The completion nudge
|
|
14
14
|
// only cares about these — `Bash`/`Git*` in MUTATING_TOOLS are not edits.
|
|
15
15
|
const EDIT_TOOLS = new Set(['Write', 'Edit', 'MultiEdit', 'ApplyPatch']);
|
|
16
|
-
export async function runAgentLoop({ browser, tools, task, workdir, maxIterations = 0, freshChat = false, sendSystemPrompt = false, transcript = null, attachments = [], onThinking = () => { }, onSendPause = () => { }, onSendState = () => { }, onNotice = () => { }, onAssistantThought = () => { }, onToolCall = () => { }, onToolResult = () => { }, onAssistantMessage = () => { }, onChatReady = () => { }, onWarning = () => { }, debugLog = false, locale = DEFAULT_LOCALE, askDeadlineMs = 240_000, maxAfterToolRetries = 6, infiniteRetries = true, maxRetryWaitMs = 30 * 60_000, onAutoCompact = null, onContextLimit = null, onProviderExhausted = null, autoCompactPct = 95, contextLimit = 1_000_000, getTokenUsage = null, hooks = undefined, permissions = undefined, diagnostics = null, onAskPermission = undefined, selfImprovement = false, onSubagent = null, onAskUser = null, }) {
|
|
16
|
+
export async function runAgentLoop({ browser, tools, task, workdir, maxIterations = 0, freshChat = false, sendSystemPrompt = false, transcript = null, attachments = [], onThinking = () => { }, onSendPause = () => { }, onSendState = () => { }, onNotice = () => { }, onAssistantThought = () => { }, onToolCall = () => { }, onToolResult = () => { }, onAssistantMessage = () => { }, onChatReady = () => { }, onWarning = () => { }, debugLog = false, devDump = false, locale = DEFAULT_LOCALE, askDeadlineMs = 240_000, maxAfterToolRetries = 6, infiniteRetries = true, maxRetryWaitMs = 30 * 60_000, onAutoCompact = null, onContextLimit = null, onProviderExhausted = null, autoCompactPct = 95, contextLimit = 1_000_000, getTokenUsage = null, hooks = undefined, permissions = undefined, diagnostics = null, onAskPermission = undefined, selfImprovement = false, onSubagent = null, onAskUser = null, }) {
|
|
17
17
|
// Resolve the hook config ONCE per task: a read per tool call would be
|
|
18
18
|
// wasteful, and a mid-task edit of hooks.json is not something to chase.
|
|
19
19
|
// `undefined` means "read .zames/hooks.json"; an explicit null disables
|
|
@@ -469,6 +469,14 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
469
469
|
if (!isFirst &&
|
|
470
470
|
(wdEmpty || wdStale || wdNoCall) &&
|
|
471
471
|
watchdogRetries < MAX_WATCHDOG_RETRIES) {
|
|
472
|
+
if (devDump && !wdEmpty) {
|
|
473
|
+
const dumped = await dumpUnparsedCall(rawResponse, {
|
|
474
|
+
provider: providerLabel,
|
|
475
|
+
where: 'loop:watchdog_no_call',
|
|
476
|
+
});
|
|
477
|
+
if (dumped)
|
|
478
|
+
safeWarning('[dev] unparsed call saved: ' + dumped);
|
|
479
|
+
}
|
|
472
480
|
watchdogRetries++;
|
|
473
481
|
transcript?.log('watchdog_nudge', {
|
|
474
482
|
attempt: watchdogRetries,
|
|
@@ -513,6 +521,14 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
513
521
|
// agent stalls even though the model tried to call a tool.
|
|
514
522
|
const looksLikeToolCall = responseLooksLikeToolCall(rawResponse);
|
|
515
523
|
if (looksLikeToolCall && malformedRetries < MAX_MALFORMED_RETRIES) {
|
|
524
|
+
if (devDump) {
|
|
525
|
+
const dumped = await dumpUnparsedCall(rawResponse, {
|
|
526
|
+
provider: providerLabel,
|
|
527
|
+
where: 'loop:unparsed',
|
|
528
|
+
});
|
|
529
|
+
if (dumped)
|
|
530
|
+
safeWarning('[dev] unparsed call saved: ' + dumped);
|
|
531
|
+
}
|
|
516
532
|
malformedRetries++;
|
|
517
533
|
unparsedRetries++;
|
|
518
534
|
transcript?.log('malformed_toolcall', {
|
|
@@ -1344,5 +1360,62 @@ ${diag}`;
|
|
|
1344
1360
|
}
|
|
1345
1361
|
// The pure helpers (tool-call parser + answer heuristics) live in
|
|
1346
1362
|
// answer-parse.ts and are imported here for runAgentLoop. They are
|
|
1347
|
-
// NOT re-exported: importers get them from answer-parse.js directly
|
|
1348
|
-
|
|
1363
|
+
// NOT re-exported: importers get them from answer-parse.js directly.
|
|
1364
|
+
// parseToolCall and responseLooksLikeToolCall live in let bindings:
|
|
1365
|
+
// their modules (answer-parse.ts, xml-toolcall.ts) are NOT hot-reloadable,
|
|
1366
|
+
// so an edit to the parser was reported by the dev watcher and then
|
|
1367
|
+
// silently ignored for the whole run. /reload swaps them through
|
|
1368
|
+
// _setParserBindings().
|
|
1369
|
+
import { truncateToolResult, normForStale, looksLikeUnfinishedWork, isMeaningfulRespond, extractPreToolText, } from './answer-parse.js';
|
|
1370
|
+
import * as answerParse from './answer-parse.js';
|
|
1371
|
+
let parseToolCall = answerParse.parseToolCall;
|
|
1372
|
+
let responseLooksLikeToolCall = answerParse.responseLooksLikeToolCall;
|
|
1373
|
+
export function _setParserBindings(m) {
|
|
1374
|
+
parseToolCall = m.parseToolCall;
|
|
1375
|
+
responseLooksLikeToolCall = m.responseLooksLikeToolCall;
|
|
1376
|
+
}
|
|
1377
|
+
let unparsedDumps = 0;
|
|
1378
|
+
const UNPARSED_DUMP_MAX = 20;
|
|
1379
|
+
const UNPARSED_DUMP_BYTES = 64 * 1024;
|
|
1380
|
+
/** Dev mode: save an unrecognized (but call-looking) answer for analysis. */
|
|
1381
|
+
export async function dumpUnparsedCall(raw, meta) {
|
|
1382
|
+
if (unparsedDumps >= UNPARSED_DUMP_MAX)
|
|
1383
|
+
return '';
|
|
1384
|
+
const text = String(raw || '');
|
|
1385
|
+
if (!text.trim())
|
|
1386
|
+
return '';
|
|
1387
|
+
const fs = await import('node:fs/promises');
|
|
1388
|
+
const p = await import('node:path');
|
|
1389
|
+
const dir = p.join(meta.workdir || process.cwd(), '.zames', 'unparsed');
|
|
1390
|
+
try {
|
|
1391
|
+
await fs.mkdir(dir, { recursive: true });
|
|
1392
|
+
unparsedDumps++;
|
|
1393
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
1394
|
+
const name = stamp + '-' + String(meta.where || 'x').replace(/[^a-z0-9_-]+/gi, '_');
|
|
1395
|
+
const file = p.join(dir, name + '.txt');
|
|
1396
|
+
const NL = String.fromCharCode(10);
|
|
1397
|
+
const head = '# unparsed tool-call candidate' +
|
|
1398
|
+
NL +
|
|
1399
|
+
'when: ' +
|
|
1400
|
+
new Date().toISOString() +
|
|
1401
|
+
NL +
|
|
1402
|
+
'provider: ' +
|
|
1403
|
+
(meta.provider || '-') +
|
|
1404
|
+
NL +
|
|
1405
|
+
'where: ' +
|
|
1406
|
+
meta.where +
|
|
1407
|
+
NL +
|
|
1408
|
+
'length: ' +
|
|
1409
|
+
text.length +
|
|
1410
|
+
NL +
|
|
1411
|
+
NL +
|
|
1412
|
+
'--- raw answer ---' +
|
|
1413
|
+
NL +
|
|
1414
|
+
NL;
|
|
1415
|
+
await fs.writeFile(file, head + text.slice(0, UNPARSED_DUMP_BYTES), 'utf-8');
|
|
1416
|
+
return file;
|
|
1417
|
+
}
|
|
1418
|
+
catch {
|
|
1419
|
+
return '';
|
|
1420
|
+
}
|
|
1421
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -369,6 +369,19 @@ async function reloadModules() {
|
|
|
369
369
|
mod.attach = loaded.get('attach-refs');
|
|
370
370
|
if (pick('run-task', 'runTask'))
|
|
371
371
|
mod.runTask = pick('run-task', 'runTask');
|
|
372
|
+
// answer-parse.ts and xml-toolcall.ts are NOT hot-reloadable: the loop
|
|
373
|
+
// keeps the parser functions in LIVE bindings, so /reload must push the
|
|
374
|
+
// freshly imported copy through it (a parser fix must not need a restart).
|
|
375
|
+
try {
|
|
376
|
+
const ap = (await import('./answer-parse.js'));
|
|
377
|
+
const loopMod = loaded.get('agent-loop');
|
|
378
|
+
const setter = loopMod ? loopMod['_setParserBindings'] : undefined;
|
|
379
|
+
if (typeof setter === 'function')
|
|
380
|
+
setter(ap);
|
|
381
|
+
}
|
|
382
|
+
catch (e) {
|
|
383
|
+
errors.push('answer-parse: ' + e.message);
|
|
384
|
+
}
|
|
372
385
|
return { count: loaded.size, errors };
|
|
373
386
|
}
|
|
374
387
|
// Initial load so that mod.buildSystemPrompt and the rest are populated.
|
|
@@ -1016,6 +1029,7 @@ function runTaskDeps() {
|
|
|
1016
1029
|
config,
|
|
1017
1030
|
runAgentLoop: mod.runAgentLoop,
|
|
1018
1031
|
createSpinner: mod.createSpinner,
|
|
1032
|
+
devDump: devMode,
|
|
1019
1033
|
onAssistantMessage: (msg) => {
|
|
1020
1034
|
lastAssistantMessage = msg;
|
|
1021
1035
|
},
|
package/dist/run-task.js
CHANGED
|
@@ -403,6 +403,7 @@ export async function runTask(deps, browser, tools, taskText, workdir, opts, att
|
|
|
403
403
|
},
|
|
404
404
|
onChatReady,
|
|
405
405
|
debugLog: debug,
|
|
406
|
+
devDump: deps.devDump === true,
|
|
406
407
|
locale,
|
|
407
408
|
askDeadlineMs: providerAskDeadlineMs(config),
|
|
408
409
|
maxAfterToolRetries: config.browser.maxAfterToolRetries,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zames_pro",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.94.1",
|
|
4
4
|
"description": "Terminal coding agent that drives a real browser to chat with DeepSeek, Qwen or GLM — no API key required. Reads and edits files, runs commands, commits to git, like Claude Code / Codex CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|