zames_pro 2.10.4 → 2.10.7

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 +89 -21
  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,10 +665,11 @@ 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).
644
- const startDeadline = Date.now() + 15_000;
672
+ const startDeadline = Date.now() + 30_000;
645
673
  const startBodyLen = await this.page
646
674
  .evaluate(() => document.body.innerText.length)
647
675
  .catch(() => 0);
@@ -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,19 +733,52 @@ 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
  }
713
- // We NO LONGER check the limit over the whole page text — that caused
714
- // false positives and 5-minute waits. We just report that
715
- // generation did not start.
716
- throw new Error('Ответ не начал генерироваться за 15с. Возможно, сообщение не отправилось.');
749
+ if (fresh) {
750
+ return this._netCapture;
751
+ }
752
+ // The send did not start generation within 15s. The most common cause is
753
+ // that the message did not actually go out (Enter lost, button not
754
+ // clicked). Instead of throwing (which made ask() retry for minutes and
755
+ // looked like a stall), press Enter once more and give it another
756
+ // window. Only if that also fails do we throw.
757
+ this._askDebug('START-failed, resending');
758
+ await this.page.keyboard.press('Enter');
759
+ this._lastSentAt = Date.now();
760
+ const retryDeadline = Date.now() + 20_000;
761
+ while (Date.now() < retryDeadline) {
762
+ if (this._abort)
763
+ return '(прервано пользователем)';
764
+ const cur2 = await this._readLastAnswerTextClean().catch(() => '');
765
+ const net2 = !!this._netCapture && this._netCaptureAt >= this._lastSentAt;
766
+ const grew2 = (await this.page
767
+ .evaluate(() => document.body.innerText.length)
768
+ .catch(() => 0)) > startBodyLen;
769
+ if (net2 ||
770
+ grew2 ||
771
+ (!!cur2 && normText(cur2) !== normText(beforeText))) {
772
+ started = true;
773
+ this._askDebug('STARTED-after-resend');
774
+ break;
775
+ }
776
+ await this.page.waitForTimeout(300);
777
+ }
778
+ }
779
+ if (!started) {
780
+ throw new Error('Ответ не начал генерироваться за 35с даже после повторной отправки. ' +
781
+ 'Проверьте чат DeepSeek вручную.');
717
782
  }
718
783
  // Wait until the answer stops changing. We check the "not generating"
719
784
  // condition via text growth, NOT via _isGenerating().
@@ -752,30 +817,33 @@ export class DeepSeekBrowser {
752
817
  // tool call" hang. If generation has clearly ENDED (no Stop button) and
753
818
  // the text is stable, accept it (even when it repeats the previous one).
754
819
  const sameAsBefore = !!cur && !isNew && normText(cur) === normText(beforeText);
755
- if ((isNew || sameAsBefore) && cur === last) {
820
+ if (isNew && cur === last) {
756
821
  stable++;
757
822
  if (stable >= 2) {
758
- if (isNew || !(await this._isGenerating()))
823
+ if (isNew || !(await this._isGenerating())) {
824
+ this._askDebug('RETURN stable curLen=' + cur.length);
759
825
  return cur;
826
+ }
760
827
  }
761
828
  }
762
829
  else {
763
830
  stable = 0;
764
831
  }
765
- if (isNew || sameAsBefore)
832
+ if (isNew)
766
833
  last = cur;
834
+ this._askDebug('FIN-loop isNew=' + isNew + ' sameAsBefore=' + sameAsBefore + ' stable=' + stable + ' curLen=' + cur.length + ' lastLen=' + last.length + ' netFresh=' + netFresh);
767
835
  await this.page.waitForTimeout(800);
768
836
  }
769
837
  if (last && (normText(last) !== normText(beforeText) || this._netCapture)) {
838
+ this._askDebug('RETURN last len=' + last.length);
770
839
  return last;
771
840
  }
772
- // Fallback: the turn settled on a text identical to the previous answer.
773
- if (last && !(await this._isGenerating())) {
774
- return last;
775
- }
841
+ // No fallback on a text equal to beforeText: returning it would re-run
842
+ // the previous tool call. Only a fresh network capture is accepted below.
776
843
  if (this._netCapture && this._netCaptureAt >= this._lastSentAt) {
777
844
  return this._netCapture;
778
845
  }
846
+ this._askDebug('THROW no-new-answer lastLen=' + last.length + ' beforeLen=' + beforeText.length);
779
847
  throw new Error('Новый ответ не получен (на странице остался прежний текст). ' +
780
848
  'Возможно, сообщение не отправилось.');
781
849
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.10.4",
3
+ "version": "2.10.7",
4
4
  "description": "Terminal coding agent over chat.deepseek.com via Playwright",
5
5
  "type": "module",
6
6
  "bin": {