page-agent-sdk 2.5.0 → 2.5.1
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 +13 -13
- package/README.zh-CN.md +8 -8
- package/dist/page-agent-sdk.iife.js +54 -54
- package/dist/page-agent-sdk.js +35 -25
- package/dist/page-agent-sdk.umd.cjs +6 -6
- package/package.json +1 -1
- package/skills/page-agent-sdk-integrate/SKILL.md +39 -30
- package/skills/page-agent-sdk-integrate/references/advanced.md +37 -41
- package/skills/page-agent-sdk-integrate/references/api.md +38 -40
- package/skills/page-agent-sdk-integrate/references/options.md +17 -14
- package/skills/page-agent-sdk-integrate/references/quickstart.md +43 -43
- package/skills/page-agent-sdk-integrate/references/use-cases.md +66 -62
- package/types/index.d.ts +7 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Use cases — end-to-end scenarios
|
|
2
2
|
|
|
3
|
-
Concrete integration patterns for common scenarios. Each shows the key `
|
|
3
|
+
Concrete integration patterns for common scenarios. Each shows the key `data` + options that matter. Adapt the LLM config to your provider.
|
|
4
4
|
|
|
5
5
|
## 1. Low-code page builder
|
|
6
6
|
|
|
7
7
|
A visual builder where the page is a component tree; the AI edits the tree via jsonPath patches and the canvas re-renders live.
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
|
-
|
|
10
|
+
const page = {
|
|
11
11
|
components: [
|
|
12
12
|
{ id: 'banner', type: 'banner', props: { title: 'Welcome', bg: '#1f4d3a' } },
|
|
13
13
|
{ id: 'card1', type: 'card', props: { title: '新品', price: 99 } },
|
|
@@ -18,16 +18,18 @@ createChatSdk({
|
|
|
18
18
|
container: '#chat',
|
|
19
19
|
llm: { apiKey, baseUrl: 'https://api.deepseek.com/v1', model: 'deepseek-chat', temperature: 0.3 },
|
|
20
20
|
systemPrompt: '你是页面搭建助手。用 write 的 patch 按 jsonPath 增量改 components,不要重传整树。',
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
data: {
|
|
22
|
+
schema: z.object({
|
|
23
|
+
components: z.array(z.object({
|
|
24
24
|
id: z.string(), type: z.string(),
|
|
25
25
|
props: z.record(z.any()),
|
|
26
|
-
}))
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
})).describe('组件树'),
|
|
27
|
+
}),
|
|
28
|
+
bind: page,
|
|
29
|
+
},
|
|
30
|
+
onEvent(e) { if (e.type === 'data_change') renderCanvas() }, // canvas refresh (plain-object bind)
|
|
29
31
|
checkpoint: true, // bad edit → one-click rollback
|
|
30
|
-
approval: { tools: ['write'] },
|
|
32
|
+
approval: { tools: ['write'] }, // confirm writes
|
|
31
33
|
}).mount()
|
|
32
34
|
```
|
|
33
35
|
|
|
@@ -38,7 +40,7 @@ User: "顶部 Banner 改深色、主标题加粗、加一张新品卡" → AI ca
|
|
|
38
40
|
Form schema as data; AI edits field definitions, schema validation prevents malformed forms.
|
|
39
41
|
|
|
40
42
|
```ts
|
|
41
|
-
|
|
43
|
+
const form = {
|
|
42
44
|
fields: [
|
|
43
45
|
{ name: 'phone', label: '手机号', type: 'text', required: true, validation: 'none' },
|
|
44
46
|
{ name: 'address', label: '地址', type: 'text', required: false, cascade: false },
|
|
@@ -47,29 +49,31 @@ window.form = {
|
|
|
47
49
|
|
|
48
50
|
createChatSdk({
|
|
49
51
|
container: '#chat', llm: { ... },
|
|
50
|
-
systemPrompt: '你是表单设计助手。改
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
systemPrompt: '你是表单设计助手。改 fields 的字段定义,保持 schema 合法。',
|
|
53
|
+
data: {
|
|
54
|
+
schema: z.object({
|
|
55
|
+
fields: z.array(z.object({
|
|
54
56
|
name: z.string(), label: z.string(),
|
|
55
57
|
type: z.enum(['text','number','select','date']),
|
|
56
58
|
required: z.boolean(),
|
|
57
59
|
validation: z.enum(['none','phone','email','idcard']),
|
|
58
60
|
cascade: z.boolean().optional(),
|
|
59
|
-
}))
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
})).describe('字段定义数组'),
|
|
62
|
+
}),
|
|
63
|
+
bind: form,
|
|
64
|
+
},
|
|
65
|
+
onEvent(e) { if (e.type === 'data_change') renderForm() },
|
|
62
66
|
}).mount()
|
|
63
67
|
```
|
|
64
68
|
|
|
65
|
-
User: "手机号加格式校验、地址改三级联动" → AI patches `
|
|
69
|
+
User: "手机号加格式校验、地址改三级联动" → AI patches `fields.0.validation='phone'`, `fields.1.cascade=true`.
|
|
66
70
|
|
|
67
71
|
## 3. CMS batch operation
|
|
68
72
|
|
|
69
|
-
Bulk-edit a product list; use `eval_script` or `
|
|
73
|
+
Bulk-edit a product list; use `eval_script` or `search_data` + `write` with `patch` for batch ops.
|
|
70
74
|
|
|
71
75
|
```ts
|
|
72
|
-
|
|
76
|
+
const products = [
|
|
73
77
|
{ id: 1, title: '商品A', price: 99, highlight: false },
|
|
74
78
|
{ id: 2, title: '商品B', price: 150, highlight: false },
|
|
75
79
|
// ...hundreds
|
|
@@ -77,25 +81,27 @@ window.products = [
|
|
|
77
81
|
|
|
78
82
|
createChatSdk({
|
|
79
83
|
container: '#chat', llm: { ... },
|
|
80
|
-
systemPrompt: '你是运营助手。批量改 products;标题加前缀用 eval_script,按条件筛选用
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
systemPrompt: '你是运营助手。批量改 products;标题加前缀用 eval_script,按条件筛选用 search_data。',
|
|
85
|
+
data: {
|
|
86
|
+
schema: z.object({
|
|
87
|
+
products: z.array(z.object({
|
|
84
88
|
id: z.number(), title: z.string(), price: z.number(), highlight: z.boolean(),
|
|
85
|
-
}))
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
})).describe('商品列表'),
|
|
90
|
+
}),
|
|
91
|
+
bind: { products },
|
|
92
|
+
},
|
|
93
|
+
onEvent(e) { if (e.type === 'data_change') renderTable() },
|
|
88
94
|
}).mount()
|
|
89
95
|
```
|
|
90
96
|
|
|
91
|
-
User: "标题加『限时』前缀、低于 100 元的标红" → AI uses `eval_script` for the prefix loop + `
|
|
97
|
+
User: "标题加『限时』前缀、低于 100 元的标红" → AI uses `eval_script` for the prefix loop + `search_data` to find `<100` then `write` with `patch` to set `highlight`.
|
|
92
98
|
|
|
93
99
|
## 4. Ops config console
|
|
94
100
|
|
|
95
101
|
Edit experiment thresholds / feature flags with human confirmation.
|
|
96
102
|
|
|
97
103
|
```ts
|
|
98
|
-
|
|
104
|
+
const config = {
|
|
99
105
|
expA: { threshold: 0.5, enabled: true },
|
|
100
106
|
featureB: { enabled: false },
|
|
101
107
|
}
|
|
@@ -103,12 +109,13 @@ window.config = {
|
|
|
103
109
|
createChatSdk({
|
|
104
110
|
container: '#chat', llm: { ... },
|
|
105
111
|
systemPrompt: '你是运维助手。改 config 前必须经用户确认。',
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
data: {
|
|
113
|
+
schema: z.object({
|
|
114
|
+
expA: z.object({ threshold: z.number().min(0).max(1), enabled: z.boolean() }).describe('实验A'),
|
|
115
|
+
featureB: z.object({ enabled: z.boolean() }).describe('B开关'),
|
|
116
|
+
}),
|
|
117
|
+
bind: config,
|
|
118
|
+
},
|
|
112
119
|
approval: { tools: ['write'] }, // human-in-the-loop
|
|
113
120
|
checkpoint: true,
|
|
114
121
|
capabilities: { verify: true }, // write-back read + schema check
|
|
@@ -119,7 +126,7 @@ User: "A 实验阈值调到 30%、关掉 B 开关" → AI proposes writes → us
|
|
|
119
126
|
|
|
120
127
|
## 5. AI-native assistant (no page data, custom tools)
|
|
121
128
|
|
|
122
|
-
The agent drives your product's own API via custom tools (no
|
|
129
|
+
The agent drives your product's own API via custom tools (no dataOps).
|
|
123
130
|
|
|
124
131
|
```ts
|
|
125
132
|
const lookupTool = defineTool({
|
|
@@ -134,7 +141,7 @@ createChatSdk({
|
|
|
134
141
|
llm: { ... },
|
|
135
142
|
systemPrompt: '你是订单助手。用 lookup_order 查询。',
|
|
136
143
|
tools: [lookupTool],
|
|
137
|
-
capabilities: {
|
|
144
|
+
capabilities: { dataOps: false, fetch: false }, // pure custom-tool agent
|
|
138
145
|
}).mount()
|
|
139
146
|
```
|
|
140
147
|
|
|
@@ -146,15 +153,15 @@ Pure research: fetch docs, parallel subagents for multi-source investigation.
|
|
|
146
153
|
createChatSdk({
|
|
147
154
|
container: '#chat', llm: { ... },
|
|
148
155
|
systemPrompt: '你是调研助手。多源对比用 spawn_agents 并行委派。',
|
|
149
|
-
capabilities: {
|
|
156
|
+
capabilities: { dataOps: false }, // read-only, no data edits
|
|
150
157
|
subagent: { allowedTools: ['fetch_document'] },
|
|
151
|
-
contextPreset: 'conservative',
|
|
158
|
+
contextPreset: 'conservative', // long research sessions
|
|
152
159
|
}).mount()
|
|
153
160
|
```
|
|
154
161
|
|
|
155
162
|
## 7. Headless server-side (Node.js)
|
|
156
163
|
|
|
157
|
-
Run the agent in Node (no browser).
|
|
164
|
+
Run the agent in Node (no browser). dataOps body works in Node with any `bind` object; only `eval_script` needs Web Worker (disable via `capabilities:{dataOps:false}` if unused).
|
|
158
165
|
|
|
159
166
|
```ts
|
|
160
167
|
// node mjs
|
|
@@ -165,7 +172,8 @@ const sdk = createChatSdk({
|
|
|
165
172
|
storage: 'memory',
|
|
166
173
|
llm: { apiKey, baseUrl, model },
|
|
167
174
|
systemPrompt: '...',
|
|
168
|
-
|
|
175
|
+
data: { schema: z.object({ result: z.string() }), bind: { result: '' } },
|
|
176
|
+
capabilities: { fetch: false }, // dataOps body works; eval_script needs worker
|
|
169
177
|
tools: [/* your tools */],
|
|
170
178
|
})
|
|
171
179
|
await sdk.mount()
|
|
@@ -179,9 +187,9 @@ sdk.unmount()
|
|
|
179
187
|
Two dialogs backed by one agent brain.
|
|
180
188
|
|
|
181
189
|
```ts
|
|
182
|
-
const a = createChatSdk({ id: 'shared', container: '#dlg-a', llm: {...}, shareContext: true,
|
|
183
|
-
const b = createChatSdk({ id: 'shared', container: '#dlg-b', llm: {...}, shareContext: true,
|
|
184
|
-
// a & b share messages/agent/vfs/todos/memory — two views of one agent
|
|
190
|
+
const a = createChatSdk({ id: 'shared', container: '#dlg-a', llm: {...}, shareContext: true, data }).mount()
|
|
191
|
+
const b = createChatSdk({ id: 'shared', container: '#dlg-b', llm: {...}, shareContext: true, data }).mount()
|
|
192
|
+
// a & b share messages/agent/vfs/todos/memory/bind — two views of one agent
|
|
185
193
|
```
|
|
186
194
|
|
|
187
195
|
## 9. MCP integration (external tool servers)
|
|
@@ -199,33 +207,29 @@ createChatSdk({
|
|
|
199
207
|
|
|
200
208
|
> Note: `@modelcontextprotocol/sdk` is an optional peerDep — install it only if you use `mcp`. Browser supports only remote transports (http/sse/websocket), not stdio.
|
|
201
209
|
|
|
202
|
-
## 10.
|
|
210
|
+
## 10. Dynamic / lazy-loaded schema (swap main data at runtime)
|
|
203
211
|
|
|
204
|
-
|
|
212
|
+
When the page schema changes dynamically (lazy-loaded components with different structures), swap the whole main data config at runtime — tools pick up the new bind/schema immediately, no rebuild.
|
|
205
213
|
|
|
206
214
|
```ts
|
|
207
215
|
const sdk = createChatSdk({
|
|
208
216
|
container: '#chat', llm: { ... },
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
systemPrompt: '用 read() 查看当前可操作的组件 path,再按各自 schema 操作',
|
|
217
|
+
data: { schema: initialSchema, bind: initialObj, description: '初始数据' },
|
|
218
|
+
systemPrompt: '用 read() 查看当前可操作字段,按 schema 操作',
|
|
212
219
|
}).mount()
|
|
213
220
|
|
|
214
|
-
//
|
|
215
|
-
function
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
description: `${comp.type}
|
|
220
|
-
schema: compSchemas[comp.type], // 结构各异:banner/card/stat/chart 各自 schema
|
|
221
|
+
// later: swap to a different schema + bind (lazy-loaded / dynamic)
|
|
222
|
+
function onComponentTypeChange(comp: { schema: z.ZodType; bind: any }) {
|
|
223
|
+
sdk.setData({
|
|
224
|
+
schema: comp.schema, // new zod schema (validation + field hints auto-injected)
|
|
225
|
+
bind: comp.bind, // new reactive/plain object
|
|
226
|
+
description: `${comp.type} 组件数据`,
|
|
221
227
|
})
|
|
228
|
+
// tools now operate on comp.bind with comp.schema — immediately, no rebuild
|
|
222
229
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
delete window.app.components[id]
|
|
226
|
-
sdk.removeDataSlot(`app.components.${id}`)
|
|
227
|
-
}
|
|
230
|
+
|
|
231
|
+
sdk.getData() // read current config (reflects runtime swap)
|
|
228
232
|
```
|
|
229
233
|
|
|
230
234
|
**完整可运行示例**:`examples/dynamic-demo/`(`npm run dev` → `/examples/dynamic-demo/`)。
|
|
231
|
-
**何时用**:可视化编辑器/低代码平台中,组件按需加载且结构各异(图表/表单/卡片 schema 各不同)
|
|
235
|
+
**何时用**:可视化编辑器/低代码平台中,组件按需加载且结构各异(图表/表单/卡片 schema 各不同),无法在初始化时确定唯一 schema。详见 `advanced.md` §0。
|
package/types/index.d.ts
CHANGED
|
@@ -231,7 +231,13 @@ export interface VerifyMiddlewareOptions {
|
|
|
231
231
|
export interface WriteBackCheckOptions {
|
|
232
232
|
/** name → zod schema(由 createChatSdk 从 data 构造注入,键 '' 代表主数据);省略则只校验「读回非空」 */
|
|
233
233
|
schemas?: Record<string, any>;
|
|
234
|
-
/**
|
|
234
|
+
/**
|
|
235
|
+
* 读回的根对象。优先于 `window`。
|
|
236
|
+
* - 单对象 data 模式:传 bind 对象(或 getter `() => liveData()?.bind`,适配 sdk.setData 运行时替换)
|
|
237
|
+
* - 旧 windowProps 模式:省略则用 `window`(默认 globalThis.window)
|
|
238
|
+
*/
|
|
239
|
+
root?: unknown | (() => unknown);
|
|
240
|
+
/** 读 window 的根对象(旧 windowProps 模式;data 模式应传 root)。默认 globalThis.window */
|
|
235
241
|
window?: unknown;
|
|
236
242
|
}
|
|
237
243
|
|