page-agent-sdk 4.20.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.20.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 {
@@ -420,6 +449,10 @@ export interface AgentInfo {
420
449
  staleReadsInvalidated?: number;
421
450
  /** S2 宿主变更失效会话累计(host-integration-contract;notifyHostChange 触发的页面读占位替换次数,与写驱动分列) */
422
451
  hostReadsInvalidated?: number;
452
+ /** hostWatch 装配反射(4.21+;配置存在才出现):enabled=false = 服务端/headless 特性探测全缺(合法 no-op);autoNotified = 自动报案会话累计 */
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 };
423
456
  /** A9 收口门禁会话累计(stage → { retries 回灌, exhausted 耗尽放行 };page_assertion_gate 键存在性 = domInspect 装配反射) */
424
457
  gates?: Record<string, { retries: number; exhausted: number }>;
425
458
  /** A9 最近一次 system 段构成(段名/字节/超预算 drop 标记;集成方 augmentSystem/pageContext 段被 drop 时可观察) */
@@ -1064,10 +1097,52 @@ export interface ChatSdkOptions {
1064
1097
  onEvent?: SdkEventHandler;
1065
1098
  /** 流式输出(默认 true);false 时等整段回复再显示 */
1066
1099
  streaming?: boolean;
1100
+ /**
1101
+ * 宿主导航自动报案(4.21+,配置即开关):监听 URL/title 变化自动触发 notifyHostChange 全链路
1102
+ * (流内页面读占位失效 + 一次性重读提示段)—— 把「防线靠宿主记得调」变「防线自动」。
1103
+ * `true` = { url: true };细配见 HostWatchConfig。服务端/headless(无 window)逐 API 特性探测
1104
+ * 静默降级 no-op(合法形态,inspect().hostWatch.enabled=false 可确认)。
1105
+ * 另:dom_edit/dom_restore 落地成功后既有页面读自动失效(默认开,与本选项无关)
1106
+ */
1107
+ hostWatch?: boolean | HostWatchConfig;
1108
+ /**
1109
+ * 内容提案-评审-应用通道(4.22+,配置即开关;不配置 = 零注册零开销):数据槽之外内容的受控修改 ——
1110
+ * 模型零写权限,propose_content 只送提案(非阻塞),diff 评审与写回在宿主侧由用户显式完成。
1111
+ * sdk.resolveProposal(id, 'applied'|'discarded') 裁决回传 → 事件 + 下轮结局告知
1112
+ */
1113
+ proposals?: ProposalsConfig;
1067
1114
  /** Dialog UI config (title/placeholder/drawer/drawerWidth/drawerHidden/inputRows/onClose grouped) */
1068
1115
  dialog?: DialogConfig;
1069
1116
  }
1070
1117
 
1118
+ /** hostWatch 细配(4.21+):各项独立降级,缺失依赖只关该项不弃整个 watcher */
1119
+ export interface HostWatchConfig {
1120
+ /** 原生 hashchange + popstate(默认项,零 patch;hash 路由文档站主场景) */
1121
+ url?: boolean;
1122
+ /** patch history.pushState/replaceState(hashless SPA 路由;链式保留 + unmount 还原;opt-in) */
1123
+ pushState?: boolean;
1124
+ /** 观察 document.title(不改 URL 的换文站;噪声较高故 opt-in;配 debounceMs 消化) */
1125
+ title?: boolean;
1126
+ /** 去抖窗口 ms(默认 300:路由切换常伴 hash+title 连发,窗口内合并为一次报案,url 类优先) */
1127
+ debounceMs?: number;
1128
+ /** 宿主自定义忽略(如自家 #section 纯锚点):返回 true 不报案 */
1129
+ ignore?: (e: { kind: 'hash' | 'pop' | 'push' | 'title'; from: string; to: string }) => boolean;
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
+ }
1071
1146
  /** Dialog UI config (grouped form, recommended) */
1072
1147
  export interface DialogConfig {
1073
1148
  title?: string;
@@ -1177,6 +1252,10 @@ export interface ChatSdk {
1177
1252
  clearQuote(): void;
1178
1253
  /** S2 宿主变更通知:SPA 换文/路由切换/tab 切换后调用 —— 流内页面读结果(read_page/dom_search/dom_info/get_dom/take_screenshot)置过期占位,并注入一次性「重读当前页面」提示段(下一 invoke 的 system,pin 段跨压缩,轮末清除);幂等可重复调 */
1179
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;
1180
1259
  /** 回退到最近一次正常 checkpoint(整体还原对话历史 + 主数据 + vfs + todos);需开启 checkpoint,无可用返回 false */
1181
1260
  restoreLastCheckpoint(): boolean;
1182
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 {
@@ -729,6 +758,10 @@ export interface AgentInfo {
729
758
  staleReadsInvalidated?: number;
730
759
  /** S2 宿主变更失效会话累计(host-integration-contract;notifyHostChange 触发的页面读占位替换次数,与写驱动分列) */
731
760
  hostReadsInvalidated?: number;
761
+ /** hostWatch 装配反射(4.21+;配置存在才出现):enabled=false = 服务端/headless 特性探测全缺(合法 no-op);autoNotified = 自动报案会话累计 */
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 };
732
765
  /** A9 收口门禁会话累计(stage → { retries 回灌, exhausted 耗尽放行 };page_assertion_gate 键存在性 = domInspect 装配反射) */
733
766
  gates?: Record<string, { retries: number; exhausted: number }>;
734
767
  /** A9 最近一次 system 段构成(段名/字节/超预算 drop 标记;集成方 augmentSystem/pageContext 段被 drop 时可观察) */
@@ -1432,6 +1465,20 @@ export interface ChatSdkOptions {
1432
1465
  dialog?: DialogConfig;
1433
1466
  /** 国际化:locale 切语言 + messages 键级覆盖文案(3.22+;UI 文案包 + 默认 systemPrompt/autoTitle 语言;原 dialog.locale/dialog.messages 两键合并至此) */
1434
1467
  i18n?: I18nOptions;
1468
+ /**
1469
+ * 宿主导航自动报案(4.21+,配置即开关):监听 URL/title 变化自动触发 notifyHostChange 全链路
1470
+ * (流内页面读占位失效 + 一次性重读提示段)—— 把「防线靠宿主记得调」变「防线自动」。
1471
+ * `true` = { url: true };细配见 HostWatchConfig。服务端/headless(无 window)逐 API 特性探测
1472
+ * 静默降级 no-op(合法形态,inspect().hostWatch.enabled=false 可确认)。
1473
+ * 另:dom_edit/dom_restore 落地成功后既有页面读自动失效(默认开,与本选项无关)
1474
+ */
1475
+ hostWatch?: boolean | HostWatchConfig;
1476
+ /**
1477
+ * 内容提案-评审-应用通道(4.22+,配置即开关;不配置 = 零注册零开销):数据槽之外内容的受控修改 ——
1478
+ * 模型零写权限,propose_content 只送提案(非阻塞),diff 评审与写回在宿主侧由用户显式完成。
1479
+ * sdk.resolveProposal(id, 'applied'|'discarded') 裁决回传 → 事件 + 下轮结局告知
1480
+ */
1481
+ proposals?: ProposalsConfig;
1435
1482
  }
1436
1483
 
1437
1484
  /** Dialog UI config (grouped form, recommended) */
@@ -1484,6 +1531,34 @@ export interface QuickActionItem {
1484
1531
  * 国际化配置(顶层 i18n;3.22 起,原 dialog.locale/dialog.messages 两键移入此处合并)。
1485
1532
  * 不放 dialog 组:locale 除 UI 文案包外还驱动默认 systemPrompt 语言与 autoTitle 标题语言(agent 层)。
1486
1533
  */
1534
+ /** hostWatch 细配(4.21+):各项独立降级,缺失依赖只关该项不弃整个 watcher */
1535
+ export interface HostWatchConfig {
1536
+ /** 原生 hashchange + popstate(默认项,零 patch;hash 路由文档站主场景) */
1537
+ url?: boolean;
1538
+ /** patch history.pushState/replaceState(hashless SPA 路由;链式保留 + unmount 还原;opt-in) */
1539
+ pushState?: boolean;
1540
+ /** 观察 document.title(不改 URL 的换文站;噪声较高故 opt-in;配 debounceMs 消化) */
1541
+ title?: boolean;
1542
+ /** 去抖窗口 ms(默认 300:路由切换常伴 hash+title 连发,窗口内合并为一次报案,url 类优先) */
1543
+ debounceMs?: number;
1544
+ /** 宿主自定义忽略(如自家 #section 纯锚点):返回 true 不报案 */
1545
+ ignore?: (e: { kind: 'hash' | 'pop' | 'push' | 'title'; from: string; to: string }) => boolean;
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
+ }
1487
1562
  export interface I18nOptions {
1488
1563
  /** 语言:'zh-CN'(默认)/'en-US';切换内置文案包(聊天面 + Debug 抽屉 + Skill 面板 + 代码预览);
1489
1564
  * formatTime(12h/24h)/autoTitle/默认 systemPrompt 跟随(en → 英文版身份 + "Respond in English" 锚,
@@ -1593,6 +1668,10 @@ export interface ChatSdk {
1593
1668
  clearQuote(): void;
1594
1669
  /** S2 宿主变更通知:SPA 换文/路由切换/tab 切换后调用 —— 流内页面读结果(read_page/dom_search/dom_info/get_dom/take_screenshot)置过期占位,并注入一次性「重读当前页面」提示段(下一 invoke 的 system,pin 段跨压缩,轮末清除);幂等可重复调 */
1595
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;
1596
1675
  /** 回退到最近一次正常 checkpoint(整体还原对话历史 + 主数据 + vfs + todos);需开启 checkpoint,无可用返回 false */
1597
1676
  restoreLastCheckpoint(): boolean;
1598
1677
  /** 列出可用 checkpoint(回退点);需开启 checkpoint,未开启返回空数组 */