zames_pro 2.29.8 → 2.29.10

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.
@@ -357,6 +357,11 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
357
357
  const looksService = !trimmed ||
358
358
  trimmed.length < 2 ||
359
359
  /^(reading|thinking|searching|analyzing|generating|stop|остановить|читаю|думаю|поиск|анализ)[\s.…]*$/i.test(trimmed) ||
360
+ // DeepSeek sometimes returns its OWN safety-classification block
361
+ // ("<ds_safety>…</ds_safety>Safe") INSTEAD of an answer. It is not a
362
+ // tool-call and not a real final answer — treat it as a service
363
+ // answer so the loop re-asks instead of stopping on it.
364
+ /<ds_safety>|<\/ds_safety>/i.test(trimmed) ||
360
365
  (trimmed.length <= 200 &&
361
366
  /(messages? too frequent|too many requests|rate limit|server (is )?busy|service (is )?unavailable|слишком часто|try again later)/i.test(trimmed));
362
367
  if (looksService && stallRetries < MAX_STALL_RETRIES) {
package/dist/browser.js CHANGED
@@ -309,6 +309,11 @@ export class DeepSeekBrowser {
309
309
  // credentials into the user config (the browser does not write config).
310
310
  onAuthSave;
311
311
  _lastSentAt;
312
+ // Timestamp of the last Continue click. Clicks send a `chat/continue`
313
+ // request and used to bypass `_waitForSendSlot()` entirely — a run that
314
+ // keeps getting truncated could fire them back-to-back and hammer the
315
+ // rate limit. The click path now respects `minSendIntervalMs` like a send.
316
+ _lastContinueAt;
312
317
  _abort;
313
318
  // The user pressed Esc/Ctrl+C — a "stop" for the WHOLE current batch of
314
319
  // tasks (including the queue). Unlike _abort (reset on every send), this
@@ -388,6 +393,7 @@ export class DeepSeekBrowser {
388
393
  this.locale = locale || DEFAULT_LOCALE;
389
394
  this.onAuthSave = onAuthSave || null;
390
395
  this._lastSentAt = 0;
396
+ this._lastContinueAt = 0;
391
397
  this._abort = false;
392
398
  this._stopped = false;
393
399
  this._netCapture = '';
@@ -1155,6 +1161,11 @@ export class DeepSeekBrowser {
1155
1161
  // event and reliably triggers React handlers. The old in-page
1156
1162
  // dispatchEvent/click often did nothing, which is exactly why the
1157
1163
  // operator saw the button and the "жму Continue" message but no resume.
1164
+ //
1165
+ // We LOOK for the button first and only then wait out the send slot:
1166
+ // probing this every tick must stay cheap, and there is no point
1167
+ // throttling a click that will not happen.
1168
+ let found = null;
1158
1169
  for (const name of CONTINUE_NAMES) {
1159
1170
  try {
1160
1171
  const loc = this.page.getByRole('button', { name }).first();
@@ -1162,7 +1173,35 @@ export class DeepSeekBrowser {
1162
1173
  continue;
1163
1174
  if (!(await loc.isVisible().catch(() => false)))
1164
1175
  continue;
1165
- await loc.click({ timeout: 2000 });
1176
+ found = loc;
1177
+ break;
1178
+ }
1179
+ catch { }
1180
+ }
1181
+ if (found) {
1182
+ // One Continue click per `minSendIntervalMs`: a `chat/continue` request
1183
+ // hits the rate limit like a send, and a run that keeps getting
1184
+ // truncated could otherwise fire clicks back-to-back. The gap counts
1185
+ // from the LATEST of the last send and the last Continue click.
1186
+ const since = Math.max(this._lastSentAt, this._lastContinueAt);
1187
+ if (since) {
1188
+ const gap = this.minSendIntervalMs - (Date.now() - since);
1189
+ if (gap > 0) {
1190
+ const aborted = await this._sleepInterruptible(gap, (leftMs) => {
1191
+ if (this.onSendPause) {
1192
+ try {
1193
+ this.onSendPause(Math.max(0, Math.ceil(leftMs / 1000)));
1194
+ }
1195
+ catch { }
1196
+ }
1197
+ });
1198
+ if (aborted)
1199
+ return false;
1200
+ }
1201
+ }
1202
+ try {
1203
+ await found.click({ timeout: 2000 });
1204
+ this._lastContinueAt = Date.now();
1166
1205
  return true;
1167
1206
  }
1168
1207
  catch { }
@@ -1974,8 +2013,12 @@ export class DeepSeekBrowser {
1974
2013
  continue;
1975
2014
  }
1976
2015
  }
1977
- if (truncated) {
1978
- throw new GenerationIncompleteError(this._netBody.slice(-300));
2016
+ // No Continue button to click (DeepSeek shows "Stopped" without one) OR
2017
+ // autoContinue is off. Do NOT wait out the whole timeout — the turn is
2018
+ // dead (truncated / finished with no answer), so tell ask() to RESEND
2019
+ // the prompt right away (that is the only remaining way to continue).
2020
+ if (truncated || noAnswer) {
2021
+ throw new GenerationIncompleteError((this._netBody || 'finished without answer').slice(-300));
1979
2022
  }
1980
2023
  // Reasoning-mode pause: DeepSeek caps the THINK phase and shows a
1981
2024
  // Continue button; the model does not resume by itself. Click it so the
package/dist/i18n.js CHANGED
@@ -534,8 +534,8 @@ const CATALOG = {
534
534
  en: '⚠ No answer yet ({attempt}/{max}): {error} — retrying...',
535
535
  },
536
536
  'ds.incomplete_retry': {
537
- ru: '⏳ DeepSeek оборвал ответ — жму «Continue», чтобы продолжить (повтор {attempt}/{max})...',
538
- en: '⏳ DeepSeek truncated the answer — clicking Continue to resume (retry {attempt}/{max})...',
537
+ ru: '⏳ DeepSeek оборвал ответ и кнопки Continue нет — переотправляю задачу ({attempt}/{max})...',
538
+ en: '⏳ DeepSeek truncated the answer and there is no Continue button — resending the task ({attempt}/{max})...',
539
539
  },
540
540
  'ds.incomplete_give_up': {
541
541
  ru: '✖ DeepSeek {attempt} раз подряд оборвал ответ, не дойдя до конца. Возможно, включён режим размышления — попробуй выключить его (browser.deepThinking) или повтори позже.',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.29.8",
3
+ "version": "2.29.10",
4
4
  "description": "Terminal coding agent over chat.deepseek.com via Playwright",
5
5
  "type": "module",
6
6
  "bin": {