zames_pro 2.10.0 → 2.10.2

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/agent-loop.js +36 -13
  2. package/package.json +1 -1
@@ -3,6 +3,27 @@ import { getGitContext, formatGitContext } from './gitTools.js';
3
3
  import { parseXmlToolCalls } from './xml-toolcall.js';
4
4
  import { translate } from './i18n.js';
5
5
  export async function runAgentLoop({ browser, tools, task, workdir, maxIterations = 40, freshChat = false, sendSystemPrompt = false, transcript = null, attachments = [], onThinking = () => { }, onAssistantThought = () => { }, onToolCall = () => { }, onToolResult = () => { }, onAssistantMessage = () => { }, onChatReady = () => { }, onWarning = () => { }, debugLog = false, locale = 'ru', }) {
6
+ // UI callbacks must NEVER break the agent loop. A rendering error (a huge
7
+ // tool result, a broken markdown frame, a closed terminal) used to throw
8
+ // out of the loop right after a tool call — the session looked "stopped
9
+ // after a tool call", with a tool_call but no tool_result in the log. We
10
+ // wrap every callback so a UI failure is swallowed and the loop continues.
11
+ const safe = (fn) => {
12
+ return (...a) => {
13
+ try {
14
+ fn(...a);
15
+ }
16
+ catch {
17
+ // Intentionally ignored: the loop must survive UI failures.
18
+ }
19
+ };
20
+ };
21
+ const safeThinking = safe(onThinking);
22
+ const safeAssistantThought = safe(onAssistantThought);
23
+ const safeToolCall = safe(onToolCall);
24
+ const safeToolResult = safe(onToolResult);
25
+ const safeAssistantMessage = safe(onAssistantMessage);
26
+ const safeWarning = safe(onWarning);
6
27
  if (freshChat) {
7
28
  await browser.newChat();
8
29
  transcript?.log('new_chat');
@@ -42,7 +63,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
42
63
  length: systemPrompt.length,
43
64
  gitContext: gitText,
44
65
  });
45
- onThinking();
66
+ safeThinking();
46
67
  // system-prompt is an agent send: throttled (agent: true).
47
68
  await browser.ask(systemPrompt, { timeout: 60_000, agent: true });
48
69
  await reportChat();
@@ -104,7 +125,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
104
125
  let afterToolRetries = 0;
105
126
  const MAX_AFTER_TOOL_RETRIES = 6;
106
127
  for (let i = 0; i < maxIterations; i++) {
107
- onThinking();
128
+ safeThinking();
108
129
  // The first message (task) is user input: no throttle.
109
130
  // Subsequent ones (tool-result and resend requests) are agent sends:
110
131
  // throttled so we don't hit the rate limit.
@@ -139,7 +160,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
139
160
  attempt: afterToolRetries,
140
161
  error: e.message,
141
162
  });
142
- onWarning('browser.ask() не вернул ответ за ' +
163
+ safeWarning('browser.ask() не вернул ответ за ' +
143
164
  Math.round(askDeadlineMs / 1000) +
144
165
  'с — повторяю запрос.');
145
166
  if (afterToolRetries < MAX_AFTER_TOOL_RETRIES) {
@@ -150,7 +171,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
150
171
  transcript?.log('ask_timeout_exhausted', {
151
172
  message: 'ask() не вернул ответ и лимит повторов исчерпан',
152
173
  });
153
- onWarning('browser.ask() перестал отвечать; лимит повторов исчерпан, ' +
174
+ safeWarning('browser.ask() перестал отвечать; лимит повторов исчерпан, ' +
154
175
  'останавливаюсь. Ответа модели нет — проверьте чат DeepSeek вручную.');
155
176
  return 'ask() watchdog: ответ модели не получен';
156
177
  }
@@ -205,7 +226,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
205
226
  if (parsed) {
206
227
  const thought = extractPreToolText(rawResponse);
207
228
  if (thought)
208
- onAssistantThought(thought);
229
+ safeAssistantThought(thought);
209
230
  }
210
231
  const parsedCalls = Array.isArray(parsed) ? parsed : parsed ? [parsed] : [];
211
232
  if (parsedCalls.some((p) => p && p._permissive)) {
@@ -334,12 +355,14 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
334
355
  continue;
335
356
  }
336
357
  const suspiciousFinal = responseLooksLikeToolCall(rawResponse) ||
358
+ looksLikeUnfinishedWork((rawResponse || '').trim()) ||
337
359
  !(rawResponse || '').trim();
338
360
  if (suspiciousFinal) {
339
- // The answer LOOKS like a call (or is empty) but could not be parsed
340
- // even after all retries: warn the operator.
361
+ // The answer LOOKS like a call / promises work / is empty, but could
362
+ // not be turned into a tool call even after all retries: warn the
363
+ // operator instead of silently printing e.g. "Stale. Let me verify".
341
364
  transcript?.log('suspicious_final', { response: rawResponse });
342
- onWarning(translate(locale)('msg.suspicious_stop'));
365
+ safeWarning(translate(locale)('msg.suspicious_stop'));
343
366
  }
344
367
  // A meaningful plain-text answer (e.g. a final report the model forgot to
345
368
  // wrap in respond) is surfaced as-is WITHOUT a warning: after the bounded
@@ -391,11 +414,11 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
391
414
  // the task normally.
392
415
  if (!isMeaningfulRespond(msg)) {
393
416
  transcript?.log('empty_respond_exhausted', { response: rawResponse });
394
- onWarning('Модель вызвала respond без текста, и лимит повторов исчерпан. ' +
417
+ safeWarning('Модель вызвала respond без текста, и лимит повторов исчерпан. ' +
395
418
  'Проверьте чат DeepSeek вручную.');
396
419
  return 'Модель не сформировала итоговое сообщение (пустой respond).';
397
420
  }
398
- onAssistantMessage(msg);
421
+ safeAssistantMessage(msg);
399
422
  transcript?.log('assistant_final', { message: msg });
400
423
  return msg;
401
424
  }
@@ -408,12 +431,12 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
408
431
  const tool = tools.find((t) => t.name === call.tool);
409
432
  if (!tool) {
410
433
  const err = `Неизвестный инструмент: ${call.tool}`;
411
- onToolResult(err);
434
+ safeToolResult(err);
412
435
  transcript?.log('tool_error', { tool: call.tool, error: err });
413
436
  results.push({ tool: call.tool, result: err });
414
437
  continue;
415
438
  }
416
- onToolCall(call.tool, call.args);
439
+ safeToolCall(call.tool, call.args);
417
440
  transcript?.log('tool_call', { tool: call.tool, args: call.args });
418
441
  let result;
419
442
  try {
@@ -422,7 +445,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
422
445
  catch (e) {
423
446
  result = `Ошибка: ${e.message}`;
424
447
  }
425
- onToolResult(result);
448
+ safeToolResult(result);
426
449
  transcript?.log('tool_result', {
427
450
  tool: call.tool,
428
451
  result: String(result),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.10.0",
3
+ "version": "2.10.2",
4
4
  "description": "Terminal coding agent over chat.deepseek.com via Playwright",
5
5
  "type": "module",
6
6
  "bin": {