zames_pro 2.80.5 → 2.81.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/dist/glm-ui.js ADDED
@@ -0,0 +1,171 @@
1
+ // GLM (chat.z.ai) UI constants - the SINGLE place where the z.ai web app's
2
+ // specifics live (mirrors qwen-ui.ts / deepseek-ui.ts).
3
+ //
4
+ // WHY a data module: zames drives the site through Playwright, so every
5
+ // selector and protocol marker is a hardcoded assumption about a page we do
6
+ // not control. Concentrating them here turns "z.ai redesigned the UI" into ONE
7
+ // file to audit and lets probeUiHealth name the exact broken capability.
8
+ //
9
+ // EVERY value below was verified against a LIVE signed-in session (Chromium,
10
+ // October 2026); the raw fixtures live in test/fixtures/glm/. Values marked
11
+ // "not observed" are deliberately NOT implemented - the recon dump had no
12
+ // trace of them.
13
+ //
14
+ // What the recon showed:
15
+ // home -> https://chat.z.ai/
16
+ // chat url -> /c/<uuid>
17
+ // input -> textarea#chat-input (a plain <textarea>)
18
+ // send -> button#send-message-button (type=submit)
19
+ // new chat -> button#sidebar-new-chat-button, #new-chat-button (mobile)
20
+ // model -> button#model-selector-<id>-button (label = display name)
21
+ // stop -> no dedicated id was observed; Escape is the interrupt
22
+ // answer -> div.chat-assistant (markdown-prose); user: div.chat-user;
23
+ // reasoning lives in .thinking-chain-container
24
+ // send flow -> POST /api/v1/chats/new (creates the chat), then
25
+ // POST /api/v2/chat/completions?... (SSE)
26
+ // history -> GET /api/v1/chats/?page=N and GET /api/v1/chats/<id>
27
+ // models -> GET /api/models (OpenAI-style {data:[{id,name,info}]})
28
+ // user -> GET /api/v1/auths/ ({email, role: 'guest' | 'user', token})
29
+ //
30
+ // IMPORTANT (captcha): the first message from a fresh profile is gated by an
31
+ // Aliyun slider captcha that a headless browser cannot pass. That is why login
32
+ // is browser-based (src/browser-login.ts) and why a long agent run needs a
33
+ // REAL session.
34
+ // ---------- endpoints ----------
35
+ export const CHAT_URL = 'https://chat.z.ai/';
36
+ export const LOGIN_URL = 'https://chat.z.ai/auth';
37
+ // A real chat lives at /c/<uuid>; the bare home page has no id yet.
38
+ export const CHAT_ID_RE = /\/c\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i;
39
+ export function chatUrl(id) {
40
+ return CHAT_URL + 'c/' + id;
41
+ }
42
+ /** GET - the OpenAI-style model catalogue. */
43
+ export const MODELS_URL = 'https://chat.z.ai/api/models';
44
+ /** GET - the sidebar chat list (newest first). */
45
+ export const CHAT_LIST_URL = 'https://chat.z.ai/api/v1/chats/?page=1';
46
+ /** GET - one chat with its full message tree. */
47
+ export function chatHistoryUrl(chatId) {
48
+ return 'https://chat.z.ai/api/v1/chats/' + encodeURIComponent(chatId);
49
+ }
50
+ /** GET - the current user (or guest) record. */
51
+ export const AUTH_URL = 'https://chat.z.ai/api/v1/auths/';
52
+ /** POST - creates a chat and returns { id }. */
53
+ export const NEW_CHAT_URL = 'https://chat.z.ai/api/v1/chats/new';
54
+ /** POST - the SSE completion endpoint (the answer stream). */
55
+ export const ANSWER_URL_RE = /\/api\/v2\/chat\/completions/i;
56
+ // ---------- input ----------
57
+ export const INPUT_SELECTORS = [
58
+ 'textarea#chat-input',
59
+ 'textarea[placeholder]',
60
+ 'textarea',
61
+ 'div[contenteditable="true"]',
62
+ '[role="textbox"]',
63
+ ];
64
+ // ---------- send ----------
65
+ export const SEND_SELECTORS = [
66
+ 'button#send-message-button',
67
+ 'button.sendMessageButton',
68
+ 'button[type="submit"]',
69
+ ];
70
+ // ---------- stop ----------
71
+ // No dedicated stop id was observed: z.ai swaps the send button's icon and
72
+ // disables the input while generating. A dedicated button is still probed (a
73
+ // future build may add one); Escape is the fallback that works today.
74
+ export const STOP_SELECTORS = [
75
+ 'button#stop-generating-button',
76
+ 'button[aria-label*="stop" i]',
77
+ 'button[aria-label*="останов" i]',
78
+ ];
79
+ export const STOP_NAME_RE = /^(?:stop|остановить)(?:\s+\S{0,20})?\s*[.!…]?$/i;
80
+ // ---------- new chat ----------
81
+ export const NEW_CHAT_SELECTOR = 'button#sidebar-new-chat-button, button#new-chat-button';
82
+ // ---------- model selector ----------
83
+ // The header button carries the model id in its OWN id and the display name in
84
+ // its label: button#model-selector-<id>-button -> "GLM-5.3-Flash".
85
+ export const MODEL_TRIGGER_SELECTOR = 'button[id^="model-selector-"]';
86
+ /** The model id embedded in the trigger's id (`model-selector-<id>-button`). */
87
+ export function modelIdFromTriggerId(id) {
88
+ const m = String(id || '').match(/^model-selector-(.+)-button$/);
89
+ return m ? m[1] : '';
90
+ }
91
+ // ---------- messages / answers ----------
92
+ // The assistant turn is div.chat-assistant (markdown-prose); a user turn is
93
+ // div.chat-user. A message WRAPPER carries id="message-<uuid>" on both.
94
+ export const ANSWER_SELECTORS = ['.chat-assistant', '.markdown-prose'];
95
+ // Reasoning blocks (the "Thought Process" chain) must never be read as the
96
+ // answer.
97
+ export const THINK_CLASS_RE = /thinking-chain|thought|reason/i;
98
+ export const MESSAGE_CONTAINER_SELECTORS = [
99
+ '[id^="message-"]',
100
+ '.chat-user',
101
+ '.chat-assistant',
102
+ ];
103
+ export const USER_CLASS_RE = /chat-user|user-message/i;
104
+ export const ASSISTANT_CLASS_RE = /chat-assistant|markdown-prose/i;
105
+ // A cheap "did the page grow?" signal.
106
+ export const CHAT_SIGNAL_NODES_SELECTOR = '[id^="message-"], .chat-user, .chat-assistant';
107
+ export const MARKDOWN_SELECTOR = '.chat-assistant, .markdown-prose';
108
+ // ---------- context windows ----------
109
+ // GLM windows are PER-MODEL and reported by GET /api/models
110
+ // (`info.params.max_tokens` when present). The table is the fallback for a
111
+ // model whose catalogue entry carries no explicit value, ordered MOST SPECIFIC
112
+ // first. Values come from the live catalogue snapshot (test/fixtures/glm/).
113
+ const CONTEXT_WINDOWS = [
114
+ // The DEFAULT chat model's internal id is `x-preview-l` (label
115
+ // GLM-5.3-Flash), so the id and the label are matched separately.
116
+ [/xpreviewl/, 128_000],
117
+ [/glm5\.?3flash/, 128_000],
118
+ [/glm5\.?3/, 128_000],
119
+ [/glm5\.?2/, 64_064],
120
+ [/glm5vturbo/, 128_000],
121
+ [/glm5turbo/, 32_000],
122
+ [/glm47/, 40_000],
123
+ [/glm46v/, 16_000],
124
+ [/glm45air/, 80_000],
125
+ [/glm45/, 80_000],
126
+ ];
127
+ /** Lowercase and drop every non-alphanumeric so `glm-5.3` -> `glm53`. */
128
+ export function normalizeGlmModelId(model) {
129
+ return String(model || '')
130
+ .toLowerCase()
131
+ .replace(/[^a-z0-9]/g, '');
132
+ }
133
+ /** The context window (tokens) for a GLM model id, or null when unknown. */
134
+ export function glmContextWindow(model) {
135
+ const id = normalizeGlmModelId(model);
136
+ if (!id)
137
+ return null;
138
+ for (const [re, window] of CONTEXT_WINDOWS) {
139
+ if (re.test(id))
140
+ return window;
141
+ }
142
+ return null;
143
+ }
144
+ // ---------- service statuses / errors ----------
145
+ // A placeholder that must never be taken for an answer.
146
+ export const STATUS_RE = /^(thinking|generating|thinking\s+process|thought\s+process)[\s.…]*$/i;
147
+ // z.ai's captcha gate (an Aliyun slider). Visible text on the modal.
148
+ export const CAPTCHA_RE = /security verification|drag the slider/i;
149
+ export const CAPTCHA_SELECTORS = [
150
+ '.aliyun-captcha',
151
+ '[class*="aliyunCaptcha"]',
152
+ '[id*="aliyunCaptcha"]',
153
+ ];
154
+ // Rate limit / busy notices. Kept NARROW: the classifier additionally requires
155
+ // an error payload or an answer-less body (same rule as qwen-net-capture.ts),
156
+ // so a normal answer that merely mentions "try again" is not mistaken for a
157
+ // limit.
158
+ export const RATE_LIMIT_RE = /too many requests|rate limit|too frequent|please try again later|слишком часто/i;
159
+ export const SERVER_BUSY_RE = /server is busy|service unavailable|try again later|high demand/i;
160
+ export const GUEST_LIMIT_RE = /guest.*limit|log ?in to continue|sign ?in to continue|гостевой лимит/i;
161
+ // ---------- mode flags ----------
162
+ // The completion body carries the mode flags. `preview_mode` and the
163
+ // `general_agent` flag change the ANSWER FORMAT (they enable z.ai's own agent
164
+ // runtime, which emits its own tool calls), and that would break the zames
165
+ // tool-call protocol. The provider asserts the safe values on every send; the
166
+ // request body is verified per chat (see glm-net-capture.ts).
167
+ export const SAFE_PREVIEW_MODE = false;
168
+ export const SAFE_ENABLE_THINKING = true;
169
+ // ---------- attachments ----------
170
+ // The observed upload control (a real filechooser on click).
171
+ export const UPLOAD_BUTTON_SELECTOR = '#upload-file-button, button[class*="upload"]';
@@ -89,8 +89,24 @@ export const commonMessages = {
89
89
  en: 'Interactive mode. Enter a task. Commands — /help. Exit — /exit.',
90
90
  },
