page-agent-sdk 4.1.0 → 4.2.1

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.
@@ -20,7 +20,7 @@ function v(e) {
20
20
  return !!(e == null || typeof e == "string" || e instanceof ArrayBuffer || ArrayBuffer.isView(e) || typeof Blob < "u" && e instanceof Blob || e instanceof URLSearchParams || e instanceof FormData);
21
21
  }
22
22
  function y(e) {
23
- let t = e.model || "gpt-3.5-turbo", r = e.temperature, i = e.maxTokens, a = e.baseUrl;
23
+ let t = e.model || "deepseek-v4-flash", r = e.temperature, i = e.maxTokens, a = e.baseUrl;
24
24
  if (e.mode === "direct") {
25
25
  let o = !1;
26
26
  try {
@@ -5996,7 +5996,7 @@ function yf(e) {
5996
5996
  return Array.isArray(r) && r.length && r[0] && typeof r[0].jsonPath == "string" ? r[0].jsonPath : "";
5997
5997
  }
5998
5998
  function bf(e) {
5999
- let { apiKey: t, baseUrl: r, model: c = "gpt-3.5-turbo", temperature: l = .7, maxTokens: u, extraBody: d, extraConfig: f, systemPrompt: p, tools: m = [], middleware: h = [], maxToolRounds: g, maxIterations: _, maxRetries: v = 2, retryDelayMs: y = 500, stallMs: b = Eu, streamMaxMs: x = Ou, toolTimeoutMs: S, maxParallelTools: D = 1, maxVerifyAttempts: ee = 0, roundTokenBudget: te = 0, onLog: A, onLlmChange: ne, imageContentFormat: re = "openai", staleReadInvalidation: ie = !0, debug: P = !1 } = e, F = g ?? ff;
5999
+ let { apiKey: t, baseUrl: r, model: c = "deepseek-v4-flash", temperature: l = .7, maxTokens: u, extraBody: d, extraConfig: f, systemPrompt: p, tools: m = [], middleware: h = [], maxToolRounds: g, maxIterations: _, maxRetries: v = 2, retryDelayMs: y = 500, stallMs: b = Eu, streamMaxMs: x = Ou, toolTimeoutMs: S, maxParallelTools: D = 1, maxVerifyAttempts: ee = 0, roundTokenBudget: te = 0, onLog: A, onLlmChange: ne, imageContentFormat: re = "openai", staleReadInvalidation: ie = !0, debug: P = !1 } = e, F = g ?? ff;
6000
6000
  (!Number.isFinite(F) || F < 1) && (console.warn(`[page-agent-sdk] maxToolRounds=${F} 非法(须 ≥1 正整数),已 clamp 到 1(0/负数致主循环 while 不进 → agent 不调 LLM 静默返回兜底文案)`), F = 1);
6001
6001
  let I = C({
6002
6002
  model: c,
@@ -7493,7 +7493,7 @@ function Mp(e, t, n, r) {
7493
7493
  }
7494
7494
  if (t === "move") return Pp(e, n, r);
7495
7495
  let i = n ? bp(e, n) : e;
7496
- return Array.isArray(i) ? (Array.isArray(r) ? i.push(...r) : i.push(r), null) : `append 目标${n ? `(${n})` : "(根)"}不是数组`;
7496
+ return typeof i == "string" ? typeof r == "string" ? (xp(e, n, i + r), null) : `append 目标(${n})是字符串,value 必须也是字符串(拼接语义)` : Array.isArray(i) ? (Array.isArray(r) ? i.push(...r) : i.push(r), null) : `append 目标${n ? `(${n})` : "(根)"}不是数组(也不支持非字符串标量拼接)`;
7497
7497
  }
7498
7498
  function Np(e, t) {
7499
7499
  let n = t.split("."), r = e;
@@ -7636,6 +7636,7 @@ function Wp(e) {
7636
7636
  "## 当前精修目标",
7637
7637
  t.map((e) => `· ${e.path}${e.label ? `(${e.label})` : ""}`).join("\n"),
7638
7638
  `仅操作上述 ${t.length} 个聚焦子树${t.length > 1 ? "之一" : ""},用户未指明目标的指令默认作用于聚焦组件(「增加/修改/删除 X」类指令优先理解为对聚焦组件本身的改动 —— 如为其加页签/子项,写焦点路径的子路径;仅用户明确要求新建独立组件时才需解除焦点);不要改动其他组件;${a}`,
7639
+ "用户用指示代词提问(「这是啥/这个/它是干什么的」等)时,所指默认是聚焦目标 —— 先 read 聚焦子树,再围绕聚焦组件回答,勿泛答整页",
7639
7640
  "read 不带路径时默认只返回聚焦子树;需要全量主数据时显式列顶层键(read({jsonPaths:[...]}) )"
7640
7641
  ], r = e.getSchema();
7641
7642
  if (r) {
@@ -10065,47 +10066,63 @@ function Sg(e, t, n, r) {
10065
10066
  hint: "重新 read 该字段触发懒注册重建句柄,再写回新句柄 ⟦res:<handle>⟧"
10066
10067
  };
10067
10068
  }
10068
- function Cg(e, t) {
10069
- let n = t.getBind();
10070
- for (let [r, i] of t.resourcesByPath) {
10071
- let a = bp(n, r), o = bp(e, r);
10072
- if (o === void 0) {
10073
- a !== void 0 && xp(e, r, a);
10074
- continue;
10069
+ function Cg(e, t, n) {
10070
+ let r = t.getBind();
10071
+ for (let [i, a] of t.resourcesByPath) {
10072
+ let o = bp(r, i), s = bp(e, i);
10073
+ if (s === void 0) {
10074
+ if (o === void 0) continue;
10075
+ let t = i.split(".");
10076
+ if (bp(e, t.length > 1 ? t.slice(0, -1).join(".") : "") !== void 0) {
10077
+ xp(e, i, o);
10078
+ continue;
10079
+ }
10080
+ if (!(e && typeof e == "object" && t[0] in e)) {
10081
+ if (n) continue;
10082
+ xp(e, i, o);
10083
+ continue;
10084
+ }
10085
+ return {
10086
+ ok: !1,
10087
+ code: a.mode === "freeze" ? "FROZEN_FIELD" : "VERBATIM_PROTECTED",
10088
+ path: i,
10089
+ message: `整体替换会移除受保护字段 "${i}"(${a.mode}),已拒绝`,
10090
+ hint: a.mode === "freeze" ? "含冻结字段的容器不可整体清空/替换:保留包含该字段的元素(补齐其必填字段,如 type),或逐个 remove 其余元素;彻底移除该字段需集成方调整 data.resources" : "含 verbatim 字段的容器不可整体清空/替换:保留包含该字段的元素,或先 resource_delete({path}) 释放保护后再整体替换"
10091
+ };
10075
10092
  }
10076
- if (i.mode === "freeze") {
10077
- if (o === pg(r)) {
10078
- xp(e, r, a);
10093
+ if (a.mode === "freeze") {
10094
+ if (s === pg(i)) {
10095
+ xp(e, i, o);
10079
10096
  continue;
10080
10097
  }
10081
- if (!vg(o, a)) return {
10098
+ if (!vg(s, o)) return {
10082
10099
  ok: !1,
10083
10100
  code: "FROZEN_FIELD",
10084
- path: r,
10085
- message: `字段 "${r}" 已冻结(freeze 保护),不可修改`,
10101
+ path: i,
10102
+ message: `字段 "${i}" 已冻结(freeze 保护),不可修改`,
10086
10103
  hint: "该字段由系统/集成方维护,LLM 不得改动。如需展示其值用 resource_get({path}) 取真值"
10087
10104
  };
10088
10105
  } else {
10089
- let n = hg(o);
10106
+ let n = hg(s);
10090
10107
  if (n && n.type === "res") {
10091
- let i = Sg(n.handle, r, a, t.resourceStore);
10092
- if ("value" in i) {
10093
- xp(e, r, i.value);
10108
+ let r = Sg(n.handle, i, o, t.resourceStore);
10109
+ if ("value" in r) {
10110
+ xp(e, i, r.value);
10094
10111
  continue;
10095
10112
  }
10096
10113
  return {
10097
10114
  ok: !1,
10098
- code: i.code,
10099
- path: r,
10100
- message: i.message,
10101
- hint: i.hint
10115
+ code: r.code,
10116
+ path: i,
10117
+ message: r.message,
10118
+ hint: r.hint
10102
10119
  };
10103
10120
  }
10104
- if (!vg(o, a)) return {
10121
+ if (!vg(s, o)) return {
10105
10122
  ok: !1,
10106
10123
  code: "VERBATIM_MISMATCH",
10107
- path: r,
10108
- message: `字段 "${r}" 为 verbatim 保护(精确原样保留),写入值与原值不符`,
10124
+ path: i,
10125
+ message: `字段 "${i}" 为 verbatim 保护(精确原样保留),写入值与原值不符`,
10109
10126
  hint: "要改该值请先 resource_update({path, value}) 更新资源池,再写回句柄 ⟦res:<handle>⟧;或写回原值(经 resource_get 取到的值)保持不变"
10110
10127
  };
10111
10128
  }
@@ -10126,18 +10143,18 @@ function wg(e, t, n) {
10126
10143
  });
10127
10144
  }
10128
10145
  function Tg(e) {
10129
- let { value: t, ctx: n } = e;
10146
+ let { value: t, ctx: n, mergeMode: r } = e;
10130
10147
  if (!n || !n.resourcesByPath.size) return {
10131
10148
  ok: !0,
10132
10149
  value: t
10133
10150
  };
10134
- let r = Cp(t), i = Cg(r, n);
10135
- return i.ok ? {
10151
+ let i = Cp(t), a = Cg(i, n, r);
10152
+ return a.ok ? {
10136
10153
  ok: !0,
10137
- value: r
10154
+ value: i
10138
10155
  } : {
10139
10156
  ok: !1,
10140
- error: wg(i)
10157
+ error: wg(a)
10141
10158
  };
10142
10159
  }
10143
10160
  function Eg(e) {
@@ -10356,7 +10373,32 @@ function Mg(e) {
10356
10373
  continue;
10357
10374
  }
10358
10375
  if (i === "append") {
10359
- let e = o[p++]?.elems ?? [];
10376
+ let e = o[p++]?.elems ?? [], r = bp(n, a);
10377
+ if (typeof r == "string" && typeof e[0] == "string") {
10378
+ let n = e[0], i = Df(t, a);
10379
+ if (i.kind === "missing") return {
10380
+ ok: !1,
10381
+ error: d([a]),
10382
+ writeBacks: [],
10383
+ notices: c
10384
+ };
10385
+ let o = r + n;
10386
+ if (i.kind !== "open") {
10387
+ let e = i.schemas.map((e) => e.safeParse(o)).find((e) => !e.success);
10388
+ if (e) return {
10389
+ ok: !1,
10390
+ error: u(a, e.error?.issues ?? []),
10391
+ writeBacks: [],
10392
+ notices: c
10393
+ };
10394
+ }
10395
+ f.push({
10396
+ op: "appendStr",
10397
+ jp: a,
10398
+ str: n
10399
+ });
10400
+ continue;
10401
+ }
10360
10402
  if (!e.length) {
10361
10403
  f.push({
10362
10404
  op: "appendElems",
@@ -10365,14 +10407,14 @@ function Mg(e) {
10365
10407
  });
10366
10408
  continue;
10367
10409
  }
10368
- let n = Df(t, a);
10369
- if (n.kind === "missing") return {
10410
+ let i = Df(t, a);
10411
+ if (i.kind === "missing") return {
10370
10412
  ok: !1,
10371
10413
  error: d([a || "(根)"]),
10372
10414
  writeBacks: [],
10373
10415
  notices: c
10374
10416
  };
10375
- if (n.kind === "open") {
10417
+ if (i.kind === "open") {
10376
10418
  c.push(`${a || "(根)"}=开放节点放行`), f.push({
10377
10419
  op: "appendElems",
10378
10420
  jp: a,
@@ -10380,8 +10422,8 @@ function Mg(e) {
10380
10422
  });
10381
10423
  continue;
10382
10424
  }
10383
- let r = jf(n.schemas);
10384
- if (!r.length) {
10425
+ let s = jf(i.schemas);
10426
+ if (!s.length) {
10385
10427
  c.push(`${a || "(根)"}:目标非 schema 声明数组,元素未校验放行`), f.push({
10386
10428
  op: "appendElems",
10387
10429
  jp: a,
@@ -10389,36 +10431,36 @@ function Mg(e) {
10389
10431
  });
10390
10432
  continue;
10391
10433
  }
10392
- let i = [];
10434
+ let l = [];
10393
10435
  for (let t = 0; t < e.length; t++) {
10394
- let n = [], o, s = !1;
10395
- for (let i of r) {
10396
- let r = i.safeParse(e[t]);
10397
- if (r.success) {
10398
- s = !0, o = r.data;
10436
+ let n = [], r, i = !1;
10437
+ for (let a of s) {
10438
+ let o = a.safeParse(e[t]);
10439
+ if (o.success) {
10440
+ i = !0, r = o.data;
10399
10441
  break;
10400
10442
  }
10401
- n.push(...r.error?.issues ?? []);
10443
+ n.push(...o.error?.issues ?? []);
10402
10444
  }
10403
- if (!s) return {
10445
+ if (!i) return {
10404
10446
  ok: !1,
10405
10447
  error: u(`${a || "(根)"}[新增元素${t}]`, n),
10406
10448
  writeBacks: [],
10407
10449
  notices: c
10408
10450
  };
10409
- let l = Rp(void 0, e[t], o, a ? `${a}.${t}` : String(t));
10410
- if (l.length) return {
10451
+ let o = Rp(void 0, e[t], r, a ? `${a}.${t}` : String(t));
10452
+ if (o.length) return {
10411
10453
  ok: !1,
10412
- error: d(l),
10454
+ error: d(o),
10413
10455
  writeBacks: [],
10414
10456
  notices: c
10415
10457
  };
10416
- i.push(o);
10458
+ l.push(r);
10417
10459
  }
10418
10460
  f.push({
10419
10461
  op: "appendElems",
10420
10462
  jp: a,
10421
- elems: i
10463
+ elems: l
10422
10464
  });
10423
10465
  continue;
10424
10466
  }
@@ -10551,7 +10593,8 @@ function Ng(e) {
10551
10593
  if (l) {
10552
10594
  let e = Tg({
10553
10595
  value: d,
10554
- ctx: l
10596
+ ctx: l,
10597
+ mergeMode: !!r
10555
10598
  });
10556
10599
  if (!e.ok) return {
10557
10600
  ok: !1,
@@ -10673,7 +10716,7 @@ function Pg(e) {
10673
10716
  error: $({
10674
10717
  code: "PATCH_FAILED",
10675
10718
  message: `patches[${e}]: ${c}`,
10676
- hint: "检查 op 与目标类型:merge 需对象,append 需数组"
10719
+ hint: "检查 op 与目标类型:merge 需对象,append 需数组或字符串"
10677
10720
  })
10678
10721
  };
10679
10722
  v(o, a), m.push({
@@ -10730,6 +10773,9 @@ function Pg(e) {
10730
10773
  } else if (e.op === "appendElems") {
10731
10774
  let n = e.jp ? bp(t, e.jp) : t;
10732
10775
  Array.isArray(n) && e.elems?.length && n.push(...e.elems);
10776
+ } else if (e.op === "appendStr") {
10777
+ let n = e.jp ? bp(t, e.jp) : t;
10778
+ typeof n == "string" && typeof e.str == "string" && xp(t, e.jp, n + e.str);
10733
10779
  }
10734
10780
  return e.internalAfterWrite?.(t, f), s?.(), {
10735
10781
  ok: !0,
@@ -11772,14 +11818,22 @@ function Gg(e, n = {}) {
11772
11818
  I(n);
11773
11819
  let i = r(async () => {
11774
11820
  let e = d.list();
11775
- return e.length ? Op({ resources: e }) : "当前无已注册的受保护资源(read 受保护路径会懒注册)";
11821
+ if (!e.length) {
11822
+ let e = [...p.resourcesByPath.entries()].filter(([, e]) => e.mode === "freeze").map(([e]) => e);
11823
+ return e.length ? `资源池为空,但集成方静态配置了 freeze 只读字段:${e.join("、 ")}(freeze 无句柄、不可释放;resource_delete 仅对 verbatim 生效)` : "当前无已注册的受保护资源(read 受保护路径会懒注册)";
11824
+ }
11825
+ return Op({ resources: e });
11776
11826
  }, {
11777
11827
  name: "resource_list",
11778
11828
  description: "列出所有已注册的受保护资源(path/mode/handle/bytes)。",
11779
11829
  schema: t.object({})
11780
11830
  }), a = r(async ({ path: e, handle: t }) => {
11781
11831
  let n = e;
11782
- return !n && t && (n = d.get(t)?.path), n ? d.delete(n) ? `已释放资源 "${n}"(后续 read 该字段会重新懒注册)` : `资源 "${n}" 不存在(无需释放)` : $({
11832
+ return !n && t && (n = d.get(t)?.path), n ? d.delete(n) ? `已释放资源 "${n}"(后续 read 该字段会重新懒注册)` : p.resourcesByPath.get(n)?.mode === "freeze" ? $({
11833
+ code: "FROZEN_FIELD",
11834
+ message: `字段 "${n}" 为 freeze 静态保护(不在资源池、无句柄、不可释放)`,
11835
+ hint: "freeze 由集成方在 data.resources 静态配置,只读不可解;含冻结字段的元素无法整体删除,请保留该元素或由集成方调整 data.resources"
11836
+ }) : `资源 "${n}" 不存在(无需释放)` : $({
11783
11837
  code: "RESOURCE_NOT_FOUND",
11784
11838
  message: "未提供 path 或有效 handle",
11785
11839
  hint: "传要释放的受保护字段 path 或 handle"
@@ -12817,6 +12871,7 @@ ${`- 输出形态:完整、自包含的 HTML 页面(.${r},可独立成页)`}
12817
12871
  - **机械决定一次定**:写法选择(read 回读 vs 复制、vfs 草稿 vs 直写 data、并行 vs 串行)快速选一个,**不在思考里反复权衡 token 成本**(为之纠结反更费 token)。
12818
12872
  - **禁止在思考里整段写出完整代码草稿**:CSS/JS/HTML 代码只写进 write / vfs_write / vfs_edit 工具调用(代码只出现一次);思考里只做高层设计(结构 / 字段 / 方案选择),不要先逐行预写一遍代码再在工具里重复一遍 —— 那会让代码 token 翻倍。
12819
12873
  - **终稿纪律(一次写成)**:动手前要点清单一次定稿(≤10 条:结构 + DOM 分层/z-index + 关键尺寸 + 动画时序),清单齐了**直接在工具调用里写终稿**;① 不先写一版再推翻重写第二版(整段重写 = 代码 token 翻倍,写前多花 30 秒把清单想齐);② 同一几何/层级约束(bottom 定位/遮挡/z-index)**只推演一次**,不重复推导第二遍;③ 写完发现小问题(遮挡/重叠/命名),只改那一处,不重写整段。
12874
+ - **大段 code 分块写(超长代码硬约束)**:预计 code 超过 ~8K 字符时,**一次工具调用装不下会被 max_tokens 掐断** —— 必须分块:① 首块用 write 把组件连同 code 第一段写入(如 code 写到 CSS 中段即止);② 后续每段用 write({op:'append', jsonPath:'${n}.N.${t}', value:'下一段文本'}) 逐块尾接(每块 ≤4K 字符);③ 全部拼完再 validate_code。**禁止**在任何一次调用里塞完整超长代码(截断 = 静默失败重来,token 全废)。
12820
12875
  - **代码字符串不纠结转义**:代码字段(${t})/ content 参数就是普通字符串,直接写完整代码文本(换行、引号照常写),不要纠结「\n」转义、单双引号、字面换行会不会被拒 —— 框架自动序列化,反复权衡纯属浪费 token。
12821
12876
  - 一次想清楚 → 动手 → 验证 → 收口。**思考是手段不是目的,产出代码才是**。
12822
12877
  8. **收口格式(必守,最后一行)**:收口回复 = 简短结果总结 + **末行交接笔记** \`[note] <一句话实现要点>\` —— 关键设计决策 / 用户偏好 / 踩坑(如「[note] 液面用 height keyframes 4.2s 循环;装饰仅灯串+光斑 2 类」)。框架只识别末尾 [note] 行存进组件、自动转交下次维护该组件的子 agent;**漏写 = 下任失去交接**(真 LLM 实测漏写率 3/4,务必末行带上)。一行内,只写可复用结论。`;