page-agent-sdk 4.1.0 → 4.2.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 +2 -2
- package/README.zh-CN.md +2 -2
- package/dist/page-agent-sdk.headless.js +153 -99
- package/dist/page-agent-sdk.iife.js +4 -3
- package/dist/page-agent-sdk.js +107 -53
- package/dist/page-agent-sdk.legacy.js +131 -76
- package/dist/page-agent-sdk.umd.cjs +4 -3
- package/package.json +1 -1
|
@@ -57341,7 +57341,7 @@ function v$(e, t, n, r) {
|
|
|
57341
57341
|
}
|
|
57342
57342
|
if (t === "move") return b$(e, n, r);
|
|
57343
57343
|
let i = n ? s$(e, n) : e;
|
|
57344
|
-
return Array.isArray(i) ? (Array.isArray(r) ? i.push(...r) : i.push(r), null) : `append 目标${n ? `(${n})` : "(根)"}
|
|
57344
|
+
return typeof i == "string" ? typeof r == "string" ? (c$(e, n, i + r), null) : `append 目标(${n})是字符串,value 必须也是字符串(拼接语义)` : Array.isArray(i) ? (Array.isArray(r) ? i.push(...r) : i.push(r), null) : `append 目标${n ? `(${n})` : "(根)"}不是数组(也不支持非字符串标量拼接)`;
|
|
57345
57345
|
}
|
|
57346
57346
|
function y$(e, t) {
|
|
57347
57347
|
let n = t.split("."), r = e;
|
|
@@ -67659,47 +67659,63 @@ function Mke(e, t, n, r) {
|
|
|
67659
67659
|
hint: "重新 read 该字段触发懒注册重建句柄,再写回新句柄 ⟦res:<handle>⟧"
|
|
67660
67660
|
};
|
|
67661
67661
|
}
|
|
67662
|
-
function Nke(e, t) {
|
|
67663
|
-
let
|
|
67664
|
-
for (let [
|
|
67665
|
-
let
|
|
67666
|
-
if (
|
|
67667
|
-
|
|
67668
|
-
|
|
67662
|
+
function Nke(e, t, n) {
|
|
67663
|
+
let r = t.getBind();
|
|
67664
|
+
for (let [i, a] of t.resourcesByPath) {
|
|
67665
|
+
let o = s$(r, i), s = s$(e, i);
|
|
67666
|
+
if (s === void 0) {
|
|
67667
|
+
if (o === void 0) continue;
|
|
67668
|
+
let t = i.split(".");
|
|
67669
|
+
if (s$(e, t.length > 1 ? t.slice(0, -1).join(".") : "") !== void 0) {
|
|
67670
|
+
c$(e, i, o);
|
|
67671
|
+
continue;
|
|
67672
|
+
}
|
|
67673
|
+
if (!(e && typeof e == "object" && t[0] in e)) {
|
|
67674
|
+
if (n) continue;
|
|
67675
|
+
c$(e, i, o);
|
|
67676
|
+
continue;
|
|
67677
|
+
}
|
|
67678
|
+
return {
|
|
67679
|
+
ok: !1,
|
|
67680
|
+
code: a.mode === "freeze" ? "FROZEN_FIELD" : "VERBATIM_PROTECTED",
|
|
67681
|
+
path: i,
|
|
67682
|
+
message: `整体替换会移除受保护字段 "${i}"(${a.mode}),已拒绝`,
|
|
67683
|
+
hint: a.mode === "freeze" ? "含冻结字段的容器不可整体清空/替换:保留包含该字段的元素(补齐其必填字段,如 type),或逐个 remove 其余元素;彻底移除该字段需集成方调整 data.resources" : "含 verbatim 字段的容器不可整体清空/替换:保留包含该字段的元素,或先 resource_delete({path}) 释放保护后再整体替换"
|
|
67684
|
+
};
|
|
67669
67685
|
}
|
|
67670
|
-
if (
|
|
67671
|
-
if (
|
|
67672
|
-
c$(e,
|
|
67686
|
+
if (a.mode === "freeze") {
|
|
67687
|
+
if (s === V6(i)) {
|
|
67688
|
+
c$(e, i, o);
|
|
67673
67689
|
continue;
|
|
67674
67690
|
}
|
|
67675
|
-
if (!W6(
|
|
67691
|
+
if (!W6(s, o)) return {
|
|
67676
67692
|
ok: !1,
|
|
67677
67693
|
code: "FROZEN_FIELD",
|
|
67678
|
-
path:
|
|
67679
|
-
message: `字段 "${
|
|
67694
|
+
path: i,
|
|
67695
|
+
message: `字段 "${i}" 已冻结(freeze 保护),不可修改`,
|
|
67680
67696
|
hint: "该字段由系统/集成方维护,LLM 不得改动。如需展示其值用 resource_get({path}) 取真值"
|
|
67681
67697
|
};
|
|
67682
67698
|
} else {
|
|
67683
|
-
let n = Oke(
|
|
67699
|
+
let n = Oke(s);
|
|
67684
67700
|
if (n && n.type === "res") {
|
|
67685
|
-
let
|
|
67686
|
-
if ("value" in
|
|
67687
|
-
c$(e,
|
|
67701
|
+
let r = Mke(n.handle, i, o, t.resourceStore);
|
|
67702
|
+
if ("value" in r) {
|
|
67703
|
+
c$(e, i, r.value);
|
|
67688
67704
|
continue;
|
|
67689
67705
|
}
|
|
67690
67706
|
return {
|
|
67691
67707
|
ok: !1,
|
|
67692
|
-
code:
|
|
67693
|
-
path:
|
|
67694
|
-
message:
|
|
67695
|
-
hint:
|
|
67708
|
+
code: r.code,
|
|
67709
|
+
path: i,
|
|
67710
|
+
message: r.message,
|
|
67711
|
+
hint: r.hint
|
|
67696
67712
|
};
|
|
67697
67713
|
}
|
|
67698
|
-
if (!W6(
|
|
67714
|
+
if (!W6(s, o)) return {
|
|
67699
67715
|
ok: !1,
|
|
67700
67716
|
code: "VERBATIM_MISMATCH",
|
|
67701
|
-
path:
|
|
67702
|
-
message: `字段 "${
|
|
67717
|
+
path: i,
|
|
67718
|
+
message: `字段 "${i}" 为 verbatim 保护(精确原样保留),写入值与原值不符`,
|
|
67703
67719
|
hint: "要改该值请先 resource_update({path, value}) 更新资源池,再写回句柄 ⟦res:<handle>⟧;或写回原值(经 resource_get 取到的值)保持不变"
|
|
67704
67720
|
};
|
|
67705
67721
|
}
|
|
@@ -67719,18 +67735,18 @@ function Pke(e, t, n) {
|
|
|
67719
67735
|
} }));
|
|
67720
67736
|
}
|
|
67721
67737
|
function Fke(e) {
|
|
67722
|
-
let { value: t, ctx: n } = e;
|
|
67738
|
+
let { value: t, ctx: n, mergeMode: r } = e;
|
|
67723
67739
|
if (!n || !n.resourcesByPath.size) return {
|
|
67724
67740
|
ok: !0,
|
|
67725
67741
|
value: t
|
|
67726
67742
|
};
|
|
67727
|
-
let
|
|
67728
|
-
return
|
|
67743
|
+
let i = u$(t), a = Nke(i, n, r);
|
|
67744
|
+
return a.ok ? {
|
|
67729
67745
|
ok: !0,
|
|
67730
|
-
value:
|
|
67746
|
+
value: i
|
|
67731
67747
|
} : {
|
|
67732
67748
|
ok: !1,
|
|
67733
|
-
error: Pke(
|
|
67749
|
+
error: Pke(a)
|
|
67734
67750
|
};
|
|
67735
67751
|
}
|
|
67736
67752
|
function Ike(e) {
|
|
@@ -67954,8 +67970,34 @@ function Rke(e) {
|
|
|
67954
67970
|
}
|
|
67955
67971
|
if (i === "append") {
|
|
67956
67972
|
var v;
|
|
67957
|
-
let e = o[p++],
|
|
67958
|
-
if (
|
|
67973
|
+
let e = o[p++], r = (v = e == null ? void 0 : e.elems) == null ? [] : v, i = s$(n, a);
|
|
67974
|
+
if (typeof i == "string" && typeof r[0] == "string") {
|
|
67975
|
+
let e = r[0], n = IQ(t, a);
|
|
67976
|
+
if (n.kind === "missing") return {
|
|
67977
|
+
ok: !1,
|
|
67978
|
+
error: d([a]),
|
|
67979
|
+
writeBacks: [],
|
|
67980
|
+
notices: c
|
|
67981
|
+
};
|
|
67982
|
+
let o = i + e;
|
|
67983
|
+
if (n.kind !== "open") {
|
|
67984
|
+
var y, b;
|
|
67985
|
+
let e = n.schemas.map((e) => e.safeParse(o)).find((e) => !e.success);
|
|
67986
|
+
if (e) return {
|
|
67987
|
+
ok: !1,
|
|
67988
|
+
error: u(a, (y = (b = e.error) == null ? void 0 : b.issues) == null ? [] : y),
|
|
67989
|
+
writeBacks: [],
|
|
67990
|
+
notices: c
|
|
67991
|
+
};
|
|
67992
|
+
}
|
|
67993
|
+
f.push({
|
|
67994
|
+
op: "appendStr",
|
|
67995
|
+
jp: a,
|
|
67996
|
+
str: e
|
|
67997
|
+
});
|
|
67998
|
+
continue;
|
|
67999
|
+
}
|
|
68000
|
+
if (!r.length) {
|
|
67959
68001
|
f.push({
|
|
67960
68002
|
op: "appendElems",
|
|
67961
68003
|
jp: a,
|
|
@@ -67963,61 +68005,61 @@ function Rke(e) {
|
|
|
67963
68005
|
});
|
|
67964
68006
|
continue;
|
|
67965
68007
|
}
|
|
67966
|
-
let
|
|
67967
|
-
if (
|
|
68008
|
+
let s = IQ(t, a);
|
|
68009
|
+
if (s.kind === "missing") return {
|
|
67968
68010
|
ok: !1,
|
|
67969
68011
|
error: d([a || "(根)"]),
|
|
67970
68012
|
writeBacks: [],
|
|
67971
68013
|
notices: c
|
|
67972
68014
|
};
|
|
67973
|
-
if (
|
|
68015
|
+
if (s.kind === "open") {
|
|
67974
68016
|
c.push(`${a || "(根)"}=开放节点放行`), f.push({
|
|
67975
68017
|
op: "appendElems",
|
|
67976
68018
|
jp: a,
|
|
67977
|
-
elems:
|
|
68019
|
+
elems: r
|
|
67978
68020
|
});
|
|
67979
68021
|
continue;
|
|
67980
68022
|
}
|
|
67981
|
-
let
|
|
67982
|
-
if (!
|
|
68023
|
+
let l = BQ(s.schemas);
|
|
68024
|
+
if (!l.length) {
|
|
67983
68025
|
c.push(`${a || "(根)"}:目标非 schema 声明数组,元素未校验放行`), f.push({
|
|
67984
68026
|
op: "appendElems",
|
|
67985
68027
|
jp: a,
|
|
67986
|
-
elems:
|
|
68028
|
+
elems: r
|
|
67987
68029
|
});
|
|
67988
68030
|
continue;
|
|
67989
68031
|
}
|
|
67990
|
-
let
|
|
67991
|
-
for (let e = 0; e <
|
|
67992
|
-
let t = [],
|
|
67993
|
-
for (let a of
|
|
67994
|
-
var
|
|
67995
|
-
let
|
|
67996
|
-
if (
|
|
67997
|
-
|
|
68032
|
+
let m = [];
|
|
68033
|
+
for (let e = 0; e < r.length; e++) {
|
|
68034
|
+
let t = [], n, i = !1;
|
|
68035
|
+
for (let a of l) {
|
|
68036
|
+
var x, S;
|
|
68037
|
+
let o = a.safeParse(r[e]);
|
|
68038
|
+
if (o.success) {
|
|
68039
|
+
i = !0, n = o.data;
|
|
67998
68040
|
break;
|
|
67999
68041
|
}
|
|
68000
|
-
t.push(...(
|
|
68042
|
+
t.push(...(x = (S = o.error) == null ? void 0 : S.issues) == null ? [] : x);
|
|
68001
68043
|
}
|
|
68002
|
-
if (!
|
|
68044
|
+
if (!i) return {
|
|
68003
68045
|
ok: !1,
|
|
68004
68046
|
error: u(`${a || "(根)"}[新增元素${e}]`, t),
|
|
68005
68047
|
writeBacks: [],
|
|
68006
68048
|
notices: c
|
|
68007
68049
|
};
|
|
68008
|
-
let
|
|
68009
|
-
if (
|
|
68050
|
+
let o = C$(void 0, r[e], n, a ? `${a}.${e}` : String(e));
|
|
68051
|
+
if (o.length) return {
|
|
68010
68052
|
ok: !1,
|
|
68011
|
-
error: d(
|
|
68053
|
+
error: d(o),
|
|
68012
68054
|
writeBacks: [],
|
|
68013
68055
|
notices: c
|
|
68014
68056
|
};
|
|
68015
|
-
|
|
68057
|
+
m.push(n);
|
|
68016
68058
|
}
|
|
68017
68059
|
f.push({
|
|
68018
68060
|
op: "appendElems",
|
|
68019
68061
|
jp: a,
|
|
68020
|
-
elems:
|
|
68062
|
+
elems: m
|
|
68021
68063
|
});
|
|
68022
68064
|
continue;
|
|
68023
68065
|
}
|
|
@@ -68048,7 +68090,7 @@ function Rke(e) {
|
|
|
68048
68090
|
if (e.startsWith("__pg") || i$.has(e)) continue;
|
|
68049
68091
|
let r = a ? `${a}.${e}` : e, o = l(r), s = LQ(t, r, o);
|
|
68050
68092
|
if (!s.ok) {
|
|
68051
|
-
var
|
|
68093
|
+
var C;
|
|
68052
68094
|
if (s.resolution === "missing") {
|
|
68053
68095
|
if (s$(n, r) === void 0) return {
|
|
68054
68096
|
ok: !1,
|
|
@@ -68061,7 +68103,7 @@ function Rke(e) {
|
|
|
68061
68103
|
}
|
|
68062
68104
|
return {
|
|
68063
68105
|
ok: !1,
|
|
68064
|
-
error: u(r, (
|
|
68106
|
+
error: u(r, (C = s.issues) == null ? [] : C),
|
|
68065
68107
|
writeBacks: [],
|
|
68066
68108
|
notices: c
|
|
68067
68109
|
};
|
|
@@ -68083,9 +68125,9 @@ function Rke(e) {
|
|
|
68083
68125
|
});
|
|
68084
68126
|
continue;
|
|
68085
68127
|
}
|
|
68086
|
-
let
|
|
68087
|
-
if (
|
|
68088
|
-
let e = s$(r, a.slice(0,
|
|
68128
|
+
let T = l(a), E = a.lastIndexOf(".");
|
|
68129
|
+
if (E > 0 && /^\d+$/.test(a.slice(E + 1))) {
|
|
68130
|
+
let e = s$(r, a.slice(0, E));
|
|
68089
68131
|
if (Array.isArray(e)) {
|
|
68090
68132
|
for (let t = 0; t < e.length; t++) if (!(t in e)) return {
|
|
68091
68133
|
ok: !1,
|
|
@@ -68099,10 +68141,10 @@ function Rke(e) {
|
|
|
68099
68141
|
};
|
|
68100
68142
|
}
|
|
68101
68143
|
}
|
|
68102
|
-
let
|
|
68103
|
-
if (!
|
|
68104
|
-
var
|
|
68105
|
-
if (
|
|
68144
|
+
let D = LQ(t, a, T);
|
|
68145
|
+
if (!D.ok) {
|
|
68146
|
+
var w;
|
|
68147
|
+
if (D.resolution === "missing") {
|
|
68106
68148
|
if (s$(n, a) === void 0) return {
|
|
68107
68149
|
ok: !1,
|
|
68108
68150
|
error: d([a]),
|
|
@@ -68112,29 +68154,29 @@ function Rke(e) {
|
|
|
68112
68154
|
f.push({
|
|
68113
68155
|
op: "set",
|
|
68114
68156
|
jp: a,
|
|
68115
|
-
value:
|
|
68157
|
+
value: T
|
|
68116
68158
|
});
|
|
68117
68159
|
continue;
|
|
68118
68160
|
}
|
|
68119
68161
|
return {
|
|
68120
68162
|
ok: !1,
|
|
68121
|
-
error: u(a, (
|
|
68163
|
+
error: u(a, (w = D.issues) == null ? [] : w),
|
|
68122
68164
|
writeBacks: [],
|
|
68123
68165
|
notices: c
|
|
68124
68166
|
};
|
|
68125
68167
|
}
|
|
68126
|
-
|
|
68127
|
-
let
|
|
68128
|
-
if (
|
|
68168
|
+
D.resolution === "open" && c.push(`${a || "(根)"}=开放节点放行`);
|
|
68169
|
+
let O = C$(s$(n, a), T, D.data, a);
|
|
68170
|
+
if (O.length) return {
|
|
68129
68171
|
ok: !1,
|
|
68130
|
-
error: d(
|
|
68172
|
+
error: d(O),
|
|
68131
68173
|
writeBacks: [],
|
|
68132
68174
|
notices: c
|
|
68133
68175
|
};
|
|
68134
68176
|
f.push({
|
|
68135
68177
|
op: "set",
|
|
68136
68178
|
jp: a,
|
|
68137
|
-
value:
|
|
68179
|
+
value: D.data
|
|
68138
68180
|
});
|
|
68139
68181
|
}
|
|
68140
68182
|
return {
|
|
@@ -68153,7 +68195,8 @@ function Y6(e) {
|
|
|
68153
68195
|
if (d) {
|
|
68154
68196
|
let e = Fke({
|
|
68155
68197
|
value: p,
|
|
68156
|
-
ctx: d
|
|
68198
|
+
ctx: d,
|
|
68199
|
+
mergeMode: !!a
|
|
68157
68200
|
});
|
|
68158
68201
|
if (!e.ok) return {
|
|
68159
68202
|
ok: !1,
|
|
@@ -68276,7 +68319,7 @@ function X6(e) {
|
|
|
68276
68319
|
error: AZ({
|
|
68277
68320
|
code: "PATCH_FAILED",
|
|
68278
68321
|
message: `patches[${e}]: ${c}`,
|
|
68279
|
-
hint: "检查 op 与目标类型:merge 需对象,append
|
|
68322
|
+
hint: "检查 op 与目标类型:merge 需对象,append 需数组或字符串"
|
|
68280
68323
|
})
|
|
68281
68324
|
};
|
|
68282
68325
|
y(o, n), h.push({
|
|
@@ -68339,6 +68382,9 @@ function X6(e) {
|
|
|
68339
68382
|
var w;
|
|
68340
68383
|
let t = e.jp ? s$(n, e.jp) : n;
|
|
68341
68384
|
Array.isArray(t) && (w = e.elems) != null && w.length && t.push(...e.elems);
|
|
68385
|
+
} else if (e.op === "appendStr") {
|
|
68386
|
+
let t = e.jp ? s$(n, e.jp) : n;
|
|
68387
|
+
typeof t == "string" && typeof e.str == "string" && c$(n, e.jp, t + e.str);
|
|
68342
68388
|
}
|
|
68343
68389
|
return (t = e.internalAfterWrite) == null || t.call(e, n, p), c == null || c(), {
|
|
68344
68390
|
ok: !0,
|
|
@@ -69406,15 +69452,23 @@ function t8(e, t = {}) {
|
|
|
69406
69452
|
fe(t);
|
|
69407
69453
|
let n = fF(async () => {
|
|
69408
69454
|
let e = v.list();
|
|
69409
|
-
|
|
69455
|
+
if (!e.length) {
|
|
69456
|
+
let e = [...b.resourcesByPath.entries()].filter(([, e]) => e.mode === "freeze").map(([e]) => e);
|
|
69457
|
+
return e.length ? `资源池为空,但集成方静态配置了 freeze 只读字段:${e.join("、 ")}(freeze 无句柄、不可释放;resource_delete 仅对 verbatim 生效)` : "当前无已注册的受保护资源(read 受保护路径会懒注册)";
|
|
69458
|
+
}
|
|
69459
|
+
return m$({ resources: e });
|
|
69410
69460
|
}, {
|
|
69411
69461
|
name: "resource_list",
|
|
69412
69462
|
description: "列出所有已注册的受保护资源(path/mode/handle/bytes)。",
|
|
69413
69463
|
schema: B({})
|
|
69414
69464
|
}), r = fF(async ({ path: e, handle: t }) => {
|
|
69415
|
-
var n;
|
|
69416
|
-
let
|
|
69417
|
-
return !
|
|
69465
|
+
var n, r;
|
|
69466
|
+
let i = e;
|
|
69467
|
+
return !i && t && (i = (n = v.get(t)) == null ? void 0 : n.path), i ? v.delete(i) ? `已释放资源 "${i}"(后续 read 该字段会重新懒注册)` : ((r = b.resourcesByPath.get(i)) == null ? void 0 : r.mode) === "freeze" ? AZ({
|
|
69468
|
+
code: "FROZEN_FIELD",
|
|
69469
|
+
message: `字段 "${i}" 为 freeze 静态保护(不在资源池、无句柄、不可释放)`,
|
|
69470
|
+
hint: "freeze 由集成方在 data.resources 静态配置,只读不可解;含冻结字段的元素无法整体删除,请保留该元素或由集成方调整 data.resources"
|
|
69471
|
+
}) : `资源 "${i}" 不存在(无需释放)` : AZ({
|
|
69418
69472
|
code: "RESOURCE_NOT_FOUND",
|
|
69419
69473
|
message: "未提供 path 或有效 handle",
|
|
69420
69474
|
hint: "传要释放的受保护字段 path 或 handle"
|
|
@@ -70489,6 +70543,7 @@ ${`- 输出形态:完整、自包含的 HTML 页面(.${r},可独立成页)`}
|
|
|
70489
70543
|
- **机械决定一次定**:写法选择(read 回读 vs 复制、vfs 草稿 vs 直写 data、并行 vs 串行)快速选一个,**不在思考里反复权衡 token 成本**(为之纠结反更费 token)。
|
|
70490
70544
|
- **禁止在思考里整段写出完整代码草稿**:CSS/JS/HTML 代码只写进 write / vfs_write / vfs_edit 工具调用(代码只出现一次);思考里只做高层设计(结构 / 字段 / 方案选择),不要先逐行预写一遍代码再在工具里重复一遍 —— 那会让代码 token 翻倍。
|
|
70491
70545
|
- **终稿纪律(一次写成)**:动手前要点清单一次定稿(≤10 条:结构 + DOM 分层/z-index + 关键尺寸 + 动画时序),清单齐了**直接在工具调用里写终稿**;① 不先写一版再推翻重写第二版(整段重写 = 代码 token 翻倍,写前多花 30 秒把清单想齐);② 同一几何/层级约束(bottom 定位/遮挡/z-index)**只推演一次**,不重复推导第二遍;③ 写完发现小问题(遮挡/重叠/命名),只改那一处,不重写整段。
|
|
70546
|
+
- **大段 code 分块写(超长代码硬约束)**:预计 code 超过 ~8K 字符时,**一次工具调用装不下会被 max_tokens 掐断** —— 必须分块:① 首块用 write 把组件连同 code 第一段写入(如 code 写到 CSS 中段即止);② 后续每段用 write({op:'append', jsonPath:'${n}.N.${t}', value:'下一段文本'}) 逐块尾接(每块 ≤4K 字符);③ 全部拼完再 validate_code。**禁止**在任何一次调用里塞完整超长代码(截断 = 静默失败重来,token 全废)。
|
|
70492
70547
|
- **代码字符串不纠结转义**:代码字段(${t})/ content 参数就是普通字符串,直接写完整代码文本(换行、引号照常写),不要纠结「\n」转义、单双引号、字面换行会不会被拒 —— 框架自动序列化,反复权衡纯属浪费 token。
|
|
70493
70548
|
- 一次想清楚 → 动手 → 验证 → 收口。**思考是手段不是目的,产出代码才是**。
|
|
70494
70549
|
8. **收口格式(必守,最后一行)**:收口回复 = 简短结果总结 + **末行交接笔记** \`[note] <一句话实现要点>\` —— 关键设计决策 / 用户偏好 / 踩坑(如「[note] 液面用 height keyframes 4.2s 循环;装饰仅灯串+光斑 2 类」)。框架只识别末尾 [note] 行存进组件、自动转交下次维护该组件的子 agent;**漏写 = 下任失去交接**(真 LLM 实测漏写率 3/4,务必末行带上)。一行内,只写可复用结论。`;
|