page-agent-sdk 2.4.0 → 2.5.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 CHANGED
@@ -24,9 +24,10 @@ At its core, it gives the AI a **standardized, safe JSON-operation channel**. AI
24
24
 
25
25
  | Constraint | Mechanism | Effect |
26
26
  |---|---|---|
27
- | **Scope control** | Property registry (`dataSlots`) — only declared paths are writable | AI touching undeclared fields → rejected |
27
+ | **Scope control** | Property registry (`data`) — only declared paths are writable; schema shape auto-whitelist (top-level keys limit visible + writable; undeclared fields hidden/denied; whole-set becomes merge to prevent accidental deletion) | AI touching undeclared fields → `PATH_DENIED` |
28
28
  | **Validity check** | zod schema — `write`/`set`/`edit` validated against schema | Invalid type/enum/structure → structured error, no write |
29
- | **Incremental op** | `write` with `patch` (or advanced `edit_data_slot`) patches by `jsonPath` (set/remove/merge/append) | Avoid re-sending the whole large JSON; precise local edits |
29
+ | **Incremental op** | `write` with `patch`/`patches` (batch, atomic rollback) or advanced `edit_data` patches by `jsonPath` (set/remove/merge/append) | Avoid re-sending the whole large JSON; precise local edits; use `patches` to edit many at once |
30
+ | **Large-object retrieval** | `read` supports `fields` (projection) + `depth` (truncation) to shrink payload; `query_data` (JSONPath)/`search_data` (text)/`eval_script` (sandboxed JS) | Efficient retrieval + pinpoint location in large JSON |
30
31
  | **Rollbackable** | per-path snapshots (auto-stacked) + session checkpoint | Bad edit → one-click restore to the last good state |
31
32
  | **Optimistic lock** | `expectedHash` on `set`/`edit`/`delete` + conflict human-in-the-loop | Concurrent external edits detected → suspend, user picks keep/overwrite/restore |
32
33
 
@@ -58,16 +59,21 @@ npm install page-agent-sdk zod @langchain/openai @langchain/core
58
59
  import { createChatSdk } from 'page-agent-sdk'
59
60
  import { z } from 'zod'
60
61
 
61
- window.page = { title: 'New Products', theme: 'light' }
62
+ const page = { title: 'New Products', theme: 'light' }
63
+ window.page = page // optional: mount to window for your page to read; SDK tools operate on `bind` directly
62
64
 
63
65
  createChatSdk({
64
66
  container: '#chat',
65
67
  llm: { apiKey: 'sk-...', baseUrl: 'https://api.deepseek.com', model: 'deepseek-chat' },
66
- systemPrompt: 'You are a page-builder assistant; read/write window.page via tools.',
67
- dataSlots: [
68
- { path: 'page.title', description: 'Page title', schema: z.string() },
69
- { path: 'page.theme', description: 'Theme', schema: z.enum(['light', 'dark']) },
70
- ],
68
+ systemPrompt: 'You are a page-builder assistant; read/write the main data via tools.',
69
+ data: {
70
+ schema: z.object({
71
+ title: z.string().describe('Page title'),
72
+ theme: z.enum(['light', 'dark']).describe('Theme'),
73
+ }),
74
+ bind: page,
75
+ description: 'Page config',
76
+ },
71
77
  approval: { tools: ['write'] }, // confirm writes
72
78
  checkpoint: true, // one-click rollback on mistake
73
79
  }).mount()
@@ -81,7 +87,7 @@ CDN zero-config: `<script src="https://unpkg.com/page-agent-sdk"></script>` →
81
87
 
82
88
  | Capability | Description | Option |
83
89
  |---|---|---|
84
- | 🛠 window ops | Read/write registered props, schema validation + incremental patch + snapshot rollback | `dataSlots` |
90
+ | 🛠 window ops | Read/write registered props, schema validation + incremental patch + snapshot rollback | `data` |
85
91
  | 🧠 ReAct harness | Pluggable middleware (8 hooks), in-house (no LangGraph) | `middleware` |
86
92
  | 📋 planning/skills/memory | `write_todos` / `define_skill` / AGENTS.md directives | `capabilities.*` |
