page-agent-sdk 4.21.0 → 4.22.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "page-agent-sdk",
3
- "version": "4.21.0",
3
+ "version": "4.22.0",
4
4
  "type": "module",
5
5
  "description": "AI agent SDK for web pages — embed a chat assistant that edits page data via schema-validated tools. A lighter, framework-agnostic alternative to CopilotKit/LangChain for in-page JSON-editing agents. Vue-bundled; works with DeepSeek, OpenAI, MCP.",
6
6
  "main": "./dist/page-agent-sdk.umd.cjs",
@@ -157,6 +157,33 @@ export interface QuoteAnchor {
157
157
  }
158
158
  export declare function captureSelectionQuote(doc: { getSelection?(): { isCollapsed?: boolean; anchorNode?: Node | null; toString(): string } | null; title?: string; location?: { href?: string }; querySelectorAll?: (selector: string) => ArrayLike<Element> }): MessageQuote | null;
159
159
 
160
+ /** 逐行 diff 行类型(content-proposals;lineDiff 产出;skip 行由宿主渲染折叠产生,本函数不产出) */
161
+ export interface DiffRow {
162
+ type: 'same' | 'add' | 'del';
163
+ text: string;
164
+ }
165
+ /** 内容提案增量操作(判别联合;字面锚点纪律:find/anchor 须在当前内容唯一命中) */
166
+ export type ProposalOp = { op: 'replace'; find: string; with: string } | { op: 'insertAfter'; anchor: string; text: string } | { op: 'insertBefore'; anchor: string; text: string } | { op: 'append'; text: string };
167
+ /** 逐行 diff(公共前后缀修剪 + 中段 LCS;中段超 4e6 格回退整块替换)。宿主评审面板渲染/预演用 */
168
+ export declare function lineDiff(oldText: string, newText: string): { rows: DiffRow[]; stats: { added: number; removed: number } };
169
+ /** 顺序应用增量 ops(原子:任一失败整批拒,错误指名第几个 op 与命中数);测试缝/预演用 */
170
+ export declare function applyProposalOps(base: string, ops: ProposalOp[]): { ok: true; content: string } | { ok: false; error: string };
171
+ /** 内容指纹(FNV-1a → base36;提案基底锚定用;非密码学) */
172
+ export declare function hashContent(text: string): string;
173
+ /** 字面锚点命中数(锚为空串按 0 计) */
174
+ export declare function countOccurrences(haystack: string, needle: string): number;
175
+ /** 送达评审面板的提案(content-proposals;SDK 已校验基底/应用 ops/算 diff,宿主渲染面板 + 裁决) */
176
+ export interface ReviewableProposal {
177
+ id: string;
178
+ summary: string;
179
+ label?: string;
180
+ baseHash: string;
181
+ baseContent: string;
182
+ content: string;
183
+ diff: { rows: DiffRow[]; stats: { added: number; removed: number } };
184
+ createdAt: number;
185
+ }
186
+
160
187
  export interface AgentConfig {
161
188
  model: string;
162
189
  temperature?: number;
@@ -220,7 +247,9 @@ export type SdkEvent =
220
247
  | { type: 'error'; message: string; severity?: 'recoverable' | 'fatal' | 'observable'; code?: string; context?: unknown }
221
248
  | { type: 'context_trimmed'; dropped: { round: number; user: unknown; assistant: unknown[]; steps: unknown[] }[]; vfsResults: Record<string, string>; summary: string; reason: string }
222
249
  | { type: 'focus_chip_click'; path: string; label?: string }
223
- | { type: 'focus_change'; focuses: Focus[] };
250
+ | { type: 'focus_change'; focuses: Focus[] }
251
+ | { type: 'proposal_pending'; id: string; summary: string; added: number; removed: number }
252
+ | { type: 'proposal_resolved'; id: string; outcome: 'applied' | 'discarded'; summary: string };
224
253
 
225
254
  /** token 用量(OpenAI 协议字段名) */
226
255
  export interface TokenUsage {
@@ -422,6 +451,8 @@ export interface AgentInfo {
422
451
  hostReadsInvalidated?: number;
423
452
  /** hostWatch 装配反射(4.21+;配置存在才出现):enabled=false = 服务端/headless 特性探测全缺(合法 no-op);autoNotified = 自动报案会话累计 */
424
453
  hostWatch?: { enabled: boolean; url: boolean; pushState: boolean; title: boolean; autoNotified: number };
454
+ /** content-proposals 反射(4.22+;配置存在才出现):pending 轻投影 + 会话累计 + 最近裁决 */
455
+ proposals?: { pending: Array<{ id: string; summary: string; createdAt: number; added: number; removed: number }>; applied: number; discarded: number; lastResolved: { id: string; outcome: 'applied' | 'discarded'; summary: string; detail?: string; at: number } | null };
425
456
  /** A9 收口门禁会话累计(stage → { retries 回灌, exhausted 耗尽放行 };page_assertion_gate 键存在性 = domInspect 装配反射) */
426
457
  gates?: Record<string, { retries: number; exhausted: number }>;
427
458
  /** A9 最近一次 system 段构成(段名/字节/超预算 drop 标记;集成方 augmentSystem/pageContext 段被 drop 时可观察) */
@@ -1074,6 +1105,12 @@ export interface ChatSdkOptions {
1074
1105
  * 另:dom_edit/dom_restore 落地成功后既有页面读自动失效(默认开,与本选项无关)
1075
1106
  */
1076
1107
  hostWatch?: boolean | HostWatchConfig;
1108
+ /**
1109
+ * 内容提案-评审-应用通道(4.22+,配置即开关;不配置 = 零注册零开销):数据槽之外内容的受控修改 ——
1110
+ * 模型零写权限,propose_content 只送提案(非阻塞),diff 评审与写回在宿主侧由用户显式完成。
1111
+ * sdk.resolveProposal(id, 'applied'|'discarded') 裁决回传 → 事件 + 下轮结局告知
1112
+ */
1113
+ proposals?: ProposalsConfig;
1077
1114
  /** Dialog UI config (title/placeholder/drawer/drawerWidth/drawerHidden/inputRows/onClose grouped) */
1078
1115
  dialog?: DialogConfig;
1079
1116
  }
@@ -1091,6 +1128,21 @@ export interface HostWatchConfig {
1091
1128
  /** 宿主自定义忽略(如自家 #section 纯锚点):返回 true 不报案 */
1092
1129
  ignore?: (e: { kind: 'hash' | 'pop' | 'push' | 'title'; from: string; to: string }) => boolean;
1093
1130
  }
1131
+ /** 内容提案通道配置(content-proposals,4.22+) */
1132
+ export interface ProposalsConfig {
1133
+ /** 读通道:返回当前内容(SDK 计算 hash;null = 当前无可编辑对象,工具内如实报) */
1134
+ read: () => Promise<{ content: string; label?: string } | null> | { content: string; label?: string } | null;
1135
+ /** 评审回调:SDK 已完成基底校验/ops 应用/diff 计算;宿主渲染面板。返回字符串回灌模型(非阻塞:勿等待用户裁决) */
1136
+ onProposal: (p: ReviewableProposal) => string | Promise<string>;
1137
+ /** 提案工具名(默认 'propose_content') */
1138
+ toolName?: string;
1139
+ /** 读工具名(默认 'read_content') */
1140
+ readToolName?: string;
1141
+ /** 内容是什么(进工具 description) */
1142
+ contentKind?: string;
1143
+ /** 在审提案上限(默认 1:新提案替换最旧在审,留痕) */
1144
+ maxPending?: number;
1145
+ }
1094
1146
  /** Dialog UI config (grouped form, recommended) */
1095
1147
  export interface DialogConfig {
1096
1148
  title?: string;
@@ -1200,6 +1252,10 @@ export interface ChatSdk {
1200
1252
  clearQuote(): void;
1201
1253
  /** S2 宿主变更通知:SPA 换文/路由切换/tab 切换后调用 —— 流内页面读结果(read_page/dom_search/dom_info/get_dom/take_screenshot)置过期占位,并注入一次性「重读当前页面」提示段(下一 invoke 的 system,pin 段跨压缩,轮末清除);幂等可重复调 */
1202
1254
  notifyHostChange(opts?: { reason?: string }): void;
1255
+ /** content-proposals(4.22+):宿主裁决回传 → 出队 + proposal_resolved 事件 + 下轮结局注入;false = id 未知/已裁决 */
1256
+ resolveProposal(id: string, outcome: 'applied' | 'discarded', detail?: string): boolean;
1257
+ /** content-proposals:只读状态投射(未配置恒 null) */
1258
+ readonly proposals: { pending: Array<{ id: string; summary: string; createdAt: number; added: number; removed: number }>; applied: number; discarded: number; lastResolved: { id: string; outcome: 'applied' | 'discarded'; summary: string; detail?: string; at: number } | null } | null;
1203
1259
  /** 回退到最近一次正常 checkpoint(整体还原对话历史 + 主数据 + vfs + todos);需开启 checkpoint,无可用返回 false */
1204
1260
  restoreLastCheckpoint(): boolean;
1205
1261
  /** 列出可用 checkpoint(回退点);需开启 checkpoint,未开启返回空数组 */
package/types/index.d.ts CHANGED
@@ -165,6 +165,33 @@ export interface QuoteAnchor {
165
165
  }
166
166
  export declare function captureSelectionQuote(doc: { getSelection?(): { isCollapsed?: boolean; anchorNode?: Node | null; toString(): string } | null; title?: string; location?: { href?: string }; querySelectorAll?: (selector: string) => ArrayLike<Element> }): MessageQuote | null;
167
167
 
168
+ /** 逐行 diff 行类型(content-proposals;lineDiff 产出;skip 行由宿主渲染折叠产生,本函数不产出) */
169
+ export interface DiffRow {
170
+ type: 'same' | 'add' | 'del';
171
+ text: string;
172
+ }
173
+ /** 内容提案增量操作(判别联合;字面锚点纪律:find/anchor 须在当前内容唯一命中) */
174
+ export type ProposalOp = { op: 'replace'; find: string; with: string } | { op: 'insertAfter'; anchor: string; text: string } | { op: 'insertBefore'; anchor: string; text: string } | { op: 'append'; text: string };
175
+ /** 逐行 diff(公共前后缀修剪 + 中段 LCS;中段超 4e6 格回退整块替换)。宿主评审面板渲染/预演用 */
176
+ export declare function lineDiff(oldText: string, newText: string): { rows: DiffRow[]; stats: { added: number; removed: number } };
177
+ /** 顺序应用增量 ops(原子:任一失败整批拒,错误指名第几个 op 与命中数);测试缝/预演用 */
178
+ export declare function applyProposalOps(base: string, ops: ProposalOp[]): { ok: true; content: string } | { ok: false; error: string };
179
+ /** 内容指纹(FNV-1a → base36;提案基底锚定用;非密码学) */
180
+ export declare function hashContent(text: string): string;
181
+ /** 字面锚点命中数(锚为空串按 0 计) */
182
+ export declare function countOccurrences(haystack: string, needle: string): number;
183
+ /** 送达评审面板的提案(content-proposals;SDK 已校验基底/应用 ops/算 diff,宿主渲染面板 + 裁决) */
184
+ export interface ReviewableProposal {
185
+ id: string;
186
+ summary: string;
187
+ label?: string;
188
+ baseHash: string;
189
+ baseContent: string;
190
+ content: string;
191
+ diff: { rows: DiffRow[]; stats: { added: number; removed: number } };
192
+ createdAt: number;
193
+ }
194
+
168
195
  export interface AgentMessage {
169
196
  role: 'user' | 'assistant' | 'system';
170
197
  content: string;
@@ -224,7 +251,9 @@ export type SdkEvent =
224
251
  | { type: 'error'; message: string; severity?: 'recoverable' | 'fatal' | 'observable'; code?: string; context?: unknown }
225
252
  | { type: 'context_trimmed'; dropped: { round: number; user: unknown; assistant: unknown[]; steps: unknown[] }[]; vfsResults: Record<string, string>; summary: string; reason: string }
226
253
  | { type: 'focus_chip_click'; path: string; label?: string }
227
- | { type: 'focus_change'; focuses: Focus[] };
254
+ | { type: 'focus_change'; focuses: Focus[] }
255
+ | { type: 'proposal_pending'; id: string; summary: string; added: number; removed: number }
256
+ | { type: 'proposal_resolved'; id: string; outcome: 'applied' | 'discarded'; summary: string };
228
257
 
229
258
  /** token 用量(OpenAI 协议字段名) */
230
259
  export interface TokenUsage {
@@ -731,6 +760,8 @@ export interface AgentInfo {
731
760
  hostReadsInvalidated?: number;
732
761
  /** hostWatch 装配反射(4.21+;配置存在才出现):enabled=false = 服务端/headless 特性探测全缺(合法 no-op);autoNotified = 自动报案会话累计 */
733
762
  hostWatch?: { enabled: boolean; url: boolean; pushState: boolean; title: boolean; autoNotified: number };
763
+ /** content-proposals 反射(4.22+;配置存在才出现):pending 轻投影 + 会话累计 + 最近裁决 */
764
+ proposals?: { pending: Array<{ id: string; summary: string; createdAt: number; added: number; removed: number }>; applied: number; discarded: number; lastResolved: { id: string; outcome: 'applied' | 'discarded'; summary: string; detail?: string; at: number } | null };
734
765
  /** A9 收口门禁会话累计(stage → { retries 回灌, exhausted 耗尽放行 };page_assertion_gate 键存在性 = domInspect 装配反射) */
735
766
  gates?: Record<string, { retries: number; exhausted: number }>;
736
767
  /** A9 最近一次 system 段构成(段名/字节/超预算 drop 标记;集成方 augmentSystem/pageContext 段被 drop 时可观察) */
@@ -1442,6 +1473,12 @@ export interface ChatSdkOptions {
1442
1473
  * 另:dom_edit/dom_restore 落地成功后既有页面读自动失效(默认开,与本选项无关)
1443
1474
  */
1444
1475
  hostWatch?: boolean | HostWatchConfig;
1476
+ /**
1477
+ * 内容提案-评审-应用通道(4.22+,配置即开关;不配置 = 零注册零开销):数据槽之外内容的受控修改 ——
1478
+ * 模型零写权限,propose_content 只送提案(非阻塞),diff 评审与写回在宿主侧由用户显式完成。
1479
+ * sdk.resolveProposal(id, 'applied'|'discarded') 裁决回传 → 事件 + 下轮结局告知
1480
+ */
1481
+ proposals?: ProposalsConfig;
1445
1482
  }
1446
1483
 
1447
1484
  /** Dialog UI config (grouped form, recommended) */
@@ -1507,6 +1544,21 @@ export interface HostWatchConfig {
1507
1544
  /** 宿主自定义忽略(如自家 #section 纯锚点):返回 true 不报案 */
1508
1545
  ignore?: (e: { kind: 'hash' | 'pop' | 'push' | 'title'; from: string; to: string }) => boolean;
1509
1546
  }
1547
+ /** 内容提案通道配置(content-proposals,4.22+) */
1548
+ export interface ProposalsConfig {
1549
+ /** 读通道:返回当前内容(SDK 计算 hash;null = 当前无可编辑对象,工具内如实报) */
1550
+ read: () => Promise<{ content: string; label?: string } | null> | { content: string; label?: string } | null;
1551
+ /** 评审回调:SDK 已完成基底校验/ops 应用/diff 计算;宿主渲染面板。返回字符串回灌模型(非阻塞:勿等待用户裁决) */
1552
+ onProposal: (p: ReviewableProposal) => string | Promise<string>;
1553
+ /** 提案工具名(默认 'propose_content') */
1554
+ toolName?: string;
1555
+ /** 读工具名(默认 'read_content') */
1556
+ readToolName?: string;
1557
+ /** 内容是什么(进工具 description) */
1558
+ contentKind?: string;
1559
+ /** 在审提案上限(默认 1:新提案替换最旧在审,留痕) */
1560
+ maxPending?: number;
1561
+ }
1510
1562
  export interface I18nOptions {
1511
1563
  /** 语言:'zh-CN'(默认)/'en-US';切换内置文案包(聊天面 + Debug 抽屉 + Skill 面板 + 代码预览);
1512
1564
  * formatTime(12h/24h)/autoTitle/默认 systemPrompt 跟随(en → 英文版身份 + "Respond in English" 锚,
@@ -1616,6 +1668,10 @@ export interface ChatSdk {
1616
1668
  clearQuote(): void;
1617
1669
  /** S2 宿主变更通知:SPA 换文/路由切换/tab 切换后调用 —— 流内页面读结果(read_page/dom_search/dom_info/get_dom/take_screenshot)置过期占位,并注入一次性「重读当前页面」提示段(下一 invoke 的 system,pin 段跨压缩,轮末清除);幂等可重复调 */
1618
1670
  notifyHostChange(opts?: { reason?: string }): void;
1671
+ /** content-proposals(4.22+):宿主裁决回传 → 出队 + proposal_resolved 事件 + 下轮结局注入;false = id 未知/已裁决 */
1672
+ resolveProposal(id: string, outcome: 'applied' | 'discarded', detail?: string): boolean;
1673
+ /** content-proposals:只读状态投射(未配置恒 null) */
1674
+ readonly proposals: { pending: Array<{ id: string; summary: string; createdAt: number; added: number; removed: number }>; applied: number; discarded: number; lastResolved: { id: string; outcome: 'applied' | 'discarded'; summary: string; detail?: string; at: number } | null } | null;
1619
1675
  /** 回退到最近一次正常 checkpoint(整体还原对话历史 + 主数据 + vfs + todos);需开启 checkpoint,无可用返回 false */
1620
1676
  restoreLastCheckpoint(): boolean;
1621
1677
  /** 列出可用 checkpoint(回退点);需开启 checkpoint,未开启返回空数组 */