zames_pro 2.16.0 → 2.18.0

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/README.md CHANGED
@@ -9,7 +9,42 @@ directory, reads and edits files, runs commands, and commits to git.
9
9
  ## Requirements
10
10
 
11
11
  - Node.js >= 18
12
- - A DeepSeek account (you log in manually in the browser window that opens on first launch)
12
+ - A DeepSeek account. On first launch zames asks for your DeepSeek
13
+ login/password in the terminal (and stores them in `~/.zames/config.json`
14
+ after a successful sign-in, so a later logout is handled automatically
15
+ without asking you again). You can also sign in manually in the browser
16
+ window when the browser is headed.
17
+
18
+ ## Signing in
19
+
20
+ The browser runs **headless by default**. When DeepSeek requires a sign-in,
21
+ zames:
22
+
23
+ 1. reuses the session stored in the persistent profile (`~/.zames/profile`)
24
+ if it is still valid;
25
+ 2. otherwise signs in automatically with the saved credentials
26
+ (`browser.auth.username` / `browser.auth.password`);
27
+ 3. otherwise asks you for the login/password in the terminal (in a TTY) and,
28
+ after a successful sign-in, remembers them for next time;
29
+ 4. otherwise falls back to a manual sign-in hint.
30
+
31
+ To sign in by hand (for example, if DeepSeek shows a captcha), run with a
32
+ visible window:
33
+
34
+ ```bash
35
+ zames --headed
36
+ ```
37
+
38
+ The `--headless` flag (the default) and `headless: true` in the config keep
39
+ the browser without a window; `--headed` / `headless: false` show it.
40
+
41
+ Headless works out of the box: a headless Chrome normally advertises a
42
+ `HeadlessChrome/...` User-Agent that DeepSeek's CDN blocks with a 403, so
43
+ zames strips that marker before loading the page (keeping the real engine
44
+ version). You do not need `--headed` just to log in.
45
+
46
+ Credentials and toggles can also be edited from `/config`
47
+ (`browser.auth.username`, `browser.auth.password`, `browser.auth.saveSession`).
13
48
 
14
49
  ## Installation
15
50
 
@@ -71,6 +106,7 @@ zames --new-chat
71
106
  zames --resend-prompt
72
107
  zames --dir <path>
73
108
  zames --headless
109
+ zames --headed
74
110
  zames --debug
75
111
  zames --version
76
112
  zames --help
@@ -111,6 +147,9 @@ Codex CLI:
111
147
  alwaysConfirm regex list).
112
148
  - /add-dir <path> — validate an extra directory (the sandbox is fixed at
113
149
  startup; relaunch with --dir to write there).
150
+ - /resume <n> (after /chats) and /resume-id <id> — open a chat and PRINT its
151
+ dialogue into the terminal, so the restored context is visible. Only the
152
+ last 20 messages are shown (`RESTORED_HISTORY_LIMIT`).
114
153
  - /review [focus] [--staged] — ask the agent to review uncommitted changes
115
154
  and report findings (no code changes).
116
155
 
@@ -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 = () => { }, 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 = () => { }, 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
@@ -26,6 +26,10 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
26
26
  // Previously safeThinking() fired before browser.ask(), so the spinner ran
27
27
  // through the whole throttle pause / chat-open phase with nothing in flight.
28
28
  browser.onSendStart = safeThinking;
29
+ // Animate the send-interval pause too: the browser reports the remaining
30
+ // seconds, the UI shows an animated status instead of a frozen line.
31
+ const safeSendPause = safe(onSendPause);
32
+ browser.onSendPause = safeSendPause;
29
33
  const safeAssistantThought = safe(onAssistantThought);
30
34
  const safeToolCall = safe(onToolCall);
31
35
  const safeToolResult = safe(onToolResult);
@@ -125,6 +129,9 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
125
129
  let unparsedRetries = 0;
126
130
  const MAX_UNPARSED_RETRIES = 4;
127
131
  let finalRespondAsked = false;
132
+ // The operator is told ONCE that the agent is re-asking the model for a
133
+ // proper tool call (not on every retry — that would spam the terminal).
134
+ let toolRetryWarned = false;
128
135
  // Guard against "the agent stalled": DeepSeek sometimes sends a final text
129
136
  // that merely DESCRIBES the next tool call (or cuts the answer off
130
137
  // mid-word), and the agent silently finishes the task even though the work
@@ -203,9 +210,9 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
203
210
  attempt: afterToolRetries,
204
211
  error: e.message,
205
212
  });
206
- safeWarning('browser.ask() did not return an answer within ' +
207
- Math.round(askDeadlineMs / 1000) +
208
- 's — retrying the request.');
213
+ safeWarning(translate(locale)('ds.answer_timeout', {
214
+ sec: Math.round(askDeadlineMs / 1000),
215
+ }));
209
216
  if (afterToolRetries < MAX_AFTER_TOOL_RETRIES) {
210
217
  afterToolRetries++;
211
218
  await new Promise((r) => setTimeout(r, 1500));
@@ -214,8 +221,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
214
221
  transcript?.log('ask_timeout_exhausted', {
215
222
  message: 'ask() did not return an answer and the retry limit is exhausted',
216
223
  });
217
- safeWarning('browser.ask() stopped responding; retry limit exhausted, ' +
218
- 'stopping. No model answer — check the DeepSeek chat manually.');
224
+ safeWarning(translate(locale)('ds.answer_timeout_give_up'));
219
225
  return 'ask() watchdog: no model answer received';
220
226
  }
221
227
  await reportChat();
@@ -398,6 +404,16 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
398
404
  attempt: unparsedRetries,
399
405
  response: rawResponse.slice(0, 500),
400
406
  });
407
+ // Tell the operator WHY nothing is happening: the model wrote text
408
+ // instead of a tool call and the agent is asking it to continue. Only
409
+ // once per task, otherwise the retry budget spams the terminal.
410
+ if (!toolRetryWarned) {
411
+ toolRetryWarned = true;
412
+ safeWarning(translate(locale)('ds.tool_retry', {
413
+ attempt: unparsedRetries,
414
+ max: MAX_UNPARSED_RETRIES,
415
+ }));
416
+ }
401
417
  message =
402
418
  (justRanTool
403
419
  ? 'You stopped after a tool call and wrote plain text. '