page-agent-sdk 2.30.0 → 2.32.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": "2.30.0",
3
+ "version": "2.32.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",
@@ -200,6 +200,14 @@ createChatSdk({
200
200
 
201
201
  - **`bind` is required** (any object): reactive → auto-refresh on write (recommended for UI); plain object → write works but no auto-refresh (suitable for headless / backend; integrator uses `onEvent`/`hook` `data_change` to be notified). Tools mutate in-place (`restoreInPlace`), compatible with reactive proxies; plain objects also write fine.
202
202
  - **Notifying the outside world of changes**: subscribe `data_change` via `onEvent` (constructor) or `sdk.hook` (runtime, multi-listener, cancellable) — fires after `write`/`set`/`edit`/`delete`/`restore`, with `operation`/`value`. For Vue + reactive bind, template/watch auto-react (no manual notify needed); `onEvent` can coexist for audit/analytics.
203
+ - **Protected resources (precise-value protection)**: declare `data.resources: [{ path, mode }]` to protect fields needing exact preservation (ids / hashes / tokens / long verbatim / critical config).
204
+ - `mode: 'freeze'` = read-only (exact value hidden from LLM via `⟦frozen:path⟧` placeholder; any write rejected with `FROZEN_FIELD`; need value via `resource_get`).
205
+ - `mode: 'verbatim'` = exact string preserved (returns `⟦res:handle⟧` placeholder, original in resource pool; modify via `resource_update({path,value})` first, then write back handle; direct new value → `VERBATIM_MISMATCH`).
206
+ - opt-in: only when `data.resources` non-empty + vfs enabled (`capabilities.vfs`, default on) → exposes `resource_get`/`resource_update`/`resource_list`/`resource_delete` tools (advanced mode) + injects cross-compression pin. Unconfigured → zero behavior change.
207
+ ```js
208
+ data: { schema, bind, resources: [{ path: 'id', mode: 'freeze' }, { path: 'token', mode: 'verbatim' }] }
209
+ ```
210
+ SDK API: `sdk.createResource/getResource/updateResource/deleteResource/listResources/releaseResources`.
203
211
  - **Runtime swap**: `sdk.setData({ schema, bind, description? })` replaces the whole config; tools pick up immediately (no rebuild). Snapshots & lock hash reset.
204
212
  - **Runtime skill swap**: `sdk.setSkills(skills)` replaces the entire skill list (same-name overwrites); the skill index section of the system prompt re-renders next round, and the skill full-text cache is cleared so the next `load_skill` re-fetches the latest content (incl. vfs doc). Use `sdk.invalidateSkillCache(name?)` to proactively invalidate the cache when a dynamic skill's content changes (without swapping the whole list).
205
213
  - **Runtime dynamic reconfiguration (zero-breakage; not calling = current behavior)**: beyond data/skills, you can also dynamically reconfigure tools / LLM / memory / subagents at runtime without rebuilding the agent:
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: precise-value-protection
3
+ description: 识别需精确保存的字段(id/hash/token/长 verbatim/关键配置),正确处理 ⟦frozen⟧/⟦res⟧ 占位符读写,避免幻觉改错或压缩丢字
4
+ ---
5
+
6
+ # 精确值保护(precise-value-protection)
7
+
8
+ ## 何时用
9
+
10
+ 当主数据含需精确保存的字段(集成方在 `data.resources` 声明 freeze/verbatim)时,read 会返回**占位符**而非真值。本 skill 指导你正确读写受保护字段,避免幻觉改错精确值(如猜一个"差不多"的 id/hash 写回)或长串被压缩丢字后重打错字。
11
+
12
+ ## 占位符
13
+
14
+ read 受保护路径返回占位符(精确值不入你的消息流,从源头防幻觉/防丢字):
15
+ - `⟦frozen:<path>⟧` — freeze 字段(只读,精确值完全不可见)。
16
+ - `⟦res:<handle>⟧` — verbatim 字段(原值存资源池,handle 是路径派生短哈希,值变句柄不变)。
17
+
18
+ system prompt 的「受保护资源」段每轮列出受保护字段 + 模式 + 句柄(跨压缩保留)。
19
+
20
+ ## 读
21
+
22
+ - read 受保护路径 → 占位符(非真值)。
23
+ - 确需真值(如展示/比对):`resource_get({path})` 或 `resource_get({handle})`(仅受保护路径)。
24
+
25
+ ## 写
26
+
27
+ - **freeze 字段完全不可改**(集成方/系统维护,如 id/createdAt/状态码)。撞 `FROZEN_FIELD` 即**放弃该字段改动**,不要重试不同值。
28
+ - **verbatim 字段**(精确长串,如 token/hash/签名/原始配置):
29
+ - 不改 → write 时**原样写回句柄** `⟦res:<handle>⟧`(整体 set 时把占位符带回,框架识别为"未改")。
30
+ - 改新值 → 先 `resource_update({path, value})` 更新资源池(自动同步 bind),再 write 写回句柄。**直接 write 新值会 `VERBATIM_MISMATCH`**。
31
+
32
+ ## 错误码应对
33
+
34
+ | 错误码 | 含义 | 应对 |
35
+ |---|---|---|
36
+ | `FROZEN_FIELD` | 改 freeze 字段 | 放弃该字段改动 |
37
+ | `VERBATIM_MISMATCH` | verbatim 写新值未先 update | 先 `resource_update({path,value})` 再写句柄 |
38
+ | `VERBATIM_PROTECTED` | 删 verbatim 字段被拒 | 先 `resource_delete({path})` 释放再删 |
39
+ | `RESOURCE_EVICTED` | 资源被池淘汰(LRU) | 重新 `read` 该字段懒注册重建句柄 |
40
+ | `RESOURCE_NOT_FOUND` | 句柄失效/字段未注册 | 重新 `read` 触发懒注册 |
41
+
42
+ ## 识别需保护字段
43
+
44
+ 集成方在 `data.resources` 声明,你无需自行判断。常见保护对象:唯一标识(id/uid/slug)、时间戳(createdAt/updatedAt)、签名/hash/token、长 verbatim 内容(原始文本/密钥/配置版本)。按 read 返回的占位符识别受保护字段。
45
+
46
+ ## 关键不变式
47
+
48
+ - 占位符背后的精确值**永不在你的消息流里**(freeze 完全隐藏;verbatim 经 `resource_get` 按需取)。不要凭记忆猜测精确值写回 —— 要么写句柄,要么经 `resource_get` 取真值。
49
+ - 整体 set 时,受保护字段若不改动,**带回占位符**(框架识别为未改保留当前值);若改动走对应通道(freeze 不可改;verbatim 先 update)。
package/types/index.d.ts CHANGED
@@ -281,6 +281,14 @@ export type ChatModelLike = {
281
281
  bindTools: (tools: any[]) => any;
282
282
  };
283
283
 
284
+ /** 受保护资源配置(精确值保护:占位符替换读写) */
285
+ export interface ResourceProtectSpec {
286
+ /** 相对主数据根的点号路径(如 id / components.0.verification) */
287
+ path: string;
288
+ /** freeze=只读不可改(精确值不入消息流);verbatim=原样保留(防压缩丢字,改须经 resource_update) */
289
+ mode: 'freeze' | 'verbatim';
290
+ }
291
+
284
292
  export interface DataConfig {
285
293
  /** 值的 zod schema(写入时校验);字段的 .describe() 自动提取注入 systemPrompt「可操作数据」段 */
286
294
  schema: any;
@@ -288,6 +296,10 @@ export interface DataConfig {
288
296
  bind: any;
289
297
  /** 数据说明,供 Agent 理解用途;不传则自动生成 */
290
298
  description?: string;
299
+ /** 受保护资源(精确值保护):声明需 freeze(只读)/verbatim(原样保留)的字段路径。
300
+ * 配置后 read 受保护路径返占位符(精确值不入 LLM 消息流),写侧强制(freeze 拒/verbatim 展开校验)。
301
+ * opt-in:未配(默认)全部行为零变化 */
302
+ resources?: ResourceProtectSpec[];
291
303
  }
292
304
  /** createDataOps 选项(审计回调 / 快照上限 / 乐观锁) */
293
305
  export interface DataOpsOptions {
@@ -324,6 +336,14 @@ export interface DataOpsController {
324
336
  set(config: DataConfig): void;
325
337
  /** 仅替换 bind 引用;清空快照栈与乐观锁缓存 */
326
338
  update(bind: any): void;
339
+ /** 受保护资源清单快照(供跨压缩 pin 中间件注入「受保护资源」段;freeze 无 handle,verbatim 有) */
340
+ getResourcesSnapshot?(): { path: string; mode: 'freeze' | 'verbatim'; handle?: string }[];
341
+ /** 资源池操作(经 controller 同闭包;有 vfsStore 时可用) */
342
+ createResource?(path: string, value?: unknown): string;
343
+ getResource?(pathOrHandle: string): { path: string; mode: string; value: unknown; handle: string } | undefined;
344
+ updateResource?(path: string, value: unknown): void;
345
+ deleteResource?(pathOrHandle: string): boolean;
346
+ listResources?(): { path: string; mode: string; handle: string; bytes: number }[];
327
347
  }
328
348
 
329
349
  export interface SkillsController {
@@ -477,6 +497,8 @@ export interface SessionSnapshot {
477
497
  mission?: Mission;
478
498
  /** 跨压缩工作记忆 path/hash 备忘(context-persist-resilience:刷新后少重复 read;capabilities.workingMemory 开启时写入) */
479
499
  workingMemory?: WorkingMemory;
500
+ /** 上下文聚焦焦点(focus-auto-switch:刷新/切会话后聚焦状态保留;capabilities.focus 开启时写入;null=清除标记) */
501
+ focus?: Focus | null;
480
502
  }
481
503
  export type StorageEvent =
482
504
  | { type: 'degraded'; reason: string }
@@ -761,6 +783,18 @@ export interface ChatSdk {
761
783
  exportData(): any;
762
784
  /** 导入数据整体替换主数据 bind(就地还原,保留 reactive 引用);默认经 schema 校验,不合法返回 {ok:false,error};opts.validate:false 跳过校验,opts.emit:false 不发 data_change */
763
785
  importData(json: any, opts?: { validate?: boolean; emit?: boolean }): { ok: boolean; error?: string };
786
+ /** 创建/注册受保护资源(返回 handle);需配 data.resources + vfsStore,否则抛错 */
787
+ createResource(path: string, value?: unknown): string;
788
+ /** 取受保护资源真值(by path 或 handle);不存在返 undefined */
789
+ getResource(pathOrHandle: string): { path: string; mode: string; value: unknown; handle: string } | undefined;
790
+ /** 更新 verbatim 受保护资源真值(同步 bind+标脏);freeze 抛错 */
791
+ updateResource(path: string, value: unknown): void;
792
+ /** 删除/释放单个受保护资源(by path 或 handle);返是否存在过 */
793
+ deleteResource(pathOrHandle: string): boolean;
794
+ /** 列出全部受保护资源(path/mode/handle/bytes) */
795
+ listResources(): { path: string; mode: string; handle: string; bytes: number }[];
796
+ /** 批量释放受保护资源;传 paths 释放指定,未传释放全部 */
797
+ releaseResources(paths?: string[]): void;
764
798
  /** 累计 token 用量(每轮 LLM 调用累加;prompt/completion/total_tokens)。无调用时为 0 */
765
799
  usage: TokenUsage;
766
800
  /** 乐观锁冲突挂起状态(响应式 ref;无冲突为 null,有冲突时 UI 据此渲染冲突对话框)。headless 集成方可 watch 自建 UI */