zames_pro 2.82.50 → 2.82.51

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.
@@ -96,9 +96,9 @@ export const deepseekMessages = {
96
96
  ru: '✖ {provider} перестал отвечать, лимит повторов исчерпан. Модель не дала ответа — проверь чат вручную.',
97
97
  en: '✖ {provider} stopped responding, retry limit exhausted. The model gave no answer — check the chat manually.',
98
98
  },
99
- 'ds.tool_retry': {
100
- ru: '⏳ Агент не распознал ответ модели — прошу продолжить ({attempt}/{max})...',
101
- en: '⏳ The agent did not recognize the model answer — asking it to continue ({attempt}/{max})...',
99
+ 'ds.text_no_tool': {
100
+ ru: '⏳ Модель ответила текстом без вызова инструмента ({attempt}/{max}) — прошу вызвать инструмент...',
101
+ en: '⏳ The model answered with plain text and no tool call ({attempt}/{max}) — asking for a tool call...',
102
102
  },
103
103
  'ds.not_launched': {
104
104
  ru: '✖ Браузер не запущен.',
package/dist/i18n.js CHANGED
@@ -37,7 +37,7 @@ export function normalizeLocale(v) {
37
37
  return DEFAULT_LOCALE;
38
38
  }
39
39
  // String catalog. Key -> { ru, en }. If a key is missing we return the key itself.
40
- // Split into section files (C3 step 1); merged here so callers keep importing
40
+ // Split into section files; merged here so callers keep importing
41
41
  // CATALOG from a single place.
42
42
  export const CATALOG = {
43
43
  ...commonMessages,
package/dist/index.js CHANGED
@@ -77,7 +77,7 @@ function authMarkerExists(provider = config.provider) {
77
77
  }
78
78
  }
79
79
  // ---------- CLI parsing ----------
80
- // The pure helpers live in src/cli-args.ts (C3) and are bound to this process's
80
+ // The pure helpers live in src/cli-args.ts and are bound to this process's
81
81
  // argv ONCE here. Call sites keep using getArg/hasFlag/getPositional.
82
82
  const { getArg, hasFlag, getPositional } = createCliArgs(process.argv.slice(2));
83
83
  // /compact asks the OLD chat for a summary. If browser.ask() exhausts its own
@@ -1274,7 +1274,7 @@ async function main() {
1274
1274
  // Write the checklist whenever the agent changes it, so a restart/resume
1275
1275
  // brings the tasks back (they used to be in-memory only).
1276
1276
  todoStore.onChange = () => persistTodos();
1277
- // Subagents (BACKLOG N36): the `Task` tool delegates a self-contained
1277
+ // Subagents: the `Task` tool delegates a self-contained
1278
1278
  // sub-task to a nested agent loop in its OWN chat (context isolation — in
1279
1279
  // zames "context" IS the chat), then restores this chat and returns only
1280
1280
  // the report. Sequential by design (one browser, one send slot). On by
@@ -4109,7 +4109,7 @@ async function main() {
4109
4109
  task: finalTaskText,
4110
4110
  workdir: currentWorkdir,
4111
4111
  });
4112
- // BACKLOG B3: snapshot the working tree BEFORE the task so /rewind can
4112
+ // Snapshot the working tree BEFORE the task so /rewind can
4113
4113
  // undo the whole task in one step. Best-effort: create() never throws, so
4114
4114
  // a missing tar cannot abort the task it was meant to protect. Skipped
4115
4115
  // while reviewing a snapshot (workdir is a throwaway copy).
@@ -2,7 +2,7 @@
2
2
  // LineEditor (src/input.ts). No terminal access, no state: given a prompt, a
3
3
  // buffer, a cursor and a width these compute the visual rows, the cursor
4
4
  // position, the visible width (wide chars count 2) and the status formatting.
5
- // Split out (C3 step 3) so the geometry can be unit-tested without driving the
5
+ // Split out so the geometry can be unit-tested without driving the
6
6
  // real editor, and so the editor class keeps only render/key handling.
7
7
  // All control characters are assembled from codes so the file has no
8
8
  // "raw" ESC/CR/LF in string literals (see AGENTS.md).
@@ -2,7 +2,7 @@
2
2
  // of the LineEditor's «/» hint list (src/input.ts). No terminal access and no
3
3
  // editor state: given the buffer text and the command list these decide which
4
4
  // commands to show, the visible window, and the Tab completion. Split out
5
- // (C3) so the fuzzy match can be unit-tested without driving the editor.
5
+ // so the fuzzy match can be unit-tested without driving the editor.
6
6
  import { SUGGEST_PAGE, isSubsequence, visLen, } from './layout.js';
7
7
  /**
8
8
  * The commands matching the current buffer. Shown only when the line starts
package/dist/input.js CHANGED
@@ -9,7 +9,7 @@ import { NL, CR, ESC, PASTE_START, PASTE_END, SUGGEST_PAGE, pasteReplacement, ex
9
9
  // The pure layout/formatting helpers (visual rows, cursor position, visible
10
10
  // width, paste markers, token formatting) live in ./input/layout.js. They are
11
11
  // re-exported here so every existing import from './input.js' keeps working,
12
- // and so tests can import them from either module (C3 step 3).
12
+ // and so tests can import them from either module.
13
13
  export { PASTE_MIN_LINES, SUGGEST_PAGE, isSubsequence, countPasteLines, formatPasteMarker, pasteReplacement, expandPastes, visRows, visLen, charWidth, layoutInput, tokenStatusLevel, formatTokenStatus, formatCompactTokens, splitPasteTail, truncateToWidth, wrapToWidth, CONTEXT_LIMIT, CONTEXT_YELLOW_PCT, CONTEXT_RED_PCT, } from './input/layout.js';
14
14
  // PURE slash-command suggestion logic (match / paging / completion), split out
15
15
  // of the class so the fuzzy match is unit-tested without driving the editor.
package/dist/mcp.js CHANGED
@@ -180,8 +180,14 @@ export function jsonSchemaToParams(schema) {
180
180
  // descriptions and enums. The flat map alone cannot convey them, and MCP
181
181
  // tools (browser_snapshot, browser_click, ...) rely on them heavily.
182
182
  export function describeParamsExternally(description, schema) {
183
- const type = schema?.type;
184
- if (!schema || type !== 'object')
183
+ // A JSON Schema may spell the object type as a LIST (`type: ['object']`, a
184
+ // zod-derived or nullable wrapper). Rejecting anything but the exact string
185
+ // 'object' silently dropped the schema — field descriptions and enums — from
186
+ // the model-facing tool description while the flat param map still listed
187
+ // the fields.
188
+ const raw = schema?.type;
189
+ const isObject = raw === 'object' || (Array.isArray(raw) && raw.includes('object'));
190
+ if (!schema || !isObject)
185
191
  return description;
186
192
  try {
187
193
  const json = JSON.stringify(schema);
@@ -89,7 +89,7 @@ function stripRefPunct(tok) {
89
89
  t = t.slice(0, -1);
90
90
  return t;
91
91
  }
92
- // Find all `@path` references in a task text (B5). Returns the unique paths in
92
+ // Find all `@path` references in a task text. Returns the unique paths in
93
93
  // order of appearance. A reference is an '@' at a word boundary followed by a
94
94
  // token that looks like a file name/path (a known extension). Implemented
95
95
  // without regular expressions, like extractPathToken, to keep the source free
package/dist/subagent.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { loadHooks, runLifecycleHooks } from './hooks.js';
2
2
  import { markInternalChat } from './sessions.js';
3
- // Subagent runner (BACKLOG N36). A `Task` tool call from the model is handled
3
+ // Subagent runner. A `Task` tool call from the model is handled
4
4
  // by the agent loop as a SEAM (like onAutoCompact): it calls back into the
5
5
  // caller, which owns the whole lifecycle. This module builds that callback.
6
6
  //
@@ -101,17 +101,10 @@ export function createSubagentRunner(opts) {
101
101
  // parent chat id) returned BEFORE anything ran, and charging those
102
102
  // attempts burned the whole budget on runs that never started.
103
103
  used++;
104
- // The model is told to fill `description` (a short label for the log/UI).
105
- // Without logging it every subagent turn in the transcript was anonymous,
106
- // so a long run could not be attributed to a sub-task.
107
- try {
108
- transcript?.log('subagent_start', {
109
- type: req.type,
110
- description: req.description || '',
111
- promptChars: String(req.prompt || '').length,
112
- });
113
- }
114
- catch { }
104
+ // NOTE: `subagent_start` is NOT logged here. agent-loop already writes it
105
+ // for the `Task` seam (with the description and the prompt), so logging it
106
+ // here too put a DUPLICATE event for the same run into the transcript —
107
+ // /export rendered every delegation twice. The seam owns the event.
115
108
  const subTools = buildTools(req.type === 'explore');
116
109
  const taskText = subagentPersona(req.type) + '\n\n--- SUB-TASK ---\n' + req.prompt;
117
110
  // Save the parent's send hooks: the nested loop OVERWRITES them on
package/dist/tools.js CHANGED
@@ -70,6 +70,15 @@ export function createTools(workdir, { undo, todos, readOnly = false, subagents
70
70
  if (v === undefined || v === null) {
71
71
  throw new Error(`Missing required argument: ${name}. Add "${name}" to the tool call arguments and retry.`);
72
72
  }
73
+ // The contract says `path: string`/`command: string`; nothing used to
74
+ // enforce it, so an OBJECT became "[object Object]" and the file tools
75
+ // CREATED a file with that literal name (the same family as the old
76
+ // `undefined` file). A garbled tool call is exactly this shape.
77
+ if (typeof v === 'object' || typeof v === 'function') {
78
+ throw new Error(`Invalid required argument ${name}: expected a string, got ` +
79
+ JSON.stringify(v) +
80
+ '. Re-send the call with a plain string value.');
81
+ }
73
82
  const s = String(v);
74
83
  if (s === '' || s === 'undefined' || s === 'null') {
75
84
  throw new Error(`Invalid required argument ${name}: ${JSON.stringify(v)}. Provide a non-empty value for "${name}" and retry.`);
@@ -27,7 +27,7 @@ function stateLabel(state, locale) {
27
27
  * status). Measured with the shared `visLen` so wide chars (CJK/emoji) count
28
28
  * as 2 and the emoji's text-presentation selector (\uFE0E) as 0 — a plain
29
29
  * `.length` counted an emoji as 1 and a CJK badge was clipped on a narrow
30
- * terminal (BACKLOG T0.7). Exported so the width arithmetic is unit-tested
30
+ * terminal. Exported so the width arithmetic is unit-tested
31
31
  * without rendering. */
32
32
  export function badgeTextWidth(state) {
33
33
  let w = 0;
package/dist/web.js CHANGED
@@ -654,22 +654,32 @@ export function parseDuckDuckGoResults(body, limit) {
654
654
  // single regex made the snippet group OPTIONAL with an unbounded gap, so a
655
655
  // result without a snippet picked up the FOLLOWING result's snippet (wrong
656
656
  // text under a URL). A row scan ties every snippet to its own result.
657
- const anchorRe = /<a[^>]*class="[^"]*result__(a|snippet)[^"]*"[^>]*>([\s\S]*?)<\/a>/gi;
657
+ // A result anchor is `<a … class="… result__a|result__snippet …" …>`. The
658
+ // attribute VALUES may be single-quoted (HTML allows both, and a page served
659
+ // through a proxy does), so each quote style is accepted rather than only
660
+ // `class="…"`. Rejecting them made a valid page parse to zero results and
661
+ // WebSearch answer "the output format may have changed".
662
+ const anchorRe = /<a[^>]*class=(?:"([^"]*)"|'([^']*)')[^>]*>([\s\S]*?)<\/a>/gi;
658
663
  const hrefOf = (tag) => {
659
- const m = tag.match(/href="([^"]*)"/i);
660
- return m ? m[1] : '';
664
+ const m = tag.match(/href=(?:"([^"]*)"|'([^']*)')/i);
665
+ return m ? (m[1] ?? m[2] ?? '') : '';
661
666
  };
662
667
  let cur = null;
663
668
  let m;
664
669
  while ((m = anchorRe.exec(body))) {
665
- const kind = m[1].toLowerCase();
670
+ const classes = m[1] ?? m[2] ?? '';
671
+ const kindMatch = /result__(a|snippet)/i.exec(classes);
672
+ if (!kindMatch)
673
+ continue;
674
+ const kind = kindMatch[1].toLowerCase();
675
+ const text = m[3] || '';
666
676
  if (kind === 'a') {
667
677
  if (cur && cur.title && /^https?:\/\//i.test(cur.url)) {
668
678
  results.push(cur);
669
679
  if (results.length >= limit)
670
680
  return results;
671
681
  }
672
- cur = { title: htmlToText(m[2] || '').trim(), url: '', snippet: '' };
682
+ cur = { title: htmlToText(text).trim(), url: '', snippet: '' };
673
683
  // The href lives in the OPENING tag, which m[0] starts with.
674
684
  let href = hrefOf(m[0].slice(0, m[0].indexOf('>') + 1));
675
685
  const uddg = href.match(/[?&]uddg=([^&]+)/);
@@ -685,7 +695,7 @@ export function parseDuckDuckGoResults(body, limit) {
685
695
  continue;
686
696
  }
687
697
  if (cur && !cur.snippet)
688
- cur.snippet = htmlToText(m[2] || '').trim();
698
+ cur.snippet = htmlToText(text).trim();
689
699
  }
690
700
  if (cur && cur.title && /^https?:\/\//i.test(cur.url))
691
701
  results.push(cur);