zames_pro 2.95.0 → 2.95.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/agent-loop.js +33 -0
- package/dist/browser.js +18 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.95.2] - 2026-11-04
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- fix-deepseek-head-only
|
|
15
|
+
- test: pin the streamed-answer head snapshot (the resend loop)
|
|
16
|
+
- docs: theme gallery, mobile menu and code copy buttons
|
|
17
|
+
|
|
18
|
+
## [2.95.1] - 2026-11-03
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- **loop:** skip the stall path for a stale BashOutput poll
|
|
23
|
+
|
|
10
24
|
## [2.95.0] - 2026-11-03
|
|
11
25
|
|
|
12
26
|
### Added
|
package/dist/agent-loop.js
CHANGED
|
@@ -523,6 +523,15 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
523
523
|
}
|
|
524
524
|
}
|
|
525
525
|
if (!parsed) {
|
|
526
|
+
// SILENT BACKGROUND POLL: {"tool": "BashOutput", "args": {...}} for a
|
|
527
|
+
// process that has ALREADY finished (the watchdog killed its promise,
|
|
528
|
+
// or the id is stale). The tool itself answers "no background process"
|
|
529
|
+
// and does not move the task forward, so an EMPTY model turn is not a
|
|
530
|
+
// stall worth a dev dump / a nudge - the loop simply re-asks quietly.
|
|
531
|
+
// Matching is DELIBERATELY narrow: only BashOutput with a plain id.
|
|
532
|
+
if (isEmptyPollCall(rawResponse)) {
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
526
535
|
// The answer looks like a (possibly truncated) tool call. We catch not
|
|
527
536
|
// only explicit JSON but also XML/DSML forms, "dirty" variants and
|
|
528
537
|
// unclosed fragments: if such an answer is silently taken as final, the
|
|
@@ -1387,6 +1396,30 @@ let unparsedDumps = 0;
|
|
|
1387
1396
|
const UNPARSED_DUMP_MAX = 20;
|
|
1388
1397
|
const UNPARSED_DUMP_BYTES = 64 * 1024;
|
|
1389
1398
|
/** Dev mode: save an unrecognized (but call-looking) answer for analysis. */
|
|
1399
|
+
/**
|
|
1400
|
+
* True when the raw answer is a bare `{"tool":"BashOutput","args":{"id":...}}`
|
|
1401
|
+
* (optionally wrapped in whitespace/fences). A finished background process is
|
|
1402
|
+
* polled by the model with such a call; the tool returns "no background
|
|
1403
|
+
* process with id ..." which does not advance the task. Used to skip the
|
|
1404
|
+
* stall nudge / dev dump for this one case only.
|
|
1405
|
+
*/
|
|
1406
|
+
export function isEmptyPollCall(raw) {
|
|
1407
|
+
const t = String(raw || '').trim();
|
|
1408
|
+
if (!t || t.length > 400)
|
|
1409
|
+
return false;
|
|
1410
|
+
let obj;
|
|
1411
|
+
try {
|
|
1412
|
+
obj = JSON.parse(t);
|
|
1413
|
+
}
|
|
1414
|
+
catch {
|
|
1415
|
+
return false;
|
|
1416
|
+
}
|
|
1417
|
+
const o = obj;
|
|
1418
|
+
if (!o || o.tool !== 'BashOutput')
|
|
1419
|
+
return false;
|
|
1420
|
+
const a = o.args;
|
|
1421
|
+
return !!a && typeof a.id === 'string';
|
|
1422
|
+
}
|
|
1390
1423
|
export async function dumpUnparsedCall(raw, meta) {
|
|
1391
1424
|
if (unparsedDumps >= UNPARSED_DUMP_MAX)
|
|
1392
1425
|
return '';
|
package/dist/browser.js
CHANGED
|
@@ -510,6 +510,12 @@ export class DeepSeekBrowser {
|
|
|
510
510
|
this._lastSentAt = Date.now();
|
|
511
511
|
}
|
|
512
512
|
this._netBody = body;
|
|
513
|
+
// The answer clock drives the "is this body FRESH?" gate in both
|
|
514
|
+
// ask loops. A body that carries a (head) fragment but no decodable
|
|
515
|
+
// answer text left the clock at 0, so every detector below saw a
|
|
516
|
+
// stale body and stayed silent. Give it a fresh timestamp.
|
|
517
|
+
if (!this._netCaptureAt)
|
|
518
|
+
this._netCaptureAt = Date.now();
|
|
513
519
|
const cid = url.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/);
|
|
514
520
|
if (cid)
|
|
515
521
|
this._netChatId = cid[0];
|
|
@@ -2631,6 +2637,15 @@ export class DeepSeekBrowser {
|
|
|
2631
2637
|
const noAnswer = !doneAnswer &&
|
|
2632
2638
|
this._netNoAnswer &&
|
|
2633
2639
|
this._netCaptureAt >= this._lastSentAt;
|
|
2640
|
+
// A HEAD-ONLY snapshot is NOT a dead turn: DeepSeek opens a turn
|
|
2641
|
+
// with a RESPONSE fragment that holds only newlines, and the text
|
|
2642
|
+
// arrives in the following bare `data: {"v":...}` chunks.
|
|
2643
|
+
// `_netBody` is the body of the LAST network event, so a poll that
|
|
2644
|
+
// lands between the snapshot and the first chunk sees FINISHED with
|
|
2645
|
+
// no answer, and the old code threw at once (the operator saw
|
|
2646
|
+
// "DeepSeek оборвал ответ") while the chat was still streaming.
|
|
2647
|
+
const headOnly = this._netCaptureAt >= this._lastSentAt &&
|
|
2648
|
+
isFinishedAwaitingAnswer(this._netBody);
|
|
2634
2649
|
if ((truncated || noAnswer) && this.autoContinue) {
|
|
2635
2650
|
// MEASURED: a COMPLETE DSML tool call ends with the event `close`
|
|
2636
2651
|
// and `{click_behavior:'none', auto_resume:false}`, yet the DOM may
|
|
@@ -2660,7 +2675,9 @@ export class DeepSeekBrowser {
|
|
|
2660
2675
|
// autoContinue is off. Do NOT wait out the whole timeout — the turn is
|
|
2661
2676
|
// dead (truncated / finished with no answer), so tell ask() to RESEND
|
|
2662
2677
|
// the prompt right away (that is the only remaining way to continue).
|
|
2663
|
-
|
|
2678
|
+
// EXCEPT a head-only snapshot: the rest of the answer is still on
|
|
2679
|
+
// its way (see `headOnly`), so keep waiting for the append chunks.
|
|
2680
|
+
if ((truncated || noAnswer) && !headOnly) {
|
|
2664
2681
|
throw new GenerationIncompleteError((this._netBody || 'finished without answer').slice(-300));
|
|
2665
2682
|
}
|
|
2666
2683
|
// Reasoning-mode pause: DeepSeek caps the THINK phase and shows a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zames_pro",
|
|
3
|
-
"version": "2.95.
|
|
3
|
+
"version": "2.95.2",
|
|
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": {
|