zames_pro 2.10.8 → 2.10.9
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 +8 -1
- package/dist/browser.js +16 -0
- package/dist/i18n.js +1 -0
- package/dist/index.js +51 -2
- package/dist/input.js +42 -0
- package/package.json +1 -1
package/dist/agent-loop.js
CHANGED
|
@@ -20,6 +20,11 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
22
|
const safeThinking = safe(onThinking);
|
|
23
|
+
// Start the "working" indicator ONLY when a message is really sent (after
|
|
24
|
+
// the send-pause), not while the loop is still preparing the request.
|
|
25
|
+
// Previously safeThinking() fired before browser.ask(), so the spinner ran
|
|
26
|
+
// through the whole throttle pause / chat-open phase with nothing in flight.
|
|
27
|
+
browser.onSendStart = safeThinking;
|
|
23
28
|
const safeAssistantThought = safe(onAssistantThought);
|
|
24
29
|
const safeToolCall = safe(onToolCall);
|
|
25
30
|
const safeToolResult = safe(onToolResult);
|
|
@@ -134,7 +139,9 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
134
139
|
let afterToolRetries = 0;
|
|
135
140
|
const MAX_AFTER_TOOL_RETRIES = 6;
|
|
136
141
|
for (let i = 0; i < maxIterations; i++) {
|
|
137
|
-
|
|
142
|
+
// NOTE: the spinner is NOT started here. browser.onSendStart fires it
|
|
143
|
+
// right when the message is actually typed/sent (after the send-pause),
|
|
144
|
+
// so no spinner runs during the pre-send phase.
|
|
138
145
|
// The first message (task) is user input: no throttle.
|
|
139
146
|
// Subsequent ones (tool-result and resend requests) are agent sends:
|
|
140
147
|
// throttled so we don't hit the rate limit.
|
package/dist/browser.js
CHANGED
|
@@ -139,6 +139,11 @@ export class DeepSeekBrowser {
|
|
|
139
139
|
_netSniff;
|
|
140
140
|
_netSniffLimit;
|
|
141
141
|
_netHookInstalled;
|
|
142
|
+
// Fired right when a message is actually typed/sent (AFTER the send-pause
|
|
143
|
+
// and attachments). Used to start the "agent is working" spinner only when
|
|
144
|
+
// a generation really begins, not during the pre-send phase (chat open,
|
|
145
|
+
// throttle wait), which used to show a spinner with no work in flight.
|
|
146
|
+
onSendStart;
|
|
142
147
|
constructor({ headless = false, debug = false, channel = 'chrome', answerTimeoutMs = 180000, askRetries = 3, stabilityChecks = 3, stabilityDelayMs = 1000, minSendIntervalMs = 15000, rateLimitWaitMs = 300000, maxRateLimitRetries = 6, maxServerBusyRetries = 5, serverBusyWaitMs = 3000, } = {}) {
|
|
143
148
|
this.headless = headless;
|
|
144
149
|
this.debug = debug;
|
|
@@ -161,6 +166,7 @@ export class DeepSeekBrowser {
|
|
|
161
166
|
this._netSniff = [];
|
|
162
167
|
this._netSniffLimit = 5;
|
|
163
168
|
this._netHookInstalled = false;
|
|
169
|
+
this.onSendStart = null;
|
|
164
170
|
}
|
|
165
171
|
async launch() {
|
|
166
172
|
await killStaleChrome();
|
|
@@ -670,6 +676,16 @@ export class DeepSeekBrowser {
|
|
|
670
676
|
// Esc/Ctrl+C pressed during the pause — do not send anything.
|
|
671
677
|
if (this._abort)
|
|
672
678
|
return '(прервано пользователем)';
|
|
679
|
+
// The pause is over and we are really about to type/send: only NOW start
|
|
680
|
+
// the "working" indicator. The spinner used to be started by the caller
|
|
681
|
+
// BEFORE ask(), so it ran for the whole throttle pause and chat-opening
|
|
682
|
+
// phase with no generation in flight.
|
|
683
|
+
if (this.onSendStart) {
|
|
684
|
+
try {
|
|
685
|
+
this.onSendStart();
|
|
686
|
+
}
|
|
687
|
+
catch { }
|
|
688
|
+
}
|
|
673
689
|
this._netCapture = '';
|
|
674
690
|
this._netCaptureAt = 0;
|
|
675
691
|
// Attach files/images FIRST (before the text): the DeepSeek upload widget
|
package/dist/i18n.js
CHANGED
|
@@ -128,6 +128,7 @@ const CATALOG = {
|
|
|
128
128
|
'msg.new_chat': { ru: 'Создаю новый чат...', en: 'Creating a new chat...' },
|
|
129
129
|
'msg.new_chat_ok': { ru: 'Новый чат.', en: 'New chat.' },
|
|
130
130
|
'msg.resuming': { ru: 'Восстанавливаю сессию {id}...', en: 'Restoring session {id}...' },
|
|
131
|
+
'msg.input_locked': { ru: 'Идёт операция, ввод временно заблокирован…', en: 'Operation in progress, input is temporarily locked…' },
|
|
131
132
|
'msg.opening_chat': { ru: 'Открываю чат {id}...', en: 'Opening chat {id}...' },
|
|
132
133
|
'msg.chat_opened': { ru: 'Чат открыт.', en: 'Chat opened.' },
|
|
133
134
|
'msg.interactive': { ru: 'Интерактивный режим. Введите задачу. Команды — /help. Выход — /exit.', en: 'Interactive mode. Enter a task. Commands — /help. Exit — /exit.' },
|
package/dist/index.js
CHANGED
|
@@ -714,9 +714,15 @@ async function runTask(browser, tools, taskText, workdir, opts, attachments = []
|
|
|
714
714
|
};
|
|
715
715
|
// Execute the task, then everything the user managed to type while it
|
|
716
716
|
// ran. The queue may be replenished right during draining.
|
|
717
|
+
//
|
|
718
|
+
// NOTE: we do NOT call ui.thinking() here. runAgentLoop() fires
|
|
719
|
+
// onThinking() right before the actual browser send (after the send
|
|
720
|
+
// pause, system-prompt, etc.), so the spinner only appears when a
|
|
721
|
+
// generation really starts. Calling it here made the spinner run for
|
|
722
|
+
// the whole pre-send phase (chat creation, throttle wait) with no
|
|
723
|
+
// generation in flight.
|
|
717
724
|
while (true) {
|
|
718
|
-
|
|
719
|
-
await mod.runAgentLoop({
|
|
725
|
+
const outcome = await mod.runAgentLoop({
|
|
720
726
|
browser,
|
|
721
727
|
tools,
|
|
722
728
|
task: next.text,
|
|
@@ -735,6 +741,16 @@ async function runTask(browser, tools, taskText, workdir, opts, attachments = []
|
|
|
735
741
|
debugLog: debug,
|
|
736
742
|
locale: currentLocale,
|
|
737
743
|
});
|
|
744
|
+
// The loop may end WITHOUT a model answer: an exhausted iteration
|
|
745
|
+
// limit or an ask() watchdog (the model stopped responding). In that
|
|
746
|
+
// case no assistant message was shown, and the operator saw the run
|
|
747
|
+
// just "stop" after a tool call with no explanation. Surface it.
|
|
748
|
+
if (outcome &&
|
|
749
|
+
(outcome.startsWith('Достигнут лимит итераций') ||
|
|
750
|
+
outcome.startsWith('ask() watchdog'))) {
|
|
751
|
+
ui.warning(outcome);
|
|
752
|
+
transcript?.log('agent_no_answer', { outcome });
|
|
753
|
+
}
|
|
738
754
|
// Aborted (Esc/Ctrl+C) — we don't start the next tasks from the queue
|
|
739
755
|
// and clear it, so "stop" really stops everything.
|
|
740
756
|
if (browser._stopped) {
|
|
@@ -770,6 +786,9 @@ async function runTask(browser, tools, taskText, workdir, opts, attachments = []
|
|
|
770
786
|
finally {
|
|
771
787
|
stopWatching();
|
|
772
788
|
ui.stop();
|
|
789
|
+
// Detach the send hook so a later browser.ask() outside this task cannot
|
|
790
|
+
// start a stale spinner.
|
|
791
|
+
browser.onSendStart = null;
|
|
773
792
|
}
|
|
774
793
|
}
|
|
775
794
|
// ---------- main ----------
|
|
@@ -1339,6 +1358,8 @@ async function main() {
|
|
|
1339
1358
|
}
|
|
1340
1359
|
if (['/new', '/clear', 'new'].includes(lower)) {
|
|
1341
1360
|
console.log(theme.system(t('msg.new_chat')));
|
|
1361
|
+
if (editor)
|
|
1362
|
+
editor.lock(t('msg.input_locked'));
|
|
1342
1363
|
try {
|
|
1343
1364
|
await browser.newChat();
|
|
1344
1365
|
freshChatNext = false;
|
|
@@ -1351,6 +1372,10 @@ async function main() {
|
|
|
1351
1372
|
catch (e) {
|
|
1352
1373
|
console.error(theme.error(t('msg.new_chat_error', { v: e.message })), e.message);
|
|
1353
1374
|
}
|
|
1375
|
+
finally {
|
|
1376
|
+
if (editor)
|
|
1377
|
+
editor.unlock();
|
|
1378
|
+
}
|
|
1354
1379
|
continue;
|
|
1355
1380
|
}
|
|
1356
1381
|
// ---------- Self-review ----------
|
|
@@ -1360,6 +1385,8 @@ async function main() {
|
|
|
1360
1385
|
const originalWorkdir = reviewMode
|
|
1361
1386
|
? reviewMode.originalWorkdir
|
|
1362
1387
|
: currentWorkdir;
|
|
1388
|
+
if (editor)
|
|
1389
|
+
editor.lock(t('msg.input_locked'));
|
|
1363
1390
|
try {
|
|
1364
1391
|
const result = await mod.selfReview({
|
|
1365
1392
|
browser,
|
|
@@ -1388,6 +1415,10 @@ async function main() {
|
|
|
1388
1415
|
if (debug)
|
|
1389
1416
|
console.error(e.stack);
|
|
1390
1417
|
}
|
|
1418
|
+
finally {
|
|
1419
|
+
if (editor)
|
|
1420
|
+
editor.unlock();
|
|
1421
|
+
}
|
|
1391
1422
|
continue;
|
|
1392
1423
|
}
|
|
1393
1424
|
if (lower === '/self-fix' || lower.startsWith('/self-fix ')) {
|
|
@@ -1513,6 +1544,8 @@ async function main() {
|
|
|
1513
1544
|
// ---------- Regular commands ----------
|
|
1514
1545
|
if (lower === '/chats') {
|
|
1515
1546
|
const spin = editor || mod.createSpinner(currentLocale);
|
|
1547
|
+
if (editor)
|
|
1548
|
+
editor.lock(t('msg.input_locked'));
|
|
1516
1549
|
spin.thinking();
|
|
1517
1550
|
try {
|
|
1518
1551
|
lastChats = await browser.listChats(30);
|
|
@@ -1533,6 +1566,10 @@ async function main() {
|
|
|
1533
1566
|
spin.stop();
|
|
1534
1567
|
console.error(theme.error(t('chats.fetch_error')), e.message);
|
|
1535
1568
|
}
|
|
1569
|
+
finally {
|
|
1570
|
+
if (editor)
|
|
1571
|
+
editor.unlock();
|
|
1572
|
+
}
|
|
1536
1573
|
continue;
|
|
1537
1574
|
}
|
|
1538
1575
|
if (lower === '/resume' || lower.startsWith('/resume ')) {
|
|
@@ -1556,6 +1593,8 @@ async function main() {
|
|
|
1556
1593
|
continue;
|
|
1557
1594
|
}
|
|
1558
1595
|
console.log(theme.system(t('chats.opening', { v: pick.title })));
|
|
1596
|
+
if (editor)
|
|
1597
|
+
editor.lock(t('msg.input_locked'));
|
|
1559
1598
|
try {
|
|
1560
1599
|
await browser.openChat(pick.id);
|
|
1561
1600
|
currentChatId = pick.id;
|
|
@@ -1571,6 +1610,10 @@ async function main() {
|
|
|
1571
1610
|
catch (e) {
|
|
1572
1611
|
console.error(theme.error(t('msg.open_chat_error', { v: '' })), e.message);
|
|
1573
1612
|
}
|
|
1613
|
+
finally {
|
|
1614
|
+
if (editor)
|
|
1615
|
+
editor.unlock();
|
|
1616
|
+
}
|
|
1574
1617
|
continue;
|
|
1575
1618
|
}
|
|
1576
1619
|
if (lower === '/chat') {
|
|
@@ -1608,6 +1651,8 @@ async function main() {
|
|
|
1608
1651
|
console.error(theme.error(t('sessions.resume_id_usage')));
|
|
1609
1652
|
continue;
|
|
1610
1653
|
}
|
|
1654
|
+
if (editor)
|
|
1655
|
+
editor.lock(t('msg.input_locked'));
|
|
1611
1656
|
try {
|
|
1612
1657
|
console.log(theme.system(t('msg.opening_chat', { id })));
|
|
1613
1658
|
await browser.openChat(id);
|
|
@@ -1622,6 +1667,10 @@ async function main() {
|
|
|
1622
1667
|
catch (e) {
|
|
1623
1668
|
console.error(theme.error(t('msg.open_chat_error', { v: '' })), e.message);
|
|
1624
1669
|
}
|
|
1670
|
+
finally {
|
|
1671
|
+
if (editor)
|
|
1672
|
+
editor.unlock();
|
|
1673
|
+
}
|
|
1625
1674
|
continue;
|
|
1626
1675
|
}
|
|
1627
1676
|
if (lower === '/pwd') {
|
package/dist/input.js
CHANGED
|
@@ -207,6 +207,11 @@ export class LineEditor {
|
|
|
207
207
|
// Clipboard callback: tries to read an image from the OS clipboard when the
|
|
208
208
|
// terminal itself sends no usable data (Ctrl+V, right-click, empty paste).
|
|
209
209
|
onClipboard;
|
|
210
|
+
// When locked, the editor ignores text input and Enter (submit). Used while
|
|
211
|
+
// a long operation runs (chat resume/open, /new, self-review): otherwise the
|
|
212
|
+
// user could type and send a message mid-operation, and it would be queued
|
|
213
|
+
// and sent right after the operation, breaking the restored session.
|
|
214
|
+
locked;
|
|
210
215
|
constructor({ prompt = '> ', commands = [] } = {}) {
|
|
211
216
|
this.promptStr = prompt;
|
|
212
217
|
this.buf = '';
|
|
@@ -236,6 +241,7 @@ export class LineEditor {
|
|
|
236
241
|
this._tmpDir = '';
|
|
237
242
|
this.onAttach = null;
|
|
238
243
|
this.onClipboard = null;
|
|
244
|
+
this.locked = false;
|
|
239
245
|
}
|
|
240
246
|
// Read the OS clipboard for an image and insert its marker. Used when the
|
|
241
247
|
// terminal sends no usable paste data (Ctrl+V / right-click / empty paste).
|
|
@@ -333,6 +339,19 @@ export class LineEditor {
|
|
|
333
339
|
this._writeBlock();
|
|
334
340
|
this._render();
|
|
335
341
|
}
|
|
342
|
+
// Lock input while a long operation runs (chat resume/open, /new,
|
|
343
|
+
// self-review). The line stays visible but text input and Enter are ignored,
|
|
344
|
+
// so a message typed mid-operation is not queued and sent afterwards,
|
|
345
|
+
// breaking the restored session. Ctrl+C/Ctrl+D still work so the user can
|
|
346
|
+
// abort.
|
|
347
|
+
lock(status) {
|
|
348
|
+
this.locked = true;
|
|
349
|
+
if (status)
|
|
350
|
+
this.setStatus(theme.dim(status));
|
|
351
|
+
}
|
|
352
|
+
unlock() {
|
|
353
|
+
this.locked = false;
|
|
354
|
+
}
|
|
336
355
|
setPrompt(str) {
|
|
337
356
|
this.promptStr = str;
|
|
338
357
|
this._render();
|
|
@@ -481,6 +500,10 @@ export class LineEditor {
|
|
|
481
500
|
}
|
|
482
501
|
// ---------- input ----------
|
|
483
502
|
_submit() {
|
|
503
|
+
if (this.locked) {
|
|
504
|
+
this._render();
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
484
507
|
const display = this.buf;
|
|
485
508
|
if (!display.trim()) {
|
|
486
509
|
this._render();
|
|
@@ -716,6 +739,25 @@ export class LineEditor {
|
|
|
716
739
|
}
|
|
717
740
|
_handle(data) {
|
|
718
741
|
let s = data.toString('utf-8');
|
|
742
|
+
// While locked (a long operation is running), swallow all input except
|
|
743
|
+
// Ctrl+C / Ctrl+D — so the user can still abort, but cannot type a message
|
|
744
|
+
// that would be queued and sent after the operation.
|
|
745
|
+
if (this.locked) {
|
|
746
|
+
if (s.length === 1) {
|
|
747
|
+
const c = s.charCodeAt(0);
|
|
748
|
+
if (c === 3) {
|
|
749
|
+
if (this.onCtrlC)
|
|
750
|
+
this.onCtrlC();
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
if (c === 4) {
|
|
754
|
+
if (this.onCtrlC)
|
|
755
|
+
this.onCtrlC();
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
719
761
|
if (!this._inPaste && s === ESC) {
|
|
720
762
|
if (this.onEscape)
|
|
721
763
|
this.onEscape();
|