page-agent-sdk 2.9.0 → 2.10.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/README.md +23 -6
- package/README.zh-CN.md +23 -6
- package/dist/page-agent-sdk.css +1 -1
- package/dist/page-agent-sdk.iife.js +112 -112
- package/dist/page-agent-sdk.js +1016 -721
- package/dist/page-agent-sdk.umd.cjs +45 -45
- package/package.json +1 -1
- package/skills/page-agent-sdk-integrate/SKILL.md +1 -0
- package/skills/page-agent-sdk-integrate/references/api.md +4 -0
- package/skills/page-agent-sdk-integrate/references/integration-prompt.md +179 -0
- package/skills/page-agent-sdk-integrate/references/options.md +30 -2
- package/skills/page-agent-sdk-integrate/references/use-cases.md +3 -3
- package/types/index.d.ts +47 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "page-agent-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "框架无关的页面内 Agent JS SDK —— 以对话框形态挂载到任意网页,通过自定义 tool 读写宿主预注册的数据槽(经 schema 校验 + jsonPath 增量 patch + 快照回退;GET 抓文档),具备 planning/skills/虚拟工作区/context 管理能力。Vue 打包进库,使用者无需安装 Vue。",
|
|
6
6
|
"main": "./dist/page-agent-sdk.umd.cjs",
|
|
@@ -113,6 +113,7 @@ Detailed docs live in this skill's `references/` folder — load the one matchin
|
|
|
113
113
|
- **[references/api.md](references/api.md)** — instance methods (`mount`/`send`/`stream`/`inspect`/`switchSession`/`hook`/`setData`/`getData`/checkpoints), `defineTool`/`defineSkill`/`presets`, built-in data tools, and the full `SdkEvent` type table. Read when the user asks about APIs, tools, or events.
|
|
114
114
|
- **[references/use-cases.md](references/use-cases.md)** — 10 end-to-end scenarios (low-code builder / form designer / CMS batch / ops console / AI-native / research / server-side / multi-agent / MCP / dynamic schema via setData). Read when the user wants a concrete pattern for their use case.
|
|
115
115
|
- **[references/advanced.md](references/advanced.md)** — detailed examples for the extensibility surfaces: **dynamic schema (`sdk.setData` to swap main data at runtime)**, custom `defineTool` (with error handling + coexisting with dataOps), `defineSkill` (inline content + remote doc), subagents (ad-hoc `spawn_agent`/`spawn_agents` + pre-declared `subagents` → `use_<id>`), MCP (http/sse/websocket + auth + dev gotcha). Read when the user asks "how to add custom tools / skills / subagents / MCP" or "swap data/schema at runtime".
|
|
116
|
+
- **[references/integration-prompt.md](references/integration-prompt.md)** — a generic integration prompt template to copy into the target project's AI (Cursor / Claude Code) when the skill is NOT installed there. Fill in `[...]` per scenario. Read when the user asks "give me a prompt to integrate the SDK in another project" or wants a copy-paste prompt for a teammate's AI tool.
|
|
116
117
|
|
|
117
118
|
Project-level docs (in the repo, not bundled in this skill):
|
|
118
119
|
- `doc/usage-guide.md` (zh) / `doc/usage-guide.en.md` — full options reference
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
| `usage` | `TokenUsage` | Cumulative token usage `{prompt_tokens, completion_tokens, total_tokens}` (accumulated per LLM call). |
|
|
22
22
|
| `restoreLastCheckpoint()` | `() => boolean` | Restore last good checkpoint (needs `checkpoint` enabled). |
|
|
23
23
|
| `listCheckpoints()` | `() => CheckpointMeta[]` | List available checkpoints. |
|
|
24
|
+
| `addSkill(skill)` | `(skill: { name, description, prompt \| getContent \| doc }) => void` | Add a user-created skill at runtime. Auto-merges into the skill list, persists via **independent SkillStore** (default indexedDB, separate from `storage` option), takes effect next round. Same-name overwrites. Requires `capabilities.skills` (default on) + `skillStorage` not `false` for persistence. |
|
|
25
|
+
| `removeSkill(name)` | `(name: string) => void` | Remove a user-created skill by name (only user-created, not init-time skills). Removes from SkillStore. No-op if not found. |
|
|
26
|
+
| `listUserSkills()` | `() => string[]` | List names of user-created skills (not init-time skills). Useful for UI panels. |
|
|
27
|
+
| `getUserSkill(name)` | `(name: string) => { name, description, content } \| undefined` | Read a user-created skill's detail (for SkillPanel edit). Returns `undefined` if not found. |
|
|
24
28
|
|
|
25
29
|
## defineTool (custom tools)
|
|
26
30
|
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Integration prompt template (generic)
|
|
2
|
+
|
|
3
|
+
Copy this prompt into the target project's Cursor / Claude Code so its AI integrates `page-agent-sdk` following the workflow. Fill in `[...]` per your scenario.
|
|
4
|
+
|
|
5
|
+
> Recommended: install the skill in the target project first (`cp -R node_modules/page-agent-sdk/skills/page-agent-sdk-integrate ~/.claude/skills/`) — the AI auto-integrates per workflow. Use this prompt only when the skill can't be installed.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Your task
|
|
10
|
+
|
|
11
|
+
Integrate `page-agent-sdk` (npm package) into the current project to enable "[business scenario: e.g. low-code page builder / form designer / ops config console / CMS batch ops / AI-native assistant...]". The integrator declares ONE main data object; an AI agent edits it via schema-validated tools `read`/`write` incrementally, with [UI form: built-in dialog / drawer mode / headless custom UI].
|
|
12
|
+
|
|
13
|
+
## Background
|
|
14
|
+
|
|
15
|
+
- `page-agent-sdk` is a **framework-agnostic JS SDK** (bundles Vue 3.5 internally, no conflict with host; works with Vue2/React/vanilla/Node)
|
|
16
|
+
- Core model: integrator declares **one main data object** `data: { schema, bind, description? }`; the agent reads/writes `bind` via tools (schema validation + whitelist + optimistic lock + snapshot)
|
|
17
|
+
- `bind` is any reactive/plain object; tools read/write it directly, **no `window` dependency**
|
|
18
|
+
- `schema` is a zod schema; field `.describe()` text is auto-injected into the systemPrompt so the LLM knows each field's purpose — no manual field descriptions needed
|
|
19
|
+
- Tools: `read` (read, supports jsonPath/fields/depth projection), `write` (write, merges set/edit/delete + auto optimistic lock + auto snapshot, supports patch jsonPath increments)
|
|
20
|
+
- Full docs: load the `page-agent-sdk-integrate` skill (if installed), or see `node_modules/page-agent-sdk/skills/page-agent-sdk-integrate/`
|
|
21
|
+
|
|
22
|
+
## Steps
|
|
23
|
+
|
|
24
|
+
### 1. Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm i page-agent-sdk zod @langchain/openai @langchain/core
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 2. Declare the main data object + schema (key step)
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
// dataSchema.ts
|
|
34
|
+
import { z } from 'page-agent-sdk'
|
|
35
|
+
|
|
36
|
+
// [Define schema per business: field names/types/shapes; field .describe() auto-injects into systemPrompt]
|
|
37
|
+
export const mainSchema = z.object({
|
|
38
|
+
title: z.string().describe('Page title'),
|
|
39
|
+
items: z.array(z.object({
|
|
40
|
+
id: z.string().describe('Item id'),
|
|
41
|
+
name: z.string().describe('Name'),
|
|
42
|
+
// ... other fields
|
|
43
|
+
})).describe('List items array'),
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
export type MainData = z.infer<typeof mainSchema>
|
|
47
|
+
|
|
48
|
+
// [Optional] skill content: business field/component docs for Agent load_skill on demand (saves systemPrompt tokens)
|
|
49
|
+
export const builderSkillContent = `# [Business name] Skill
|
|
50
|
+
|
|
51
|
+
Main data = { title, items[] }.
|
|
52
|
+
|
|
53
|
+
## Fields
|
|
54
|
+
- title: page title
|
|
55
|
+
- items[]: list items, each = { id, name, ... }
|
|
56
|
+
|
|
57
|
+
## Edit rules
|
|
58
|
+
- Add/remove items: edit items array (append/splice)
|
|
59
|
+
- Prefer incremental patch for single-item edits (only changed fields), avoid re-sending the whole array
|
|
60
|
+
- Validation failures return structured errors; fix per hint and retry
|
|
61
|
+
- jsonPath locates relative to main data root (e.g. items.0.name)`
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 3. Integrate the SDK
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { createChatSdk, defineSkill } from 'page-agent-sdk'
|
|
68
|
+
import 'page-agent-sdk/style.css'
|
|
69
|
+
import { mainSchema, builderSkillContent } from './dataSchema'
|
|
70
|
+
|
|
71
|
+
// [bind: use a reactive object (Vue3 reactive / Vue2 data() return / React useState or ref.current)]
|
|
72
|
+
const mainData = { title: 'Initial title', items: [] }
|
|
73
|
+
|
|
74
|
+
const sdk = createChatSdk({
|
|
75
|
+
container: '#agent-root',
|
|
76
|
+
id: '[stable id, e.g. page-builder]', // multi-agent isolation + persistence namespace
|
|
77
|
+
storage: 'memory',
|
|
78
|
+
llm: {
|
|
79
|
+
apiKey: import.meta.env.VITE_AI_API_KEY || 'YOUR_API_KEY',
|
|
80
|
+
baseUrl: 'https://api.deepseek.com/v1', // OpenAI-compatible protocol; DeepSeek by default
|
|
81
|
+
model: 'deepseek-chat',
|
|
82
|
+
temperature: 0.3, // low temp recommended for large JSON ops
|
|
83
|
+
},
|
|
84
|
+
// [UI form: built-in dialog (default) / drawer mode (dialog.drawer:true) / headless (ui:false)]
|
|
85
|
+
dialog: {
|
|
86
|
+
drawer: true, // drawer mode: right slide-in + mask; close defaults to hide() preserving history
|
|
87
|
+
title: '[Business] Agent',
|
|
88
|
+
placeholder: 'Try: [example operation]',
|
|
89
|
+
},
|
|
90
|
+
// systemPrompt: describe business + data structure; reliableWriteRules auto-appended with '---' separator (default true)
|
|
91
|
+
systemPrompt: 'You are a [business] assistant. Main data = { title, items[] }. To edit, change title or items (add/remove/edit items, adjust fields); [page/UI] updates live. See load_skill("[skill-name]") for fields.',
|
|
92
|
+
appendReliableWriteRules: true, // default true, auto-appends reliable write rules (read-before-write, fields per describe, retry on validation error, prefer incremental patch)
|
|
93
|
+
// data single main object: schema + bind directly bound to object
|
|
94
|
+
data: { schema: mainSchema, bind: mainData, description: '[main data purpose]' },
|
|
95
|
+
// skill: business field docs, Agent load_skill on demand
|
|
96
|
+
skills: [
|
|
97
|
+
defineSkill({
|
|
98
|
+
name: '[skill-name]',
|
|
99
|
+
description: 'Edit [business] data. Use when user requests changes',
|
|
100
|
+
getContent: () => builderSkillContent,
|
|
101
|
+
}),
|
|
102
|
+
],
|
|
103
|
+
debug: true,
|
|
104
|
+
// onEvent: for non-reactive bind or new-property cases, use data_change to trigger re-render
|
|
105
|
+
onEvent(e) {
|
|
106
|
+
if (e.type === 'data_change') {
|
|
107
|
+
// [non-reactive bind: tick++ to force re-render; reactive bind: not needed or use for audit/联动]
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
}).mount()
|
|
111
|
+
|
|
112
|
+
// Drawer mode: call show() to open (hide() to close, preserves history & in-flight generation)
|
|
113
|
+
// sdk.show() / sdk.hide()
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 4. [Optional] Page render + refresh
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
// Reactive bind (Vue3 reactive / Vue2 data()): Agent write → auto-reactive, no manual refresh
|
|
120
|
+
// Non-reactive bind (plain object): onEvent('data_change') triggers tick, :key="tick" forces component rebuild to read latest bind
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Options cheat sheet
|
|
124
|
+
|
|
125
|
+
| Option | Value | Purpose |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| `drawer` | `true` | Drawer mode: right slide-in + mask; close defaults to `hide()` |
|
|
128
|
+
| `ui` | `false` | headless: no dialog, use `sdk.messages` + `send`/`stream` to build your own UI |
|
|
129
|
+
| `data` | `{ schema, bind, description? }` | Main data declaration (key); `bind` directly bound |
|
|
130
|
+
| `systemPrompt` | string | Business description; `reliableWriteRules` auto-appended with `---` |
|
|
131
|
+
| `appendReliableWriteRules` | `true` (default) | Auto-append reliable write rules; set `false` to disable |
|
|
132
|
+
| `skills` | `defineSkill[]` | Business field docs, Agent `load_skill` on demand |
|
|
133
|
+
| `storage` | `'memory'`/`'local'`/... | Persistence (messages/vfs/todos/memory; **does NOT persist bind**) |
|
|
134
|
+
| `llm.temperature` | `0.3` | Low temp recommended for large JSON ops |
|
|
135
|
+
| `onEvent` | `(e) => {}` | Event callback; `data_change` triggers re-render |
|
|
136
|
+
| `checkpoint` | `true` | Session-level rollback (per-round snapshot; one-click restore if broken) |
|
|
137
|
+
| `approval` | `{ tools: ['write'] }` | Human-confirm before write ops (prevent AI mis-edits) |
|
|
138
|
+
| `capabilities` | `{ dataOps:false, fetch:false, ... }` | Turn off unused built-ins to save tokens/size |
|
|
139
|
+
|
|
140
|
+
## Common pitfalls
|
|
141
|
+
|
|
142
|
+
1. **bind not persisted**: `storage` persists messages/vfs/todos/memory but **NOT bind**; to restore across refresh, store it yourself + `sdk.setData({ bind: restoredBind })`
|
|
143
|
+
2. **DeepSeek 400 `missing field tool_call_id`**: handled internally; only relevant for custom tool plumbing (use snake_case)
|
|
144
|
+
3. **`.env` `VITE_AI_SYSTEM_PROMPT` must be single-line** (dotenv doesn't support multi-line)
|
|
145
|
+
4. **Large JSON incremental edit**: use `write({ value:180, patch:{ op:'set', jsonPath:'items.0.price' } })` to avoid re-sending the whole blob (truncated by max_tokens)
|
|
146
|
+
5. **Schema whitelist**: `z.object` auto-enables whitelist (only declared fields exposed); `discriminatedUnion`/`record`/`lazy` non-top-level don't enable (fully open)
|
|
147
|
+
6. **Vue2 new-property non-reactive**: `write` patch `set` on a new field — Vue2 `Object.defineProperty` won't react → `onEvent('data_change')` `tick++`, use `:key="tick"` to force rebuild
|
|
148
|
+
7. **MCP cold-start injects 0 tools**: `vite.config.ts` `optimizeDeps.include` pre-declares SDK sub-paths; keep those entries when forking config, else first MCP page load injects nothing (reload fixes)
|
|
149
|
+
|
|
150
|
+
## Verification checklist
|
|
151
|
+
|
|
152
|
+
- [ ] After `npm i`, `import { createChatSdk, z } from 'page-agent-sdk'` doesn't error
|
|
153
|
+
- [ ] `import 'page-agent-sdk/style.css'` styles load
|
|
154
|
+
- [ ] Agent `read` sees main data structure; `write` patch edits sub-path fields
|
|
155
|
+
- [ ] [Reactive bind] edits → UI reacts; [non-reactive] `data_change` → re-render
|
|
156
|
+
- [ ] [Drawer mode] close then open (`show()`) → history & in-flight generation preserved
|
|
157
|
+
- [ ] Schema validation failure → structured error, no write
|
|
158
|
+
|
|
159
|
+
## References
|
|
160
|
+
|
|
161
|
+
- `node_modules/page-agent-sdk/skills/page-agent-sdk-integrate/` (integration skill, full docs)
|
|
162
|
+
- `references/quickstart.md` (progressive setup), `references/options.md` (all options), `references/api.md` (API/tools/events)
|
|
163
|
+
- `references/use-cases.md` (10 end-to-end scenarios: low-code/form/CMS/ops/AI-native/research/server-side/multi-agent/MCP/dynamic schema)
|
|
164
|
+
- `references/advanced.md` (custom tools/skills/subagents/MCP/dynamic schema)
|
|
165
|
+
- `node_modules/page-agent-sdk/dist/` (build artifacts)
|
|
166
|
+
- Online: `https://esm.sh/page-agent-sdk@2.9.0` (CDN verify)
|
|
167
|
+
|
|
168
|
+
## Scenario customization
|
|
169
|
+
|
|
170
|
+
Per your business scenario, fill in `systemPrompt` / `skills` / `data.schema`:
|
|
171
|
+
|
|
172
|
+
- **Low-code page builder**: `data` = component tree; `write` patch jsonPath incremental; `onEvent('data_change')` refresh canvas; `checkpoint` + `approval`
|
|
173
|
+
- **Form designer**: `data` = field definitions (enum/required); schema validation prevents malformed forms
|
|
174
|
+
- **CMS batch ops**: `eval_script` loops; `search_data` filter; `write` patch targeted edits
|
|
175
|
+
- **Ops config console**: `approval:{tools:['write']}` human-confirm; `capabilities.verify:true` write-back read; `checkpoint`
|
|
176
|
+
- **AI-native assistant**: `capabilities:{dataOps:false,fetch:false}` + custom `tools` (your product API)
|
|
177
|
+
- **Multi-agent on one page**: same `id` + `shareContext:true` → multiple dialogs share one `AgentCore`; or independent `id`s + `dialog.drawer:true` + `hide`/`show` for exclusive switching
|
|
178
|
+
- **MCP integration**: `mcp:[{transport,url}]` remote tool servers; `@modelcontextprotocol/sdk` optional peerDep
|
|
179
|
+
- **Dynamic/lazy-loaded schema**: `sdk.setData({ schema, bind })` on component mount to swap main data; tools pick up immediately, no rebuild
|
|
@@ -10,7 +10,6 @@ Full reference for `createChatSdk(options)`. Grouped by purpose. Required: `llm`
|
|
|
10
10
|
| `systemPrompt` | `string` | built-in default (JSON-operation assistant + reliable write rules) | Agent identity/instructions. Inject here, not hardcoded. Keep single-line in `.env` (`VITE_AI_SYSTEM_PROMPT`). If omitted, a built-in default is used (JSON-operation assistant + `systemPromptHelpers.reliableWriteRules`); passing your own fully overrides it. |
|
|
11
11
|
| `appendReliableWriteRules` | `boolean` | `true` | When `true` (default) and a custom `systemPrompt` is set, auto-append `systemPromptHelpers.reliableWriteRules` to it with a `---` separator (clearly distinguishes user content from SDK-appended write rules; avoids forgetting the write rules). Set `false` to disable. No effect when `systemPrompt` is omitted (default prompt already includes them). |
|
|
12
12
|
| `id` | `string` | random + warn | Stable agent id for multi-agent isolation & persistence. **Must pass a stable value** if you use `storage` or run multiple agents on one page. |
|
|
13
|
-
| `title` / `placeholder` | `string` | — | Dialog title / input placeholder (cosmetic). |
|
|
14
13
|
|
|
15
14
|
## UI & mounting
|
|
16
15
|
|
|
@@ -19,6 +18,19 @@ Full reference for `createChatSdk(options)`. Grouped by purpose. Required: `llm`
|
|
|
19
18
|
| `container` | `string \| HTMLElement` | — | Where the built-in dialog mounts. Required when `ui !== false`. |
|
|
20
19
|
| `ui` | `boolean \| 'default'` | `true` | `false` = headless (no built-in dialog; you build UI from `sdk.messages` + `sdk.send`). `'default'` = built-in `ChatDialog`. |
|
|
21
20
|
| `streaming` | `boolean` | `true` | Stream tokens live. `false` = wait for full reply. Headless `sdk.send` always uses invoke (no stream events, but data/message/error still fire). |
|
|
21
|
+
| `dialog` | `DialogConfig` | — | Grouped dialog UI config (recommended form). See `DialogConfig` fields below. |
|
|
22
|
+
|
|
23
|
+
### `DialogConfig` fields
|
|
24
|
+
|
|
25
|
+
| Field | Type | Default | Purpose / when |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| `title` | `string` | — | Dialog title (cosmetic). |
|
|
28
|
+
| `placeholder` | `string` | — | Input placeholder (cosmetic). |
|
|
29
|
+
| `drawer` | `boolean` | `false` | Drawer mode: ChatDialog slides in from the right + mask + close button (replaces the collapse arrow). Default `false` (inline, fills container). |
|
|
30
|
+
| `drawerWidth` | `number \| string` | `420` | Drawer mode width (pixels or CSS string, e.g. `500` / `'500px'` / `'40vw'`). Only effective when `drawer: true`. Inline mode width is determined by `container`. |
|
|
31
|
+
| `drawerHidden` | `boolean` | `false` | Drawer mode hidden by default (not shown after `mount`; requires `sdk.show()` to display): for "click button to show chatbox" scenarios. Only effective when `drawer: true`. |
|
|
32
|
+
| `inputRows` | `number` | `2` | Input box rows (visible height). `1` = single row; `2` = 2-row initial height, auto-expands up to max-height:100px; `>2` = taller initial height. |
|
|
33
|
+
| `onClose` | `() => void` | — | Drawer mode close callback (called when mask/close button clicked). Default: `hide()` in drawer mode (keeps agent/history/in-flight generation), `unmount()` otherwise. Pass this to sync external mount state. |
|
|
22
34
|
|
|
23
35
|
## Data operation (the core)
|
|
24
36
|
|
|
@@ -39,6 +51,7 @@ Full reference for `createChatSdk(options)`. Grouped by purpose. Required: `llm`
|
|
|
39
51
|
|---|---|---|---|
|
|
40
52
|
| `tools` | `Tool[]` | `[]` | Custom tools beyond built-ins. Use `defineTool({ name, description, schema, handler })`. |
|
|
41
53
|
| `skills` | `SkillSpec[]` | `[]` | Progressive-disclosure skills (`defineSkill({ name, description, prompt }`) loaded on demand by the agent. |
|
|
54
|
+
| `skillStorage` | `SkillStoreConfig \| false` | `{ backend: 'indexed' }` | **User-created skill independent persistence** (separate from `storage`). Default indexedDB (persists even when `storage: false`); `false` disables persistence (current session only). `id` manually specifies the same id to share skills across pages/agents; omit for per-agent isolation. |
|
|
42
55
|
| `memory` | `string` | — | AGENTS.md-style persistent instructions injected into every prompt (project conventions, hard rules). |
|
|
43
56
|
| `middleware` | `Middleware[]` | `[]` | Custom middleware appended after built-ins. 8 hooks: `beforeAgent`/`wrapModelCall`/`beforeModel`/`afterModel`/`wrapToolCall`/`afterAgent`/`beforeReturn` + `augmentPrompt`/`compressInput`/`tools`. For interception, instrumentation, prompt enhancement. |
|
|
44
57
|
|
|
@@ -124,13 +137,28 @@ Full reference for `createChatSdk(options)`. Grouped by purpose. Required: `llm`
|
|
|
124
137
|
|
|
125
138
|
Runtime subscription via `sdk.hook(handler) => () => void` (multi-listener, cancellable) — see [api.md](api.md).
|
|
126
139
|
|
|
127
|
-
## Convenience APIs (export / import / usage)
|
|
140
|
+
## Convenience APIs (export / import / usage / user skills)
|
|
128
141
|
|
|
129
142
|
| API | Purpose | Notes |
|
|
130
143
|
|---|---|---|
|
|
131
144
|
| `sdk.exportData()` | Deep copy of main data `bind` (backup/migration) | Returns `null` if dataOps off / no data; mutating return does not affect original bind |
|
|
132
145
|
| `sdk.importData(json, opts?)` | Replace `bind` entirely (in-place, preserves reactive ref) | Schema-validated by default → `{ok:false,error}` if invalid; `opts.validate:false` skips; `opts.emit:false` suppresses `data_change` |
|
|
133
146
|
| `sdk.usage` | Cumulative token usage `{prompt_tokens, completion_tokens, total_tokens}` | Accumulated per LLM call; per-round detail via `onEvent('usage')` |
|
|
147
|
+
| `sdk.addSkill(skill)` | Add a user-created skill at runtime | `skill: { name, description, prompt \| getContent \| doc }`. Auto-merges into the skill list, **persists via independent SkillStore** (default indexedDB, separate from `storage` option — even `storage:false` persists skills), and takes effect next round. Same-name overwrites. Requires `capabilities.skills` (default on) + `skillStorage` not `false` for persistence. |
|
|
148
|
+
| `sdk.removeSkill(name)` | Remove a user-created skill by name | Only removes user-created skills (not the ones passed via `skills` option at init). Removes from SkillStore. No-op if not found. |
|
|
149
|
+
| `sdk.listUserSkills()` | List names of user-created skills | Returns `string[]` (only user-created, not init-time skills). Useful for UI panels. |
|
|
150
|
+
| `sdk.getUserSkill(name)` | Read a user-created skill's detail | Returns `{ name, description, content }` or `undefined` if not found. Used by SkillPanel for editing. |
|
|
151
|
+
|
|
152
|
+
**User-created skills** are skills added at runtime via `sdk.addSkill` (or via the built-in `SkillPanel` UI component). They are persisted via an **independent SkillStore** (default indexedDB), **separate from the `storage` option** — even when `storage: false` (session persistence off), user skills still persist across refreshes. To **share the same set of user skills across pages/agents**, manually specify the same `skillStorage.id`:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
// Page A
|
|
156
|
+
createChatSdk({ id: 'agent-a', skillStorage: { id: 'shared-skills' }, ... })
|
|
157
|
+
// Page B (different agent, same skill set)
|
|
158
|
+
createChatSdk({ id: 'agent-b', skillStorage: { id: 'shared-skills' }, ... })
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Without `skillStorage.id`, skills default to per-agent isolation (`agent::{agentId}`). The built-in `ChatDialog` exposes a "Skill Management" button (header) that opens `SkillPanel` — supports create, **edit** (click a skill to load into the form), and delete. Integrators can also `import { SkillPanel }` directly for custom UIs.
|
|
134
162
|
|
|
135
163
|
## vfs (in-memory workspace)
|
|
136
164
|
|
|
@@ -275,9 +275,9 @@ const boxB = document.createElement('div'); document.body.appendChild(boxB)
|
|
|
275
275
|
const boxC = document.createElement('div'); document.body.appendChild(boxC)
|
|
276
276
|
|
|
277
277
|
const agents = [
|
|
278
|
-
createChatSdk({ id: 'agent-page', container: boxA, drawer: true, storage: 'memory', llm: LLM, data: { schema: pageSchema, bind: pageObj }, systemPrompt: '页面构建助手…' }),
|
|
279
|
-
createChatSdk({ id: 'agent-copy', container: boxB, drawer: true, storage: 'memory', llm: LLM, data: { schema: copySchema, bind: copyObj }, systemPrompt: '文案优化助手…' }),
|
|
280
|
-
createChatSdk({ id: 'agent-stats', container: boxC, drawer: true, storage: 'memory', llm: LLM, data: { schema: statsSchema, bind: statsObj }, systemPrompt: '数据分析助手…' }),
|
|
278
|
+
createChatSdk({ id: 'agent-page', container: boxA, dialog: { drawer: true }, storage: 'memory', llm: LLM, data: { schema: pageSchema, bind: pageObj }, systemPrompt: '页面构建助手…' }),
|
|
279
|
+
createChatSdk({ id: 'agent-copy', container: boxB, dialog: { drawer: true }, storage: 'memory', llm: LLM, data: { schema: copySchema, bind: copyObj }, systemPrompt: '文案优化助手…' }),
|
|
280
|
+
createChatSdk({ id: 'agent-stats', container: boxC, dialog: { drawer: true }, storage: 'memory', llm: LLM, data: { schema: statsSchema, bind: statsObj }, systemPrompt: '数据分析助手…' }),
|
|
281
281
|
]
|
|
282
282
|
await Promise.all(agents.map(a => a.mount())) // three independent agents ready in parallel
|
|
283
283
|
agents.slice(1).forEach(a => a.hide()) // show only the first initially
|
package/types/index.d.ts
CHANGED
|
@@ -137,6 +137,7 @@ export interface McpServerConfig { transport: 'http' | 'sse' | 'websocket'; url:
|
|
|
137
137
|
export declare const ChatDialog: DefineComponent<ChatDialogProps>;
|
|
138
138
|
export declare const MessageContent: DefineComponent<any>;
|
|
139
139
|
export declare const CodePreview: DefineComponent<any>;
|
|
140
|
+
export declare const SkillPanel: DefineComponent<any>;
|
|
140
141
|
export declare function useChat(opts?: any): any;
|
|
141
142
|
|
|
142
143
|
// ===== 框架无关 SDK(页面内 Agent)=====
|
|
@@ -301,6 +302,15 @@ export interface StorageConfig {
|
|
|
301
302
|
evictionWatermark?: number;
|
|
302
303
|
debounceMs?: number;
|
|
303
304
|
}
|
|
305
|
+
/** Skill 独立持久化存储配置(与 storage 选项分离) */
|
|
306
|
+
export interface SkillStoreConfig {
|
|
307
|
+
/** 存储 id(命名空间)。手动指定同一 id 即可跨页面/跨 agent 复用同一套用户 skill;不传默认按 agentId 隔离 */
|
|
308
|
+
id?: string;
|
|
309
|
+
/** 后端类型,默认 'indexed'(大容量、跨刷新);'local' 跨页持久;'session' 刷新保留关页清;'memory' 纯内存降级 */
|
|
310
|
+
backend?: StorageBackendType;
|
|
311
|
+
/** DB 命名空间,默认 'chat-sdk'(与 SessionStore 同库,不同 key 前缀) */
|
|
312
|
+
dbName?: string;
|
|
313
|
+
}
|
|
304
314
|
export interface SessionMeta {
|
|
305
315
|
agentId: string;
|
|
306
316
|
sessionId: string;
|
|
@@ -362,6 +372,8 @@ export interface ChatSdkOptions {
|
|
|
362
372
|
appendReliableWriteRules?: boolean;
|
|
363
373
|
tools?: any[];
|
|
364
374
|
skills?: SkillSpec[];
|
|
375
|
+
/** 用户创建 skill 的独立持久化存储(与 storage 选项分离)。默认 `{ backend: 'indexed' }`(即使 storage:false 也持久化);`false` 关闭;`id` 手动指定同一 id 可跨页面/跨 agent 复用 */
|
|
376
|
+
skillStorage?: SkillStoreConfig | false;
|
|
365
377
|
memory?: string;
|
|
366
378
|
data?: DataConfig;
|
|
367
379
|
permissions?: PermissionRule[];
|
|
@@ -430,11 +442,19 @@ export interface ChatSdkOptions {
|
|
|
430
442
|
onEvent?: SdkEventHandler;
|
|
431
443
|
/** 流式输出(默认 true);false 时等整段回复再显示 */
|
|
432
444
|
streaming?: boolean;
|
|
445
|
+
/** Dialog UI config (title/placeholder/drawer/drawerWidth/drawerHidden/inputRows/onClose grouped) */
|
|
446
|
+
dialog?: DialogConfig;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/** Dialog UI config (grouped form, recommended) */
|
|
450
|
+
export interface DialogConfig {
|
|
433
451
|
title?: string;
|
|
434
452
|
placeholder?: string;
|
|
435
|
-
/** Drawer mode: ChatDialog slides in from the right + mask + close button (replaces the collapse arrow); clicking mask/close triggers unmount (with exit animation). Default false (inline, fills container). */
|
|
436
453
|
drawer?: boolean;
|
|
437
|
-
|
|
454
|
+
drawerWidth?: number | string;
|
|
455
|
+
drawerHidden?: boolean;
|
|
456
|
+
/** Input box rows (visible height); default 2 (2-row initial height, auto-expands up to max-height:100px). 1 = single row; >2 = taller. */
|
|
457
|
+
inputRows?: number;
|
|
438
458
|
onClose?: () => void;
|
|
439
459
|
}
|
|
440
460
|
|
|
@@ -467,6 +487,14 @@ export interface ChatSdk {
|
|
|
467
487
|
* 清空 skill 全文缓存与本轮已加载记录,下次 load_skill 重新取最新全文(含 vfs doc)。需开启 skills(默认开)
|
|
468
488
|
*/
|
|
469
489
|
setSkills(skills: SkillSpec[]): void;
|
|
490
|
+
/** 添加用户创建的 skill(持久化,跨刷新恢复;同名覆盖)。需开启 skills(默认开) */
|
|
491
|
+
addSkill(skill: SkillSpec): void;
|
|
492
|
+
/** 删除用户创建的 skill(仅删用户创建的,不删集成方 initialSkills)。返回是否删除成功 */
|
|
493
|
+
removeSkill(name: string): boolean;
|
|
494
|
+
/** 列出用户创建的 skill 名(仅用户创建的,不含集成方 initialSkills) */
|
|
495
|
+
listUserSkills(): string[];
|
|
496
|
+
/** 读取用户创建的 skill 详情(返回 {name, description, content};不存在返回 undefined) */
|
|
497
|
+
getUserSkill(name: string): { name: string; description: string; content: string } | undefined;
|
|
470
498
|
/**
|
|
471
499
|
* 清 skill 全文缓存(动态 skill 内容变化时主动失效)。不传 name 清全部;传 name 清指定。
|
|
472
500
|
* 下次 load_skill 重新 getContent/readSkillDoc 取最新。需开启 skills(默认开)
|
|
@@ -545,6 +573,23 @@ export declare function createSessionStore(config?: StorageConfig): SessionStore
|
|
|
545
573
|
export declare function createMemoryBackend(): StorageBackend;
|
|
546
574
|
export declare function createWebStorageBackend(storage: Storage): StorageBackend;
|
|
547
575
|
export declare function isQuotaError(err: unknown): boolean;
|
|
576
|
+
/** 创建 Skill 独立持久化存储(与 storage 选项分离;默认 indexedDB,可手动指定 id 跨页复用) */
|
|
577
|
+
export declare function createSkillStore(config?: SkillStoreConfig): SkillStore;
|
|
578
|
+
export interface SkillStore {
|
|
579
|
+
ready: Promise<boolean>;
|
|
580
|
+
list(): Promise<PersistedSkill[]>;
|
|
581
|
+
get(name: string): Promise<PersistedSkill | undefined>;
|
|
582
|
+
put(skill: PersistedSkill): Promise<void>;
|
|
583
|
+
remove(name: string): Promise<boolean>;
|
|
584
|
+
clear(): Promise<void>;
|
|
585
|
+
dispose(): void;
|
|
586
|
+
}
|
|
587
|
+
/** 持久化的用户创建 skill(getContent 函数不可序列化,故 content 直接存字符串) */
|
|
588
|
+
export interface PersistedSkill {
|
|
589
|
+
name: string;
|
|
590
|
+
description: string;
|
|
591
|
+
content: string;
|
|
592
|
+
}
|
|
548
593
|
|
|
549
594
|
// ============ 大 JSON 查询/搜索/沙箱脚本(dataSlotQuery)============
|
|
550
595
|
export interface JpNode {
|