91
91
  'msg.first_login_hint': {
92
- ru: 'Сохранённой сессии DeepSeek нет — при первом запросе потребуется вход (логин/пароль спросят в терминале или открой --headed).',
93
- en: 'No saved DeepSeek session — the first task will need a sign-in (login/password are asked in the terminal, or use --headed).',
92
+ ru: 'Сохранённой сессии {provider} нет — при первом запросе потребуется вход: откроется окно браузера, войдите в нём (капчу решает человек), затем zames вернётся в headless.',
93
+ en: 'No saved {provider} session — the first task will need a sign-in: a browser window opens, sign in there (a human solves the captcha), then zames returns to headless.',
94
+ },
95
+ 'login.browser_prompt': {
96
+ ru: '🔐 {provider}: войдите в открывшемся окне браузера. Как только вход завершится, zames продолжит сам (Esc — отмена).',
97
+ en: '🔐 {provider}: sign in in the opened browser window. As soon as the sign-in completes, zames continues on its own (Esc — cancel).',
98
+ },
99
+ 'login.window_closed': {
100
+ ru: 'Окно входа закрыто — продолжаю.',
101
+ en: 'The login window was closed — continuing.',
102
+ },
103
+ 'login.timeout': {
104
+ ru: 'Вход через окно браузера не завершился за отведённое время. Войдите вручную и повторите /provider login.',
105
+ en: 'The browser-window sign-in did not complete in time. Sign in manually and retry /provider login.',
106
+ },
107
+ 'login.headless_failed': {
108
+ ru: 'Вход не перенёсся в headless-режим — остаюсь в видимом окне (его можно свернуть).',
109
+ en: 'The sign-in did not carry over to headless — staying in the visible window (it can be minimised).',
94
110
  },
