zames_pro 2.29.11 → 2.29.13
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/dist/agent-loop.js +6 -1
- package/dist/browser.js +40 -20
- package/dist/config.js +1 -1
- package/dist/i18n.js +12 -0
- package/dist/index.js +2 -0
- package/dist/input.js +7 -0
- package/package.json +1 -1
package/dist/agent-loop.js
CHANGED
|
@@ -4,7 +4,7 @@ import { getGitContext, formatGitContext } from './gitTools.js';
|
|
|
4
4
|
import { parseXmlToolCalls } from './xml-toolcall.js';
|
|
5
5
|
import { translate } from './i18n.js';
|
|
6
6
|
import { normText } from './browser.js';
|
|
7
|
-
export async function runAgentLoop({ browser, tools, task, workdir, maxIterations = 0, freshChat = false, sendSystemPrompt = false, transcript = null, attachments = [], onThinking = () => { }, onSendPause = () => { }, onAssistantThought = () => { }, onToolCall = () => { }, onToolResult = () => { }, onAssistantMessage = () => { }, onChatReady = () => { }, onWarning = () => { }, debugLog = false, locale = 'ru', }) {
|
|
7
|
+
export async function runAgentLoop({ browser, tools, task, workdir, maxIterations = 0, freshChat = false, sendSystemPrompt = false, transcript = null, attachments = [], onThinking = () => { }, onSendPause = () => { }, onNotice = () => { }, onAssistantThought = () => { }, onToolCall = () => { }, onToolResult = () => { }, onAssistantMessage = () => { }, onChatReady = () => { }, onWarning = () => { }, debugLog = false, locale = 'ru', }) {
|
|
8
8
|
// UI callbacks must NEVER break the agent loop. A rendering error (a huge
|
|
9
9
|
// tool result, a broken markdown frame, a closed terminal) used to throw
|
|
10
10
|
// out of the loop right after a tool call — the session looked "stopped
|
|
@@ -30,6 +30,11 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
30
30
|
// seconds, the UI shows an animated status instead of a frozen line.
|
|
31
31
|
const safeSendPause = safe(onSendPause);
|
|
32
32
|
browser.onSendPause = safeSendPause;
|
|
33
|
+
// Service notices (rate limit, server busy, resend) must reach the OPERATOR.
|
|
34
|
+
// While a LineEditor is active a raw console.error is overwritten by the
|
|
35
|
+
// editor's repaint, so the operator only saw the spinner. `onNotice` prints
|
|
36
|
+
// the notice ABOVE the input line.
|
|
37
|
+
browser.onNotice = safe(onNotice);
|
|
33
38
|
const safeAssistantThought = safe(onAssistantThought);
|
|
34
39
|
const safeToolCall = safe(onToolCall);
|
|
35
40
|
const safeToolResult = safe(onToolResult);
|
package/dist/browser.js
CHANGED
|
@@ -363,6 +363,13 @@ export class DeepSeekBrowser {
|
|
|
363
363
|
// remaining seconds. Lets the UI animate the pause status instead of
|
|
364
364
|
// printing a static line (the dots used to be frozen during the pause).
|
|
365
365
|
onSendPause;
|
|
366
|
+
// A service notice for the OPERATOR (rate limit, server busy, resend, …).
|
|
367
|
+
// IMPORTANT: these must NOT go through `console.error` directly — while a
|
|
368
|
+
// LineEditor is active it repaints its own status line and the raw stderr
|
|
369
|
+
// write is overwritten, so the operator saw only the spinner and no reason
|
|
370
|
+
// (the "агент завис на спиннере" symptom after "Messages too frequent").
|
|
371
|
+
// When set, the UI prints the notice ABOVE the input line.
|
|
372
|
+
onNotice;
|
|
366
373
|
// User-Agent sent by the browser. In headless mode the "Headless" marker
|
|
367
374
|
// must be stripped (DeepSeek's CDN answers 403 to it); computed in the
|
|
368
375
|
// constructor, overridable by an explicit UA in the options/config.
|
|
@@ -411,6 +418,7 @@ export class DeepSeekBrowser {
|
|
|
411
418
|
this._netHookInstalled = false;
|
|
412
419
|
this.onSendStart = null;
|
|
413
420
|
this.onSendPause = null;
|
|
421
|
+
this.onNotice = null;
|
|
414
422
|
// An explicit UA (config/options) is respected as-is. Otherwise it stays
|
|
415
423
|
// empty here and is derived from the real engine UA after launch — see
|
|
416
424
|
// _fixHeadlessUserAgent (a headless "HeadlessChrome/..." UA gets 403 from
|
|
@@ -421,6 +429,19 @@ export class DeepSeekBrowser {
|
|
|
421
429
|
_t(key, params) {
|
|
422
430
|
return translate(this.locale)(key, params);
|
|
423
431
|
}
|
|
432
|
+
// A service notice for the operator. When a UI hook is wired (LineEditor is
|
|
433
|
+
// active during a task) the notice goes ABOVE the input line so it is not
|
|
434
|
+
// overwritten by the editor's repaint; otherwise it falls back to stderr.
|
|
435
|
+
_notice(text) {
|
|
436
|
+
if (this.onNotice) {
|
|
437
|
+
try {
|
|
438
|
+
this.onNotice(text);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
catch { }
|
|
442
|
+
}
|
|
443
|
+
console.error(text);
|
|
444
|
+
}
|
|
424
445
|
async launch() {
|
|
425
446
|
// NOTE: we deliberately do NOT kill stray chrome processes here. Per the
|
|
426
447
|
// project rules, an agent must never kill a browser it did not start —
|
|
@@ -1379,13 +1400,13 @@ export class DeepSeekBrowser {
|
|
|
1379
1400
|
if (e instanceof RateLimitError) {
|
|
1380
1401
|
rateLimitRetries++;
|
|
1381
1402
|
if (rateLimitRetries > this.maxRateLimitRetries) {
|
|
1382
|
-
|
|
1403
|
+
this._notice(theme.error(this._t('ds.rate_limit_give_up', {
|
|
1383
1404
|
attempt: rateLimitRetries,
|
|
1384
1405
|
min: Math.ceil(this.rateLimitWaitMs / 60000),
|
|
1385
1406
|
})));
|
|
1386
1407
|
throw e;
|
|
1387
1408
|
}
|
|
1388
|
-
|
|
1409
|
+
this._notice(theme.warn(this._t('ds.rate_limit_wait', {
|
|
1389
1410
|
min: Math.ceil(this.rateLimitWaitMs / 60000),
|
|
1390
1411
|
attempt: rateLimitRetries,
|
|
1391
1412
|
max: this.maxRateLimitRetries,
|
|
@@ -1408,12 +1429,12 @@ export class DeepSeekBrowser {
|
|
|
1408
1429
|
if (e instanceof ServerBusyError) {
|
|
1409
1430
|
serverBusyRetries++;
|
|
1410
1431
|
if (serverBusyRetries > this.maxServerBusyRetries) {
|
|
1411
|
-
|
|
1432
|
+
this._notice(theme.error(this._t('ds.server_busy_give_up', {
|
|
1412
1433
|
attempt: serverBusyRetries,
|
|
1413
1434
|
})));
|
|
1414
1435
|
throw e;
|
|
1415
1436
|
}
|
|
1416
|
-
|
|
1437
|
+
this._notice(theme.warn(this._t('ds.server_busy_wait', {
|
|
1417
1438
|
sec: Math.ceil(this.serverBusyWaitMs / 1000),
|
|
1418
1439
|
attempt: serverBusyRetries,
|
|
1419
1440
|
max: this.maxServerBusyRetries,
|
|
@@ -1431,12 +1452,12 @@ export class DeepSeekBrowser {
|
|
|
1431
1452
|
if (e instanceof GenerationIncompleteError) {
|
|
1432
1453
|
incompleteRetries++;
|
|
1433
1454
|
if (incompleteRetries > this.maxIncompleteRetries) {
|
|
1434
|
-
|
|
1455
|
+
this._notice(theme.error(this._t('ds.incomplete_give_up', {
|
|
1435
1456
|
attempt: incompleteRetries,
|
|
1436
1457
|
})));
|
|
1437
1458
|
throw e;
|
|
1438
1459
|
}
|
|
1439
|
-
|
|
1460
|
+
this._notice(theme.warn(this._t('ds.incomplete_retry', {
|
|
1440
1461
|
attempt: incompleteRetries,
|
|
1441
1462
|
max: this.maxIncompleteRetries,
|
|
1442
1463
|
})));
|
|
@@ -1445,25 +1466,24 @@ export class DeepSeekBrowser {
|
|
|
1445
1466
|
return '(прервано пользователем)';
|
|
1446
1467
|
continue;
|
|
1447
1468
|
}
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
})));
|
|
1469
|
+
this._notice(theme.warn(this._t('ds.ask_retry', {
|
|
1470
|
+
attempt,
|
|
1471
|
+
max: this.askRetries,
|
|
1472
|
+
error: e.message,
|
|
1473
|
+
})));
|
|
1454
1474
|
// Only a genuinely LOST page justifies a restart. "Target page,
|
|
1455
1475
|
// context or browser has been closed" means the page is gone for good;
|
|
1456
1476
|
// a bare "browser" mention (e.g. a selector error containing the word)
|
|
1457
1477
|
// must NOT tear the window down — that was the "a new window opened"
|
|
1458
1478
|
// surprise during a resumed chat. We re-open the SAME context instead.
|
|
1459
1479
|
if (/target page, context or browser has been closed|page.*has been closed/i.test(e.message)) {
|
|
1460
|
-
|
|
1480
|
+
this._notice(theme.warn(this._t('ds.ask_restart_browser')));
|
|
1461
1481
|
try {
|
|
1462
1482
|
await this.restart();
|
|
1463
1483
|
await this.waitForLogin();
|
|
1464
1484
|
}
|
|
1465
1485
|
catch (re) {
|
|
1466
|
-
|
|
1486
|
+
this._notice(theme.warn(this._t('ds.ask_restart_failed', {
|
|
1467
1487
|
error: re.message,
|
|
1468
1488
|
})));
|
|
1469
1489
|
}
|
|
@@ -1551,10 +1571,10 @@ export class DeepSeekBrowser {
|
|
|
1551
1571
|
bufPayload.push({ name: f.name, mimeType: f.mime, buffer });
|
|
1552
1572
|
}
|
|
1553
1573
|
catch (e) {
|
|
1554
|
-
|
|
1555
|
-
f.name
|
|
1556
|
-
|
|
1557
|
-
|
|
1574
|
+
this._notice(theme.warn(this._t('ds.attach_read_failed', {
|
|
1575
|
+
name: f.name,
|
|
1576
|
+
error: e.message,
|
|
1577
|
+
})));
|
|
1558
1578
|
}
|
|
1559
1579
|
}
|
|
1560
1580
|
if (!bufPayload.length)
|
|
@@ -1590,14 +1610,14 @@ export class DeepSeekBrowser {
|
|
|
1590
1610
|
// Fallback: set the files directly on the hidden <input type=file>.
|
|
1591
1611
|
const input = this.page.locator('input[type="file"]').first();
|
|
1592
1612
|
if ((await input.count()) === 0) {
|
|
1593
|
-
|
|
1613
|
+
this._notice(theme.warn(this._t('ds.attach_no_input')));
|
|
1594
1614
|
return;
|
|
1595
1615
|
}
|
|
1596
1616
|
try {
|
|
1597
1617
|
await input.setInputFiles(bufPayload, { timeout: 15_000 });
|
|
1598
1618
|
}
|
|
1599
1619
|
catch (e) {
|
|
1600
|
-
|
|
1620
|
+
this._notice(theme.warn(this._t('ds.attach_failed', { error: e.message })));
|
|
1601
1621
|
return;
|
|
1602
1622
|
}
|
|
1603
1623
|
// Wait for the upload to finish (the attach preview to appear).
|
package/dist/config.js
CHANGED
package/dist/i18n.js
CHANGED
|
@@ -537,6 +537,18 @@ const CATALOG = {
|
|
|
537
537
|
ru: '⏳ DeepSeek оборвал ответ и кнопки Continue нет — переотправляю задачу ({attempt}/{max})...',
|
|
538
538
|
en: '⏳ DeepSeek truncated the answer and there is no Continue button — resending the task ({attempt}/{max})...',
|
|
539
539
|
},
|
|
540
|
+
'ds.attach_read_failed': {
|
|
541
|
+
ru: '⚠ не удалось прочитать вложение {name}: {error}',
|
|
542
|
+
en: '⚠ could not read the attachment {name}: {error}',
|
|
543
|
+
},
|
|
544
|
+
'ds.attach_no_input': {
|
|
545
|
+
ru: '⚠ не найдено поле загрузки файлов — вложения не прикреплены',
|
|
546
|
+
en: '⚠ file upload field not found — the attachments were not attached',
|
|
547
|
+
},
|
|
548
|
+
'ds.attach_failed': {
|
|
549
|
+
ru: '⚠ не удалось прикрепить файлы: {error}',
|
|
550
|
+
en: '⚠ could not attach the files: {error}',
|
|
551
|
+
},
|
|
540
552
|
'ds.incomplete_give_up': {
|
|
541
553
|
ru: '✖ DeepSeek {attempt} раз подряд оборвал ответ, не дойдя до конца. Возможно, включён режим размышления — попробуй выключить его (browser.deepThinking) или повтори позже.',
|
|
542
554
|
en: '✖ DeepSeek truncated the answer {attempt} times in a row. The reasoning mode (deep thinking) may be on — try turning it off (browser.deepThinking) or retry later.',
|
package/dist/index.js
CHANGED
|
@@ -975,6 +975,7 @@ async function runTask(browser, tools, taskText, workdir, opts, attachments = []
|
|
|
975
975
|
transcript,
|
|
976
976
|
onThinking: () => ui.thinking(),
|
|
977
977
|
onSendPause: (seconds) => ui.sendPause(seconds),
|
|
978
|
+
onNotice: (msg) => ui.warning(msg),
|
|
978
979
|
onToolCall: (name, toolArgs) => ui.toolCall(name, toolArgs),
|
|
979
980
|
onToolResult: (result) => ui.toolResult(result),
|
|
980
981
|
onAssistantMessage: (msg) => ui.assistant(msg),
|
|
@@ -1034,6 +1035,7 @@ async function runTask(browser, tools, taskText, workdir, opts, attachments = []
|
|
|
1034
1035
|
// start a stale spinner.
|
|
1035
1036
|
browser.onSendStart = null;
|
|
1036
1037
|
browser.onSendPause = null;
|
|
1038
|
+
browser.onNotice = null;
|
|
1037
1039
|
}
|
|
1038
1040
|
}
|
|
1039
1041
|
// ---------- main ----------
|
package/dist/input.js
CHANGED
|
@@ -977,6 +977,13 @@ export class LineEditor {
|
|
|
977
977
|
this.attachments.reset();
|
|
978
978
|
if (this.onSubmit)
|
|
979
979
|
this.onSubmit(text, attached);
|
|
980
|
+
// When a message is queued DURING a running task (`busy`), keep the
|
|
981
|
+
// "agent is working" indicator alive: `_stopDots()` above cleared the
|
|
982
|
+
// status, and nothing would restart it until the next send/tool — so the
|
|
983
|
+
// operator saw the spinner vanish and could not tell whether the agent
|
|
984
|
+
// was still working. Restart the animated status unless we are idle.
|
|
985
|
+
if (this.busy)
|
|
986
|
+
this._startThinking();
|
|
980
987
|
}
|
|
981
988
|
_insert(text) {
|
|
982
989
|
const chars = Array.from(this.buf);
|