page-agent-sdk 4.2.2 → 4.3.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
@@ -8,7 +8,7 @@
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/page-agent-sdk.svg)](https://www.npmjs.com/package/page-agent-sdk)
10
10
  [![license](https://img.shields.io/badge/license-ISC-blue.svg)](https://github.com/whyymj/page-agent-sdk/blob/master/LICENSE)
11
- [![tests](https://img.shields.io/badge/self%20tests-3055%20asserts-brightgreen.svg)](#self-tests)
11
+ [![tests](https://img.shields.io/badge/self%20tests-3079%20asserts-brightgreen.svg)](#self-tests)
12
12
 
13
13
  ---
14
14
 
@@ -280,6 +280,7 @@ ChatDialog, MessageContent, CodePreview, SkillPanel, DebugDrawer, useChat
280
280
  | `i18n` | `I18nOptions` | **Top-level i18n group (3.22+; replaces `dialog.locale`/`dialog.messages`)**: `locale` switches the built-in message pack — chat surface + Debug drawer + Skill panel + CodePreview; `formatTime` (12h/24h), autoTitle, and the **default systemPrompt** follow (`en-US` → English `DEFAULT_SYSTEM_PROMPT_EN` with a "Respond in English" anchor, so agent replies match the UI language; a custom `systemPrompt` is untouched, but the auto-appended `reliableWriteRules` segment switches to English). `messages` = per-key overrides (priority over the locale pack, e.g. `statusDone: '<b style="color:#10b981">Done ✓</b>'` — values may be inline HTML fragments on rich-text render spots, sanitized via a text allowlist). Full key list (~226 keys) in `DialogMessages` |
281
281
  | `icons` | `Partial<DialogIcons>` | **Icon customization**: partial override of default emojis (`header` 🤖 / `subagent` 🤖 / `subagentProgress` 🧬 / `empty` 💬 / `focus` 🎯 / `queued` 📋 / `queuedEdit` ✏️ / `recommend` 💡 / `conflict` ⚠️; `assistantAvatar`/`userAvatar`/`send` and the header-button keys `newSession`/`history`/`more`/`close` default to built-in SVG — pass emoji/char/HTML fragment to replace; history delete button `sessionDelete` defaults to ✕ text). Values: plain text (emoji/char) **or an HTML fragment** (starting with `<`, e.g. inline `<svg>`/`<img>` — sanitized via a DOMPurify icon allowlist; event attributes/dangerous protocols stripped); empty string hides the icon (button keys treat it as unset, prevents an empty button); unset keys keep defaults |
282
282
  | `headerLabels` | `boolean` · default `true` | **Adaptive header-button text labels**: when wide enough (header content ≥440px ≈ dialog ≥472px with default padding), "New chat / History / More" show text+icon; narrower widths fall back to icon-only (close stays icon-only; pure CSS container queries, old browsers gracefully degrade to icon-only); `false` = always icon-only. Button text = i18n `newSession`/`history`/`more` keys (overridable via `i18n.messages`), icons = the four same-named `dialog.icons` keys |
283
+ | `toolStepView` | `ToolStepViewFn` | **Tool-step display mapper (pure display-layer interceptor)**: replaces raw tool names (read/write/use_html …) on the tool-call step rows with business-friendly names/content. Called on each tool-call render with `name`/`args`/`status`/`result` (map dynamically by args); return `{ title?, detail? }` or `undefined` (fall back to the raw name); mapper exceptions are safe (fall back to the raw name). Example: `toolStepView: (s) => s.name === 'write' ? { title: 'Edit page', detail: (s.args as any)?.jsonPath } : undefined`. Never affects the tool names/protocol/validation sent to the LLM; subagent steps map too; the expanded args/result detail panel stays raw |
283
284
 
284
285
  ### Extension points
285
286
 
package/README.zh-CN.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/page-agent-sdk.svg)](https://www.npmjs.com/package/page-agent-sdk)
10
10
  [![license](https://img.shields.io/badge/license-ISC-blue.svg)](https://github.com/whyymj/page-agent-sdk/blob/master/LICENSE)
11
- [![tests](https://img.shields.io/badge/self%20tests-3055%20asserts-brightgreen.svg)](#自测)
11
+ [![tests](https://img.shields.io/badge/self%20tests-3079%20asserts-brightgreen.svg)](#自测)
12
12
 
13
13
  ---
14
14
 
@@ -276,6 +276,7 @@ ChatDialog, MessageContent, CodePreview, SkillPanel, DebugDrawer, useChat
276
276
  | `i18n` | `I18nOptions` | **顶层国际化配置组(3.22+;原 `dialog.locale`/`dialog.messages` 两键合并至此)**:`locale` 切换内置文案包 —— 聊天面 + Debug 抽屉 + Skill 面板 + 代码预览;`formatTime`(12h/24h)、autoTitle 与**默认 systemPrompt** 跟随(`en-US` → 英文版 `DEFAULT_SYSTEM_PROMPT_EN` 含 "Respond in English" 语言锚,agent 回复语言与 UI 一致;自定义 `systemPrompt` 不受影响,但其自动追加的 `reliableWriteRules` 段切英文)。`messages` = 键级覆盖(优先于 locale 包,如 `statusDone: '<b style="color:#10b981">完成</b>'` —— 富文本渲染位的值支持行内 HTML 片段,文案白名单净化);完整键清单(~226 键)见 `DialogMessages` |
277
277
  | `icons` | `Partial<DialogIcons>` | **图标自定义**:局部覆盖默认 emoji(`header` 🤖 / `subagent` 🤖 / `subagentProgress` 🧬 / `empty` 💬 / `focus` 🎯 / `queued` 📋 / `queuedEdit` ✏️ / `recommend` 💡 / `conflict` ⚠️;`assistantAvatar`/`userAvatar`/`send` 与顶部按钮四键 `newSession`/`history`/`more`/`close` 缺省 = 内置 SVG,传 emoji/字符/HTML 片段替换;历史删除按钮 `sessionDelete` 缺省 = ✕ 文本)。值为纯文本(emoji/字符)或 **HTML 片段**(以 `<` 开头,如内联 `<svg>`/`<img>`,经 DOMPurify 图标白名单净化,事件属性/危险协议剥除);空串 = 隐藏该图标(按钮键视为未传,防空按钮);未传键用默认 |
278
278
  | `headerLabels` | `boolean` · 默认 `true` | **顶部按钮自适应文字标签**:宽度足够(头部内容区 ≥440px,默认 padding 下 ≈ 对话框 ≥472px)时「新建会话/历史记录/更多」展示文字+图标,更窄自动回退纯图标(关闭钮恒纯图标;纯 CSS 容器查询,旧浏览器优雅降级为纯图标);`false` 恒纯图标。按钮文字走 i18n `newSession`/`history`/`more` 键(`i18n.messages` 键级覆盖生效),图标走 `dialog.icons` 同名四键 |
279
+ | `toolStepView` | `ToolStepViewFn` | **工具步骤展示映射(纯展示层拦截器)**:把工具调用步骤行的原始工具名(read/write/use_html …)替换为业务友好名称/内容。每次工具调用渲染时调,入参含 `name`/`args`/`status`/`result`(可按 args 动态映射),返回 `{ title?, detail? }` 或 `undefined`(回退原始工具名);映射抛错安全(回退原名)。例:`toolStepView: (s) => s.name === 'write' ? { title: '修改页面', detail: (s.args as any)?.jsonPath } : undefined`。不影响发给 LLM 的工具名/协议/校验;子 agent 步骤同样应用;展开细节面板的 args/result 仍为原始数据 |
279
280
 
280
281
  ### 扩展点
281
282
 
@@ -186,6 +186,22 @@ var d = [
186
186
  vision: !0
187
187
  }
188
188
  },
189
+ {
190
+ pattern: /qwen3(\.\d+)?-vl/i,
191
+ caps: {
192
+ contextWindow: 262144,
193
+ maxOutputTokens: 32768,
194
+ vision: !0
195
+ }
196
+ },
197
+ {
198
+ pattern: /qwen3(\.\d+)?-(max|plus|flash)/i,
199
+ caps: {
200
+ contextWindow: 262144,
201
+ maxOutputTokens: 32768,
202
+ thinking: !0
203
+ }
204
+ },
189
205
  {
190
206
  pattern: /qwen-max|qwen-plus/i,
191
207
  caps: {
@@ -5202,63 +5218,70 @@ function tc(e, t) {
5202
5218
  return Array.isArray(a) && Number(i) >= a.length;
5203
5219
  }
5204
5220
  function nc(e) {
5205
- let t = e.initialFocuses ? [...e.initialFocuses] : [], n = () => e.onChange?.([...t]), r = e.unfocusGuidance ?? "tool", i = (e) => `若你的意图是修改聚焦组件本身(如给它新增页签/子项),请改写焦点路径的子路径重试${e ? `(如 ${e})` : ""};`, a = r === "tool" ? `需改其他组件请先 remove_focus / clear_focus 或换焦点。${i()}` : r === "ask-user" ? `焦点由用户在输入框设定与移除(聚焦 chip ✕);用户要求改其他组件时,提示用户移除聚焦后重试,勿尝试写焦点外(会被拒)。${i()}` : `需改其他组件时,在收口回复中说明需先取消焦点(焦点由主会话管理),勿尝试越界写。${i()}`, o = (e) => r === "tool" ? `${i(e)}需操作焦点外组件请先 remove_focus / clear_focus 或换焦点后重试。` : r === "ask-user" ? `${i(e)}焦点由用户在输入框管理,请提示用户移除输入框中的聚焦 chip 后重试(当前模式无 focus 工具)。` : `${i(e)}请只改焦点子树;需改其他组件时,在收口回复中说明需先取消焦点。`;
5221
+ let t = e.initialFocuses ? [...e.initialFocuses] : [], n = null, r = () => n ?? t, i = () => e.onChange?.([...t]), a = (e, r) => {
5222
+ t = r(t), n !== null && e === "agent" && (n = r(n)), i();
5223
+ }, o = e.unfocusGuidance ?? "tool", s = (e) => `若你的意图是修改聚焦组件本身(如给它新增页签/子项),请改写焦点路径的子路径重试${e ? `(如 ${e})` : ""};`, c = o === "tool" ? `需改其他组件请先 remove_focus / clear_focus 或换焦点。${s()}` : o === "ask-user" ? `焦点由用户在输入框设定与移除(聚焦 chip ✕);用户要求改其他组件时,提示用户移除聚焦后重试,勿尝试写焦点外(会被拒)。${s()}` : `需改其他组件时,在收口回复中说明需先取消焦点(焦点由主会话管理),勿尝试越界写。${s()}`, l = (e) => o === "tool" ? `${s(e)}需操作焦点外组件请先 remove_focus / clear_focus 或换焦点后重试。` : o === "ask-user" ? `${s(e)}焦点由用户在输入框管理,请提示用户移除输入框中的聚焦 chip 后重试(当前模式无 focus 工具)。` : `${s(e)}请只改焦点子树;需改其他组件时,在收口回复中说明需先取消焦点。`;
5206
5224
  return {
5207
5225
  name: "focus",
5208
- beforeAgent: () => t.length ? {
5209
- focuses: [...t],
5210
- focus: t[0]
5211
- } : {},
5226
+ beforeAgent: () => (n = [...t], n.length ? {
5227
+ focuses: [...n],
5228
+ focus: n[0]
5229
+ } : {}),
5230
+ afterAgent: () => {
5231
+ n = null;
5232
+ },
5212
5233
  augmentPrompt: () => {
5234
+ let t = r();
5213
5235
  if (!t.length) return;
5214
5236
  let n = [
5215
5237
  "## 当前精修目标",
5216
5238
  t.map((e) => `· ${e.path}${e.label ? `(${e.label})` : ""}`).join("\n"),
5217
- `仅操作上述 ${t.length} 个聚焦子树${t.length > 1 ? "之一" : ""},用户未指明目标的指令默认作用于聚焦组件(「增加/修改/删除 X」类指令优先理解为对聚焦组件本身的改动 —— 如为其加页签/子项,写焦点路径的子路径;仅用户明确要求新建独立组件时才需解除焦点);不要改动其他组件;${a}`,
5239
+ `仅操作上述 ${t.length} 个聚焦子树${t.length > 1 ? "之一" : ""},用户未指明目标的指令默认作用于聚焦组件(「增加/修改/删除 X」类指令优先理解为对聚焦组件本身的改动 —— 如为其加页签/子项,写焦点路径的子路径;仅用户明确要求新建独立组件时才需解除焦点);不要改动其他组件;${c}`,
5218
5240
  "用户用指示代词提问(「这是啥/这个/它是干什么的」等)时,所指默认是聚焦目标 —— 先 read 聚焦子树,再围绕聚焦组件回答,勿泛答整页",
5219
5241
  "read 不带路径时默认只返回聚焦子树;需要全量主数据时显式列顶层键(read({jsonPaths:[...]}) )"
5220
- ], r = e.getSchema();
5221
- if (r) {
5242
+ ], i = e.getSchema();
5243
+ if (i) {
5222
5244
  let e = t.map((e) => {
5223
- let t = Ro(r, e.path);
5245
+ let t = Ro(i, e.path);
5224
5246
  return t ? _s(t) : null;
5225
5247
  }).filter((e) => !!e);
5226
5248
  e.length && n.push("", "## 焦点子树结构(仅此范围可操作)", ...e);
5227
5249
  }
5228
5250
  return n.join("\n");
5229
5251
  },
5230
- wrapToolCall: async (n, r) => {
5231
- if (t.length) {
5232
- let i = t.map((e) => e.label ? `${e.path}(${e.label})` : e.path).join(", "), a = t.length === 1 ? `${t[0].path}.props.xxx` : void 0, s = (e) => ({
5233
- content: `PATH_DENIED · 聚焦越界:当前聚焦 [${i}],不可操作「${e}」。${o(a)}`,
5252
+ wrapToolCall: async (t, n) => {
5253
+ let i = r();
5254
+ if (i.length) {
5255
+ let r = i.map((e) => e.label ? `${e.path}(${e.label})` : e.path).join(", "), a = i.length === 1 ? `${i[0].path}.props.xxx` : void 0, o = (e) => ({
5256
+ content: `PATH_DENIED · 聚焦越界:当前聚焦 [${r}],不可操作「${e}」。${l(a)}`,
5234
5257
  status: "error"
5235
5258
  });
5236
- if (n.name === "eval_script") {
5237
- if (n.args?.mode !== "transform") return r(n);
5238
- let i = $s(n.args);
5239
- if (!i.length) return s("(整体数据)");
5240
- for (let n of i) if (!t.some((e) => ec(n, e.path)) && !tc(n, e.getBind?.())) return s(n);
5241
- return r(n);
5259
+ if (t.name === "eval_script") {
5260
+ if (t.args?.mode !== "transform") return n(t);
5261
+ let r = $s(t.args);
5262
+ if (!r.length) return o("(整体数据)");
5263
+ for (let t of r) if (!i.some((e) => ec(t, e.path)) && !tc(t, e.getBind?.())) return o(t);
5264
+ return n(t);
5242
5265
  }
5243
- if (Qs.has(n.name)) {
5244
- let r = $s(n.args);
5245
- if (!r.length) return s("(整体数据)");
5246
- for (let n of r) if (!t.some((e) => ec(n, e.path)) && !tc(n, e.getBind?.())) return s(n);
5266
+ if (Qs.has(t.name)) {
5267
+ let n = $s(t.args);
5268
+ if (!n.length) return o("(整体数据)");
5269
+ for (let t of n) if (!i.some((e) => ec(t, e.path)) && !tc(t, e.getBind?.())) return o(t);
5247
5270
  }
5248
- if (n.name === "read") {
5249
- n.callConfig = {
5250
- ...n.callConfig ?? {},
5251
- __pgFullTextPaths: t.map((e) => e.path)
5271
+ if (t.name === "read") {
5272
+ t.callConfig = {
5273
+ ...t.callConfig ?? {},
5274
+ __pgFullTextPaths: i.map((e) => e.path)
5252
5275
  };
5253
- let e = n.args;
5276
+ let e = t.args;
5254
5277
  if (!e?.jsonPath && !e?.jsonPaths) {
5255
- let i = t.map((e) => e.path), a = await r({
5256
- ...n,
5278
+ let r = i.map((e) => e.path), a = await n({
5279
+ ...t,
5257
5280
  args: {
5258
5281
  ...e,
5259
- jsonPaths: i
5282
+ jsonPaths: r
5260
5283
  }
5261
- }), o = `【聚焦模式】read 未带路径 → 默认返回聚焦子树(${i.join(", ")});需要全量主数据时显式列顶层键,如 read({jsonPaths:['<顶层键1>','<顶层键2>']})\n`;
5284
+ }), o = `【聚焦模式】read 未带路径 → 默认返回聚焦子树(${r.join(", ")});需要全量主数据时显式列顶层键,如 read({jsonPaths:['<顶层键1>','<顶层键2>']})\n`;
5262
5285
  return {
5263
5286
  ...a,
5264
5287
  content: o + a.content
@@ -5266,26 +5289,33 @@ function nc(e) {
5266
5289
  }
5267
5290
  }
5268
5291
  }
5269
- return r(n);
5292
+ return n(t);
5270
5293
  },
5271
- setFocus: (e) => {
5272
- t = e ? [e] : [], n();
5294
+ setFocus: (e, t) => {
5295
+ a(t, () => e ? [e] : []);
5273
5296
  },
5274
5297
  getFocus: () => t[0],
5275
5298
  getFocuses: () => [...t],
5276
- addFocus: (e) => {
5277
- let r = t.findIndex((t) => t.path === e.path);
5278
- r >= 0 ? t[r] = e : t.push(e), n();
5299
+ addFocus: (e, t) => {
5300
+ a(t, (t) => {
5301
+ let n = t.findIndex((t) => t.path === e.path);
5302
+ if (n >= 0) {
5303
+ let r = [...t];
5304
+ return r[n] = e, r;
5305
+ }
5306
+ return [...t, e];
5307
+ });
5279
5308
  },
5280
- removeFocus: (e) => {
5281
- t = t.filter((t) => t.path !== e), n();
5309
+ removeFocus: (e, t) => {
5310
+ a(t, (t) => t.filter((t) => t.path !== e));
5282
5311
  },
5283
- clearFocus: () => {
5284
- t = [], n();
5312
+ clearFocus: (e) => {
5313
+ a(e, () => []);
5285
5314
  },
5286
5315
  reset: () => {
5287
- t = [], n();
5288
- }
5316
+ t = [], n = null, i();
5317
+ },
5318
+ isInvokeActive: () => n !== null
5289
5319
  };
5290
5320
  }
5291
5321
  //#endregion
@@ -12330,7 +12360,7 @@ function am(e, n) {
12330
12360
  return n ? Ro(n, e) ? (A.setFocus({
12331
12361
  path: e,
12332
12362
  ...t ? { label: t } : {}
12333
- }), `已聚焦到 ${e}${t ? `(${t})` : ""}。后续仅可写该子树(越界被拒),每轮只看到该组件结构。完成精修后调 clear_focus 退出。`) : `PATH_DENIED · 聚焦失败:path "${e}" 不在 schema 内。请先用 read 查看可操作路径再聚焦。` : "聚焦失败:当前无主数据 schema,无法聚焦。";
12363
+ }, "agent"), `已聚焦到 ${e}${t ? `(${t})` : ""}。后续仅可写该子树(越界被拒),每轮只看到该组件结构。完成精修后调 clear_focus 退出。`) : `PATH_DENIED · 聚焦失败:path "${e}" 不在 schema 内。请先用 read 查看可操作路径再聚焦。` : "聚焦失败:当前无主数据 schema,无法聚焦。";
12334
12364
  }, {
12335
12365
  name: "set_focus",
12336
12366
  description: "聚焦到指定组件子树(如 components.3)精修,替换全部已有焦点(非累积;要保留已有焦点追加用 add_focus)。聚焦后:仅可写该子树(越界 PATH_DENIED)+ 每轮只看到该组件结构。多组件页面精修其中一个时用,避免改到别处。先 read 定位 path 再聚焦;完成调 clear_focus。",
@@ -12338,7 +12368,7 @@ function am(e, n) {
12338
12368
  path: t.string().describe("要聚焦的组件 jsonPath,如 components.3"),
12339
12369
  label: t.string().optional().describe("人类可读标签,如「导航栏」")
12340
12370
  })
12341
- }), je = r(async () => (A.clearFocus(), "已清除聚焦,恢复全量可操作范围(可读写所有组件)。"), {
12371
+ }), je = r(async () => (A.clearFocus("agent"), "已清除聚焦,恢复全量可操作范围(可读写所有组件)。"), {
12342
12372
  name: "clear_focus",
12343
12373
  description: "清除当前聚焦,退出精修模式,恢复对全部组件的读写权限。",
12344
12374
  schema: t.object({}).optional()
@@ -12349,7 +12379,7 @@ function am(e, n) {
12349
12379
  A.addFocus({
12350
12380
  path: e,
12351
12381
  ...t ? { label: t } : {}
12352
- });
12382
+ }, "agent");
12353
12383
  let r = A.getFocuses();
12354
12384
  return `已聚焦 ${e}${t ? `(${t})` : ""}(当前共 ${r.length} 个焦点:${r.map((e) => e.path).join(", ")})。后续仅可写这些子树之一(越界被拒)。`;
12355
12385
  }, {
@@ -12361,7 +12391,7 @@ function am(e, n) {
12361
12391
  })
12362
12392
  }), Ne = r(async ({ path: e }) => {
12363
12393
  let t = A.getFocuses().length;
12364
- A.removeFocus(e);
12394
+ A.removeFocus(e, "agent");
12365
12395
  let n = A.getFocuses();
12366
12396
  return n.length === t ? `path "${e}" 不在当前焦点列表中(当前:${n.map((e) => e.path).join(", ") || "无"})。` : n.length ? `已移除焦点 ${e}(剩余 ${n.length} 个:${n.map((e) => e.path).join(", ")})。` : `已移除焦点 ${e},聚焦已清空,恢复全量操作范围。`;
12367
12397
  }, {
@@ -13188,14 +13218,14 @@ function am(e, n) {
13188
13218
  },
13189
13219
  setFocus(t) {
13190
13220
  let n = im(t, "setFocus", ke, () => U()?.schema, e.debug);
13191
- return n.ok ? (A.setFocus(t), X.infoTick.value++, { ok: !0 }) : n;
13221
+ return n.ok ? (A.setFocus(t), e.debug && A.isInvokeActive() && console.info("[page-agent-sdk][focus] 在途流程进行中,聚焦将在下一次输入生效(当前流程不受影响)"), X.infoTick.value++, { ok: !0 }) : n;
13192
13222
  },
13193
13223
  addFocus(t) {
13194
13224
  let n = im(t, "addFocus", ke, () => U()?.schema, e.debug);
13195
13225
  return n.ok ? A.getFocuses().length >= 8 ? (e.debug && console.warn("[page-agent-sdk][focus] addFocus 拒绝:焦点数已达上限 8(augmentPrompt 注入每焦点子树 schema,过多致 system prompt 超预算)"), {
13196
13226
  ok: !1,
13197
13227
  error: "焦点数上限 8(避免 system prompt 撑爆)"
13198
- }) : (A.addFocus(t), X.infoTick.value++, { ok: !0 }) : n;
13228
+ }) : (A.addFocus(t), e.debug && A.isInvokeActive() && console.info("[page-agent-sdk][focus] 在途流程进行中,聚焦将在下一次输入生效(当前流程不受影响)"), X.infoTick.value++, { ok: !0 }) : n;
13199
13229
  },
13200
13230
  removeFocus(e) {
13201
13231
  ke && (A.removeFocus(e), X.infoTick.value++);
@@ -13938,8 +13968,8 @@ function hm(e = {}) {
13938
13968
  await r?.(s.messages);
13939
13969
  } catch {}
13940
13970
  s.loading = !1, u = null;
13941
- let e = d.value.shift();
13942
- e !== void 0 && (g("user", e), s.loading = !0, s.error = null, u = new AbortController(), await _(u.signal));
13971
+ let t = d.value.shift();
13972
+ t !== void 0 && (g("user", t, e.getFocuses?.()), s.loading = !0, s.error = null, u = new AbortController(), await _(u.signal));
13943
13973
  }
13944
13974
  function b(e) {
13945
13975
  d.value.splice(e, 1);
@@ -14078,7 +14108,7 @@ var vm = {
14078
14108
  copyThinkingTruncTitle: "复制完整思考(渲染已截尾,复制取全量)",
14079
14109
  focusChipTitlePrefix: "精修中:",
14080
14110
  focusChipTitleHint: "(点击回看 · ✕ 移除)",
14081
- historyFocusChipTitlePrefix: "回看 ",
14111
+ historyFocusChipTitlePrefix: "发送时聚焦(路径可能已变):",
14082
14112
  removeFocus: "移除此焦点",
14083
14113
  sendHint: "Enter 发送 · Shift+Enter 换行",
14084
14114
  sendTitle: "发送",
@@ -14304,7 +14334,7 @@ var vm = {
14304
14334
  copyThinkingTruncTitle: "Copy full reasoning (display truncated, copy gets all)",
14305
14335
  focusChipTitlePrefix: "Focus:",
14306
14336
  focusChipTitleHint: "(click to view · ✕ remove)",
14307
- historyFocusChipTitlePrefix: "View ",
14337
+ historyFocusChipTitlePrefix: "Focused at send (path may have changed): ",
14308
14338
  removeFocus: "Remove this focus",
14309
14339
  sendHint: "Enter to send · Shift+Enter for newline",
14310
14340
  sendTitle: "Send",
@@ -14508,7 +14538,8 @@ function Sm(e = {}) {
14508
14538
  onPersist: e.onPersist,
14509
14539
  onClear: e.onClear,
14510
14540
  onQueuedCleared: e.onQueuedCleared,
14511
- onBeforeRegenerate: e.onBeforeRegenerate
14541
+ onBeforeRegenerate: e.onBeforeRegenerate,
14542
+ getFocuses: e.getFocuses
14512
14543
  }), { state: n, sendMessage: r, removeQueuedTask: i, queuedTasks: a } = t, o = /* @__PURE__ */ Lt(""), s = /* @__PURE__ */ Lt(!0), c = () => {
14513
14544
  s.value = !s.value;
14514
14545
  }, l = /* @__PURE__ */ Lt(!1), u = () => {
@@ -14622,7 +14653,8 @@ function Sm(e = {}) {
14622
14653
  focusChipClick: F,
14623
14654
  icons: I,
14624
14655
  locale: ae,
14625
- messages: oe
14656
+ messages: oe,
14657
+ toolStepView: e.toolStepView
14626
14658
  };
14627
14659
  }
14628
14660
  function Cm() {