95
111
  'msg.first_hint': {
96
112
  ru: 'Подсказка: «/» — список команд, Ctrl+R — поиск по истории, картинку можно вставить через Ctrl+Shift+V.',
@@ -5,12 +5,36 @@ export const configMessages = {
5
5
  'cfg.group.undo': { ru: 'Откат (undo)', en: 'Undo' },
6
6
  'cfg.group.checkpoint': { ru: 'Чекпойнты', en: 'Checkpoints' },
7
7
  'cfg.group.transcript': { ru: 'Транскрипт', en: 'Transcript' },
8
- 'cfg.group.browser': { ru: 'Браузер / DeepSeek', en: 'Browser / DeepSeek' },
8
+ 'cfg.group.browser': { ru: 'Браузер / чат', en: 'Browser / chat' },
9
9
  'cfg.f.provider': { ru: 'Провайдер чата', en: 'Chat provider' },
10
10
  'cfg.f.qwen_model': {
11
11
  ru: 'Модель Qwen (id)',
12
12
  en: 'Qwen model (id)',
13
13
  },
14
+ 'cfg.f.glm_model': {
15
+ ru: 'Модель GLM (id)',
16
+ en: 'GLM model (id)',
17
+ },
18
+ 'cfg.f.glm_contextLimit': {
19
+ ru: 'GLM: размер контекста, токены',
20
+ en: 'GLM: context window, tokens',
21
+ },
22
+ 'cfg.f.glm_minSendIntervalMs': {
23
+ ru: 'GLM: пауза между отправками (мс, 0 = адаптивно)',
24
+ en: 'GLM: pause between sends (ms, 0 = adaptive)',
25
+ },
26
+ 'cfg.f.glm_answerTimeoutMs': {
27
+ ru: 'GLM: таймаут ответа (мс)',
28
+ en: 'GLM: answer timeout (ms)',
29
+ },
30
+ 'cfg.f.browser_sendTelemetry': {
31
+ ru: 'Писать телеметрию отправок (пауза, флаги, исход; без промптов)',
32
+ en: 'Write send telemetry (pause, flags, outcome; no prompts)',
33
+ },
34
+ 'cfg.f.browser_loginTimeoutMs': {
35
+ ru: 'Сколько ждать входа в окне браузера (мс)',
36
+ en: 'How long to wait for a browser sign-in (ms)',
37
+ },
14
38
  'cfg.f.qwen_contextLimit': {
15
39
  ru: 'Qwen: размер контекста, токены (258K у Qwen3-Max, 1M у 3.7/3.8/Coder)',
16
40
  en: 'Qwen: context window, tokens (258K on Qwen3-Max, 1M on 3.7/3.8/Coder)',
@@ -172,6 +196,22 @@ export const configMessages = {
172
196
  ru: 'Пароль DeepSeek для авто-входа',
173
197
  en: 'DeepSeek password for auto sign-in',
174
198
  },
199
+ 'cfg.f.qwen_authUsername': {
200
+ ru: 'Логин Qwen для авто-входа',
201
+ en: 'Qwen login for auto sign-in',
202
+ },
203
+ 'cfg.f.qwen_authPassword': {
204
+ ru: 'Пароль Qwen для авто-входа',
205
+ en: 'Qwen password for auto sign-in',
206
+ },
207
+ 'cfg.f.glm_authUsername': {
208
+ ru: 'Логин GLM для авто-входа',
209
+ en: 'GLM login for auto sign-in',
210
+ },
211
+ 'cfg.f.glm_authPassword': {
212
+ ru: 'Пароль GLM для авто-входа',
213
+ en: 'GLM password for auto sign-in',
214
+ },
175
215
  'cfg.f.browser_authSaveSession': {
176
216
  ru: 'Сохранять сессию входа в профиле',
177
217
  en: 'Persist the login session in the profile',
@@ -46,17 +46,22 @@ export const doctorMessages = {
46
46
  ru: 'часть элементов не найдена: {v} (агент может работать некорректно)',
47
47
  en: 'some elements not found: {v} (the agent may misbehave)',
48
48
  },
49
+ 'doctor.display': { ru: '{v}', en: '{v}' },
50
+ 'doctor.adaptive_pause': {
51
+ ru: 'адаптивная пауза, текущий интервал {n}с',
52
+ en: 'adaptive pause, current interval {n}s',
53
+ },
49
54
  'doctor.ui_broken': {
50
- ru: 'НЕ найдено критичное: {v} — DeepSeek сменил вёрстку, задачи не будут отправляться. Запусти /debug-dom.',
51
- en: 'MISSING critical: {v} — DeepSeek changed the markup, tasks will not send. Run /debug-dom.',
55
+ ru: 'НЕ найдено критичное: {v} — {provider} сменил вёрстку, задачи не будут отправляться. Запусти /debug-dom.',
56
+ en: 'MISSING critical: {v} — {provider} changed the markup, tasks will not send. Run /debug-dom.',
52
57
  },
53
58
  'ui.probe_failed': {
54
- ru: '⚠ DeepSeek UI: не найдено критичное ({v}) — возможно, сменилась вёрстка chat.deepseek.com. Задачи могут не отправляться; проверь /doctor и /debug-dom.',
55
- en: '⚠ DeepSeek UI: missing critical element(s) ({v}) — chat.deepseek.com markup may have changed. Tasks may not send; check /doctor and /debug-dom.',
59
+ ru: '⚠ {provider} UI: не найдено критичное ({v}) — возможно, сменилась вёрстка. Задачи могут не отправляться; проверь /doctor и /debug-dom.',
60
+ en: '⚠ {provider} UI: missing critical element(s) ({v}) — the page markup may have changed. Tasks may not send; check /doctor and /debug-dom.',
56
61
  },
57
62
  'ui.probe_degraded': {
58
- ru: '⚠ DeepSeek UI: не найдено ({v}) — часть возможностей (тумблеры/новый чат) может не работать.',
59
- en: '⚠ DeepSeek UI: not found ({v}) — some features (toggles/new chat) may not work.',
63
+ ru: '⚠ {provider} UI: не найдено ({v}) — часть возможностей (тумблеры/новый чат) может не работать.',
64
+ en: '⚠ {provider} UI: not found ({v}) — some features (toggles/new chat) may not work.',
60
65
  },
61
66
  'adddir.usage': {
62
67
  ru: 'Использование: /add-dir <path>',
@@ -0,0 +1,86 @@
1
+ // GLM (chat.z.ai) provider messages — everything the operator sees while the
2
+ // active backend is GLM. Kept in its own section file (like qwen.ts /
3
+ // deepseek.ts) so provider-specific wording has one home. The generic
4
+ // `model.*` / `provider.*` keys live in i18n/help.ts and i18n/qwen.ts.
5
+ export const glmMessages = {
6
+ 'glm.guest_mode': {
7
+ ru: 'GLM: вход не выполнен, работаю гостем (сообщения может блокировать капча). Войдите через /provider login или запустите с --headed.',
8
+ en: 'GLM: not signed in, running as a guest (a captcha may block messages). Log in via /provider login or launch with --headed.',
9
+ },
10
+ 'glm.login_ok': {
11
+ ru: 'GLM: вход выполнен.',
12
+ en: 'GLM: signed in.',
13
+ },
14
+ 'glm.captcha': {
15
+ ru: '✖ GLM показывает проверку «security verification» (капча-слайдер) и не отправляет сообщение. Войдите в аккаунт: /provider login (в видимом окне капчу решает человек).',
16
+ en: '✖ GLM shows a "security verification" slider captcha and blocks the send. Sign in with /provider login (a human solves the captcha in the visible window).',
17
+ },
18
+ 'glm.restart_browser': {
19
+ ru: '⚠ GLM: страница браузера потеряна — перезапускаю и вхожу заново...',
20
+ en: '⚠ GLM: the browser lost the page — restarting and signing in again...',
21
+ },
22
+ 'glm.restart_failed': {
23
+ ru: '⚠ GLM: не удалось перезапустить браузер: {error}',
24
+ en: '⚠ GLM: could not restart the browser: {error}',
25
+ },
26
+ 'glm.model_error': {
27
+ ru: 'Не удалось получить список моделей GLM: {v}',
28
+ en: 'Failed to fetch the GLM model list: {v}',
29
+ },
30
+ 'glm.rate_limit_wait': {
31
+ ru: '⏳ {provider}: «слишком часто». Жду {min} мин ({attempt}/{max}) и повторю отправку...',
32
+ en: '⏳ {provider}: "too frequent". Waiting {min} min ({attempt}/{max}), then resending...',
33
+ },
34
+ 'glm.server_busy_wait': {
35
+ ru: '⏳ {provider}: сервер занят. Жду {sec}с ({attempt}/{max}) и повторю...',
36
+ en: '⏳ {provider}: server busy. Waiting {sec}s ({attempt}/{max}), then retrying...',
37
+ },
38
+ 'glm.incomplete_retry': {
39
+ ru: '⏳ {provider} оборвал ответ — переотправляю задачу ({attempt}/{max})...',
40
+ en: '⏳ {provider} truncated the answer — resending the task ({attempt}/{max})...',
41
+ },
42
+ 'glm.ask_retry': {
43
+ ru: '⚠ Отправка не удалась (попытка {attempt}/{max} на этот запрос): {error} — повторяю...',
44
+ en: '⚠ Send failed (attempt {attempt}/{max} for this request): {error} — retrying...',
45
+ },
46
+ 'glm.ask_failed': {
47
+ ru: '✖ Не удалось получить ответ от {provider} после {max} попыток: {error}',
48
+ en: '✖ Could not get an answer from {provider} after {max} attempts: {error}',
49
+ },
50
+ 'glm.attach_read_failed': {
51
+ ru: '⚠ не удалось прочитать вложение {name}: {error}',
52
+ en: '⚠ could not read the attachment {name}: {error}',
53
+ },
54
+ 'glm.attach_no_input': {
55
+ ru: '⚠ не найдено поле загрузки файлов — вложения не прикреплены',
56
+ en: '⚠ file upload field not found — the attachments were not attached',
57
+ },
58
+ 'glm.input_missing': {
59
+ ru: '✖ Не найдено поле ввода на странице {provider}. Запусти /debug-dom и поправь INPUT_SELECTORS.',
60
+ en: '✖ The {provider} input field was not found. Run /debug-dom and fix INPUT_SELECTORS.',
61
+ },
62
+ 'glm.send_no_new_answer': {
63
+ ru: '✖ Новый ответ не получен — на странице остался прежний текст. Проверь чат {provider} вручную.',
64
+ en: '✖ No new answer received — the page still shows the previous text. Check the {provider} chat manually.',
65
+ },
66
+ 'glm.page_busy': {
67
+ ru: '✖ GLM всё ещё генерирует ответ (страница занята) — отправка невозможна. Это не сломанная кнопка: дождитесь конца хода или нажмите Stop в окне.',
68
+ en: '✖ GLM is still generating (the page is busy) — the message cannot be sent. This is not a broken button: wait for the turn to finish or press Stop in the window.',
69
+ },
70
+ 'glm.send_button_missing': {
71
+ ru: '✖ Кнопка отправки GLM не найдена или недоступна — сообщение не отправлено. Проверь чат вручную.',
72
+ en: '✖ The GLM send button was not found or is disabled — the message was not sent. Check the chat manually.',
73
+ },
74
+ 'glm.quota_exhausted': {
75
+ ru: '✖ У аккаунта z.ai исчерпана квота (insufficient_quota). Это лимит аккаунта, а не пауза: пополните квоту или дождитесь сброса, повторы не помогут.',
76
+ en: '✖ The z.ai account quota is exhausted (insufficient_quota). This is an account limit, not a pause: top up or wait for the reset; retrying will not help.',
77
+ },
78
+ 'glm.mode_flags': {
79
+ ru: '⚠ GLM: в теле запроса включён режим {v} — он меняет формат ответа и может сломать протокол tool-call.',
80
+ en: '⚠ GLM: the request body has {v} enabled — it changes the answer format and may break the tool-call protocol.',
81
+ },
82
+ 'glm.mode_mismatch': {
83
+ ru: '⚠ GLM: сайт не применил ваши настройки режима ({v}) — ответ может прийти без размышлений/поиска.',
84
+ en: '⚠ GLM: the site did not apply your mode setting ({v}) — the answer may come without thinking/search.',
85
+ },
86
+ };
package/dist/i18n/help.js CHANGED
@@ -39,8 +39,8 @@ export const helpMessages = {
39
39
  en: 'show the browser window (debug/sign-in)',
40
40
  },
41
41
  'help.opt.provider': {
42
- ru: 'выбрать провайдера чата (deepseek | qwen) на этот запуск',
43
- en: 'select the chat provider (deepseek | qwen) for this run',
42
+ ru: 'выбрать провайдера чата (deepseek | qwen | glm) на этот запуск',
43
+ en: 'select the chat provider (deepseek | qwen | glm) for this run',
44
44
  },
45
45
  'help.opt.debug': { ru: 'подробный лог', en: 'verbose log' },
46
46
  'help.opt.dev': {
@@ -130,8 +130,8 @@ export const helpMessages = {
130
130
  en: '/resume-id <id> resume a session by full id',
131
131
  },
132
132
  'help.cmd.chats': {
133
- ru: '/chats [фильтр] список последних чатов DeepSeek',
134
- en: '/chats [filter] recent DeepSeek chats',
133
+ ru: '/chats [фильтр] список последних чатов провайдера',
134
+ en: '/chats [filter] recent chats of the active provider',
135
135
  },
136
136
  'help.cmd.last': {
137
137
  ru: '/last открыть последний чат этого каталога',
@@ -202,6 +202,10 @@ export const helpMessages = {
202
202
  en: '/copy copy the last answer to the clipboard',
203
203
  },
204
204
  'help.cmd.cost': { ru: '/cost статистика сессии', en: '/cost session stats' },
205
+ 'help.cmd.limits': {
206
+ ru: '/limits телеметрия отправок и текущая пауза',
207
+ en: '/limits send telemetry and the current pause',
208
+ },
205
209
  'help.cmd.export': {
206
210
  ru: '/export [file] выгрузить сессию в Markdown',
207
211
  en: '/export [file] export the session to Markdown',
@@ -407,8 +411,8 @@ export const helpMessages = {
407
411
  en: '🗜️ Compaction did not open a fresh chat (same id) — disabling auto-compact for the rest of the task to avoid a loop.',
408
412
  },
409
413
  'compact.start': {
410
- ru: '🗜️ Сжимаю историю чата (DeepSeek)...',
411
- en: '🗜️ Compacting the chat history (DeepSeek)...',
414
+ ru: '🗜️ Сжимаю историю чата ({provider})...',
415
+ en: '🗜️ Compacting the chat history ({provider})...',
412
416
  },
413
417
  'compact.summary_failed': {
414
418
  ru: 'Не удалось получить резюме от модели: {v}',
@@ -457,12 +461,12 @@ export const helpMessages = {
457
461
  en: '/config lang <ru|en> switch UI and agent language',
458
462
  },
459
463
  'help.cmd.provider': {
460
- ru: '/provider <deepseek|qwen> переключить провайдера чата',
461
- en: '/provider <deepseek|qwen> switch the chat provider',
464
+ ru: '/provider <id> переключить провайдера чата',
465
+ en: '/provider <id> switch the chat provider',
462
466
  },
463
467
  'help.cmd.model': {
464
- ru: '/model [id] показать/выбрать модель Qwen',
465
- en: '/model [id] show/pick the Qwen model',
468
+ ru: '/model [id] показать/выбрать модель провайдера',
469
+ en: '/model [id] show/pick the provider model',
466
470
  },
467
471
  'help.cmd.debug_dom': {
468
472
  ru: '/debug-dom сохранить HTML страницы (для отладки)',
package/dist/i18n/qwen.js CHANGED
@@ -34,30 +34,62 @@ export const qwenMessages = {
34
34
  ru: '⚠ Qwen: не удалось перезапустить браузер: {error}',
35
35
  en: '⚠ Qwen: could not restart the browser: {error}',
36
36
  },
37
- 'qwen.model_set': {
38
- ru: 'Модель Qwen: {v}',
39
- en: 'Qwen model: {v}',
37
+ // Generic model-picker wording shared by every provider that HAS a picker
38
+ // (Qwen, GLM). The old `qwen.model_*` keys hardcoded "Qwen" and made the
39
+ // command look Qwen-only.
40
+ 'model.set': {
41
+ ru: 'Модель {provider}: {v}',
42
+ en: '{provider} model: {v}',
40
43
  },
41
- 'qwen.model_list': {
42
- ru: 'Доступные модели Qwen:\n{v}',
43
- en: 'Available Qwen models:\n{v}',
44
+ 'model.list': {
45
+ ru: 'Доступные модели:\n{v}',
46
+ en: 'Available models:\n{v}',
44
47
  },
45
- 'qwen.model_pick_title': {
46
- ru: 'Выбор модели Qwen',
47
- en: 'Select a Qwen model',
48
+ 'model.pick_title': {
49
+ ru: 'Выбор модели {provider}',
50
+ en: 'Select a {provider} model',
51
+ },
52
+ 'model.unsupported': {
53
+ ru: '/model недоступен для {provider}: у этого провайдера нет выбора модели в zames (она задаётся в его веб-UI).',
54
+ en: '/model is not available for {provider}: this provider has no model selection in zames (choose it in its web UI).',
48
55
  },
49
56
  'qwen.model_error': {
50
57
  ru: 'Не удалось получить список моделей Qwen: {v}',
51
58
  en: 'Failed to fetch the Qwen model list: {v}',
52
59
  },
53
- 'qwen.model_deepseek_only': {
54
- ru: '/model доступен только для провайдера Qwen. Сейчас активен DeepSeek (модель выбирается в веб-UI). Переключиться: /provider qwen',
55
- en: '/model is only available for the Qwen provider. DeepSeek is active (its model is chosen in the web UI). Switch with: /provider qwen',
56
- },
57
60
  'qwen.age_gate_block': {
58
61
  ru: '✖ Qwen показывает окно "Confirm your age" (гостевой режим) и не даёт отправить сообщение. Войдите в аккаунт Qwen (команда /provider login) — в гостевом режиме первое сообщение блокируется.',
59
62
  en: '✖ Qwen shows the "Confirm your age" dialog (guest mode) and blocks the send. Sign in to Qwen (/provider login) — in guest mode the first message is blocked.',
60
63
  },
64
+ 'limits.title': {
65
+ ru: 'Телеметрия отправок ({provider}):',
66
+ en: 'Send telemetry ({provider}):',
67
+ },
68
+ 'limits.window': {
69
+ ru: '{label}: {n} отправок',
70
+ en: '{label}: {n} sends',
71
+ },
72
+ 'limits.rate': {
73
+ ru: 'лимитов: {n}, средняя блокировка: {sec}с',
74
+ en: 'rate limits: {n}, average block: {sec}s',
75
+ },
76
+ 'limits.interval': {
77
+ ru: 'текущая пауза: {sec}с{adaptive}',
78
+ en: 'current pause: {sec}s{adaptive}',
79
+ },
80
+ 'limits.adaptive_on': { ru: ' (адаптивная)', en: ' (adaptive)' },
81
+ 'limits.none': {
82
+ ru: 'Файл телеметрии пока пуст ({path}).',
83
+ en: 'The telemetry file is empty so far ({path}).',
84
+ },
85
+ 'toggle.thinking_locked': {
86
+ ru: 'GLM: размышления у этой модели всегда включены (сайт не даёт их выключить).',
87
+ en: 'GLM: thinking is always on for this model (the site does not allow turning it off).',
88
+ },
89
+ 'provider.needs_headed': {
90
+ ru: '{v}: сайт не пропускает отправку в headless (капча-слайдер), поэтому браузер запущен с окном.',
91
+ en: '{v}: the site blocks headless sends (slider captcha), so the browser runs with a visible window.',
92
+ },
61
93
  'provider.switched': {
62
94
  ru: 'Провайдер чата: {v}.',
63
95
  en: 'Chat provider: {v}.',
@@ -71,8 +103,8 @@ export const qwenMessages = {
71
103
  en: '✖ Could not open the {v} browser: {error}. Staying on the previous provider; check the login and retry.',
72
104
  },
73
105
  'provider.usage': {
74
- ru: 'Использование: /provider <deepseek|qwen> | /provider login | /provider status',
75
- en: 'Usage: /provider <deepseek|qwen> | /provider login | /provider status',
106
+ ru: 'Использование: /provider <{providers}> | /provider login | /provider status',
107
+ en: 'Usage: /provider <{providers}> | /provider login | /provider status',
76
108
  },
77
109
  'provider.handoff_saved': {
78
110
  ru: 'Контекст текущего чата сжат и сохранён для {v}. Он подхватится в следующей задаче.',
@@ -105,8 +105,8 @@ export const selfReviewMessages = {
105
105
  en: '\n💡 You are now in review mode. Just ask the agent, e.g.:\n "fix the errors"\n "improve error handling in ask()"\n "show what is wrong with undo"\nExit: /self-done. Apply: /self-apply {name}\n',
106
106
  },
107
107
  'chats.recent': {
108
- ru: 'Последние чаты DeepSeek:',
109
- en: 'Recent DeepSeek chats:',
108
+ ru: 'Последние чаты:',
109
+ en: 'Recent chats:',
110
110
  },
111
111
  'chats.pick_title': {
112
112
  ru: 'Выберите чат (↑/↓, Enter — открыть, Esc — отмена)',
package/dist/i18n.js CHANGED
@@ -17,6 +17,7 @@ import { mcpMessages } from './i18n/mcp.js';
17
17
  import { configMessages } from './i18n/config.js';
18
18
  import { promptMessages } from './i18n/prompt.js';
19
19
  import { qwenMessages } from './i18n/qwen.js';
20
+ import { glmMessages } from './i18n/glm.js';
20
21
  export const DEFAULT_LOCALE = 'ru';
21
22
  export const LOCALES = [
22
23
  { code: 'ru', name: 'Русский', englishName: 'Russian' },
@@ -49,6 +50,7 @@ export const CATALOG = {
49
50
  ...configMessages,
50
51
  ...promptMessages,
51
52
  ...qwenMessages,
53
+ ...glmMessages,
52
54
  };
53
55
  export function translate(locale) {
54
56
  const loc = isLocale(locale) ? locale : DEFAULT_LOCALE;