zames_pro 2.10.4 → 2.10.5

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 +54 -10
  2. package/package.json +1 -1
package/dist/browser.js CHANGED
@@ -520,9 +520,23 @@ export class DeepSeekBrowser {
520
520
  .replace(/\r\n/g, '\n')
521
521
  .replace(/\u00a0/g, ' ')
522
522
  .trim();
523
- if (!norm(got)) {
523
+ // Verify the WHOLE text landed in the input, not just that it is non-empty.
524
+ // A partial paste (DeepSeek input limits, lost chars) used to pass the
525
+ // old "not empty" check, so a TRUNCATED message was sent, the model
526
+ // replied to the wrong thing (or nothing), and the loop looked stalled.
527
+ if (norm(got) !== norm(text)) {
524
528
  await input.click();
529
+ await this.page.keyboard.press("Control+A");
530
+ await this.page.keyboard.press("Delete");
525
531
  await this.page.keyboard.insertText(text);
532
+ const got2 = await input.evaluate((el) => {
533
+ if (el.tagName.toLowerCase() === "textarea" || el.tagName.toLowerCase() === "input")
534
+ return el.value;
535
+ return el.innerText || el.textContent || "";
536
+ });
537
+ if (norm(got2) !== norm(text)) {
538
+ throw new Error("Не удалось вставить текст в поле ввода DeepSeek целиком (вставлено " + norm(got2).length + " из " + norm(text).length + " символов). Сообщение не отправлено, чтобы не отправить обрезанный текст.");
539
+ }
526
540
  }
527
541
  }
528
542
  // Attach files/images to the chat via the hidden <input type=file> of the
@@ -602,6 +616,18 @@ export class DeepSeekBrowser {
602
616
  console.error(theme.warn(`⏳ пауза ${Math.ceil(gap / 1000)}с перед отправкой`));
603
617
  await this.page.waitForTimeout(gap);
604
618
  }
619
+ // DEBUG: append ask() phases to ~/.zames/ask-debug.log so a stall can be
620
+ // diagnosed from the field (what the DOM/network looked like at each step).
621
+ _askDebug(msg) {
622
+ if (!process.env.ZAMES_ASK_DEBUG)
623
+ return;
624
+ try {
625
+ const line = new Date().toISOString() + ' ' + msg + String.fromCharCode(10);
626
+ const dir = path.join(os.homedir(), '.zames');
627
+ void fs.appendFile(path.join(dir, 'ask-debug.log'), line).catch(() => { });
628
+ }
629
+ catch { }
630
+ }
605
631
  async _askOnce(prompt, { timeout, agent, attachments = [], }) {
606
632
  // We reset the abort flag ONLY at the very start of the send.
607
633
  this._abort = false;
@@ -610,6 +636,7 @@ export class DeepSeekBrowser {
610
636
  throw new Error('Не найдено поле ввода. Запустите /debug-dom и поправьте INPUT_SELECTORS.');
611
637
  }
612
638
  const beforeText = await this._readLastAnswerTextClean().catch(() => '');
639
+ this._askDebug('SEND agent=' + agent + ' len=' + prompt.length + ' beforeLen=' + beforeText.length + ' beforeHead=' + JSON.stringify(beforeText.slice(0, 60)));
613
640
  await this._waitForSendSlot(agent);
614
641
  this._netCapture = '';
615
642
  this._netCaptureAt = 0;
@@ -638,6 +665,7 @@ export class DeepSeekBrowser {
638
665
  await this.page.keyboard.press('Enter');
639
666
  }
640
667
  this._lastSentAt = Date.now();
668
+ this._askDebug('SENT at=' + this._lastSentAt);
641
669
  // Wait for the start: either Stop appeared, or the answer text changed,
642
670
  // or the total amount of text on the page grew. In parallel we catch
643
671
  // the rate-limit toast (only toasts, not the whole body).
@@ -684,16 +712,20 @@ export class DeepSeekBrowser {
684
712
  const netStarted = !!this._netCapture && this._netCaptureAt >= this._lastSentAt;
685
713
  if (changed || netStarted || bodyLen > startBodyLen) {
686
714
  started = true;
715
+ this._askDebug('STARTED changed=' + changed + ' netStarted=' + netStarted + ' bodyGrew=' + (bodyLen > startBodyLen));
687
716
  break;
688
717
  }
689
- // Fallback for an echo/stale answer: the send happened (lastSentAt was
690
- // just updated), the Stop button is gone and the text stopped changing.
691
- // Two stable ticks in a row mean the turn is over even if it equals the
692
- // previous text — return it instead of hanging/throwing.
718
+ // Fallback for an echo: the text equals beforeText, so it is the OLD
719
+ // answer still on screen, NOT a new one. We must NOT return it (that
720
+ // made the loop re-run the previous tool call). We only return when the
721
+ // text DIFFERS from beforeText and has settled, or when a fresh network
722
+ // capture proves a new answer exists. If it stays equal, keep waiting.
693
723
  const notGenerating = !(await this._isGenerating());
694
- if (cur && cur === lastStartCur && notGenerating && cur.trim()) {
724
+ const differs = !!cur && normText(cur) !== normText(beforeText);
725
+ if (differs && cur === lastStartCur && notGenerating) {
695
726
  settledTicks++;
696
727
  if (settledTicks >= 2) {
728
+ this._askDebug('SETTLED-differs return len=' + cur.length);
697
729
  return cur;
698
730
  }
699
731
  }
@@ -701,15 +733,22 @@ export class DeepSeekBrowser {
701
733
  settledTicks = 0;
702
734
  }
703
735
  lastStartCur = cur;
736
+ this._askDebug('START-loop curLen=' + cur.length + ' changed=' + changed + ' netStarted=' + netStarted + ' bodyLen=' + bodyLen + ' settled=' + settledTicks + ' generating=' + notGenerating);
704
737
  await this.page.waitForTimeout(300);
705
738
  }
706
739
  if (!started) {
707
- // Last chance: the answer may have arrived and settled exactly at the
708
- // deadline. Return the current text instead of a hard error.
740
+ // Last chance: accept the text only when it DIFFERS from beforeText
741
+ // (otherwise it is the old answer on screen) or a fresh network capture
742
+ // proves a new answer. Returning an equal text made the loop re-run the
743
+ // previous tool call.
709
744
  const cur = await this._readLastAnswerTextClean().catch(() => '');
710
- if (cur && cur.trim() && !(await this._isGenerating())) {
745
+ const fresh = !!this._netCapture && this._netCaptureAt >= this._lastSentAt;
746
+ if (cur && cur.trim() && normText(cur) !== normText(beforeText) && !(await this._isGenerating())) {
711
747
  return cur;
712
748
  }
749
+ if (fresh) {
750
+ return this._netCapture;
751
+ }
713
752
  // We NO LONGER check the limit over the whole page text — that caused
714
753
  // false positives and 5-minute waits. We just report that
715
754
  // generation did not start.
@@ -755,8 +794,10 @@ export class DeepSeekBrowser {
755
794
  if ((isNew || sameAsBefore) && cur === last) {
756
795
  stable++;
757
796
  if (stable >= 2) {
758
- if (isNew || !(await this._isGenerating()))
797
+ if (isNew || !(await this._isGenerating())) {
798
+ this._askDebug('RETURN stable curLen=' + cur.length);
759
799
  return cur;
800
+ }
760
801
  }
761
802
  }
762
803
  else {
@@ -764,9 +805,11 @@ export class DeepSeekBrowser {
764
805
  }
765
806
  if (isNew || sameAsBefore)
766
807
  last = cur;
808
+ this._askDebug('FIN-loop isNew=' + isNew + ' sameAsBefore=' + sameAsBefore + ' stable=' + stable + ' curLen=' + cur.length + ' lastLen=' + last.length + ' netFresh=' + netFresh);
767
809
  await this.page.waitForTimeout(800);
768
810
  }
769
811
  if (last && (normText(last) !== normText(beforeText) || this._netCapture)) {
812
+ this._askDebug('RETURN last len=' + last.length);
770
813
  return last;
771
814
  }
772
815
  // Fallback: the turn settled on a text identical to the previous answer.
@@ -776,6 +819,7 @@ export class DeepSeekBrowser {
776
819
  if (this._netCapture && this._netCaptureAt >= this._lastSentAt) {
777
820
  return this._netCapture;
778
821
  }
822
+ this._askDebug('THROW no-new-answer lastLen=' + last.length + ' beforeLen=' + beforeText.length);
779
823
  throw new Error('Новый ответ не получен (на странице остался прежний текст). ' +
780
824
  'Возможно, сообщение не отправилось.');
781
825
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.10.4",
3
+ "version": "2.10.5",
4
4
  "description": "Terminal coding agent over chat.deepseek.com via Playwright",
5
5
  "type": "module",
6
6
  "bin": {