page-agent-sdk 2.10.2 → 2.11.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 +17 -14
- package/README.zh-CN.md +16 -13
- package/dist/page-agent-sdk.iife.js +122 -122
- package/dist/page-agent-sdk.js +3102 -3047
- package/dist/page-agent-sdk.umd.cjs +66 -66
- package/package.json +2 -1
- package/skills/page-agent-sdk-integrate/references/api.md +42 -0
- package/skills/page-agent-sdk-integrate/references/integration-prompt.md +4 -0
- package/skills/page-agent-sdk-integrate/references/quickstart.md +34 -0
- package/types/index.d.ts +15 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "page-agent-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.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",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"dev": "vite",
|
|
29
29
|
"mcp:mock": "tsx scripts/mcp-mock-server.ts",
|
|
30
30
|
"mcp:probe": "tsx scripts/mcp-probe.ts",
|
|
31
|
+
"proxy:mock": "tsx scripts/proxy-mock-server.ts",
|
|
31
32
|
"verify:probe": "tsx scripts/verify-probe.ts",
|
|
32
33
|
"build": "npm run build:lib && npm run build:iife",
|
|
33
34
|
"build:lib": "vite build",
|
|
@@ -173,3 +173,45 @@ createChatSdk({
|
|
|
173
173
|
- Middleware factories: `createApprovalMiddleware`, `createVerifyMiddleware`, `createWriteBackCheck`, `createSubagentMiddleware`, `createCheckpointMiddleware`, `createUsageHintsMiddleware`
|
|
174
174
|
- Storage: `createSessionStore`, `createMemoryBackend`, `createWebStorageBackend`, `isQuotaError`
|
|
175
175
|
- JSON helpers: `jpEval`, `searchJson`, `runSandboxedScript`, `toolError`, `zodError`
|
|
176
|
+
|
|
177
|
+
## Proxy connection (`createProxyLlm`) — prevent apiKey leakage
|
|
178
|
+
|
|
179
|
+
Browser-direct LLM calls expose `apiKey` in DevTools. Use `createProxyLlm` to unify dev/prod access:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { createChatSdk, createProxyLlm } from 'page-agent-sdk'
|
|
183
|
+
|
|
184
|
+
// Production: proxy mode (server injects real key)
|
|
185
|
+
createChatSdk({
|
|
186
|
+
llm: createProxyLlm({
|
|
187
|
+
mode: 'proxy',
|
|
188
|
+
baseUrl: '/api/llm', // your proxy (same-origin avoids CORS)
|
|
189
|
+
userToken: getUserToken(), // session token (server validates)
|
|
190
|
+
model: 'deepseek-chat',
|
|
191
|
+
refreshToken?: async () => ..., // optional: refresh on 401
|
|
192
|
+
headers?: { 'X-Tenant': 'acme' }, // optional: extra headers
|
|
193
|
+
}),
|
|
194
|
+
...
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
// Dev: direct mode (browser holds real key; dev only)
|
|
198
|
+
createChatSdk({
|
|
199
|
+
llm: createProxyLlm({
|
|
200
|
+
mode: 'direct',
|
|
201
|
+
apiKey: 'sk-xxx',
|
|
202
|
+
baseUrl: 'https://api.deepseek.com/v1',
|
|
203
|
+
model: 'deepseek-chat',
|
|
204
|
+
}),
|
|
205
|
+
...
|
|
206
|
+
})
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
| | `proxy` (prod) | `direct` (dev) |
|
|
210
|
+
|---|---|---|
|
|
211
|
+
| apiKey | server (invisible) | browser (DevTools visible) |
|
|
212
|
+
| browser holds | userToken | real apiKey |
|
|
213
|
+
| token refresh | yes (401 retry) | n/a |
|
|
214
|
+
| headers | supported | n/a |
|
|
215
|
+
|
|
216
|
+
Server-side proxy essentials: validate userToken → inject real apiKey → forward to LLM API; handle CORS; stream SSE through; pass tool-calling fields. See `doc/usage-guide*.md` §8.6 for full guide.
|
|
217
|
+
|
|
@@ -146,6 +146,7 @@ const sdk = createChatSdk({
|
|
|
146
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
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
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
|
+
8. **apiKey leakage in production**: browser-direct LLM calls expose `apiKey` in DevTools. Use `createProxyLlm({ mode:'proxy', baseUrl:'/api/llm', userToken })` — browser holds only user token, your server injects the real key. See `references/quickstart.md` Stage 8 + `doc/usage-guide*.md` §8.6.
|
|
149
150
|
|
|
150
151
|
## Verification checklist
|
|
151
152
|
|
|
@@ -155,6 +156,8 @@ const sdk = createChatSdk({
|
|
|
155
156
|
- [ ] [Reactive bind] edits → UI reacts; [non-reactive] `data_change` → re-render
|
|
156
157
|
- [ ] [Drawer mode] close then open (`show()`) → history & in-flight generation preserved
|
|
157
158
|
- [ ] Schema validation failure → structured error, no write
|
|
159
|
+
- [ ] [Production] `createProxyLlm({ mode:'proxy' })` — real apiKey not in browser bundle / network tab
|
|
160
|
+
- [ ] [Production] `createProxyLlm({ mode:'proxy' })` — real apiKey not in browser bundle / network tab
|
|
158
161
|
|
|
159
162
|
## References
|
|
160
163
|
|
|
@@ -177,3 +180,4 @@ Per your business scenario, fill in `systemPrompt` / `skills` / `data.schema`:
|
|
|
177
180
|
- **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
181
|
- **MCP integration**: `mcp:[{transport,url}]` remote tool servers; `@modelcontextprotocol/sdk` optional peerDep
|
|
179
182
|
- **Dynamic/lazy-loaded schema**: `sdk.setData({ schema, bind })` on component mount to swap main data; tools pick up immediately, no rebuild
|
|
183
|
+
- **Production proxy (prevent apiKey leakage)**: `createProxyLlm({ mode:'proxy', baseUrl:'/api/llm', userToken, refreshToken })` — browser holds only user token, server injects real key + forwards; dev uses `mode:'direct'` with real key. See `examples/proxy-demo/` + `npm run proxy:mock`
|
|
@@ -147,6 +147,40 @@ sdk.getData() // read current config
|
|
|
147
147
|
|
|
148
148
|
**Full runnable demo**: `examples/dynamic-demo/` (`npm run dev` → `/examples/dynamic-demo/`).
|
|
149
149
|
|
|
150
|
+
## Stage 8 — Production: proxy the LLM (prevent apiKey leakage)
|
|
151
|
+
|
|
152
|
+
Browser-direct LLM calls expose your `apiKey` in DevTools — anyone can drain your quota. **Production must proxy through your server**: the browser holds only a user token; your server injects the real `apiKey` and forwards. Use `createProxyLlm` to unify dev (direct) and prod (proxy) without restructuring:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { createChatSdk, createProxyLlm } from 'page-agent-sdk'
|
|
156
|
+
|
|
157
|
+
// Production: proxy mode (safe — real key stays server-side)
|
|
158
|
+
const sdk = createChatSdk({
|
|
159
|
+
container: '#root',
|
|
160
|
+
llm: createProxyLlm({
|
|
161
|
+
mode: 'proxy',
|
|
162
|
+
baseUrl: '/api/llm', // your proxy (same-origin avoids CORS)
|
|
163
|
+
userToken: getUserToken(), // session token (server validates, swaps in real key)
|
|
164
|
+
model: 'deepseek-chat',
|
|
165
|
+
refreshToken: async () => (await (await fetch('/api/refresh')).json()).token, // auto-refresh on 401
|
|
166
|
+
headers: { 'X-Tenant': 'acme' }, // optional custom headers
|
|
167
|
+
}),
|
|
168
|
+
// ...data, systemPrompt...
|
|
169
|
+
}).mount()
|
|
170
|
+
|
|
171
|
+
// Dev: direct mode (convenient — real key in browser; dev only)
|
|
172
|
+
const sdkDev = createChatSdk({
|
|
173
|
+
container: '#root',
|
|
174
|
+
llm: createProxyLlm({
|
|
175
|
+
mode: 'direct',
|
|
176
|
+
apiKey: 'sk-...', baseUrl: 'https://api.deepseek.com/v1', model: 'deepseek-chat',
|
|
177
|
+
}),
|
|
178
|
+
// ...data, systemPrompt...
|
|
179
|
+
}).mount()
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Both modes require an **OpenAI Chat Completions compatible** endpoint (the SDK uses `ChatOpenAI` internally). The proxy must: validate `userToken` → inject real `apiKey` → forward to upstream → stream SSE through → pass `tools`/`tool_calls` through. See `doc/usage-guide*.md` §8.6 for the full guide + a Node.js proxy example, and `examples/proxy-demo/` for a runnable demo (`npm run proxy:mock` + `npm run dev` → `/examples/proxy-demo/`).
|
|
183
|
+
|
|
150
184
|
## Next
|
|
151
185
|
|
|
152
186
|
- All options: see [options.md](options.md)
|
package/types/index.d.ts
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { DefineComponent, Ref } from 'vue';
|
|
2
2
|
export { z } from 'zod';
|
|
3
3
|
|
|
4
|
+
// 代理连接模块(防 apiKey 泄露:proxy 代理模式 / direct 直连模式)
|
|
5
|
+
export type ProxyLlmMode = 'proxy' | 'direct';
|
|
6
|
+
export interface ProxyLlmOptions {
|
|
7
|
+
mode: ProxyLlmMode;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
userToken?: string;
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
model?: string;
|
|
12
|
+
temperature?: number;
|
|
13
|
+
maxTokens?: number;
|
|
14
|
+
refreshToken?: () => Promise<string>;
|
|
15
|
+
headers?: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
export declare function createProxyLlm(opts: ProxyLlmOptions): import('@langchain/core/language_models/chat_models').BaseChatModel;
|
|
18
|
+
|
|
4
19
|
export interface ToolStep {
|
|
5
20
|
name: string;
|
|
6
21
|
args?: any;
|