page-agent-sdk 2.16.0 → 2.18.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.16.0",
3
+ "version": "2.18.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",
@@ -50,7 +50,9 @@
50
50
  "test:e2e": "node tests/e2e-integration.mjs",
51
51
  "test:exports": "node tests/exports-consistency.mjs",
52
52
  "test:types": "tsc --noEmit -p tsconfig.test.json",
53
- "test:size": "node tests/size-check.mjs"
53
+ "test:size": "node tests/size-check.mjs",
54
+ "test:browser": "playwright test",
55
+ "test:browser:ui": "playwright test --ui"
54
56
  },
55
57
  "keywords": [
56
58
  "ai",
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: adaptive-planning
3
+ description: 自适应规划标准流程——判断任务复杂度决定是否先规划,规划后可选用户确认,执行中动态增量修订
4
+ ---
5
+
6
+ # 自适应规划流程
7
+
8
+ > 内置 skill(add-adaptive-planning)。文档化 agent 运行时的自适应规划标准流程。
9
+ > 集成方按需挂载:`createChatSdk({ skills: [adaptivePlanningSkill] })`,或从 npm 包 `skills/adaptive-planning` 取。
10
+
11
+ ## 1. 判断复杂度(自适应分流)
12
+
13
+ - **简单**(单字段、明确、可逆,如「标题改红色」)→ 跳过规划,直接 `read` → `write`。
14
+ - **复杂**(多步、大改、有歧义、不可逆,如「把首页改成营销活动页」)→ 进入规划。
15
+
16
+ 判断由你(LLM)完成,框架不强加。拿不准时倾向于规划(复杂任务不规划的代价 > 简单任务多规划的代价)。
17
+
18
+ ## 2. 规划(write_todos)
19
+
20
+ 拆解为**可执行**步骤,每步一个明确动作(`read` 某字段 / `write` 某路径 / `query` 筛选)。首个任务标 `in_progress`。
21
+
22
+ ```
23
+ write_todos({ todos: [
24
+ { content: '读取当前 components 结构', status: 'in_progress' },
25
+ { content: '给 hero 组件加标题字段', status: 'pending' },
26
+ { content: 'read 确认写入', status: 'pending' },
27
+ ]})
28
+ ```
29
+
30
+ 框架给每步自动生成稳定 id(`t-1`/`t-2`...),也可显式传语义化 id(如 `read-structure`)。
31
+
32
+ ## 3.(可选)用户确认
33
+
34
+ 若方案有歧义 / 多选 / 高风险 → `request_human_confirmation` 给选项,用户确认后再执行:
35
+
36
+ ```
37
+ request_human_confirmation({ question: '活动页主色调?', options: ['红色喜庆', '蓝色科技', '金色奢华'], recommendation: '红色喜庆' })
38
+ ```
39
+
40
+ ## 4. 执行
41
+
42
+ 按清单逐步 `read` / `write`。**完成一项立即标完成**(不必重传整个清单):
43
+
44
+ ```
45
+ update_todo({ id: 't-1', status: 'completed' })
46
+ ```
47
+
48
+ ## 5. 动态修订(执行中完善)
49
+
50
+ 执行中发现步骤要改 / 补 / 细分 → `update_todo` 增量改单项,不必重传整个清单:
51
+
52
+ - 改描述:`update_todo({ id: 't-2', content: '给 hero 组件加标题字段 + 副标题' })`
53
+ - 补步骤:用 `write_todos` 重传完整清单(新增项会获得新 id)
54
+ - 拆分:把一项标 completed,用 `write_todos` 补更细的子步骤
55
+
56
+ ## 防死循环(框架兜底)
57
+
58
+ 规划阶段有轮次预算(`maxPlanRevisions`,默认 5)。**勿反复调研 / 改计划而不执行**——超限框架会回灌「规划阶段已达上限,基于当前清单开始执行」。
59
+
60
+ 规划充分后即开始 `write` 落地(写工具成功即退出规划阶段,预算重置)。
61
+
62
+ ## 何时不用本 skill
63
+
64
+ - 纯查询任务(只 read 不 write):直接 read/query/search,不必规划
65
+ - 单步明确任务:直接 write
66
+ - 已有领域 skill(如集成方的业务 skill)指导流程时:遵循那个
package/types/index.d.ts CHANGED
@@ -75,7 +75,7 @@ export type SdkEvent =
75
75
  | { type: 'conflict'; conflict: PendingConflict }
76
76
  | { type: 'session_restored'; sessionId: string; rounds: number }
77
77
  | { type: 'usage'; round: number; usage: TokenUsage; cumulative: TokenUsage }
78
- | { type: 'error'; message: string };
78
+ | { type: 'error'; message: string; severity?: 'recoverable' | 'fatal' | 'observable'; code?: string; context?: unknown };
79
79
 
80
80
  /** token 用量(OpenAI 协议字段名) */
81
81
  export interface TokenUsage {
@@ -139,7 +139,15 @@ export interface AgentInfo {
139
139
  contextPreset: 'auto' | 'conservative' | 'aggressive' | 'complex';
140
140
  memory: string;
141
141
  middleware: string[];
142
- todos: { content: string; status: string }[];
142
+ todos: { id: string; content: string; status: string }[];
143
+ /** 规划阶段防死循环状态(maxPlanRevisions 预算;planning 关闭时 inPlanning 恒 false) */
144
+ planPhase?: { inPlanning: boolean; rounds: number; limit: number };
145
+ /** 当前任务目标锚点(mission 中间件;未开启/未 capture → undefined) */
146
+ mission?: Mission;
147
+ /** 宿主动作元信息(actions 注册;集成方 save_draft/publish 等) */
148
+ actions?: Record<string, { description: string; hasParams: boolean }>;
149
+ /** 跨压缩工作记忆(workingMemory 中间件;pin 最近 read/query/search 定位 path + read hash,≤10 LRU) */
150
+ workingMemory?: WorkingMemory;
143
151
  subagent: SubagentInfo;
144
152
  verify?: { enabled: boolean; maxAttempts: number; adversarial: boolean };
145
153
  mcp?: { servers: { name: string; url: string; toolCount: number }[] };
@@ -345,7 +353,7 @@ export interface SessionMeta {
345
353
  export interface SessionSnapshot {
346
354
  messages: AgentMessage[];
347
355
  vfs: Record<string, { content: string; mimeType?: string; updatedAt: number }>;
348
- todos: { content: string; status: 'pending' | 'in_progress' | 'completed' }[];
356
+ todos: { id: string; content: string; status: 'pending' | 'in_progress' | 'completed' }[];
349
357
  memory: string;
350
358
  }
351
359
  export type StorageEvent =
@@ -387,6 +395,17 @@ export interface SystemAugmentContext {
387
395
  data?: DataConfig;
388
396
  }
389
397
 
398
+ /** 宿主动作定义:集成方注册的页面操作(保存/发布/预览/导出等),SDK 自动包成命名 tool */
399
+ export interface ActionDef {
400
+ /** 动作描述(给 LLM 看) */
401
+ description: string;
402
+ /** 执行函数;接收 params schema 解析的参数,返回值序列化回灌 LLM */
403
+ run: (args: Record<string, unknown>) => unknown | Promise<unknown>;
404
+ /** 可选参数 schema(ZodObject);不传 = 无参 tool */
405
+ params?: any;
406
+ }
407
+ /** actions 配置:动作名 → 定义(动作名即 tool 名,须合法标识符) */
408
+ export type ActionMap = Record<string, ActionDef>;
390
409
  export interface ChatSdkOptions {
391
410
  container?: string | HTMLElement;
392
411
  /** UI:'default'(内置 ChatDialog)/ false(headless 不渲染,自建 UI) */
@@ -412,12 +431,16 @@ export interface ChatSdkOptions {
412
431
  */
413
432
  augmentSystem?: (ctx: SystemAugmentContext) => string | undefined;
414
433
  tools?: any[];
434
+ /** 宿主动作:集成方注册的页面操作(保存/发布/预览等),SDK 自动包成命名 tool;LLM 直接看到命名 tool */
435
+ actions?: ActionMap;
415
436
  skills?: SkillSpec[];
416
437
  /** 用户创建 skill 的独立持久化存储(与 storage 选项分离)。默认 `{ backend: 'indexed' }`(即使 storage:false 也持久化);`false` 关闭;`id` 手动指定同一 id 可跨页面/跨 agent 复用 */
417
438
  skillStorage?: SkillStoreConfig | false;
418
439
  /** AGENTS.md 风格持久指令。支持 string 与同步/异步函数(异步函数适合加载 RAG 文档) */
419
440
  memory?: string | (() => string | Promise<string>);
420
441
  data?: DataConfig;
442
+ /** 大 schema 分层披露阈值(默认 maxKeys=15/maxChars=4000;超则 systemPrompt 只注入顶层概览,深层约束查 schema_data) */
443
+ schemaHint?: SchemaHintOptions;
421
444
  permissions?: PermissionRule[];
422
445
  /** 自定义中间件(注入到内置中间件之后;可拦截/观察模型调用、工具、prompt) */
423
446
  middleware?: any[];
@@ -443,6 +466,8 @@ export interface ChatSdkOptions {
443
466
  maxMemoryRounds?: number;
444
467
  debug?: boolean;
445
468
  maxToolRounds?: number;
469
+ /** 规划阶段总轮次预算(默认 5);planning 状态下超限 → write_todos/update_todo 回灌,防"光规划不执行"死循环。与 maxIterations 正交 */
470
+ maxPlanRevisions?: number;
446
471
  /** 模型调用失败自动重试次数(默认 2;网络/429/5xx 重试,4xx 与 abort 不重试) */
447
472
  maxRetries?: number;
448
473
  /** 同轮工具并发上限(默认 1 串行) */
@@ -452,7 +477,7 @@ export interface ChatSdkOptions {
452
477
  /** 模型最大输出(token);顶层声明对 llm 实例场景也生效,缺省按 model 名查表 */
453
478
  maxOutputTokens?: number;
454
479
  /** 子 agent 委派(默认开启;{ enabled: false } 关闭) */
455
- capabilities?: { dataOps?: boolean; fetch?: boolean; planning?: boolean; skills?: boolean; vfs?: boolean; summarization?: boolean; memory?: boolean; subagent?: boolean; verify?: boolean };
480
+ capabilities?: { dataOps?: boolean; fetch?: boolean; planning?: boolean; missionAnchor?: boolean; skills?: boolean; vfs?: boolean; summarization?: boolean; memory?: boolean; subagent?: boolean; verify?: boolean; domInspect?: boolean; workingMemory?: boolean };
456
481
  subagent?: { enabled?: boolean; allowedTools?: string[]; systemPrompt?: string; temperature?: number; maxTokens?: number; skills?: SkillSpec[]; llm?: LLMConfig | ChatModelLike; maxDepth?: number; maxParallel?: number };
457
482
  /** 预声明子 agent 列表:每个用同主配置方式声明,自动生成 use_<id> 委派工具(与 spawn_agent 共存) */
458
483
  subagents?: SubagentConfig[];
@@ -500,6 +525,25 @@ export interface DialogConfig {
500
525
  onClose?: () => void;
501
526
  }
502
527
 
528
+ /** 会话级任务目标锚点(mission 中间件;capture 或 setMission;revive-mission-anchor Phase 1) */
529
+ /** 跨压缩工作记忆(workingMemory 中间件;经 augmentPrompt 每轮注入 system,天然跨压缩保留) */
530
+ export interface WorkingMemory {
531
+ locatedPaths: string[];
532
+ lastHashes: Record<string, string>;
533
+ }
534
+ export interface Mission {
535
+ /** 一句话任务目标(必填) */
536
+ goal: string;
537
+ /** 完成标准(可选,集成方显式传入) */
538
+ acceptanceCriteria?: string[];
539
+ /** 来源 user 消息 index(自动 capture 时填) */
540
+ sourceMessageIdx: number;
541
+ /** capture/setMission 时间戳 */
542
+ capturedAt: number;
543
+ /** true=集成方显式 setMission;false=自动 capture */
544
+ explicit: boolean;
545
+ }
546
+
503
547
  export interface ChatSdk {
504
548
  /** 渲染对话框到 container(异步:含持久化恢复);ui:false 时仅 init agent(headless)。
505
549
  * 可选传 overrideContainer(HTMLElement | 选择器字符串)覆盖创建时 options.container —— 异步绑定:创建时可省略 container,mount 时才指定 */
@@ -511,11 +555,15 @@ export interface ChatSdk {
511
555
  hide(): void;
512
556
  /** 抽屉模式显示:移除 cs-hidden class 恢复可见(配合 hide 使用;首次挂载用 mount) */
513
557
  show(): void;
514
- send(message: string): Promise<string>;
558
+ send(message: string, options?: { mission?: Partial<Mission> }): Promise<string>;
515
559
  switchSession(sessionId?: string): Promise<string>;
516
560
  stream: (messages: AgentMessage[], onEvent: StreamHandler, signal?: AbortSignal) => Promise<string>;
517
561
  /** 检视 agent 详细信息(tools/skills/data/middleware/todos) */
518
562
  inspect(): AgentInfo;
563
+ /** 读取当前任务目标锚点 mission(自动 capture 或 setMission;capabilities.missionAnchor:false → undefined) */
564
+ getMission(): Mission | undefined;
565
+ /** 显式设置/覆盖 mission(传 {goal} 重设;传 {goal,criteria} 整体替换;传 {} 清空);capabilities 关时 warn 不抛 */
566
+ setMission(mission: Partial<Mission>): void;
519
567
  /** 回退到最近一次正常 checkpoint(整体还原对话历史 + 主数据 + vfs + todos);需开启 checkpoint,无可用返回 false */
520
568
  restoreLastCheckpoint(): boolean;
521
569
  /** 列出可用 checkpoint(回退点);需开启 checkpoint,未开启返回空数组 */
@@ -639,6 +687,8 @@ export declare function applyPatchToClone(clone: any, op: EditOp, jsonPath: stri
639
687
  export declare function applyPatchToLive(bind: any, op: EditOp, jsonPath: string, value: unknown): void;
640
688
  export declare function restoreLive(bind: any, snapshotVal: unknown): void;
641
689
  export declare function restoreInPlace(live: Record<string, unknown> | unknown[], snapshotVal: unknown): void;
690
+ /** 深度差异对比(对象/数组递归,叶子差异),返回 {path, from, to}[];供 diff_data / verify 自纠 / 审计复用 */
691
+ export declare function diffObjects(a: unknown, b: unknown, prefix?: string): { path: string; from: unknown; to: unknown }[];
642
692
  // ============ schema 白名单投影纯函数(schemaUtils,refactor-module-extraction 从 dataOps 抽离)============
643
693
  export declare function getSchemaTopKeys(schema: any): string[] | null;
644
694
  export declare function isPathAllowed(jsonPath: string, schema: any | null, allowKeys: string[] | null): boolean;
@@ -646,6 +696,37 @@ export declare function unwrapSchema(schema: any): any;
646
696
  export declare function getSchemaAtPath(schema: any, jsonPath: string): any | null;
647
697
  export declare function projectBySchemaDeep(obj: unknown, schema: any | null): unknown;
648
698
  export declare function projectBySchema(obj: unknown, allowKeys: string[] | null): unknown;
699
+ // ============ schema 约束结构化提取(expose-schema-constraints;供 systemPrompt「可操作数据」段 / read 概览 / schema_data 工具)============
700
+ export interface SchemaNodeDesc {
701
+ type: string;
702
+ constraints?: {
703
+ minLength?: number; maxLength?: number; length?: number;
704
+ min?: number; max?: number; int?: boolean;
705
+ format?: string | string[];
706
+ values?: readonly (string | number)[];
707
+ value?: unknown;
708
+ item?: SchemaNodeDesc;
709
+ shape?: Record<string, SchemaNodeDesc>;
710
+ anyOf?: SchemaNodeDesc[];
711
+ valueType?: SchemaNodeDesc;
712
+ };
713
+ optional?: boolean;
714
+ nullable?: boolean;
715
+ default?: unknown;
716
+ description?: string;
717
+ }
718
+ /** 结构化提取单个 zod 节点的约束(type + 关键约束 + optional/default/nullable;zod 4 `_def`/`_zod.def` 读取) */
719
+ export declare function describeSchemaNode(schema: any): SchemaNodeDesc;
720
+ /** 把标量约束格式化为括号内短串(min/max/enum/format 等;shape/item/anyOf 不渲染) */
721
+ export declare function formatConstraints(c: NonNullable<SchemaNodeDesc['constraints']>): string;
722
+ /** 渲染单行字段标注 `- key (Type?)[约束]: description` */
723
+ export declare function renderSchemaHint(key: string, desc: SchemaNodeDesc): string;
724
+ /** 渲染 schema 顶层字段约束总览(非 object fallback 根节点;供 extractSchemaHint + read 概览复用) */
725
+ export declare function renderSchemaOverview(schema: any): string;
726
+ /** 渲染 schema 顶层字段浅概览(分层模式:只 key+type+desc,不带约束/不递归;大 schema 用,体积降) */
727
+ export declare function renderSchemaShallow(schema: any): string;
728
+ /** extractSchemaHint 分层阈值配置(默认 maxKeys=15/maxChars=4000;超则转顶层概览) */
729
+ export interface SchemaHintOptions { maxKeys?: number; maxChars?: number }
649
730
  // ============ 上下文索引纯函数(contextIndex,refactor-module-extraction 期二 从 useContextManager 抽离)============
650
731
  export declare const STOP_WORDS: Set<string>;
651
732
  export declare function tokenize(text: string): string[];
@@ -672,9 +753,20 @@ export interface SdkEvents {
672
753
  hook(handler: (e: any) => void): () => void;
673
754
  }
674
755
  export declare function createSdkEvents(onEvent?: (e: any) => void): SdkEvents;
675
- export declare function selectBuiltinTools(caps: { dataOps?: boolean; fetch?: boolean } | undefined, dataOps: any[], fetchDocs: any[]): any[];
756
+ export declare function selectBuiltinTools(caps: { dataOps?: boolean; fetch?: boolean; domInspect?: boolean } | undefined, dataOps: any[], fetchDocs: any[], dom?: any[]): any[];
676
757
  export declare function createUsageHintsMiddleware(caps: { planning?: boolean; dataOps?: boolean; subagent?: boolean } | undefined, hasDataOps: boolean, toolMode?: 'simple' | 'advanced' | 'minimal'): any;
677
758
  export declare const fetchDocTools: any[];
759
+ /** DOM 读取工具 get_dom(随 capabilities.domInspect 装配,opt-in) */
760
+ export declare const domTools: any[];
761
+ export declare const domToolsStatic: any[];
762
+ export declare const getDomTool: any;
763
+ /** 纯函数:DOM Element → 结构化 DomNode(可单测,与浏览器解耦) */
764
+ export declare function domToStructure(node: Element | null, opts: { depth: number; attrs?: string[]; includeText?: boolean }): DomNode | null;
765
+ /** 把集成方注册的 actions 转成命名 tool 数组(每个 action 一个 tool) */
766
+ export declare function actionsToTools(actions: ActionMap): any[];
767
+ export declare function actionsToInspectInfo(actions: ActionMap): Record<string, { description: string; hasParams: boolean }>;
768
+ export interface DomNode { tag: string; attrs: Record<string, string>; text?: string; children?: DomNode[]; childCount?: number }
769
+ export interface DomReadOptions { depth: number; attrs?: string[]; includeText?: boolean }
678
770
  export declare const fetchTools: any[];
679
771
  export declare function defineDataToolset(config: DataConfig, opts?: DataOpsOptions): any[];
680
772
  export declare function defineSkill(spec: SkillSpec): SkillSpec;
@@ -770,6 +862,24 @@ export declare function zodError(path: string, issues: unknown[]): string;
770
862
  export declare function jsonParseError(path: string | undefined, raw: string, err: unknown): string;
771
863
  /** 提取 zod issues 为结构化 details(每条 path/expected/received/message) */
772
864
  export declare function formatZodIssues(issues: unknown[]): unknown[];
865
+ // ============ 统一错误模型(unify-error-model:三档 severity,各 catch 点按档路由)============
866
+ /** 错误严重程度三档:recoverable(回灌)/ fatal(中断)/ observable(记录不中断) */
867
+ export type ErrorSeverity = 'recoverable' | 'fatal' | 'observable';
868
+ /** 统一错误对象(结构化,跨层传递;普通 Error 经 asAgentError 归一化) */
869
+ export interface AgentError {
870
+ severity: ErrorSeverity;
871
+ message: string;
872
+ code?: string;
873
+ context?: unknown;
874
+ }
875
+ /** 错误路由:recoverable→feedback / fatal→abort / observable→log */
876
+ export type ErrorRouting = 'feedback' | 'abort' | 'log';
877
+ /** 路由纯函数:据 severity 决定错误如何被处理 */
878
+ export declare function routeError(err: AgentError): ErrorRouting;
879
+ /** 把任意错误归一化为 AgentError(已是 AgentError 不覆盖;普通 Error 用 defaultSeverity,默认 fatal) */
880
+ export declare function asAgentError(err: unknown, defaultSeverity?: ErrorSeverity): AgentError;
881
+ /** AgentError 便捷工厂 */
882
+ export declare function agentError(severity: ErrorSeverity, message: string, code?: string, context?: unknown): AgentError;
773
883
 
774
884
  // === 与 src/core/index.ts 导出对齐(消费者类型完整;复杂内部类型用宽松声明,消费者主要消费工厂返回值) ===
775
885
  // 上下文压缩预设