zames_pro 2.29.3 → 2.29.4

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.
Files changed (2) hide show
  1. package/dist/browser.js +51 -16
  2. package/package.json +1 -1
package/dist/browser.js CHANGED
@@ -340,6 +340,13 @@ export class DeepSeekBrowser {
340
340
  _lastHistoryError;
341
341
  _netSniff;
342
342
  _netSniffLimit;
343
+ // The RAW SSE body of the LAST answer response. Unlike `_netCapture`, this
344
+ // is kept even when the body carries no RESPONSE text (a truncated turn:
345
+ // generation_err / INCOMPLETE, or FINISHED-with-only-reasoning). The
346
+ // incomplete/no-answer detectors MUST run on the raw body — guarding them on
347
+ // `_netCapture` (which is '' in exactly those cases) made them dead code and
348
+ // the agent hung until the timeout.
349
+ _netBody;
343
350
  _netHookInstalled;
344
351
  // Fired right when a message is actually typed/sent (AFTER the send-pause
345
352
  // and attachments). Used to start the "agent is working" spinner only when
@@ -393,6 +400,7 @@ export class DeepSeekBrowser {
393
400
  this._lastHistoryError = '';
394
401
  this._netSniff = [];
395
402
  this._netSniffLimit = 5;
403
+ this._netBody = '';
396
404
  this._netHookInstalled = false;
397
405
  this.onSendStart = null;
398
406
  this.onSendPause = null;
@@ -554,17 +562,31 @@ export class DeepSeekBrowser {
554
562
  this._netChatId = cid[0];
555
563
  this._netCaptureAt = Date.now();
556
564
  }
557
- else if (/chat\/(completion|continue)/i.test(url) &&
558
- isFinishedWithoutAnswer(body)) {
559
- // A FINISHED turn with NO RESPONSE fragment (only reasoning): the UI
560
- // shows a Continue button. Record it with a fresh timestamp so the
561
- // ask() loops do not wait out the timeout — they click Continue.
562
- this._netNoAnswer = true;
563
- this._netCapture = '';
565
+ // Store the RAW body for the CURRENT answer (completion/continue) so the
566
+ // truncated/no-answer detectors can inspect it even when there is no
567
+ // RESPONSE text (extractAnswer() returns '' for those bodies).
568
+ if (/chat\/(completion|continue)/i.test(url)) {
569
+ this._netBody = body;
564
570
  const cid = url.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/);
565
571
  if (cid)
566
572
  this._netChatId = cid[0];
567
- this._netCaptureAt = Date.now();
573
+ if (!extracted) {
574
+ if (isFinishedWithoutAnswer(body)) {
575
+ // A FINISHED turn with NO RESPONSE fragment (only reasoning): the
576
+ // UI shows Stopped + Continue. Record it with a fresh timestamp
577
+ // so the ask() loops do not wait out the timeout — they click
578
+ // Continue / resend.
579
+ this._netNoAnswer = true;
580
+ this._netCapture = '';
581
+ }
582
+ // A truncated turn (generation_err / INCOMPLETE) also has no
583
+ // RESPONSE; make the body visible to the incomplete check by
584
+ // refreshing the timestamp.
585
+ if (isGenerationIncompleteText(body)) {
586
+ this._netCapture = '';
587
+ }
588
+ this._netCaptureAt = Date.now();
589
+ }
568
590
  }
569
591
  }
570
592
  catch { }
@@ -1652,6 +1674,7 @@ export class DeepSeekBrowser {
1652
1674
  this._netCapture = '';
1653
1675
  this._netCaptureAt = 0;
1654
1676
  this._netNoAnswer = false;
1677
+ this._netBody = '';
1655
1678
  // Align the DeepSeek chat toggles (deep thinking / web search) with the
1656
1679
  // configured state BEFORE typing. Doing it here (after the send-pause) it
1657
1680
  // does not flip toggles for a generation that is not going to happen.
@@ -1711,10 +1734,13 @@ export class DeepSeekBrowser {
1711
1734
  // The turn was truncated by the server: the SSE body carries
1712
1735
  // finish_reason=generation_err / quasi_status=INCOMPLETE and the UI
1713
1736
  // shows "Continue". Retry instead of waiting out the whole timeout.
1714
- if (this._netCapture &&
1715
- this._netCaptureAt >= this._lastSentAt &&
1716
- isGenerationIncompleteText(this._netCapture)) {
1717
- throw new GenerationIncompleteError(this._netCapture.slice(-300));
1737
+ // NOTE: the check runs on the RAW `_netBody`, not on `_netCapture`: a
1738
+ // truncated body has NO RESPONSE fragment, so extractAnswer() returned
1739
+ // '' and `_netCapture` was empty — guarding on it made this branch dead
1740
+ // code and the agent hung on "Stopped" until the timeout.
1741
+ if (this._netCaptureAt >= this._lastSentAt &&
1742
+ isGenerationIncompleteText(this._netBody)) {
1743
+ throw new GenerationIncompleteError(this._netBody.slice(-300));
1718
1744
  }
1719
1745
  // A FINISHED turn with NO answer (only reasoning): the UI shows a
1720
1746
  // Continue button. Click it (or, if autoContinue is off, keep waiting)
@@ -1805,6 +1831,14 @@ export class DeepSeekBrowser {
1805
1831
  // previous tool call.
1806
1832
  const cur = await this._readLastAnswerTextCleanDom().catch(() => '');
1807
1833
  const fresh = !!this._netCapture && this._netCaptureAt >= this._lastSentAt;
1834
+ // The turn was truncated / produced no answer (generation_err,
1835
+ // INCOMPLETE, or FINISHED-with-only-reasoning): the message WAS sent,
1836
+ // the server just cut the turn. Resend (ask() handles it) instead of
1837
+ // treating this as "send failed" and hammering Enter.
1838
+ if (this._netCaptureAt >= this._lastSentAt &&
1839
+ (isGenerationIncompleteText(this._netBody) || this._netNoAnswer)) {
1840
+ throw new GenerationIncompleteError(this._netBody.slice(-300));
1841
+ }
1808
1842
  if (cur &&
1809
1843
  cur.trim() &&
1810
1844
  normText(cur) !== normText(beforeText) &&
@@ -1875,10 +1909,11 @@ export class DeepSeekBrowser {
1875
1909
  // keeps the partial answer, so without this check the loop waits out the
1876
1910
  // whole timeout and throws ds.send_no_new_answer — the operator sees the
1877
1911
  // agent "stop" with a Continue button in the chat. Retry the send.
1878
- if (this._netCapture &&
1879
- this._netCaptureAt >= this._lastSentAt &&
1880
- isGenerationIncompleteText(this._netCapture)) {
1881
- throw new GenerationIncompleteError(this._netCapture.slice(-300));
1912
+ // Runs on the RAW `_netBody` (a truncated body has no RESPONSE, so
1913
+ // `_netCapture` is empty and the old guard was dead code).
1914
+ if (this._netCaptureAt >= this._lastSentAt &&
1915
+ isGenerationIncompleteText(this._netBody)) {
1916
+ throw new GenerationIncompleteError(this._netBody.slice(-300));
1882
1917
  }
1883
1918
  // A FINISHED turn with NO answer (only reasoning): the UI shows a
1884
1919
  // Continue button. Click it and keep waiting — otherwise the loop spins
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.29.3",
3
+ "version": "2.29.4",
4
4
  "description": "Terminal coding agent over chat.deepseek.com via Playwright",
5
5
  "type": "module",
6
6
  "bin": {