87
93
  | 🗄 virtual workspace | In-memory file system; large results offloaded (won't blow context) | `capabilities.vfs` |
@@ -91,7 +97,7 @@ CDN zero-config: `<script src="https://unpkg.com/page-agent-sdk"></script>` →
91
97
  | 🤖 subagents | Delegate subtasks; process stays out of main context | `subagent` |
92
98
  | 🔌 MCP | Connect remote MCP servers, inject tools dynamically | `mcp` |
93
99
  | 📦 context compression | 4-layer adaptive compression, presets + LLM summary | `contextPreset` |
94
- | 🛡️ compression-safe | Live dataSlots snapshot + preserved tool results in summary; write returns hint available paths; `systemPromptHelpers.reliableWriteRules` | built-in |
100
+ | 🛡️ compression-safe | Live data snapshot + preserved tool results in summary; write returns hint available paths; `systemPromptHelpers.reliableWriteRules` | built-in |
95
101
  | 💾 persistence | IndexedDB multi-session + quota eviction + switch | `storage` |
96
102
 
97
103
  Capabilities default on (`verify`/`approval`/`checkpoint` default off; **proactive `humanConfirm` default on** — AI asks when uncertain/multi-plan instead of guessing). Turn off unneeded ones via `capabilities` to save tokens.
@@ -109,14 +115,14 @@ createChatSdk, defineTool, defineSkill, presets, z
109
115
  createAgent, createSubagentMiddleware, createSubagentsMiddleware,
110
116
  createVerifyMiddleware, createWriteBackCheck, createApprovalMiddleware,
111
117
  createHumanConfirmMiddleware, createHumanConfirmTool, createCheckpointMiddleware, createCheckpointManager,
112
- createUsageHintsMiddleware, createDataSlotOps, createVfs, connectMcp
118
+ createUsageHintsMiddleware, createDataOps, createVfs, connectMcp
113
119
  // context & model
114
120
  resolveContextOptions, CONTEXT_PRESETS, resolveModelCaps, estimateTokens
115
121
  // storage
116
122
  createSessionStore, createMemoryBackend, createWebStorageBackend, isQuotaError
117
123
  // UI (reuse when headless)
118
124
  ChatDialog, MessageContent, CodePreview, useChat
119
- // types (omitted): ChatSdkOptions, Middleware, SubagentConfig, SkillSpec, DataSlotSpec, AgentMessage, StreamEvent …
125
+ // types (omitted): ChatSdkOptions, Middleware, SubagentConfig, SkillSpec, DataConfig, AgentMessage, StreamEvent …
120
126
  ```
121
127
 
122
128
  ### `createChatSdk` options cheat sheet
@@ -128,9 +134,9 @@ ChatDialog, MessageContent, CodePreview, useChat
128
134
  | | `llm` | `LLMConfig \| BaseChatModel` · **required** | `LLMConfig={apiKey,baseUrl?,model?,temperature?,maxTokens?}`; OpenAI-compatible (default DeepSeek) |
129
135
  | | `id` | `string` | Stable id (multi-agent isolation + persistence resume; random+warn if omitted) |
130
136
  | | `systemPrompt` | `string` | Agent identity (no hardcoded business; inject via this). Optional — built-in default (page assistant + `reliableWriteRules`) used if omitted; passing your own fully overrides it |
131
- | **Page data** | `dataSlots` | `{path,description,schema}[]` | Register data slots readable/writable by tools + zod schema |
137
+ | **Page data** | `data` | `{path,description,schema}[]` | Register data slots readable/writable by tools + zod schema |
132
138
  | | `tools` / `skills` / `memory` | `Tool[]` / `SkillSpec[]` / `string` | Custom tools / skills / AGENTS.md-style directives |
133
- | **Capability toggles** | `capabilities` | `{planning?,dataSlotOps?,fetch?,skills?,vfs?,summarization?,memory?,subagent?,verify?}` | Default all on (`verify` default off); `false` to turn off |
139
+ | **Capability toggles** | `capabilities` | `{planning?,dataOps?,fetch?,skills?,vfs?,summarization?,memory?,subagent?,verify?}` | Default all on (`verify` default off); `false` to turn off |
134
140
  | | `permissions` | `PermissionRule[]` | Scope whitelist (first-match-wins, default off) |
135
141
  | | `humanConfirm` | `boolean` · default `true` | Proactive inquiry (AI asks when uncertain/multi-plan) |
136
142
  | | `approval` | `{tools?,confirm?,timeoutMs?,humanConfirmTool?}` · default off | Passive confirm whitelist (pre-write allow/deny) |
@@ -139,7 +145,7 @@ ChatDialog, MessageContent, CodePreview, useChat
139
145
  | **Subagents** | `subagent` | `{allowedTools?,systemPrompt?,temperature?,llm?,maxDepth?·1,maxParallel?·4}` | Runtime ad-hoc delegation (`spawn_agent`/`spawn_agents`) |
140
146
  | | `subagents` | `SubagentConfig[]` | Pre-declared named subagents → each generates `use_<id>` tool |
141
147
  | **Context** | `contextPreset` | `'auto' \| 'conservative' \| 'aggressive'` · default `auto` | Compression preset |
142
- | | `contextOptions` | `Partial<ContextManagerOptions> \| false` | Fine params (`false` disables compression). Includes `preserveLastToolResults` (default `['describe_data_slot','list_data_slots']` — keep field descriptions in compressed summary) |
148
+ | | `contextOptions` | `Partial<ContextManagerOptions> \| false` | Fine params (`false` disables compression). Includes `preserveLastToolResults` (default `['describe_data','describe_data']` — keep field descriptions in compressed summary) |
143
149
  | | `summaryLlm` | `BaseChatModel \| LLMConfig` | Summary-dedicated LLM (defaults to main `llm`) |
144
150
  | | `maxMemoryRounds` | `number` · default `50` | Dialog history memory round cap (`0` disables trim) |
145
151
  | | `vfs` | `{initialFiles?,maxBytes?}` · default 4MB | In-memory workspace cap (LRU evict on overflow) |
@@ -175,8 +181,8 @@ createChatSdk({ subagents: [
175
181
 
176
182
  ### Built-in tools (Agent-callable)
177
183
 
178
- - **data slot ops** (default `toolMode:'simple'`): `read` (list/get/describe merged) / `write` (set/edit/delete merged + auto optimistic lock + auto snapshot) — recommended; `toolMode:'advanced'` also exposes low-level `list_data_slots` / `describe_data_slot` / `get_data_slot` / `get_slot_paths` / `set_data_slot` / `edit_data_slot` (jsonPath patch) / `delete_data_slot` / `snapshot_data_slot` / `list_data_snapshots` / `restore_data_snapshot`
179
- - **window query**: `query_data_slot` (JSONPath) / `search_data_slot` (fuzzy) / `eval_script` (sandboxed)
184
+ - **data slot ops** (default `toolMode:'simple'`): `read` (list/get/describe merged) / `write` (set/edit/delete merged + auto optimistic lock + auto snapshot) — recommended; `toolMode:'advanced'` also exposes low-level `describe_data` / `describe_data` / `get_data` / `get_data` / `set_data` / `edit_data` (jsonPath patch) / `delete_data` / `snapshot_data` / `list_data_snapshots` / `restore_data`
185
+ - **window query**: `query_data` (JSONPath) / `search_data` (fuzzy) / `eval_script` (sandboxed)
180
186
  - **fetch**: `fetch_document`
181
187
  - **vfs**: `vfs_read` / `vfs_write` / `vfs_edit` / `vfs_ls` / `vfs_glob` / `vfs_grep`
182
188
  - **planning/skills**: `write_todos` / `define_skill` / `load_skill`
@@ -195,7 +201,7 @@ src/core/
195
201
  │ todos.ts skills.ts memory.ts summarization.ts retry.ts
196
202
  │ subagent.ts verify.ts approval.ts humanConfirm.ts checkpoint.ts
197
203
  │ permissions.ts usageHints.ts
198
- ├── tools/ # dataSlotOps (registry + incremental edit + snapshot) / dataSlotQuery / fetchDoc
204
+ ├── tools/ # dataOps (registry + incremental edit + snapshot) / dataSlotQuery / fetchDoc
199
205
  ├── backends/ # vfs (memory) / storage (IndexedDB + multi-backend + quota eviction)
200
206
  ├── mcp/client.ts # remote MCP tool integration
201
207
  ├── composables/ # useChat / useContextManager / useMarkdown
@@ -230,8 +236,8 @@ createChatSdk({ subagents: [
230
236
 
231
237
  ### Built-in tools (Agent-callable)
232
238
 
233
- - **data slot ops** (default `toolMode:'simple'`): `read` (list/get/describe merged) / `write` (set/edit/delete merged + auto optimistic lock + auto snapshot) — recommended; `toolMode:'advanced'` also exposes low-level `list_data_slots` / `describe_data_slot` / `get_data_slot` / `get_slot_paths` / `set_data_slot` / `edit_data_slot` (jsonPath patch) / `delete_data_slot` / `snapshot_data_slot` / `list_data_snapshots` / `restore_data_snapshot`
234
- - **window query**: `query_data_slot` (JSONPath) / `search_data_slot` (fuzzy) / `eval_script` (sandboxed)
239
+ - **data slot ops** (default `toolMode:'simple'`): `read` (list/get/describe merged) / `write` (set/edit/delete merged + auto optimistic lock + auto snapshot) — recommended; `toolMode:'advanced'` also exposes low-level `describe_data` / `describe_data` / `get_data` / `get_data` / `set_data` / `edit_data` (jsonPath patch) / `delete_data` / `snapshot_data` / `list_data_snapshots` / `restore_data`
240
+ - **window query**: `query_data` (JSONPath) / `search_data` (fuzzy) / `eval_script` (sandboxed)
235
241
  - **fetch**: `fetch_document`
236
242
  - **vfs**: `vfs_read` / `vfs_write` / `vfs_edit` / `vfs_ls` / `vfs_glob` / `vfs_grep`
237
243
  - **planning/skills**: `write_todos` / `define_skill` / `load_skill`
@@ -250,7 +256,7 @@ src/core/
250
256
  │ todos.ts skills.ts memory.ts summarization.ts retry.ts
251
257
  │ subagent.ts verify.ts approval.ts humanConfirm.ts checkpoint.ts
252
258
  │ permissions.ts usageHints.ts
253
- ├── tools/ # dataSlotOps (registry + incremental edit + snapshot) / dataSlotQuery / fetchDoc
259
+ ├── tools/ # dataOps (registry + incremental edit + snapshot) / dataSlotQuery / fetchDoc
254
260
  ├── backends/ # vfs (memory) / storage (IndexedDB + multi-backend + quota eviction)
255
261
  ├── mcp/client.ts # remote MCP tool integration
256
262
  ├── composables/ # useChat / useContextManager / useMarkdown
@@ -267,7 +273,7 @@ A ready-to-use Agent Skill is bundled for integrators using Claude Code / Cursor
267
273
 
268
274
  | Skill | When it triggers |
269
275
  |---|---|
270
- | `page-agent-sdk-integrate` | Embedding the SDK — choose install method, declare `dataSlots` + zod schemas, configure the LLM, mount, subscribe to events (`onEvent` / `sdk.hook`), run headless, troubleshoot common pitfalls |
276
+ | `page-agent-sdk-integrate` | Embedding the SDK — choose install method, declare `data` + zod schemas, configure the LLM, mount, subscribe to events (`onEvent` / `sdk.hook`), run headless, troubleshoot common pitfalls |
271
277
 
272
278
  **Install** (pick one):
273
279
 
@@ -293,13 +299,13 @@ flowchart TD
293
299
  SDK --> CORE[AgentCore<br/>messages / vfs / store / checkpoint]
294
300
  CORE --> AGENT[createAgent<br/>ReAct loop + middleware stack]
295
301
  AGENT --> MW[Middleware stack<br/>usageHints→todos→skills→vfs→summarization<br/>→memory→permissions→checkpoint→approval<br/>→humanConfirm→verify→subagent→user]
296
- AGENT --> TOOLS[Tools<br/>dataSlotOps / fetchDoc / vfs / MCP / user]
302
+ AGENT --> TOOLS[Tools<br/>dataOps / fetchDoc / vfs / MCP / user]
297
303
  TOOLS -->|zero-bridge| WIN[Host page window<br/>read/write registered props directly]
298
304
  AGENT --> LLM[LLM<br/>OpenAI-compatible / any ChatModel]
299
305
  SDK --> UI[ChatDialog UI<br/>Vue bundled in / or headless]
300
306
  ```
301
307
 
302
- - **Framework-agnostic**: Vue bundled in the lib (not a peer); host can be React/vanilla. Also supports `ui:false` headless — and runs in **Node.js** as a backend Agent (custom tools / subagents / verify; disable `dataSlotOps`+`fetch`, use `storage:'memory'`)
308
+ - **Framework-agnostic**: Vue bundled in the lib (not a peer); host can be React/vanilla. Also supports `ui:false` headless — and runs in **Node.js** as a backend Agent (custom tools / subagents / verify; disable `dataOps`+`fetch`, use `storage:'memory'`)
303
309
  - **Provider-agnostic**: `llm` accepts any LangChain `BaseChatModel`, or `LLMConfig` (builds `ChatOpenAI` internally, OpenAI-compatible, default DeepSeek)
304
310
  - **In-house harness**: no LangGraph/langchain full bundle; avoids browser bundling blockers
305
311
 
@@ -320,11 +326,11 @@ createChatSdk({
320
326
  llm: { apiKey, baseUrl, model },
321
327
  id: 'my-agent', // stable id (multi-agent isolation + persistence resume)
322
328
  systemPrompt: '...',
323
- dataSlots: [{ path, description, schema, bind }], // bind: reactive/plain object auto-mounted to window[path] + registered as dataSlot; schema field .describe() auto-injected into systemPrompt「可操作属性」section
329
+ data: { schema, bind, description? }, // single main object: bind directly connects reactive/plain object (tools read/write bind, not auto-mounted to window); schema field .describe() auto-injected into systemPrompt「可操作数据」section
324
330
  toolMode: 'simple', // tool presentation: simple (default, promotes read/write) / advanced (all) / minimal (read/write only)
325
331
  interceptors: { // read/write interceptors (desensitize/transform/audit/reject; input/output at agent IO entry/exit)
326
- read: (path, value) => path.endsWith('secret') ? '***' : value,
327
- write: (path, payload) => path === 'app.locked' ? { error: 'locked' } : payload,
332
+ read: (value) => value,
333
+ write: (payload) => payload,
328
334
  input: (msg) => msg, // preprocess at send entry
329
335
  output: (reply) => reply, // postprocess before return
330
336
  },
@@ -339,8 +345,8 @@ createChatSdk({
339
345
  maxRetries: 2, maxParallelTools: 1,
340
346
  subagent: { allowedTools: [...] },
341
347
  middleware: [/* custom middleware */],
342
- onEvent(e) { // SDK event callback: subscribe to common moments (data slot change / message update / tool call / error), replaces polling
343
- if (e.type === 'data_slot_change') refreshUI()
348
+ onEvent(e) { // SDK event callback: subscribe to common moments (data change / message update / tool call / error), replaces polling
349
+ if (e.type === 'data_change') refreshUI()
344
350
  },
345
351
  }).mount()
346
352
  ```
@@ -353,7 +359,7 @@ After `npm run dev`, visit the corresponding page:
353
359
  |---|---|---|
354
360
  | page-demo | `/` | Self-bootstrapping demo: left JSON reactive page + right chat |
355
361
  | nested-demo | `/examples/nested-demo/` | Nested block tree + human confirm + checkpoint |
356
- | dynamic-demo | `/examples/dynamic-demo/` | Lazy-loaded components with dynamic schemas (`sdk.addDataSlot`/`removeDataSlot`) |
362
+ | dynamic-demo | `/examples/dynamic-demo/` | Lazy-loaded components with dynamic schemas (`sdk.setData`/``) |
357
363
  | human-confirm-demo | `/examples/human-confirm-demo/` | AI proactive inquiry (multi-plan pick) + pre-write confirm |
358
364
  | planner-demo | `/examples/planner-demo/` | Plan-reflect-execute (high-temp creative planner + low-temp reflector) |
359
365
  | subagent-demo | `/examples/subagent-demo/` | Subagent parallel orchestration |
@@ -400,20 +406,25 @@ npm install -D vite typescript
400
406
  import { createChatSdk, z } from 'page-agent-sdk'
401
407
  import 'page-agent-sdk/style.css'
402
408
 
403
- window.app = { title: 'Demo', theme: 'light' }
409
+ const app = { title: 'Demo', theme: 'light' }
410
+ window.app = app // optional: mount to window for your page; tools operate on `bind` directly
404
411
 
405
412
  createChatSdk({
406
413
  container: '#root',
407
414
  llm: { apiKey: 'sk-...', baseUrl: 'https://api.deepseek.com/v1', model: 'deepseek-chat' },
408
- systemPrompt: 'You are a page assistant; read/write window.app via tools.',
409
- dataSlots: [
410
- { path: 'app.title', description: 'Title', schema: z.string() },
411
- { path: 'app.theme', description: 'Theme', schema: z.enum(['light', 'dark']) },
412
- ],
415
+ systemPrompt: 'You are a page assistant; read/write the main data via tools.',
416
+ data: {
417
+ schema: z.object({
418
+ title: z.string().describe('Title'),
419
+ theme: z.enum(['light', 'dark']).describe('Theme'),
420
+ }),
421
+ bind: app,
422
+ description: 'App config',
423
+ },
413
424
  }).mount()
414
425
  ```
415
426
 
416
- `npx vite` → type "change app.theme to dark" in the dialog → AI calls `write({ path:'app.theme', value:'dark' })` → `window.app.theme` becomes `dark` → verified.
427
+ `npx vite` → type "change app.theme to dark" in the dialog → AI calls `write({ value:{ theme:'dark' }, patch:{ op:'merge' } })` → `app.theme` becomes `dark` → verified.
417
428
 
418
429
  > Add this test dir to `.gitignore` (local only, not in repo) to avoid committing `.env` with real keys to remotes.
419
430
 
@@ -430,7 +441,7 @@ The package ships three builds — pick by integration scenario:
430
441
  `sideEffects` is set to `["**/*.css"]` only, so bundlers can tree-shake the JS when you import named symbols. Tips to keep your bundle lean:
431
442
 
432
443
  - **Headless (`ui:false`)**: skip the built-in dialog and render `agent.messages` yourself — you can avoid importing `ChatDialog`/`CodePreview` and drop the CSS (`import 'page-agent-sdk'` without `'page-agent-sdk/style.css'`).
433
- - **Disable unused capabilities**: `capabilities:{ dataSlotOps:false, fetch:false, planning:false, skills:false, vfs:false, summarization:false, memory:false, subagent:false }` — removes the corresponding tool schemas and middleware from the agent prompt (saves tokens, not bytes).
444
+ - **Disable unused capabilities**: `capabilities:{ dataOps:false, fetch:false, planning:false, skills:false, vfs:false, summarization:false, memory:false, subagent:false }` — removes the corresponding tool schemas and middleware from the agent prompt (saves tokens, not bytes).
434
445
  - **CDN via esm.sh**: `import { createChatSdk } from 'https://esm.sh/page-agent-sdk'` — peer deps (`zod`, `@langchain/*`) are resolved and deduped by esm.sh automatically; smallest for module scenarios.
435
446
  - **IIFE only for zero-config**: the all-inlined single file is convenient but heaviest; prefer ESM when the host supports modules.
436
447
  - **MCP is an optional peer**: `@modelcontextprotocol/sdk` is dynamically imported only when `options.mcp` is passed — omit it to avoid loading the MCP runtime entirely.
package/README.zh-CN.md CHANGED
@@ -24,9 +24,10 @@
24
24
 
25
25
  | 约束 | 机制 | 作用 |
26
26
  |---|---|---|
27
- | **范围控制** | 属性注册表(`dataSlots`)—— 只能动声明的 path | AI 越界改未注册字段拒绝 |
27
+ | **范围控制** | schema 校验(`data`)—— 只能改 schema 允许的值;schema 形状自动白名单(顶层 key 限制可见 + 可写,未声明字段隐藏/拒改/整体 set 转 merge 防误删) | AI 传非法值拒绝;非声明字段 → `PATH_DENIED` |
28
28
  | **合法性校验** | zod schema —— `write`/`set`/`edit` 按 schema 校验 | 类型/枚举/结构不合法 → 结构化错误,不写入 |
29
- | **增量操作** | `write` 的 `patch`(或 advanced `edit_data_slot`)按 `jsonPath` 发 patch(set/remove/merge/append) | 避免重传整个大 JSON,精确改局部 |
29
+ | **增量操作** | `write` 的 `patch`/`patches`(批量,原子回滚)或 advanced `edit_data` 按 `jsonPath` 发 patch(set/remove/merge/append) | 避免重传整个大 JSON,精确改局部;一次改多处用 `patches` |
30
+ | **大对象检索** | `read` 支持 `fields`(字段裁剪)+ `depth`(深度截断)减体积;`query_data`(JSONPath)/`search_data`(文本)/`eval_script`(沙箱 JS) | 大 JSON 高效检索 + 局部定位 |
30
31
  | **可回滚** | per-path 快照(自动入栈)+ 会话 checkpoint | 改坏了一键回退到上次正常态 |
31
32
  | **乐观锁** | `set`/`edit`/`delete` 传 `expectedHash` + 冲突人工介入 | 检测并发外部修改 → 挂起,用户选保留/覆盖/回退 |
32
33
 
@@ -58,16 +59,21 @@ npm install page-agent-sdk zod @langchain/openai @langchain/core
58
59
  import { createChatSdk } from 'page-agent-sdk'
59
60
  import { z } from 'zod'
60
61
 
61
- window.page = { title: '新品专区', theme: 'light' }
62
+ const page = { title: '新品专区', theme: 'light' }
63
+ window.page = page // 可选:挂到 window 供页面读取;SDK 工具直接读写 bind
62
64
 
63
65
  createChatSdk({
64
66
  container: '#chat',
65
67
  llm: { apiKey: 'sk-...', baseUrl: 'https://api.deepseek.com', model: 'deepseek-chat' },
66
- systemPrompt: '你是页面搭建助手,通过工具读写 window.page。',
67
- dataSlots: [
68
- { path: 'page.title', description: '页面标题', schema: z.string() },
69
- { path: 'page.theme', description: '主题', schema: z.enum(['light', 'dark']) },
70
- ],
68
+ systemPrompt: '你是页面搭建助手,通过工具读写主数据。',
69
+ data: {
70
+ schema: z.object({
71
+ title: z.string().describe('页面标题'),
72
+ theme: z.enum(['light', 'dark']).describe('主题'),
73
+ }),
74
+ bind: page,
75
+ description: '页面配置',
76
+ },
71
77
  approval: { tools: ['write'] }, // 写操作弹确认
72
78
  checkpoint: true, // 误改一键回退
73
79
  }).mount()
@@ -81,7 +87,7 @@ CDN 零配置:`<script src="https://unpkg.com/page-agent-sdk"></script>` → `
81
87
 
82
88
  | 能力 | 说明 | 选项 |
83
89
  |---|---|---|
84
- | 🛠 数据槽操作 | 读写注册属性,schema 校验 + 增量 patch + 快照回退 | `dataSlots` |
90
+ | 🛠 数据操作 | 读写注册属性,schema 校验 + 增量 patch + 快照回退 | `data` |
85
91
  | 🧠 ReAct harness | 可插拔中间件(8 钩子),自研不引 LangGraph | `middleware` |
86
92
  | 📋 规划/技能/记忆 | `write_todos` / `define_skill` / AGENTS.md 指令 | `capabilities.*` |
87
93
  | 🗄 虚拟工作区 | 内存文件系统,大结果外存不撑爆上下文 | `capabilities.vfs` |
@@ -91,7 +97,7 @@ CDN 零配置:`<script src="https://unpkg.com/page-agent-sdk"></script>` → `
91
97
  | 🤖 子 agent | 委派子任务,过程不占主上下文 | `subagent` |
92
98
  | 🔌 MCP | 连远程 MCP server 动态注入工具 | `mcp` |
93
99
  | 📦 上下文压缩 | 4 层自适应压缩,预设档位 + LLM 摘要 | `contextPreset` |
94
- | 🛡️ 压缩不丢信息 | 摘要内嵌当前 dataSlots 快照 + 保留指定工具结果;写返回附可操作 path;`systemPromptHelpers.reliableWriteRules` | 内置 |
100
+ | 🛡️ 压缩不丢信息 | 摘要内嵌当前 data 快照 + 保留指定工具结果;写返回附可操作 path;`systemPromptHelpers.reliableWriteRules` | 内置 |
95
101
  | 💾 持久化 | IndexedDB 多会话 + 配额淘汰 + 切换 | `storage` |
96
102
 
97
103
  能力默认开(`verify`/`approval`/`checkpoint` 默认关;**主动征询 `humanConfirm` 默认开**——AI 遇不确定/多方案主动问你、不猜测),可经 `capabilities` 关掉无用的省 token。
@@ -109,14 +115,14 @@ createChatSdk, defineTool, defineSkill, presets, z
109
115
  createAgent, createSubagentMiddleware, createSubagentsMiddleware,
110
116
  createVerifyMiddleware, createWriteBackCheck, createApprovalMiddleware,
111
117
  createHumanConfirmMiddleware, createHumanConfirmTool, createCheckpointMiddleware, createCheckpointManager,
112
- createUsageHintsMiddleware, createDataSlotOps, createVfs, connectMcp
118
+ createUsageHintsMiddleware, createDataOps, createVfs, connectMcp
113
119
  // 上下文/模型
114
120
  resolveContextOptions, CONTEXT_PRESETS, resolveModelCaps, estimateTokens
115
121
  // 存储
116
122
  createSessionStore, createMemoryBackend, createWebStorageBackend, isQuotaError
117
123
  // UI(headless 自建 UI 复用)
118
124
  ChatDialog, MessageContent, CodePreview, useChat
119
- // 类型(略):ChatSdkOptions, Middleware, SubagentConfig, SkillSpec, DataSlotSpec, AgentMessage, StreamEvent …
125
+ // 类型(略):ChatSdkOptions, Middleware, SubagentConfig, SkillSpec, DataConfig, AgentMessage, StreamEvent …
120
126
  ```
121
127
 
122
128
  ### `createChatSdk` 选项速查
@@ -128,9 +134,9 @@ ChatDialog, MessageContent, CodePreview, useChat
128
134
  | | `llm` | `LLMConfig \| BaseChatModel` · **必传** | `LLMConfig={apiKey,baseUrl?,model?,temperature?,maxTokens?}`;兼容 OpenAI 协议(默认 DeepSeek) |
129
135
  | | `id` | `string` | 稳定 id(多 agent 隔离 + 持久化恢复;不传随机+warn) |
130
136
  | | `systemPrompt` | `string` | Agent 身份(不硬编码业务,靠这注入)。可选——不传用内置默认(页面操作助手 + `reliableWriteRules`);传了则完全覆盖 |
131
- | **页面数据** | `dataSlots` | `{path,description,schema}[]` | 注册可被工具读写的 数据槽 + zod schema 校验 |
137
+ | **页面数据** | `data` | `{path,description,schema}[]` | 注册可被工具读写的 数据槽 + zod schema 校验 |
132
138
  | | `tools` / `skills` / `memory` | `Tool[]` / `SkillSpec[]` / `string` | 自定义工具 / 技能 / AGENTS.md 风格持久指令 |
133
- | **能力开关** | `capabilities` | `{planning?,dataSlotOps?,fetch?,skills?,vfs?,summarization?,memory?,subagent?,verify?}` | 默认全开(`verify` 默认关);`false` 关掉省 token |
139
+ | **能力开关** | `capabilities` | `{planning?,dataOps?,fetch?,skills?,vfs?,summarization?,memory?,subagent?,verify?}` | 默认全开(`verify` 默认关);`false` 关掉省 token |
134
140
  | | `permissions` | `PermissionRule[]` | scope 白名单(first-match-wins,默认不启用) |
135
141
  | | `humanConfirm` | `boolean` · 默认 `true` | 主动征询(AI 不确定/多方案主动问你,不猜测) |
136
142
  | | `approval` | `{tools?,confirm?,timeoutMs?,humanConfirmTool?}` · 默认关 | 被动确认白名单(写操作前弹允许/拒绝) |
@@ -139,7 +145,7 @@ ChatDialog, MessageContent, CodePreview, useChat
139
145
  | **子 agent** | `subagent` | `{allowedTools?,systemPrompt?,temperature?,llm?,maxDepth?·1,maxParallel?·4}` | 运行时自由委派(`spawn_agent`/`spawn_agents`) |
140
146
  | | `subagents` | `SubagentConfig[]` | 预声明命名子 agent → 每个生成 `use_<id>` 委派工具 |
141
147
  | **上下文** | `contextPreset` | `'auto' \| 'conservative' \| 'aggressive'` · 默认 `auto` | 压缩预设档位 |
142
- | | `contextOptions` | `Partial<ContextManagerOptions> \| false` | 细参覆盖(`false` 关压缩)。含 `preserveLastToolResults`(默认 `['describe_data_slot','list_data_slots']`——压缩摘要里保留字段说明) |
148
+ | | `contextOptions` | `Partial<ContextManagerOptions> \| false` | 细参覆盖(`false` 关压缩)。含 `preserveLastToolResults`(默认 `['describe_data','describe_data']`——压缩摘要里保留字段说明) |
143
149
  | | `summaryLlm` | `BaseChatModel \| LLMConfig` | 摘要专用 LLM(不配用主 `llm`) |
144
150
  | | `maxMemoryRounds` | `number` · 默认 `50` | 对话历史内存上限轮次(`0` 关裁剪) |
145
151
  | | `vfs` | `{initialFiles?,maxBytes?}` · 默认 4MB | 内存工作区上限(超限 LRU 淘汰) |
@@ -175,8 +181,8 @@ createChatSdk({ subagents: [
175
181
 
176
182
  ### 内置工具(Agent 可调用)
177
183
 
178
- - **数据槽操作**(默认 `toolMode:'simple'`):`read`(合并 list/get/describe)/ `write`(合并 set/edit/delete + 自动乐观锁 + 自动快照)—— 推荐;`toolMode:'advanced'` 另暴露底层 `list_data_slots` / `describe_data_slot` / `get_data_slot` / `get_slot_paths` / `set_data_slot` / `edit_data_slot`(jsonPath 增量 patch)/ `delete_data_slot` / `snapshot_data_slot` / `list_data_snapshots` / `restore_data_snapshot`
179
- - **window 查询**:`query_data_slot`(JSONPath)/ `search_data_slot`(模糊搜索)/ `eval_script`(沙箱脚本)
184
+ - **数据操作**(默认 `toolMode:'simple'`):`read`(合并 describe/get)/ `write`(合并 set/edit/delete + 自动乐观锁 + 自动快照)—— 推荐;`toolMode:'advanced'` 另暴露底层 `describe_data` / `get_data` / `set_data` / `edit_data`(jsonPath 增量 patch)/ `delete_data` / `snapshot_data` / `list_data_snapshots` / `restore_data`
185
+ - **window 查询**:`query_data`(JSONPath)/ `search_data`(模糊搜索)/ `eval_script`(沙箱脚本)
180
186
  - **抓取**:`fetch_document`
181
187
  - **vfs**:`vfs_read` / `vfs_write` / `vfs_edit` / `vfs_ls` / `vfs_glob` / `vfs_grep`
182
188
  - **规划/技能**:`write_todos` / `define_skill` / `load_skill`
@@ -195,7 +201,7 @@ src/core/
195
201
  │ todos.ts skills.ts memory.ts summarization.ts retry.ts
196
202
  │ subagent.ts verify.ts approval.ts humanConfirm.ts checkpoint.ts
197
203
  │ permissions.ts usageHints.ts
198
- ├── tools/ # dataSlotOps(注册表+增量编辑+快照)/ dataSlotQuery / fetchDoc
204
+ ├── tools/ # dataOps(注册表+增量编辑+快照)/ dataSlotQuery / fetchDoc
199
205
  ├── backends/ # vfs(内存) / storage(IndexedDB+多后端+配额淘汰)
200
206
  ├── mcp/client.ts # MCP 远程工具接入
201
207
  ├── composables/ # useChat / useContextManager / useMarkdown
@@ -212,7 +218,7 @@ CLAUDE.md # 架构要点 + 约定坑 + 编码规范(agen
212
218
 
213
219
  | Skill | 触发场景 |
214
220
  |---|---|
215
- | `page-agent-sdk-integrate` | 集成 SDK —— 选引入方式、声明 `dataSlots` + zod schema、配 LLM、挂载、订阅事件(`onEvent` / `sdk.hook`)、跑 headless、排查常见坑 |
221
+ | `page-agent-sdk-integrate` | 集成 SDK —— 选引入方式、声明 `data` + zod schema、配 LLM、挂载、订阅事件(`onEvent` / `sdk.hook`)、跑 headless、排查常见坑 |
216
222
 
217
223
  **安装**(任选其一):
218
224
 
@@ -238,13 +244,13 @@ flowchart TD
238
244
  SDK --> CORE[AgentCore<br/>messages / vfs / store / checkpoint]
239
245
  CORE --> AGENT[createAgent<br/>ReAct 循环 + 中间件栈]
240
246
  AGENT --> MW[中间件栈<br/>usageHints→todos→skills→vfs→summarization<br/>→memory→permissions→checkpoint→approval<br/>→humanConfirm→verify→subagent→用户]
241
- AGENT --> TOOLS[工具集<br/>dataSlotOps / fetchDoc / vfs / MCP / 用户]
247
+ AGENT --> TOOLS[工具集<br/>dataOps / fetchDoc / vfs / MCP / 用户]
242
248
  TOOLS -->|零桥接| WIN[宿主页面 window<br/>直接读写注册属性]
243
249
  AGENT --> LLM[LLM<br/>OpenAI 协议 / 任意 ChatModel]
244
250
  SDK --> UI[ChatDialog UI<br/>Vue 打包进库 / 或 headless]
245
251
  ```
246
252
 
247
- - **框架无关**:Vue 打包进库(非 peer),宿主用 React/原生都行;也支持 `ui:false` headless 自建 UI —— 且可在 **Node.js 服务端**跑作后端 Agent(自定义工具/子 agent/自检;关 `dataSlotOps`+`fetch`,用 `storage:'memory'`)
253
+ - **框架无关**:Vue 打包进库(非 peer),宿主用 React/原生都行;也支持 `ui:false` headless 自建 UI —— 且可在 **Node.js 服务端**跑作后端 Agent(自定义工具/子 agent/自检;关 `dataOps`+`fetch`,用 `storage:'memory'`)
248
254
  - **provider 抽离**:`llm` 传任意 LangChain `BaseChatModel`,或 `LLMConfig`(内部构造 `ChatOpenAI`,兼容 OpenAI 协议,默认接 DeepSeek)
249
255
  - **自研 harness**:不引 LangGraph/langchain 整包,规避浏览器打包阻塞
250
256
 
@@ -265,11 +271,11 @@ createChatSdk({
265
271
  llm: { apiKey, baseUrl, model },
266
272
  id: 'my-agent', // 稳定 id(多 agent 隔离 + 持久化恢复)
267
273
  systemPrompt: '...',
268
- dataSlots: [{ path, description, schema, bind }], // bind:reactive/普通对象自动挂 window[path] + 注册为 dataSlot;schema 字段 .describe() 自动注入 systemPrompt「可操作属性」段
274
+ data: { schema, bind, description? }, // 单主对象:bind 直连 reactive/普通对象(工具直接读写 bind,不自动挂 window);schema 字段 .describe() 自动注入 systemPrompt「可操作数据」段
269
275
  toolMode: 'simple', // 工具呈现:simple(默认,主推 read/write)/ advanced(全暴露)/ minimal(只 read/write)
270
276
  interceptors: { // 读写拦截器(脱敏/转换/审计/拒绝 LLM 读写;input/output 在 agent IO 入口/出口)
271
- read: (path, value) => path.endsWith('secret') ? '***' : value,
272
- write: (path, payload) => path === 'app.locked' ? { error: 'locked' } : payload,
277
+ read: (value) => value,
278
+ write: (payload) => payload,
273
279
  input: (msg) => msg, // send 入口预处理
274
280
  output: (reply) => reply, // 返回前 postprocess
275
281
  },
@@ -284,8 +290,8 @@ createChatSdk({
284
290
  maxRetries: 2, maxParallelTools: 1,
285
291
  subagent: { allowedTools: [...] },
286
292
  middleware: [/* 自定义中间件 */],
287
- onEvent(e) { // SDK 事件回调:订阅常用时机(数据槽变化/消息更新/工具调用/错误),替代轮询
288
- if (e.type === 'data_slot_change') refreshUI()
293
+ onEvent(e) { // SDK 事件回调:订阅常用时机(主数据变化/消息更新/工具调用/错误),替代轮询
294
+ if (e.type === 'data_change') refreshUI()
289
295
  },
290
296
  }).mount()
291
297
  ```
@@ -298,7 +304,7 @@ createChatSdk({
298
304
  |---|---|---|
299
305
  | page-demo | `/` | 自举 demo:左 JSON 响应式页面 + 右对话框 |
300
306
  | nested-demo | `/examples/nested-demo/` | 嵌套区块树 + 人工确认 + checkpoint |
301
- | dynamic-demo | `/examples/dynamic-demo/` | 懒加载组件 + 动态注册 schema(`sdk.addDataSlot`/`removeDataSlot`) |
307
+ | dynamic-demo | `/examples/dynamic-demo/` | 懒加载组件 + 动态注册 schema(`sdk.setData`/``) |
302
308
  | human-confirm-demo | `/examples/human-confirm-demo/` | AI 主动征询(多方案点选)+ 写前确认 |
303
309
  | planner-demo | `/examples/planner-demo/` | 规划-反思-执行(高温创意 planner + 低温 reflector) |
304
310
  | subagent-demo | `/examples/subagent-demo/` | 子 agent 并行编排 |
@@ -312,7 +318,7 @@ createChatSdk({
312
318
  |---|---|
313
319
  | [文档索引](./doc/README.md) | 各文档导航 + 其他信息源(规范/变更/自测) |
314
320
  | [使用手册](./doc/usage-guide.md) | 安装 / 配置项 / 能力详解 / 自定义中间件 / FAQ |
315
- | [功能架构](./doc/architecture.md) | 分层 / 控制流 / 数据槽操作安全流 |
321
+ | [功能架构](./doc/architecture.md) | 分层 / 控制流 / 数据操作安全流 |
316
322
  | [上下文与压缩](./doc/context-management.md) | 上下文组成 / 4 层压缩 / 流程图 |
317
323
  | [文件全览](./doc/architecture-files.md) | 逐文件职责 / 依赖 / 数据流 |
318
324
  | [CLAUDE.md](./CLAUDE.md) | **agent 必读** · 架构要点 / 约定坑 / 编码规范 |
@@ -345,20 +351,25 @@ npm install -D vite typescript
345
351
  import { createChatSdk, z } from 'page-agent-sdk'
346
352
  import 'page-agent-sdk/style.css'
347
353
 
348
- window.app = { title: '示例', theme: 'light' }
354
+ const app = { title: '示例', theme: 'light' }
355
+ window.app = app // 可选:挂到 window 供页面读取;工具直接读写 bind
349
356
 
350
357
  createChatSdk({
351
358
  container: '#root',
352
359
  llm: { apiKey: 'sk-...', baseUrl: 'https://api.deepseek.com/v1', model: 'deepseek-chat' },
353
- systemPrompt: '你是页面助手,用工具读写 window.app。',
354
- dataSlots: [
355
- { path: 'app.title', description: '标题', schema: z.string() },
356
- { path: 'app.theme', description: '主题', schema: z.enum(['light', 'dark']) },
357
- ],
360
+ systemPrompt: '你是页面助手,用工具读写主数据。',
361
+ data: {
362
+ schema: z.object({
363
+ title: z.string().describe('标题'),
364
+ theme: z.enum(['light', 'dark']).describe('主题'),
365
+ }),
366
+ bind: app,
367
+ description: '应用配置',
368
+ },
358
369
  }).mount()
359
370
  ```
360
371
 
361
- `npx vite` → 对话框输入「把 app.theme 改成 dark」→ AI 调 `write({ path:"app.theme", value:"dark" })` → `window.app.theme` 变为 `dark` 即验证通过。
372
+ `npx vite` → 对话框输入「把 app.theme 改成 dark」→ AI 调 `write({ value:{ theme:"dark" }, patch:{ op:"merge" } })` → `app.theme` 变为 `dark` 即验证通过。
362
373
 
363
374
  > 建议此测试目录加入 `.gitignore`(纯本地,不进仓库),避免把含真实 key 的 `.env` 提交到远程。
364
375
 
@@ -375,7 +386,7 @@ createChatSdk({
375
386
  `sideEffects` 仅标记 `["**/*.css"]`,打包器可对 JS 做 tree-shaking。瘦身建议:
376
387
 
377
388
  - **headless(`ui:false`)**:不渲染内置对话框,自渲染 `agent.messages` —— 可不引 `ChatDialog`/`CodePreview`,并省略 CSS(`import 'page-agent-sdk'` 不引 `'page-agent-sdk/style.css'`)。
378
- - **关闭无用能力**:`capabilities:{ dataSlotOps:false, fetch:false, planning:false, skills:false, vfs:false, summarization:false, memory:false, subagent:false }` —— 移除对应工具 schema 与中间件(省 token,非字节)。
389
+ - **关闭无用能力**:`capabilities:{ dataOps:false, fetch:false, planning:false, skills:false, vfs:false, summarization:false, memory:false, subagent:false }` —— 移除对应工具 schema 与中间件(省 token,非字节)。
379
390
  - **CDN 用 esm.sh**:`import { createChatSdk } from 'https://esm.sh/page-agent-sdk'` —— peer(`zod`、`@langchain/*`)由 esm.sh 自动解析去重,模块场景最小。
380
391
  - **IIFE 仅用于零配置**:全量单文件方便但最重,宿主支持模块时优先 ESM。
381
392
  - **MCP 为可选 peer**:`@modelcontextprotocol/sdk` 仅在传 `options.mcp` 时动态 import —— 不用 MCP 完全不加载该运行时。
@@ -1,2 +1,2 @@
1
- .code-preview-overlay[data-v-3d6e2a95]{z-index:9999;background:#00000080;justify-content:center;align-items:center;padding:20px;display:flex;position:fixed;inset:0}.code-preview-modal[data-v-3d6e2a95]{background:#fff;border-radius:12px;flex-direction:column;width:90%;max-width:900px;height:80vh;display:flex;overflow:hidden;box-shadow:0 20px 60px #0000004d}.preview-header[data-v-3d6e2a95]{color:#fff;background:#1f2937;align-items:center;gap:12px;padding:10px 16px;display:flex}.preview-title[data-v-3d6e2a95]{font-size:14px;font-weight:600}.preview-tabs[data-v-3d6e2a95]{gap:4px;margin-left:auto;display:flex}.preview-tabs button[data-v-3d6e2a95]{color:#fff;cursor:pointer;background:#ffffff1a;border:none;border-radius:6px;padding:4px 12px;font-size:13px}.preview-tabs button.active[data-v-3d6e2a95]{background:#667eea}.preview-tabs button[data-v-3d6e2a95]:disabled{opacity:.4;cursor:not-allowed}.preview-actions[data-v-3d6e2a95]{gap:4px;display:flex}.icon-btn[data-v-3d6e2a95]{color:#fff;cursor:pointer;background:#ffffff1a;border:none;border-radius:6px;justify-content:center;align-items:center;width:28px;height:28px;font-size:14px;display:flex}.icon-btn[data-v-3d6e2a95]:hover{background:#ffffff40}.preview-body[data-v-3d6e2a95]{background:#f9fafb;flex:1;overflow:hidden}.preview-iframe[data-v-3d6e2a95]{background:#fff;border:none;width:100%;height:100%}.preview-source[data-v-3d6e2a95]{color:#e5e7eb;white-space:pre-wrap;word-break:break-word;background:#1f2937;height:100%;margin:0;padding:16px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:13px;line-height:1.5;overflow:auto}.message-md{overflow-wrap:anywhere;word-break:break-word;font-size:13px;line-height:1.6}.message-md p{margin:0 0 8px}.message-md p:last-child{margin-bottom:0}.message-md table{border-collapse:collapse;max-width:100%;margin:8px 0;display:block;overflow-x:auto}.message-md th,.message-md td{white-space:nowrap;border:1px solid #e5e7eb;padding:4px 8px;font-size:12px}.message-md th{background:#f9fafb}.message-md img{max-width:100%}.message-md ul,.message-md ol{margin:6px 0;padding-left:20px}.message-md li{margin:2px 0}.message-md h1,.message-md h2,.message-md h3{margin:10px 0 6px;font-weight:600}.message-md h1{font-size:18px}.message-md h2{font-size:16px}.message-md h3{font-size:15px}.message-md a{color:#667eea;text-decoration:underline}.message-md code:not(.hljs){color:#4338ca;background:#667eea1a;border-radius:4px;padding:1px 5px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:13px}.message-md .code-block{background:#1f2937;border-radius:8px;margin:10px 0;padding:0;position:relative;overflow:hidden}.message-md .code-block code{color:#e5e7eb;background:0 0;padding:12px 14px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:13px;line-height:1.5;display:block;overflow-x:auto}.message-md .code-toolbar{background:#00000040;border-bottom:1px solid #ffffff14;align-items:center;gap:8px;padding:6px 12px;display:flex}.message-md .code-lang{color:#9ca3af;text-transform:lowercase;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px}.message-md .code-action-btn{color:#e5e7eb;cursor:pointer;background:#ffffff1a;border:none;border-radius:4px;margin-left:auto;padding:3px 10px;font-size:12px;transition:background .2s}.message-md .code-action-btn:hover{background:#fff3}.message-md .code-action-btn.preview-btn{color:#fff;background:#667eea;margin-left:4px}.message-md .code-action-btn.preview-btn:hover{background:#5568d3}.message-md .hljs{color:#e5e7eb}.message-md .hljs-keyword{color:#c084fc}.message-md .hljs-string{color:#86efac}.message-md .hljs-comment{color:#6b7280;font-style:italic}.message-md .hljs-number{color:#fca5a5}.message-md .hljs-function .hljs-title,.message-md .hljs-title{color:#93c5fd}.message-md .hljs-tag{color:#fca5a5}.message-md .hljs-attr{color:#fcd34d}.message-md .hljs-built_in{color:#67e8f9}.debug-drawer[data-v-2a895152]{z-index:9000;pointer-events:none;position:fixed;inset:0}.drawer-mask[data-v-2a895152]{pointer-events:auto;background:#00000040;position:absolute;inset:0}.drawer-panel[data-v-2a895152]{--cs-primary:#1f4d3a;--cs-primary-rgb:31, 77, 58;pointer-events:auto;z-index:2;background:#fff;flex-direction:column;width:520px;max-width:90vw;display:flex;position:absolute;top:0;bottom:0;right:0;box-shadow:-8px 0 32px #00000026}.drawer-mask[data-v-2a895152]{z-index:1}.drawer-header[data-v-2a895152]{color:#fff;background:linear-gradient(135deg,#1f2937,#111827);justify-content:space-between;align-items:center;padding:12px 16px;display:flex}.drawer-title[data-v-2a895152]{font-size:15px;font-weight:600}.tab-group[data-v-2a895152]{gap:4px;display:flex}.tab-btn[data-v-2a895152]{color:#fff;cursor:pointer;background:#ffffff1f;border:none;border-radius:6px;padding:4px 12px;font-size:13px;transition:background .2s}.tab-btn[data-v-2a895152]:hover{background:#ffffff38}.tab-btn.active[data-v-2a895152]{background:#ffffff73;font-weight:600}.info-body[data-v-2a895152]{padding:4px 0}.info-section[data-v-2a895152]{margin-bottom:14px}.info-title[data-v-2a895152]{color:#2d5a47;border-bottom:1px solid #f3f4f6;margin-bottom:6px;padding-bottom:4px;font-size:12px;font-weight:600}.info-item[data-v-2a895152]{background:#f9fafb;border-radius:6px;margin-bottom:4px;padding:6px 8px}.info-name[data-v-2a895152]{color:#1f2937;font-family:SF Mono,Monaco,Consolas,monospace;font-size:12px;font-weight:600}.info-desc[data-v-2a895152]{color:#6b7280;margin-top:2px;font-size:11px;line-height:1.5}.info-desc.muted[data-v-2a895152]{color:#9ca3af}.src-tag[data-v-2a895152]{vertical-align:middle;border-radius:8px;margin-left:6px;padding:0 6px;font-size:10px;font-weight:600;display:inline-block}.src-tag.builtin[data-v-2a895152]{color:#6b7280;background:#f3f4f6}.src-tag.mcp[data-v-2a895152]{color:#7c3aed;background:#f3e8ff}.src-tag.user[data-v-2a895152]{color:#2563eb;background:#dbeafe}.info-todo[data-v-2a895152]{color:#374151;background:#f9fafb;border-radius:6px;align-items:center;gap:6px;margin-bottom:4px;padding:4px 8px;font-size:12px;display:flex}.todo-tag[data-v-2a895152]{color:#fff;border-radius:8px;flex-shrink:0;padding:1px 6px;font-size:10px}.info-pre[data-v-2a895152]{color:#4b5563;white-space:pre-wrap;word-break:break-word;background:#f9fafb;border-radius:6px;max-height:200px;margin:0;padding:8px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px;overflow-y:auto}.header-actions[data-v-2a895152]{gap:4px;display:flex}.hd-btn[data-v-2a895152]{color:#fff;cursor:pointer;background:#ffffff1f;border:none;border-radius:6px;width:28px;height:28px}.hd-btn[data-v-2a895152]:hover{background:#ffffff40}.drawer-filters[data-v-2a895152]{background:#fafafa;border-bottom:1px solid #f3f4f6;flex-wrap:wrap;gap:6px;padding:10px 16px;display:flex}.filter-chip[data-v-2a895152]{color:#6b7280;cursor:pointer;background:#fff;border:1px solid #e5e7eb;border-radius:14px;align-items:center;gap:4px;padding:4px 10px;font-size:12px;transition:all .2s;display:inline-flex}.filter-chip[data-v-2a895152]:hover{border-color:var(--chip-color,var(--cs-primary))}.filter-chip.active[data-v-2a895152]{background:var(--chip-color,var(--cs-primary));border-color:var(--chip-color,var(--cs-primary));color:#fff}.chip-count[data-v-2a895152]{background:#00000014;border-radius:8px;padding:0 5px;font-size:11px}.filter-chip.active .chip-count[data-v-2a895152]{background:#ffffff40}.drawer-body[data-v-2a895152]{flex:1;padding:12px;overflow-y:auto}.empty[data-v-2a895152]{text-align:center;color:#9ca3af;padding:40px 20px;font-size:13px}.log-item[data-v-2a895152]{background:#fff;border:1px solid #e5e7eb;border-radius:8px;margin-bottom:10px;overflow:hidden}.log-head[data-v-2a895152]{background:#f9fafb;align-items:center;gap:8px;padding:8px 10px;display:flex}.log-type[data-v-2a895152]{color:#fff;white-space:nowrap;border-radius:4px;padding:2px 8px;font-size:11px;font-weight:600}.log-source[data-v-2a895152]{color:#7c3aed;white-space:nowrap;background:#f3e8ff;border-radius:4px;padding:2px 8px;font-size:10px;font-weight:600}.log-time[data-v-2a895152]{color:#9ca3af;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px}.log-body[data-v-2a895152]{padding:10px 12px}.log-footer[data-v-2a895152]{border-top:1px dashed #f3f4f6;gap:8px;padding:6px 12px;display:flex}.raw-toggle[data-v-2a895152]{color:var(--cs-primary);cursor:pointer;background:0 0;border:none;padding:2px 4px;font-size:11px}.raw-toggle[data-v-2a895152]:hover{text-decoration:underline}.log-raw[data-v-2a895152]{color:#e5e7eb;white-space:pre-wrap;word-break:break-word;background:#1f2937;border-top:1px solid #f3f4f6;max-height:280px;margin:0;padding:10px 12px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px;line-height:1.5;overflow:auto}.kv-grid[data-v-2a895152]{grid-template-columns:1fr 1fr;gap:6px;margin-bottom:8px;display:grid}.kv[data-v-2a895152]{background:#f9fafb;border-radius:6px;flex-direction:column;padding:6px 8px;display:flex}.kv .k[data-v-2a895152]{color:#9ca3af;text-transform:uppercase;font-size:10px}.kv .v[data-v-2a895152]{color:#1f2937;font-family:SF Mono,Monaco,Consolas,monospace;font-size:13px;font-weight:600}.section-label[data-v-2a895152]{color:#6b7280;margin:10px 0 4px;font-size:11px;font-weight:600}.chip-row[data-v-2a895152]{flex-wrap:wrap;gap:4px;display:flex}.tool-chip[data-v-2a895152]{color:#2d5a47;background:#ecf5ef;border-radius:10px;padding:2px 8px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px}.msg-list[data-v-2a895152]{flex-direction:column;gap:4px;display:flex}.msg-row[data-v-2a895152]{background:#f9fafb;border-radius:6px;align-items:flex-start;gap:6px;padding:5px 8px;display:flex}.msg-role[data-v-2a895152]{color:#fff;border-radius:3px;flex-shrink:0;margin-top:1px;padding:2px 6px;font-size:9px;font-weight:700}.msg-text[data-v-2a895152]{color:#374151;white-space:pre-wrap;word-break:break-word;flex:1;font-size:12px;line-height:1.5}.msg-tool-hint[data-v-2a895152]{color:#7c3aed;flex-shrink:0;font-size:10px}.badge-row[data-v-2a895152]{flex-wrap:wrap;gap:6px;margin-bottom:8px;display:flex}.badge[data-v-2a895152]{color:#2d5a47;background:#dbeee4;border-radius:10px;padding:2px 8px;font-size:11px;font-weight:600}.badge.muted[data-v-2a895152]{color:#6b7280;background:#f3f4f6}.badge.warn[data-v-2a895152]{color:#92400e;background:#fef3c7}.resp-content[data-v-2a895152]{color:#1f2937;white-space:pre-wrap;word-break:break-word;background:#fffbeb;border-left:3px solid #d97706;border-radius:4px;margin-bottom:8px;padding:6px 10px;font-size:12px}.tc-list[data-v-2a895152]{flex-direction:column;gap:6px;display:flex}.tc-card[data-v-2a895152]{border:1px solid #e5e7eb;border-radius:6px;overflow:hidden}.tc-card.inline[data-v-2a895152]{margin-top:4px}.tc-name[data-v-2a895152]{color:#2d5a47;background:#ecf5ef;padding:5px 8px;font-size:12px;font-weight:600}.tc-args[data-v-2a895152]{color:#e5e7eb;white-space:pre-wrap;word-break:break-word;background:#1f2937;max-height:200px;margin:0;padding:8px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px;line-height:1.5;overflow-y:auto}.usage-row[data-v-2a895152]{flex-wrap:wrap;gap:6px;margin-top:8px;display:flex}.usage[data-v-2a895152]{color:#047857;background:#ecfdf5;border-radius:10px;padding:2px 8px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px}.err-box[data-v-2a895152]{color:#991b1b;white-space:pre-wrap;word-break:break-word;background:#fef2f2;border:1px solid #fecaca;border-radius:6px;padding:8px 10px;font-size:12px}.msg-detail[data-v-2a895152]{flex-direction:column;flex:1;gap:3px;min-width:0;display:flex}.tc-inline[data-v-2a895152]{background:#f0f7f3;border:1px solid #c3dcd0;border-radius:4px;align-items:baseline;gap:4px;padding:2px 6px;font-size:11px;display:flex}.tc-inline-name[data-v-2a895152]{color:#2d5a47;white-space:nowrap;font-weight:600}.tc-inline-args[data-v-2a895152]{color:#16402f;word-break:break-all;font-family:SF Mono,Monaco,Consolas,monospace;font-size:10px}.tc-id[data-v-2a895152]{color:#9ca3af;font-family:SF Mono,Monaco,Consolas,monospace;font-size:10px}.view-toggle[data-v-2a895152]{color:#2d5a47;cursor:pointer;background:#ecf5ef;border:1px solid #b8d4c5;border-radius:10px;margin-left:auto;padding:2px 8px;font-size:11px}.view-toggle[data-v-2a895152]:hover{background:#dbeee4}.drawer-enter-active[data-v-2a895152],.drawer-leave-active[data-v-2a895152]{transition:opacity .25s}.drawer-enter-active .drawer-panel[data-v-2a895152],.drawer-leave-active .drawer-panel[data-v-2a895152]{transition:transform .25s}.drawer-enter-from[data-v-2a895152],.drawer-leave-to[data-v-2a895152]{opacity:0}.drawer-enter-from .drawer-panel[data-v-2a895152],.drawer-leave-to .drawer-panel[data-v-2a895152]{transform:translate(100%)}.flow-section[data-v-2a895152]{margin-bottom:14px}.flow-section-title[data-v-2a895152]{color:#6b7280;margin-bottom:6px;padding-left:2px;font-size:11px;font-weight:600}.flow-round[data-v-2a895152]{border:1px solid #e5e7eb;border-radius:8px;margin-bottom:12px;overflow:hidden}.flow-round-head[data-v-2a895152]{color:#fff;background:var(--cs-primary);padding:5px 10px;font-size:12px;font-weight:600}.flow-round-body[data-v-2a895152]{flex-direction:column;gap:3px;padding:6px;display:flex}.flow-node[data-v-2a895152]{border-left:3px solid var(--cs-primary);background:#f9fafb;border-radius:6px;align-items:center;gap:6px;padding:5px 8px;font-size:12px;display:flex}.flow-node.llm_request[data-v-2a895152]{border-left-color:#059669}.flow-node.llm_response[data-v-2a895152]{border-left-color:#d97706}.flow-node.tool_call[data-v-2a895152]{border-left-color:#7c3aed}.flow-node.tool_result[data-v-2a895152]{border-left-color:#2563eb}.flow-node.error[data-v-2a895152]{background:#fef2f2;border-left-color:#dc2626}.flow-node.middleware[data-v-2a895152]{border-left-color:#0891b2}.flow-ico[data-v-2a895152]{flex-shrink:0;font-size:13px}.flow-label[data-v-2a895152]{color:#374151;white-space:nowrap;flex-shrink:0;font-weight:600}.flow-detail[data-v-2a895152]{color:#6b7280;text-overflow:ellipsis;white-space:nowrap;flex:1;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px;overflow:hidden}.flow-time[data-v-2a895152]{color:#9ca3af;flex-shrink:0;font-family:SF Mono,Monaco,Consolas,monospace;font-size:10px}.chat-dialog[data-v-5bd12eb9]{--cs-primary:#1f4d3a;--cs-primary-rgb:31, 77, 58;--cs-bg:#fff;--cs-bubble-ai:#f3f4f6;--cs-radius:12px;border-radius:var(--cs-radius);background:var(--cs-bg);flex-direction:column;width:100%;height:100%;transition:all .3s;display:flex;overflow:hidden;box-shadow:0 8px 32px #0000001f,0 2px 8px #00000014}.chat-dialog.collapsed[data-v-5bd12eb9]{height:52px}.chat-header[data-v-5bd12eb9]{background:var(--cs-primary);color:#fff;cursor:pointer;-webkit-user-select:none;user-select:none;justify-content:space-between;align-items:center;padding:12px 16px;display:flex}.header-left[data-v-5bd12eb9]{align-items:center;gap:8px;display:flex}.header-icon[data-v-5bd12eb9]{font-size:20px}.header-title[data-v-5bd12eb9]{font-size:15px;font-weight:600}.status-dot[data-v-5bd12eb9]{background:#4ade80;border-radius:50%;width:8px;height:8px}.status-dot.pulse[data-v-5bd12eb9]{animation:1.5s infinite pulse-5bd12eb9}@keyframes pulse-5bd12eb9{0%,to{opacity:1}50%{opacity:.4}}.header-actions[data-v-5bd12eb9]{gap:4px;display:flex}.action-btn[data-v-5bd12eb9]{color:#fff;cursor:pointer;background:#ffffff26;border:none;border-radius:6px;justify-content:center;align-items:center;width:28px;height:28px;transition:background .2s;display:flex}.action-btn[data-v-5bd12eb9]:hover:not(:disabled){background:#ffffff4d}.action-btn[data-v-5bd12eb9]:disabled{opacity:.4;cursor:not-allowed}.action-btn.debug-btn[data-v-5bd12eb9]{position:relative}.action-btn.debug-btn.active[data-v-5bd12eb9]{background:#ffffff73}.debug-badge[data-v-5bd12eb9]{color:#fff;background:#ef4444;border-radius:8px;min-width:16px;height:16px;padding:0 4px;font-size:10px;font-weight:600;line-height:16px;position:absolute;top:-2px;right:-2px}.chat-body[data-v-5bd12eb9]{overscroll-behavior:contain;flex:1;min-height:0;padding:16px;overflow-y:auto}.empty-state[data-v-5bd12eb9]{color:#9ca3af;flex-direction:column;justify-content:center;align-items:center;height:200px;display:flex}.empty-icon[data-v-5bd12eb9]{margin-bottom:12px;font-size:48px}.empty-state p[data-v-5bd12eb9]{font-size:14px}.message-row[data-v-5bd12eb9]{align-items:flex-start;gap:10px;margin-bottom:16px;display:flex}.message-row.user[data-v-5bd12eb9]{flex-direction:row-reverse}.message-avatar[data-v-5bd12eb9]{background:#f3f4f6;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;width:32px;height:32px;font-size:16px;display:flex}.message-row.user .message-avatar[data-v-5bd12eb9]{background:#ecf5ef}.message-content[data-v-5bd12eb9]{min-width:0;max-width:80%}.message-bubble[data-v-5bd12eb9]{overflow-wrap:anywhere;word-break:break-word;white-space:pre-wrap;border-radius:12px;padding:9px 13px;font-size:13px;line-height:1.6}.message-row.assistant .message-bubble[data-v-5bd12eb9]{color:#1f2937;white-space:normal;overflow-wrap:anywhere;background:#f3f4f6;border-bottom-left-radius:4px}.message-row.user .message-bubble[data-v-5bd12eb9]{background:var(--cs-primary);color:#fff;border-bottom-right-radius:4px}.message-row.user .message-content[data-v-5bd12eb9]{flex-direction:column;align-items:flex-end;display:flex}.message-time[data-v-5bd12eb9]{color:#9ca3af;margin-top:4px;padding:0 4px;font-size:11px}.typing[data-v-5bd12eb9]{gap:4px;padding:12px 16px;display:flex}.typing .dot[data-v-5bd12eb9]{background:#9ca3af;border-radius:50%;width:8px;height:8px;animation:1.4s ease-in-out infinite bounce-5bd12eb9}.typing .dot[data-v-5bd12eb9]:nth-child(2){animation-delay:.2s}.typing .dot[data-v-5bd12eb9]:nth-child(3){animation-delay:.4s}@keyframes bounce-5bd12eb9{0%,80%,to{transform:translateY(0)}40%{transform:translateY(-6px)}}.typing-text[data-v-5bd12eb9]{color:#9ca3af;font-size:13px}.reasoning-block[data-v-5bd12eb9]{background:#f0f7f3;border:1px dashed #b8d4c5;border-radius:8px;margin-bottom:6px;overflow:hidden}.reasoning-header[data-v-5bd12eb9]{cursor:pointer;-webkit-user-select:none;user-select:none;color:#2d5a47;align-items:center;gap:6px;padding:5px 10px;font-size:12px;display:flex}.reasoning-icon[data-v-5bd12eb9]{font-size:13px}.reasoning-title[data-v-5bd12eb9]{font-weight:600}.reasoning-toggle[data-v-5bd12eb9]{margin-left:auto}.reasoning-body[data-v-5bd12eb9]{color:#16402f;white-space:pre-wrap;word-break:break-word;border-top:1px dashed #b8d4c5;max-height:240px;padding:8px 10px;font-size:12px;line-height:1.6;overflow-y:auto}.steps-block[data-v-5bd12eb9]{flex-direction:column;gap:4px;margin-bottom:6px;display:flex}.step-item[data-v-5bd12eb9]{color:#0e7490;background:#ecfeff;border:1px solid #a5f3fc;border-radius:10px;flex-direction:column;align-self:flex-start;align-items:flex-start;gap:3px;max-width:100%;padding:2px 8px;font-size:11px;display:flex}.step-head[data-v-5bd12eb9]{align-items:center;gap:5px;display:inline-flex}.step-icon[data-v-5bd12eb9]{font-size:11px}.step-name[data-v-5bd12eb9]{font-family:SF Mono,Monaco,Consolas,monospace}.step-count[data-v-5bd12eb9]{color:#0891b2;font-size:10px;font-weight:600}.step-status.running[data-v-5bd12eb9]{color:#0891b2}.step-children[data-v-5bd12eb9]{background:#faf5ff;border-left:2px solid #c4b5fd;border-radius:0 8px 8px 0;flex-direction:column;gap:3px;margin-top:4px;padding:4px 8px 4px 10px;display:flex}.step-children-label[data-v-5bd12eb9]{color:#7c3aed;letter-spacing:.3px;font-size:10px;font-weight:600}.step-child[data-v-5bd12eb9]{color:#6d28d9;background:#ede9fe;border:1px solid #ddd6fe;border-radius:8px;align-items:center;gap:5px;padding:1px 7px;font-size:10px;display:inline-flex}.step-child .step-name[data-v-5bd12eb9]{color:#6d28d9}.step-child .step-status.running[data-v-5bd12eb9]{color:#8b5cf6}.stream-cursor[data-v-5bd12eb9],.typing-cursor[data-v-5bd12eb9]{vertical-align:text-bottom;background:var(--cs-primary);width:7px;height:14px;margin-left:2px;animation:1s steps(2,end) infinite blink-5bd12eb9;display:inline-block}@keyframes blink-5bd12eb9{0%,50%{opacity:1}51%,to{opacity:0}}.error-bar[data-v-5bd12eb9]{color:#dc2626;background:#fef2f2;border-radius:8px;align-items:flex-start;gap:10px;margin-top:8px;padding:8px 12px;font-size:13px;display:flex}.error-text[data-v-5bd12eb9]{word-break:break-word;overflow-wrap:anywhere;white-space:pre-wrap;flex:1;min-width:0;max-height:120px;line-height:1.5;overflow-y:auto}.error-bar .retry-btn[data-v-5bd12eb9],.error-bar .undo-btn[data-v-5bd12eb9]{flex-shrink:0;margin-top:1px}.retry-btn[data-v-5bd12eb9]{color:#fff;cursor:pointer;background:#dc2626;border:none;border-radius:6px;flex-shrink:0;padding:3px 12px;font-size:12px;font-weight:600;transition:background .2s}.retry-btn[data-v-5bd12eb9]:hover{background:#b91c1c}.chat-footer[data-v-5bd12eb9]{background:#fafafa;border-top:1px solid #f3f4f6;align-items:flex-end;gap:8px;padding:12px 16px;display:flex}.chat-input[data-v-5bd12eb9]{resize:none;overflow-wrap:anywhere;word-break:break-word;border:1px solid #e5e7eb;border-radius:8px;outline:none;flex:1;max-height:100px;padding:9px 12px;font-family:inherit;font-size:13px;line-height:1.5;transition:border-color .2s;overflow-y:auto}.chat-input[data-v-5bd12eb9]:focus{border-color:var(--cs-primary);box-shadow:0 0 0 2px rgba(var(--cs-primary-rgb), .1)}.send-btn[data-v-5bd12eb9]{background:var(--cs-primary);color:#fff;cursor:pointer;border:none;border-radius:8px;flex-shrink:0;justify-content:center;align-items:center;width:38px;height:38px;transition:opacity .2s,transform .1s;display:flex}.send-btn[data-v-5bd12eb9]:hover:not(:disabled){opacity:.9;transform:scale(1.05)}.send-btn[data-v-5bd12eb9]:active:not(:disabled){transform:scale(.95)}.send-btn[data-v-5bd12eb9]:disabled{opacity:.4;cursor:not-allowed}.send-btn.stop-btn[data-v-5bd12eb9]{background:#9ca3af}.send-btn.stop-btn[data-v-5bd12eb9]:hover:not(:disabled){background:#6b7280;transform:none}.cap-badge[data-v-5bd12eb9]{color:#6b7280;white-space:nowrap;-webkit-user-select:none;user-select:none;background:#f9fafb;border:1px solid #e5e7eb;border-radius:14px;flex-shrink:0;align-self:center;padding:4px 10px;font-size:11px}.msg-actions[data-v-5bd12eb9]{opacity:0;gap:6px;margin-top:4px;transition:opacity .2s;display:flex}.message-row.assistant:hover .msg-actions[data-v-5bd12eb9]{opacity:1}.msg-action-btn[data-v-5bd12eb9]{color:#6b7280;cursor:pointer;background:#fff;border:1px solid #e5e7eb;border-radius:6px;padding:2px 8px;font-size:11px;transition:all .2s}.msg-action-btn[data-v-5bd12eb9]:hover{border-color:var(--cs-primary);color:var(--cs-primary);background:#f0f7f3}.undo-btn[data-v-5bd12eb9]{color:#92400e;cursor:pointer;background:#fffbeb;border:1px solid #f59e0b;border-radius:6px;margin-left:6px;padding:2px 10px;font-size:11px;transition:all .2s}.undo-btn[data-v-5bd12eb9]:hover{background:#fde68a}.undo-foot-btn[data-v-5bd12eb9]{color:#6b7280;cursor:pointer;background:#f9fafb;border:1px solid #e5e7eb;border-radius:14px;flex-shrink:0;align-self:center;padding:4px 10px;font-size:11px;transition:all .2s}.undo-foot-btn[data-v-5bd12eb9]:hover{border-color:var(--cs-primary);color:var(--cs-primary);background:#f0f7f3}.approval-bar[data-v-5bd12eb9]{background:#fffbeb;border:1px solid #f59e0b;border-radius:10px;margin:8px 12px;padding:10px 12px}.approval-head[data-v-5bd12eb9]{color:#92400e;align-items:center;gap:6px;font-size:13px;display:flex}.approval-icon[data-v-5bd12eb9]{font-size:15px}.approval-title code[data-v-5bd12eb9]{color:#78350f;background:#fef3c7;border-radius:4px;padding:1px 6px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.approval-toggle[data-v-5bd12eb9]{color:#92400e;cursor:pointer;background:0 0;border:none;border-radius:4px;margin-left:auto;padding:2px 8px;font-size:12px}.approval-toggle[data-v-5bd12eb9]:hover{background:#fef3c7}.approval-args[data-v-5bd12eb9]{color:#57534e;white-space:pre-wrap;word-break:break-all;background:#fff;border:1px solid #fde68a;border-radius:6px;max-height:140px;margin:8px 0;padding:8px;font-size:12px;overflow:auto}.approval-actions[data-v-5bd12eb9]{justify-content:flex-end;gap:8px;display:flex}.approval-actions button[data-v-5bd12eb9]{cursor:pointer;border:none;border-radius:6px;padding:5px 16px;font-size:13px;transition:opacity .2s}.approval-deny[data-v-5bd12eb9]{color:#6b7280;background:#f3f4f6;border:1px solid #e5e7eb}.approval-deny[data-v-5bd12eb9]:hover{color:#374151;background:#e5e7eb}.approval-allow[data-v-5bd12eb9]{background:var(--cs-primary);color:#fff}.approval-allow[data-v-5bd12eb9]:hover{opacity:.9}.approval-question[data-v-5bd12eb9]{color:#57534e;white-space:pre-wrap;background:#fff;border:1px solid #fde68a;border-radius:6px;margin:8px 0;padding:8px 10px;font-size:13px;line-height:1.5}.approval-context[data-v-5bd12eb9]{color:#92400e;margin:4px 0 8px;font-size:12px;line-height:1.5}.approval-recommend[data-v-5bd12eb9]{color:#1f4d3a;margin:4px 0 8px;font-size:12px}.approval-opt[data-v-5bd12eb9]{border:1px solid var(--cs-primary);color:var(--cs-primary);cursor:pointer;background:#fff;border-radius:6px;padding:5px 14px;font-size:13px;transition:all .2s}.approval-opt[data-v-5bd12eb9]:hover{background:var(--cs-primary);color:#fff}.conflict-bar[data-v-5bd12eb9]{background:#fef2f2;border:1px solid #dc2626;border-radius:10px;margin:8px 12px;padding:10px 12px}.conflict-head[data-v-5bd12eb9]{color:#991b1b;align-items:center;gap:6px;font-size:13px;display:flex}.conflict-icon[data-v-5bd12eb9]{font-size:15px}.conflict-title code[data-v-5bd12eb9]{color:#7f1d1d;background:#fee2e2;border-radius:4px;padding:1px 6px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.conflict-detail[data-v-5bd12eb9]{color:#7f1d1d;margin:6px 0 8px;font-size:12px;line-height:1.5}.conflict-actions[data-v-5bd12eb9]{flex-wrap:wrap;justify-content:flex-end;gap:8px;display:flex}.conflict-actions button[data-v-5bd12eb9]{cursor:pointer;border:none;border-radius:6px;padding:5px 14px;font-size:13px;transition:opacity .2s}.conflict-keep[data-v-5bd12eb9]{color:#6b7280;background:#f3f4f6;border:1px solid #e5e7eb}.conflict-keep[data-v-5bd12eb9]:hover{color:#374151;background:#e5e7eb}.conflict-overwrite[data-v-5bd12eb9]{color:#fff;background:#dc2626}.conflict-overwrite[data-v-5bd12eb9]:hover{opacity:.9}.conflict-restore[data-v-5bd12eb9]{color:#dc2626;background:#fff;border:1px solid #dc2626}.conflict-restore[data-v-5bd12eb9]:hover{background:#fee2e2}.conflict-toggle[data-v-5bd12eb9]{color:#991b1b;cursor:pointer;background:0 0;border:none;border-radius:4px;margin:2px 0 6px;padding:2px 8px;font-size:12px}.conflict-toggle[data-v-5bd12eb9]:hover{background:#fee2e2}.conflict-diff[data-v-5bd12eb9]{gap:8px;margin:4px 0 8px;display:flex}.conflict-diff-col[data-v-5bd12eb9]{flex:1;min-width:0}.conflict-diff-label[data-v-5bd12eb9]{color:#7f1d1d;margin-bottom:2px;font-size:11px}.conflict-diff-pre[data-v-5bd12eb9]{color:#57534e;white-space:pre-wrap;word-break:break-all;background:#fff;border:1px solid #fecaca;border-radius:6px;max-height:140px;margin:0;padding:6px;font-size:11px;overflow:auto}
1
+ .code-preview-overlay[data-v-3d6e2a95]{z-index:9999;background:#00000080;justify-content:center;align-items:center;padding:20px;display:flex;position:fixed;inset:0}.code-preview-modal[data-v-3d6e2a95]{background:#fff;border-radius:12px;flex-direction:column;width:90%;max-width:900px;height:80vh;display:flex;overflow:hidden;box-shadow:0 20px 60px #0000004d}.preview-header[data-v-3d6e2a95]{color:#fff;background:#1f2937;align-items:center;gap:12px;padding:10px 16px;display:flex}.preview-title[data-v-3d6e2a95]{font-size:14px;font-weight:600}.preview-tabs[data-v-3d6e2a95]{gap:4px;margin-left:auto;display:flex}.preview-tabs button[data-v-3d6e2a95]{color:#fff;cursor:pointer;background:#ffffff1a;border:none;border-radius:6px;padding:4px 12px;font-size:13px}.preview-tabs button.active[data-v-3d6e2a95]{background:#667eea}.preview-tabs button[data-v-3d6e2a95]:disabled{opacity:.4;cursor:not-allowed}.preview-actions[data-v-3d6e2a95]{gap:4px;display:flex}.icon-btn[data-v-3d6e2a95]{color:#fff;cursor:pointer;background:#ffffff1a;border:none;border-radius:6px;justify-content:center;align-items:center;width:28px;height:28px;font-size:14px;display:flex}.icon-btn[data-v-3d6e2a95]:hover{background:#ffffff40}.preview-body[data-v-3d6e2a95]{background:#f9fafb;flex:1;overflow:hidden}.preview-iframe[data-v-3d6e2a95]{background:#fff;border:none;width:100%;height:100%}.preview-source[data-v-3d6e2a95]{color:#e5e7eb;white-space:pre-wrap;word-break:break-word;background:#1f2937;height:100%;margin:0;padding:16px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:13px;line-height:1.5;overflow:auto}.message-md{overflow-wrap:anywhere;word-break:break-word;font-size:13px;line-height:1.6}.message-md p{margin:0 0 8px}.message-md p:last-child{margin-bottom:0}.message-md table{border-collapse:collapse;max-width:100%;margin:8px 0;display:block;overflow-x:auto}.message-md th,.message-md td{white-space:nowrap;border:1px solid #e5e7eb;padding:4px 8px;font-size:12px}.message-md th{background:#f9fafb}.message-md img{max-width:100%}.message-md ul,.message-md ol{margin:6px 0;padding-left:20px}.message-md li{margin:2px 0}.message-md h1,.message-md h2,.message-md h3{margin:10px 0 6px;font-weight:600}.message-md h1{font-size:18px}.message-md h2{font-size:16px}.message-md h3{font-size:15px}.message-md a{color:#667eea;text-decoration:underline}.message-md code:not(.hljs){color:#4338ca;background:#667eea1a;border-radius:4px;padding:1px 5px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:13px}.message-md .code-block{background:#1f2937;border-radius:8px;margin:10px 0;padding:0;position:relative;overflow:hidden}.message-md .code-block code{color:#e5e7eb;background:0 0;padding:12px 14px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:13px;line-height:1.5;display:block;overflow-x:auto}.message-md .code-toolbar{background:#00000040;border-bottom:1px solid #ffffff14;align-items:center;gap:8px;padding:6px 12px;display:flex}.message-md .code-lang{color:#9ca3af;text-transform:lowercase;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px}.message-md .code-action-btn{color:#e5e7eb;cursor:pointer;background:#ffffff1a;border:none;border-radius:4px;margin-left:auto;padding:3px 10px;font-size:12px;transition:background .2s}.message-md .code-action-btn:hover{background:#fff3}.message-md .code-action-btn.preview-btn{color:#fff;background:#667eea;margin-left:4px}.message-md .code-action-btn.preview-btn:hover{background:#5568d3}.message-md .hljs{color:#e5e7eb}.message-md .hljs-keyword{color:#c084fc}.message-md .hljs-string{color:#86efac}.message-md .hljs-comment{color:#6b7280;font-style:italic}.message-md .hljs-number{color:#fca5a5}.message-md .hljs-function .hljs-title,.message-md .hljs-title{color:#93c5fd}.message-md .hljs-tag{color:#fca5a5}.message-md .hljs-attr{color:#fcd34d}.message-md .hljs-built_in{color:#67e8f9}.debug-drawer[data-v-cc5d7052]{z-index:9000;pointer-events:none;position:fixed;inset:0}.drawer-mask[data-v-cc5d7052]{pointer-events:auto;background:#00000040;position:absolute;inset:0}.drawer-panel[data-v-cc5d7052]{--cs-primary:#1f4d3a;--cs-primary-rgb:31, 77, 58;pointer-events:auto;z-index:2;background:#fff;flex-direction:column;width:520px;max-width:90vw;display:flex;position:absolute;top:0;bottom:0;right:0;box-shadow:-8px 0 32px #00000026}.drawer-mask[data-v-cc5d7052]{z-index:1}.drawer-header[data-v-cc5d7052]{color:#fff;background:linear-gradient(135deg,#1f2937,#111827);justify-content:space-between;align-items:center;padding:12px 16px;display:flex}.drawer-title[data-v-cc5d7052]{font-size:15px;font-weight:600}.tab-group[data-v-cc5d7052]{gap:4px;display:flex}.tab-btn[data-v-cc5d7052]{color:#fff;cursor:pointer;background:#ffffff1f;border:none;border-radius:6px;padding:4px 12px;font-size:13px;transition:background .2s}.tab-btn[data-v-cc5d7052]:hover{background:#ffffff38}.tab-btn.active[data-v-cc5d7052]{background:#ffffff73;font-weight:600}.info-body[data-v-cc5d7052]{padding:4px 0}.info-section[data-v-cc5d7052]{margin-bottom:14px}.info-title[data-v-cc5d7052]{color:#2d5a47;border-bottom:1px solid #f3f4f6;margin-bottom:6px;padding-bottom:4px;font-size:12px;font-weight:600}.info-item[data-v-cc5d7052]{background:#f9fafb;border-radius:6px;margin-bottom:4px;padding:6px 8px}.info-name[data-v-cc5d7052]{color:#1f2937;font-family:SF Mono,Monaco,Consolas,monospace;font-size:12px;font-weight:600}.info-desc[data-v-cc5d7052]{color:#6b7280;margin-top:2px;font-size:11px;line-height:1.5}.info-desc.muted[data-v-cc5d7052]{color:#9ca3af}.src-tag[data-v-cc5d7052]{vertical-align:middle;border-radius:8px;margin-left:6px;padding:0 6px;font-size:10px;font-weight:600;display:inline-block}.src-tag.builtin[data-v-cc5d7052]{color:#6b7280;background:#f3f4f6}.src-tag.mcp[data-v-cc5d7052]{color:#7c3aed;background:#f3e8ff}.src-tag.user[data-v-cc5d7052]{color:#2563eb;background:#dbeafe}.info-todo[data-v-cc5d7052]{color:#374151;background:#f9fafb;border-radius:6px;align-items:center;gap:6px;margin-bottom:4px;padding:4px 8px;font-size:12px;display:flex}.todo-tag[data-v-cc5d7052]{color:#fff;border-radius:8px;flex-shrink:0;padding:1px 6px;font-size:10px}.info-pre[data-v-cc5d7052]{color:#4b5563;white-space:pre-wrap;word-break:break-word;background:#f9fafb;border-radius:6px;max-height:200px;margin:0;padding:8px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px;overflow-y:auto}.header-actions[data-v-cc5d7052]{gap:4px;display:flex}.hd-btn[data-v-cc5d7052]{color:#fff;cursor:pointer;background:#ffffff1f;border:none;border-radius:6px;width:28px;height:28px}.hd-btn[data-v-cc5d7052]:hover{background:#ffffff40}.drawer-filters[data-v-cc5d7052]{background:#fafafa;border-bottom:1px solid #f3f4f6;flex-wrap:wrap;gap:6px;padding:10px 16px;display:flex}.filter-chip[data-v-cc5d7052]{color:#6b7280;cursor:pointer;background:#fff;border:1px solid #e5e7eb;border-radius:14px;align-items:center;gap:4px;padding:4px 10px;font-size:12px;transition:all .2s;display:inline-flex}.filter-chip[data-v-cc5d7052]:hover{border-color:var(--chip-color,var(--cs-primary))}.filter-chip.active[data-v-cc5d7052]{background:var(--chip-color,var(--cs-primary));border-color:var(--chip-color,var(--cs-primary));color:#fff}.chip-count[data-v-cc5d7052]{background:#00000014;border-radius:8px;padding:0 5px;font-size:11px}.filter-chip.active .chip-count[data-v-cc5d7052]{background:#ffffff40}.drawer-body[data-v-cc5d7052]{flex:1;padding:12px;overflow-y:auto}.empty[data-v-cc5d7052]{text-align:center;color:#9ca3af;padding:40px 20px;font-size:13px}.log-item[data-v-cc5d7052]{background:#fff;border:1px solid #e5e7eb;border-radius:8px;margin-bottom:10px;overflow:hidden}.log-head[data-v-cc5d7052]{background:#f9fafb;align-items:center;gap:8px;padding:8px 10px;display:flex}.log-type[data-v-cc5d7052]{color:#fff;white-space:nowrap;border-radius:4px;padding:2px 8px;font-size:11px;font-weight:600}.log-source[data-v-cc5d7052]{color:#7c3aed;white-space:nowrap;background:#f3e8ff;border-radius:4px;padding:2px 8px;font-size:10px;font-weight:600}.log-time[data-v-cc5d7052]{color:#9ca3af;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px}.log-body[data-v-cc5d7052]{padding:10px 12px}.log-footer[data-v-cc5d7052]{border-top:1px dashed #f3f4f6;gap:8px;padding:6px 12px;display:flex}.raw-toggle[data-v-cc5d7052]{color:var(--cs-primary);cursor:pointer;background:0 0;border:none;padding:2px 4px;font-size:11px}.raw-toggle[data-v-cc5d7052]:hover{text-decoration:underline}.log-raw[data-v-cc5d7052]{color:#e5e7eb;white-space:pre-wrap;word-break:break-word;background:#1f2937;border-top:1px solid #f3f4f6;max-height:280px;margin:0;padding:10px 12px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px;line-height:1.5;overflow:auto}.kv-grid[data-v-cc5d7052]{grid-template-columns:1fr 1fr;gap:6px;margin-bottom:8px;display:grid}.kv[data-v-cc5d7052]{background:#f9fafb;border-radius:6px;flex-direction:column;padding:6px 8px;display:flex}.kv .k[data-v-cc5d7052]{color:#9ca3af;text-transform:uppercase;font-size:10px}.kv .v[data-v-cc5d7052]{color:#1f2937;font-family:SF Mono,Monaco,Consolas,monospace;font-size:13px;font-weight:600}.section-label[data-v-cc5d7052]{color:#6b7280;margin:10px 0 4px;font-size:11px;font-weight:600}.chip-row[data-v-cc5d7052]{flex-wrap:wrap;gap:4px;display:flex}.tool-chip[data-v-cc5d7052]{color:#2d5a47;background:#ecf5ef;border-radius:10px;padding:2px 8px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px}.msg-list[data-v-cc5d7052]{flex-direction:column;gap:4px;display:flex}.msg-row[data-v-cc5d7052]{background:#f9fafb;border-radius:6px;align-items:flex-start;gap:6px;padding:5px 8px;display:flex}.msg-role[data-v-cc5d7052]{color:#fff;border-radius:3px;flex-shrink:0;margin-top:1px;padding:2px 6px;font-size:9px;font-weight:700}.msg-text[data-v-cc5d7052]{color:#374151;white-space:pre-wrap;word-break:break-word;flex:1;font-size:12px;line-height:1.5}.msg-tool-hint[data-v-cc5d7052]{color:#7c3aed;flex-shrink:0;font-size:10px}.badge-row[data-v-cc5d7052]{flex-wrap:wrap;gap:6px;margin-bottom:8px;display:flex}.badge[data-v-cc5d7052]{color:#2d5a47;background:#dbeee4;border-radius:10px;padding:2px 8px;font-size:11px;font-weight:600}.badge.muted[data-v-cc5d7052]{color:#6b7280;background:#f3f4f6}.badge.warn[data-v-cc5d7052]{color:#92400e;background:#fef3c7}.resp-content[data-v-cc5d7052]{color:#1f2937;white-space:pre-wrap;word-break:break-word;background:#fffbeb;border-left:3px solid #d97706;border-radius:4px;margin-bottom:8px;padding:6px 10px;font-size:12px}.tc-list[data-v-cc5d7052]{flex-direction:column;gap:6px;display:flex}.tc-card[data-v-cc5d7052]{border:1px solid #e5e7eb;border-radius:6px;overflow:hidden}.tc-card.inline[data-v-cc5d7052]{margin-top:4px}.tc-name[data-v-cc5d7052]{color:#2d5a47;background:#ecf5ef;padding:5px 8px;font-size:12px;font-weight:600}.tc-args[data-v-cc5d7052]{color:#e5e7eb;white-space:pre-wrap;word-break:break-word;background:#1f2937;max-height:200px;margin:0;padding:8px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px;line-height:1.5;overflow-y:auto}.usage-row[data-v-cc5d7052]{flex-wrap:wrap;gap:6px;margin-top:8px;display:flex}.usage[data-v-cc5d7052]{color:#047857;background:#ecfdf5;border-radius:10px;padding:2px 8px;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px}.err-box[data-v-cc5d7052]{color:#991b1b;white-space:pre-wrap;word-break:break-word;background:#fef2f2;border:1px solid #fecaca;border-radius:6px;padding:8px 10px;font-size:12px}.msg-detail[data-v-cc5d7052]{flex-direction:column;flex:1;gap:3px;min-width:0;display:flex}.tc-inline[data-v-cc5d7052]{background:#f0f7f3;border:1px solid #c3dcd0;border-radius:4px;align-items:baseline;gap:4px;padding:2px 6px;font-size:11px;display:flex}.tc-inline-name[data-v-cc5d7052]{color:#2d5a47;white-space:nowrap;font-weight:600}.tc-inline-args[data-v-cc5d7052]{color:#16402f;word-break:break-all;font-family:SF Mono,Monaco,Consolas,monospace;font-size:10px}.tc-id[data-v-cc5d7052]{color:#9ca3af;font-family:SF Mono,Monaco,Consolas,monospace;font-size:10px}.view-toggle[data-v-cc5d7052]{color:#2d5a47;cursor:pointer;background:#ecf5ef;border:1px solid #b8d4c5;border-radius:10px;margin-left:auto;padding:2px 8px;font-size:11px}.view-toggle[data-v-cc5d7052]:hover{background:#dbeee4}.drawer-enter-active[data-v-cc5d7052],.drawer-leave-active[data-v-cc5d7052]{transition:opacity .25s}.drawer-enter-active .drawer-panel[data-v-cc5d7052],.drawer-leave-active .drawer-panel[data-v-cc5d7052]{transition:transform .25s}.drawer-enter-from[data-v-cc5d7052],.drawer-leave-to[data-v-cc5d7052]{opacity:0}.drawer-enter-from .drawer-panel[data-v-cc5d7052],.drawer-leave-to .drawer-panel[data-v-cc5d7052]{transform:translate(100%)}.flow-section[data-v-cc5d7052]{margin-bottom:14px}.flow-section-title[data-v-cc5d7052]{color:#6b7280;margin-bottom:6px;padding-left:2px;font-size:11px;font-weight:600}.flow-round[data-v-cc5d7052]{border:1px solid #e5e7eb;border-radius:8px;margin-bottom:12px;overflow:hidden}.flow-round-head[data-v-cc5d7052]{color:#fff;background:var(--cs-primary);padding:5px 10px;font-size:12px;font-weight:600}.flow-round-body[data-v-cc5d7052]{flex-direction:column;gap:3px;padding:6px;display:flex}.flow-node[data-v-cc5d7052]{border-left:3px solid var(--cs-primary);background:#f9fafb;border-radius:6px;align-items:center;gap:6px;padding:5px 8px;font-size:12px;display:flex}.flow-node.llm_request[data-v-cc5d7052]{border-left-color:#059669}.flow-node.llm_response[data-v-cc5d7052]{border-left-color:#d97706}.flow-node.tool_call[data-v-cc5d7052]{border-left-color:#7c3aed}.flow-node.tool_result[data-v-cc5d7052]{border-left-color:#2563eb}.flow-node.error[data-v-cc5d7052]{background:#fef2f2;border-left-color:#dc2626}.flow-node.middleware[data-v-cc5d7052]{border-left-color:#0891b2}.flow-ico[data-v-cc5d7052]{flex-shrink:0;font-size:13px}.flow-label[data-v-cc5d7052]{color:#374151;white-space:nowrap;flex-shrink:0;font-weight:600}.flow-detail[data-v-cc5d7052]{color:#6b7280;text-overflow:ellipsis;white-space:nowrap;flex:1;font-family:SF Mono,Monaco,Consolas,monospace;font-size:11px;overflow:hidden}.flow-time[data-v-cc5d7052]{color:#9ca3af;flex-shrink:0;font-family:SF Mono,Monaco,Consolas,monospace;font-size:10px}.chat-dialog[data-v-6f6e6133]{--cs-primary:#1f4d3a;--cs-primary-rgb:31, 77, 58;--cs-bg:#fff;--cs-bubble-ai:#f3f4f6;--cs-radius:12px;border-radius:var(--cs-radius);background:var(--cs-bg);flex-direction:column;width:100%;height:100%;transition:all .3s;display:flex;overflow:hidden;box-shadow:0 8px 32px #0000001f,0 2px 8px #00000014}.chat-dialog.collapsed[data-v-6f6e6133]{height:52px}.chat-header[data-v-6f6e6133]{background:var(--cs-primary);color:#fff;cursor:pointer;-webkit-user-select:none;user-select:none;justify-content:space-between;align-items:center;padding:12px 16px;display:flex}.header-left[data-v-6f6e6133]{align-items:center;gap:8px;display:flex}.header-icon[data-v-6f6e6133]{font-size:20px}.header-title[data-v-6f6e6133]{font-size:15px;font-weight:600}.status-dot[data-v-6f6e6133]{background:#4ade80;border-radius:50%;width:8px;height:8px}.status-dot.pulse[data-v-6f6e6133]{animation:1.5s infinite pulse-6f6e6133}@keyframes pulse-6f6e6133{0%,to{opacity:1}50%{opacity:.4}}.header-actions[data-v-6f6e6133]{gap:4px;display:flex}.action-btn[data-v-6f6e6133]{color:#fff;cursor:pointer;background:#ffffff26;border:none;border-radius:6px;justify-content:center;align-items:center;width:28px;height:28px;transition:background .2s;display:flex}.action-btn[data-v-6f6e6133]:hover:not(:disabled){background:#ffffff4d}.action-btn[data-v-6f6e6133]:disabled{opacity:.4;cursor:not-allowed}.action-btn.debug-btn[data-v-6f6e6133]{position:relative}.action-btn.debug-btn.active[data-v-6f6e6133]{background:#ffffff73}.debug-badge[data-v-6f6e6133]{color:#fff;background:#ef4444;border-radius:8px;min-width:16px;height:16px;padding:0 4px;font-size:10px;font-weight:600;line-height:16px;position:absolute;top:-2px;right:-2px}.chat-body[data-v-6f6e6133]{overscroll-behavior:contain;flex:1;min-height:0;padding:16px;overflow-y:auto}.empty-state[data-v-6f6e6133]{color:#9ca3af;flex-direction:column;justify-content:center;align-items:center;height:200px;display:flex}.empty-icon[data-v-6f6e6133]{margin-bottom:12px;font-size:48px}.empty-state p[data-v-6f6e6133]{font-size:14px}.message-row[data-v-6f6e6133]{align-items:flex-start;gap:10px;margin-bottom:16px;display:flex}.message-row.user[data-v-6f6e6133]{flex-direction:row-reverse}.message-avatar[data-v-6f6e6133]{background:#f3f4f6;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;width:32px;height:32px;font-size:16px;display:flex}.message-row.user .message-avatar[data-v-6f6e6133]{background:#ecf5ef}.message-content[data-v-6f6e6133]{min-width:0;max-width:80%}.message-bubble[data-v-6f6e6133]{overflow-wrap:anywhere;word-break:break-word;white-space:pre-wrap;border-radius:12px;padding:9px 13px;font-size:13px;line-height:1.6}.message-row.assistant .message-bubble[data-v-6f6e6133]{color:#1f2937;white-space:normal;overflow-wrap:anywhere;background:#f3f4f6;border-bottom-left-radius:4px}.message-row.user .message-bubble[data-v-6f6e6133]{background:var(--cs-primary);color:#fff;border-bottom-right-radius:4px}.message-row.user .message-content[data-v-6f6e6133]{flex-direction:column;align-items:flex-end;display:flex}.message-time[data-v-6f6e6133]{color:#9ca3af;margin-top:4px;padding:0 4px;font-size:11px}.typing[data-v-6f6e6133]{gap:4px;padding:12px 16px;display:flex}.typing .dot[data-v-6f6e6133]{background:#9ca3af;border-radius:50%;width:8px;height:8px;animation:1.4s ease-in-out infinite bounce-6f6e6133}.typing .dot[data-v-6f6e6133]:nth-child(2){animation-delay:.2s}.typing .dot[data-v-6f6e6133]:nth-child(3){animation-delay:.4s}@keyframes bounce-6f6e6133{0%,80%,to{transform:translateY(0)}40%{transform:translateY(-6px)}}.typing-text[data-v-6f6e6133]{color:#9ca3af;font-size:13px}.reasoning-block[data-v-6f6e6133]{background:#f0f7f3;border:1px dashed #b8d4c5;border-radius:8px;margin-bottom:6px;overflow:hidden}.reasoning-header[data-v-6f6e6133]{cursor:pointer;-webkit-user-select:none;user-select:none;color:#2d5a47;align-items:center;gap:6px;padding:5px 10px;font-size:12px;display:flex}.reasoning-icon[data-v-6f6e6133]{font-size:13px}.reasoning-title[data-v-6f6e6133]{font-weight:600}.reasoning-toggle[data-v-6f6e6133]{margin-left:auto}.reasoning-body[data-v-6f6e6133]{color:#16402f;white-space:pre-wrap;word-break:break-word;border-top:1px dashed #b8d4c5;max-height:240px;padding:8px 10px;font-size:12px;line-height:1.6;overflow-y:auto}.steps-block[data-v-6f6e6133]{flex-direction:column;gap:4px;margin-bottom:6px;display:flex}.step-item[data-v-6f6e6133]{color:#0e7490;background:#ecfeff;border:1px solid #a5f3fc;border-radius:10px;flex-direction:column;align-self:flex-start;align-items:flex-start;gap:3px;max-width:100%;padding:2px 8px;font-size:11px;display:flex}.step-head[data-v-6f6e6133]{align-items:center;gap:5px;display:inline-flex}.step-icon[data-v-6f6e6133]{font-size:11px}.step-name[data-v-6f6e6133]{font-family:SF Mono,Monaco,Consolas,monospace}.step-count[data-v-6f6e6133]{color:#0891b2;font-size:10px;font-weight:600}.step-status.running[data-v-6f6e6133]{color:#0891b2}.step-children[data-v-6f6e6133]{background:#faf5ff;border-left:2px solid #c4b5fd;border-radius:0 8px 8px 0;flex-direction:column;gap:3px;margin-top:4px;padding:4px 8px 4px 10px;display:flex}.step-children-label[data-v-6f6e6133]{color:#7c3aed;letter-spacing:.3px;font-size:10px;font-weight:600}.step-child[data-v-6f6e6133]{color:#6d28d9;background:#ede9fe;border:1px solid #ddd6fe;border-radius:8px;align-items:center;gap:5px;padding:1px 7px;font-size:10px;display:inline-flex}.step-child .step-name[data-v-6f6e6133]{color:#6d28d9}.step-child .step-status.running[data-v-6f6e6133]{color:#8b5cf6}.stream-cursor[data-v-6f6e6133],.typing-cursor[data-v-6f6e6133]{vertical-align:text-bottom;background:var(--cs-primary);width:7px;height:14px;margin-left:2px;animation:1s steps(2,end) infinite blink-6f6e6133;display:inline-block}@keyframes blink-6f6e6133{0%,50%{opacity:1}51%,to{opacity:0}}.error-bar[data-v-6f6e6133]{color:#dc2626;background:#fef2f2;border-radius:8px;align-items:flex-start;gap:10px;margin-top:8px;padding:8px 12px;font-size:13px;display:flex}.error-text[data-v-6f6e6133]{word-break:break-word;overflow-wrap:anywhere;white-space:pre-wrap;flex:1;min-width:0;max-height:120px;line-height:1.5;overflow-y:auto}.error-bar .retry-btn[data-v-6f6e6133],.error-bar .undo-btn[data-v-6f6e6133]{flex-shrink:0;margin-top:1px}.retry-btn[data-v-6f6e6133]{color:#fff;cursor:pointer;background:#dc2626;border:none;border-radius:6px;flex-shrink:0;padding:3px 12px;font-size:12px;font-weight:600;transition:background .2s}.retry-btn[data-v-6f6e6133]:hover{background:#b91c1c}.chat-footer[data-v-6f6e6133]{background:#fafafa;border-top:1px solid #f3f4f6;align-items:flex-end;gap:8px;padding:12px 16px;display:flex}.chat-input[data-v-6f6e6133]{resize:none;overflow-wrap:anywhere;word-break:break-word;border:1px solid #e5e7eb;border-radius:8px;outline:none;flex:1;max-height:100px;padding:9px 12px;font-family:inherit;font-size:13px;line-height:1.5;transition:border-color .2s;overflow-y:auto}.chat-input[data-v-6f6e6133]:focus{border-color:var(--cs-primary);box-shadow:0 0 0 2px rgba(var(--cs-primary-rgb), .1)}.send-btn[data-v-6f6e6133]{background:var(--cs-primary);color:#fff;cursor:pointer;border:none;border-radius:8px;flex-shrink:0;justify-content:center;align-items:center;width:38px;height:38px;transition:opacity .2s,transform .1s;display:flex}.send-btn[data-v-6f6e6133]:hover:not(:disabled){opacity:.9;transform:scale(1.05)}.send-btn[data-v-6f6e6133]:active:not(:disabled){transform:scale(.95)}.send-btn[data-v-6f6e6133]:disabled{opacity:.4;cursor:not-allowed}.send-btn.stop-btn[data-v-6f6e6133]{background:#9ca3af}.send-btn.stop-btn[data-v-6f6e6133]:hover:not(:disabled){background:#6b7280;transform:none}.cap-badge[data-v-6f6e6133]{color:#6b7280;white-space:nowrap;-webkit-user-select:none;user-select:none;background:#f9fafb;border:1px solid #e5e7eb;border-radius:14px;flex-shrink:0;align-self:center;padding:4px 10px;font-size:11px}.msg-actions[data-v-6f6e6133]{opacity:0;gap:6px;margin-top:4px;transition:opacity .2s;display:flex}.message-row.assistant:hover .msg-actions[data-v-6f6e6133]{opacity:1}.msg-action-btn[data-v-6f6e6133]{color:#6b7280;cursor:pointer;background:#fff;border:1px solid #e5e7eb;border-radius:6px;padding:2px 8px;font-size:11px;transition:all .2s}.msg-action-btn[data-v-6f6e6133]:hover{border-color:var(--cs-primary);color:var(--cs-primary);background:#f0f7f3}.undo-btn[data-v-6f6e6133]{color:#92400e;cursor:pointer;background:#fffbeb;border:1px solid #f59e0b;border-radius:6px;margin-left:6px;padding:2px 10px;font-size:11px;transition:all .2s}.undo-btn[data-v-6f6e6133]:hover{background:#fde68a}.undo-foot-btn[data-v-6f6e6133]{color:#6b7280;cursor:pointer;background:#f9fafb;border:1px solid #e5e7eb;border-radius:14px;flex-shrink:0;align-self:center;padding:4px 10px;font-size:11px;transition:all .2s}.undo-foot-btn[data-v-6f6e6133]:hover{border-color:var(--cs-primary);color:var(--cs-primary);background:#f0f7f3}.approval-bar[data-v-6f6e6133]{background:#fffbeb;border:1px solid #f59e0b;border-radius:10px;margin:8px 12px;padding:10px 12px}.approval-head[data-v-6f6e6133]{color:#92400e;align-items:center;gap:6px;font-size:13px;display:flex}.approval-icon[data-v-6f6e6133]{font-size:15px}.approval-title code[data-v-6f6e6133]{color:#78350f;background:#fef3c7;border-radius:4px;padding:1px 6px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.approval-toggle[data-v-6f6e6133]{color:#92400e;cursor:pointer;background:0 0;border:none;border-radius:4px;margin-left:auto;padding:2px 8px;font-size:12px}.approval-toggle[data-v-6f6e6133]:hover{background:#fef3c7}.approval-args[data-v-6f6e6133]{color:#57534e;white-space:pre-wrap;word-break:break-all;background:#fff;border:1px solid #fde68a;border-radius:6px;max-height:140px;margin:8px 0;padding:8px;font-size:12px;overflow:auto}.approval-actions[data-v-6f6e6133]{justify-content:flex-end;gap:8px;display:flex}.approval-actions button[data-v-6f6e6133]{cursor:pointer;border:none;border-radius:6px;padding:5px 16px;font-size:13px;transition:opacity .2s}.approval-deny[data-v-6f6e6133]{color:#6b7280;background:#f3f4f6;border:1px solid #e5e7eb}.approval-deny[data-v-6f6e6133]:hover{color:#374151;background:#e5e7eb}.approval-allow[data-v-6f6e6133]{background:var(--cs-primary);color:#fff}.approval-allow[data-v-6f6e6133]:hover{opacity:.9}.approval-question[data-v-6f6e6133]{color:#57534e;white-space:pre-wrap;background:#fff;border:1px solid #fde68a;border-radius:6px;margin:8px 0;padding:8px 10px;font-size:13px;line-height:1.5}.approval-context[data-v-6f6e6133]{color:#92400e;margin:4px 0 8px;font-size:12px;line-height:1.5}.approval-recommend[data-v-6f6e6133]{color:#1f4d3a;margin:4px 0 8px;font-size:12px}.approval-opt[data-v-6f6e6133]{border:1px solid var(--cs-primary);color:var(--cs-primary);cursor:pointer;background:#fff;border-radius:6px;padding:5px 14px;font-size:13px;transition:all .2s}.approval-opt[data-v-6f6e6133]:hover{background:var(--cs-primary);color:#fff}.conflict-bar[data-v-6f6e6133]{background:#fef2f2;border:1px solid #dc2626;border-radius:10px;margin:8px 12px;padding:10px 12px}.conflict-head[data-v-6f6e6133]{color:#991b1b;align-items:center;gap:6px;font-size:13px;display:flex}.conflict-icon[data-v-6f6e6133]{font-size:15px}.conflict-title code[data-v-6f6e6133]{color:#7f1d1d;background:#fee2e2;border-radius:4px;padding:1px 6px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.conflict-detail[data-v-6f6e6133]{color:#7f1d1d;margin:6px 0 8px;font-size:12px;line-height:1.5}.conflict-actions[data-v-6f6e6133]{flex-wrap:wrap;justify-content:flex-end;gap:8px;display:flex}.conflict-actions button[data-v-6f6e6133]{cursor:pointer;border:none;border-radius:6px;padding:5px 14px;font-size:13px;transition:opacity .2s}.conflict-keep[data-v-6f6e6133]{color:#6b7280;background:#f3f4f6;border:1px solid #e5e7eb}.conflict-keep[data-v-6f6e6133]:hover{color:#374151;background:#e5e7eb}.conflict-overwrite[data-v-6f6e6133]{color:#fff;background:#dc2626}.conflict-overwrite[data-v-6f6e6133]:hover{opacity:.9}.conflict-restore[data-v-6f6e6133]{color:#dc2626;background:#fff;border:1px solid #dc2626}.conflict-restore[data-v-6f6e6133]:hover{background:#fee2e2}.conflict-toggle[data-v-6f6e6133]{color:#991b1b;cursor:pointer;background:0 0;border:none;border-radius:4px;margin:2px 0 6px;padding:2px 8px;font-size:12px}.conflict-toggle[data-v-6f6e6133]:hover{background:#fee2e2}.conflict-diff[data-v-6f6e6133]{gap:8px;margin:4px 0 8px;display:flex}.conflict-diff-col[data-v-6f6e6133]{flex:1;min-width:0}.conflict-diff-label[data-v-6f6e6133]{color:#7f1d1d;margin-bottom:2px;font-size:11px}.conflict-diff-pre[data-v-6f6e6133]{color:#57534e;white-space:pre-wrap;word-break:break-all;background:#fff;border:1px solid #fecaca;border-radius:6px;max-height:140px;margin:0;padding:6px;font-size:11px;overflow:auto}
2
2
  /*$vite$:1*/