page-agent-sdk 2.4.1 → 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 +15 -14
- package/README.zh-CN.md +11 -10
- package/dist/page-agent-sdk.iife.js +117 -117
- package/dist/page-agent-sdk.js +620 -426
- package/dist/page-agent-sdk.umd.cjs +35 -35
- 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
|
@@ -5,30 +5,33 @@ From the smallest working setup to a full-featured integration. Read top-down; s
|
|
|
5
5
|
## Stage 0 — Prerequisites
|
|
6
6
|
|
|
7
7
|
- An OpenAI-compatible LLM endpoint (DeepSeek works out of the box). Get an API key.
|
|
8
|
-
-
|
|
8
|
+
- A main data object you want the AI to edit (any plain or reactive object).
|
|
9
9
|
|
|
10
10
|
## Stage 1 — Minimal (5 lines, CDN, no build)
|
|
11
11
|
|
|
12
|
-
Drop into any HTML page. The built-in dialog mounts itself. (`systemPrompt` is optional — a built-in default is used if omitted: a generic
|
|
12
|
+
Drop into any HTML page. The built-in dialog mounts itself. (`systemPrompt` is optional — a built-in default is used if omitted: a generic JSON-operation assistant + `systemPromptHelpers.reliableWriteRules`. Shown here explicitly for clarity.)
|
|
13
13
|
|
|
14
14
|
```html
|
|
15
15
|
<div id="root"></div>
|
|
16
16
|
<script src="https://unpkg.com/page-agent-sdk"></script>
|
|
17
17
|
<script>
|
|
18
|
-
|
|
18
|
+
const app = { title: 'Hello', theme: 'light' } // plain object (no window needed)
|
|
19
19
|
ChatSdk.createChatSdk({
|
|
20
20
|
container: '#root',
|
|
21
21
|
llm: { apiKey: 'sk-...', baseUrl: 'https://api.deepseek.com/v1', model: 'deepseek-chat' },
|
|
22
|
-
systemPrompt: 'You are a
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
systemPrompt: 'You are a JSON operation assistant. Read/write the main data via tools.',
|
|
23
|
+
data: {
|
|
24
|
+
schema: ChatSdk.z.object({
|
|
25
|
+
title: ChatSdk.z.string().describe('标题'),
|
|
26
|
+
theme: ChatSdk.z.enum(['light', 'dark']).describe('主题'),
|
|
27
|
+
}),
|
|
28
|
+
bind: app,
|
|
29
|
+
},
|
|
27
30
|
}).mount()
|
|
28
31
|
</script>
|
|
29
32
|
```
|
|
30
33
|
|
|
31
|
-
Talk to it: "change theme to dark" → AI calls `write({
|
|
34
|
+
Talk to it: "change theme to dark" → AI calls `write({ value: 'dark', patch: { op: 'set', jsonPath: 'theme' } })` → `app.theme === 'dark'`.
|
|
32
35
|
|
|
33
36
|
## Stage 2 — npm + module project
|
|
34
37
|
|
|
@@ -40,17 +43,20 @@ npm i page-agent-sdk zod @langchain/openai @langchain/core
|
|
|
40
43
|
import { createChatSdk, z } from 'page-agent-sdk'
|
|
41
44
|
import 'page-agent-sdk/style.css'
|
|
42
45
|
|
|
43
|
-
|
|
46
|
+
const app = { title: 'Hello', theme: 'light', items: [] }
|
|
44
47
|
|
|
45
48
|
const sdk = createChatSdk({
|
|
46
49
|
container: '#root',
|
|
47
50
|
llm: { apiKey: import.meta.env.VITE_AI_API_KEY, baseUrl: 'https://api.deepseek.com/v1', model: 'deepseek-chat' },
|
|
48
|
-
systemPrompt: 'You are a
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
systemPrompt: 'You are a JSON operation assistant. Read/write the main data via tools.',
|
|
52
|
+
data: {
|
|
53
|
+
schema: z.object({
|
|
54
|
+
title: z.string().describe('标题'),
|
|
55
|
+
theme: z.enum(['light', 'dark']).describe('主题'),
|
|
56
|
+
items: z.array(z.object({ name: z.string(), price: z.number() })).describe('列表项'),
|
|
57
|
+
}),
|
|
58
|
+
bind: app,
|
|
59
|
+
},
|
|
54
60
|
}).mount()
|
|
55
61
|
```
|
|
56
62
|
|
|
@@ -61,10 +67,10 @@ Subscribe via `onEvent` (constructor) or `sdk.hook` (runtime, multi-listener, ca
|
|
|
61
67
|
```ts
|
|
62
68
|
const sdk = createChatSdk({
|
|
63
69
|
onEvent(e) {
|
|
64
|
-
if (e.type === '
|
|
70
|
+
if (e.type === 'data_change') renderUI() // host page refresh (plain-object bind needs this; reactive bind auto-refreshes)
|
|
65
71
|
if (e.type === 'error') console.error(e.message)
|
|
66
72
|
},
|
|
67
|
-
// ...llm,
|
|
73
|
+
// ...llm, data...
|
|
68
74
|
}).mount()
|
|
69
75
|
|
|
70
76
|
// runtime listener (e.g. analytics), cancellable
|
|
@@ -72,6 +78,8 @@ const off = sdk.hook((e) => { if (e.type === 'tool_call') track(e.name) })
|
|
|
72
78
|
// off()
|
|
73
79
|
```
|
|
74
80
|
|
|
81
|
+
> For Vue + `reactive()` bind, template/watch auto-refresh on write — no manual notify needed. For plain-object bind (React/vanilla/Node), subscribe `data_change` to re-render. Both can coexist (reactive for UI, `onEvent` for audit).
|
|
82
|
+
|
|
75
83
|
## Stage 4 — Headless (custom UI, framework-agnostic)
|
|
76
84
|
|
|
77
85
|
No built-in dialog; drive the reactive `messages` array yourself.
|
|
@@ -79,7 +87,7 @@ No built-in dialog; drive the reactive `messages` array yourself.
|
|
|
79
87
|
```ts
|
|
80
88
|
const sdk = createChatSdk({
|
|
81
89
|
ui: false, // headless
|
|
82
|
-
llm: { ... }, systemPrompt: '...',
|
|
90
|
+
llm: { ... }, systemPrompt: '...', data: { schema, bind: appObj },
|
|
83
91
|
}).mount()
|
|
84
92
|
|
|
85
93
|
// your own UI reads sdk.messages (reactive) and calls sdk.send
|
|
@@ -92,10 +100,10 @@ Reusable `ChatDialog` / `MessageContent` / `CodePreview` components + `useChat`
|
|
|
92
100
|
|
|
93
101
|
```ts
|
|
94
102
|
createChatSdk({
|
|
95
|
-
// ...llm,
|
|
103
|
+
// ...llm, data...
|
|
96
104
|
capabilities: { verify: true }, // write-back self-check before agent returns
|
|
97
105
|
verify: { maxAttempts: 2 }, // auto-correct on failure (default check = write-back read + schema)
|
|
98
|
-
approval: { tools: ['write'] },
|
|
106
|
+
approval: { tools: ['write'] }, // human-confirm before writes
|
|
99
107
|
checkpoint: true, // session-level rollback on bad edits
|
|
100
108
|
maxParallelTools: 1, // serial tool calls (safe for stateful middleware)
|
|
101
109
|
contextPreset: 'conservative', // save cost on long sessions
|
|
@@ -107,43 +115,35 @@ createChatSdk({
|
|
|
107
115
|
```ts
|
|
108
116
|
createChatSdk({
|
|
109
117
|
id: 'my-page-agent', // STABLE id (multi-agent isolation); omit = random + warn
|
|
110
|
-
storage: 'indexed', // persist messages/vfs/todos/memory to IndexedDB
|
|
111
|
-
// ...llm,
|
|
118
|
+
storage: 'indexed', // persist messages/vfs/todos/memory to IndexedDB (NOT bind — store & re-inject via sdk.setData)
|
|
119
|
+
// ...llm, data...
|
|
112
120
|
}).mount()
|
|
113
121
|
|
|
114
122
|
// later, switch session:
|
|
115
123
|
await sdk.switchSession('session-abc') // load or create
|
|
116
124
|
```
|
|
117
125
|
|
|
118
|
-
## Stage 7 —
|
|
126
|
+
## Stage 7 — Swap data at runtime (dynamic / lazy-loaded schema)
|
|
119
127
|
|
|
120
|
-
|
|
128
|
+
When the page schema changes dynamically (e.g. lazy-loaded components with different structures), swap the whole main data config at runtime — tools pick up the new bind/schema immediately, no rebuild.
|
|
121
129
|
|
|
122
130
|
```ts
|
|
123
131
|
const sdk = createChatSdk({
|
|
124
132
|
container: '#root', llm: { ... },
|
|
125
|
-
|
|
126
|
-
dataSlots: [{ path: 'app.components', description: '动态组件容器(按 id 存)', schema: z.record(z.string(), z.any()) }],
|
|
133
|
+
data: { schema: initialSchema, bind: initialObj, description: '初始数据' },
|
|
127
134
|
}).mount()
|
|
128
135
|
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
// component unmounts → unregister (snapshot stack cleaned too)
|
|
139
|
-
function unmountComp(id: string) {
|
|
140
|
-
delete window.app.components[id]
|
|
141
|
-
sdk.removeDataSlot(`app.components.${id}`)
|
|
142
|
-
}
|
|
143
|
-
sdk.listDataSlots() // live registry (reflects dynamic add/remove)
|
|
136
|
+
// later: swap to a different schema + bind (lazy-loaded / dynamic)
|
|
137
|
+
sdk.setData({
|
|
138
|
+
schema: newSchema, // new zod schema (validation + field hints auto-injected)
|
|
139
|
+
bind: newObj, // new reactive/plain object
|
|
140
|
+
description: '新数据',
|
|
141
|
+
})
|
|
142
|
+
// tools now operate on newObj with newSchema — immediately, no rebuild
|
|
143
|
+
sdk.getData() // read current config
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
>
|
|
146
|
+
> `summarization` auto-embeds the current data description in compressed summaries, so the agent won't act on stale memory after a swap. Snapshots & optimistic-lock hash reset on swap (old snapshots cleared).
|
|
147
147
|
|
|
148
148
|
**Full runnable demo**: `examples/dynamic-demo/` (`npm run dev` → `/examples/dynamic-demo/`).
|
|
149
149
|
|
|
@@ -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
|
|