agent-tool-chat 1.0.1 → 1.0.2

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  基于 **ToolPackage** 架构的 AI 对话插件,工具由宿主控制执行。基于 Vue 3 + Element Plus。
4
4
 
5
- **版本:** 1.0.0
5
+ **版本:** 1.0.1
6
6
 
7
7
  ## 安装
8
8
 
@@ -29,6 +29,11 @@ const chat = useAgentChat({
29
29
  // 宿主执行工具并返回结果
30
30
  return { success: true, data: { /* ... */ } }
31
31
  },
32
+ suggestedCommands: [
33
+ // 可选:空状态快捷命令,点击即发送 text 指令
34
+ { label: '查询订单', text: '查询今天的所有订单' },
35
+ { label: '使用帮助', text: '你能做什么?介绍一下你的能力' },
36
+ ],
32
37
  })
33
38
  </script>
34
39
 
@@ -37,6 +42,68 @@ const chat = useAgentChat({
37
42
  </template>
38
43
  ```
39
44
 
45
+ ### 免 `chat` 使用(开箱即用)
46
+
47
+ `ChatPanel` 的 `chat` 属性**可选**。不传时组件内部自建聊天实例,仅启用内置工具(也可通过 `options` 传入 `AgentChatOptions` 配置):
48
+
49
+ ```vue
50
+ <template>
51
+ <!-- 仅内置工具 -->
52
+ <ChatPanel />
53
+
54
+ <!-- 带 options 配置(如 provider、suggestedCommands 等) -->
55
+ <ChatPanel :options="{ suggestedCommands: [{ label: '现在几点', text: '现在几点?' }] }" />
56
+ </template>
57
+ ```
58
+
59
+ > 注意:未传入宿主 `onToolCall` 时,仅内置工具(`get_current_time` 等)可执行,宿主自定义工具需通过 `options.toolPackages` 传入。
60
+
61
+ #### 默认快捷命令
62
+
63
+ 不传 `chat` 且 `options` 未配置 `suggestedCommands` 时,空状态面板自动展示与内置工具对应的默认可点击命令(点击即发送对应指令):
64
+
65
+ | 命令 | 指令 | 对应内置工具 |
66
+ |---|---|---|
67
+ | 现在几点 | 现在几点了? | `get_current_time` |
68
+ | 帮我计算 | 帮我计算 (1+2)*3 | `calculate_expression` |
69
+ | 生成 UUID | 帮我生成一个 UUID | `generate_uuid` |
70
+ | 客户端信息 | 获取我的客户端信息 | `get_client_info` |
71
+
72
+ 规则:
73
+ - `options.suggestedCommands` 已传(含空数组)→ 以宿主配置为准
74
+ - `builtInTools: false` → 不展示默认命令
75
+ - `builtInTools` 为名称数组 → 只展示数组内启用工具对应的命令
76
+
77
+ ### 内置工具
78
+
79
+ 插件默认启用一组开箱即用的通用工具(`BUILTIN_TOOL_PACKAGE`),不依赖宿主 `onToolCall`:
80
+
81
+ | 工具 | 说明 |
82
+ |---|---|
83
+ | `get_current_time` | 获取当前时间、日期、时区与星期 |
84
+ | `calculate_expression` | 安全计算数学表达式(支持 `+ - * / %` 和括号,白名单解析不用 eval) |
85
+ | `generate_uuid` | 生成 UUID v4 |
86
+ | `get_client_info` | 浏览器基本信息(UA、平台、语言、屏幕尺寸) |
87
+
88
+ 通过 `useAgentChat` 的 `builtInTools` 配置:
89
+
90
+ ```ts
91
+ useAgentChat({
92
+ toolPackages: [...],
93
+ builtInTools: true, // 默认:全部启用
94
+ // builtInTools: ['get_current_time', 'calculate_expression'], // 按需启用
95
+ // builtInTools: false, // 关闭
96
+ })
97
+ ```
98
+
99
+ 宿主如在 `toolPackages` 中注册同名的工具,**将覆盖内置工具**的定义与执行。
100
+
101
+ #### 自定义 systemPrompt 时内置工具仍可见
102
+
103
+ 宿主通过 `useAgentChat` 传入自定义 `systemPrompt` 时,插件会在其末尾**自动追加**一段内置工具描述(复用 `buildSystemPrompt` 的包段格式,如 `【内置工具】...` + 工具列表),因此 LLM 询问"你能做什么"时也会列举开箱即用的内置工具。内置工具关闭(`builtInTools: false` 或过滤后为空)时不追加。
104
+
105
+ 此外,无论是否自定义 `systemPrompt`、是否开启内置工具,插件都会在提示词末尾**追加"重复指令处理规则"**:用户再次发送相同或类似指令(即使之前已执行过)时,LLM 必须重新调用对应工具再次执行,不得以"已经执行过"等理由拒绝,也不能用历史结果代替重新执行。
106
+
40
107
  ## 核心概念
41
108
 
42
109
  ### ToolPackage(工具包)
@@ -129,11 +196,41 @@ chat.eventBus.dispatch({ type: 'scheme:feedback:success', timestamp: Date.now(),
129
196
  - 默认 `sendFileToLLM: false`,LLM 只能看到文件名/类型,看不到文件内容
130
197
  - 工具通过 `fileId` 从 `fileStore` 取回数据(如 `open_mapview_file` 展示空间数据)
131
198
 
199
+ #### FileAttachment 与 Blob
200
+
201
+ `FileAttachment` 新增可选字段 `blob?: Blob`,保存原始文件的 Blob 引用(**所有文件**都会存,`File` 本身即是 Blob,零额外内存开销):
202
+
203
+ ```ts
204
+ interface FileAttachment {
205
+ id: string
206
+ name: string
207
+ size: number
208
+ type: string
209
+ data: string // 文本=原始内容;二进制=base64 data URL
210
+ blob?: Blob // 原始文件 Blob 引用(仅运行时有效)
211
+ }
212
+ ```
213
+
214
+ - **`.tif`/`.tiff` 优化**:不生成 base64 `data`(`data` 为空字符串),仅保留 `blob` 引用,避免大栅格文件的内存开销
215
+ - **持久化限制**:Blob 无法被 `JSON.stringify`(会变成 `{}`)。同会话内 `f.blob` 完好;刷新/换端后需回退 `data`
216
+ - **获取 Blob**:使用 `blobFromAttachment(f)` 工具——优先返回 `f.blob`,否则把 base64 `data` 转成 Blob(覆盖刷新场景),两者都无则返回 `null`:
217
+ ```ts
218
+ import { blobFromAttachment, isTifFile } from 'agent-tool-chat'
219
+ const blob = blobFromAttachment(file) // Blob | null
220
+ if (blob) await blob.arrayBuffer() // 如 geotiff.js 解析
221
+ ```
222
+ - **消费方约定**:拿到 `.tif` 文件对象后优先用 `blobFromAttachment(f)`;返回 `null` 说明刷新后数据丢失,提示用户重新上传
223
+
224
+ ### Markdown 渲染
225
+
226
+ - AI 回复按 Markdown 渲染(`markdown-it` 实现,经 `DOMPurify` 清洗,禁用原始 HTML)
227
+ - 支持标题、列表、代码块、表格、引用、链接、分割线等,样式跟随 Element Plus 主题变量
228
+
132
229
  ## 使用说明
133
230
 
134
231
  1. **定义工具包** — 创建 `ToolPackage`,包含工具定义(`displayHints`)和可选渲染组件。
135
- 2. **创建 `useAgentChat`** — 传入工具包、宿主 `onToolCall` 回调,可选 `businessEvents`、`systemPrompt`、`provider`。
136
- 3. **渲染 `ChatPanel`** — 将返回的 `AgentChatAPI` 绑定到 `chat` prop
232
+ 2. **创建 `useAgentChat`** — 传入工具包、宿主 `onToolCall` 回调,可选 `businessEvents`、`systemPrompt`、`provider`、`suggestedCommands`。
233
+ 3. **渲染 `ChatPanel`** — 将返回的 `AgentChatAPI` 绑定到 `chat` prop;也可不传 `chat`,仅传可选 `options`(或不传,直接开箱即用内置工具)。
137
234
  4. **文件上传** — `ChatInput` 支持文件选择,工具通过 `fileId` 引用。
138
235
  5. **业务联动** — 页面操作完成后 `eventBus.dispatch` 回灌,驱动 LLM 回复或延迟建议。
139
236
  6. **持久化** — 消息与设置自动保存(direct 模式 localStorage;proxy 模式 POST `/api/messages`,按 device_id 区分)。
@@ -149,7 +246,7 @@ chat.eventBus.dispatch({ type: 'scheme:feedback:success', timestamp: Date.now(),
149
246
 
150
247
  ```ts
151
248
  useAgentChat(options) // 核心组合式函数,返回 AgentChatAPI
152
- ChatPanel // 对话面板(接收 chat prop)
249
+ ChatPanel // 对话面板(chat / options prop,chat 可选)
153
250
  buildSystemPrompt(packages) // 构建系统提示词
154
251
  createDeepSeekProvider() // 直连 DeepSeek LLM 提供者
155
252
  createProxyProvider() // 代理模式 LLM 提供者
@@ -1 +1 @@
1
- .render-block[data-v-0cb2fd61]{margin:8px 0;padding:8px 0;width:100%}.render-block__component[data-v-0cb2fd61]{border-radius:8px;background:var(--el-fill-color-lighter);box-shadow:0 0 10px #0000001a}.render-block__title[data-v-0cb2fd61]{font-weight:600;font-size:14px;margin-bottom:6px;color:var(--el-text-color-primary)}.render-block__table[data-v-0cb2fd61]{width:100%;max-width:100%}.render-block__cards[data-v-0cb2fd61]{display:flex;flex-direction:column;gap:8px}.card-item[data-v-0cb2fd61]{border:1px solid var(--el-border-color);border-radius:8px;padding:10px 14px;background:var(--el-fill-color-lighter)}.card-field[data-v-0cb2fd61]{display:flex;gap:6px;font-size:13px;line-height:1.8}.card-label[data-v-0cb2fd61]{font-weight:600;color:var(--el-text-color-secondary);min-width:80px}.card-value[data-v-0cb2fd61]{color:var(--el-text-color-primary)}.render-block__list[data-v-0cb2fd61]{display:flex;flex-direction:column;gap:4px}.list-item[data-v-0cb2fd61]{padding:6px 10px;font-size:13px;border-left:3px solid var(--el-color-primary);background:var(--el-fill-color-lighter);border-radius:0 4px 4px 0}.suggested-next[data-v-0e0e9b65]{display:flex;align-items:center;gap:8px;padding:8px 12px;margin:6px 0;background:var(--el-color-primary-light-9);border:1px solid var(--el-color-primary-light-7);border-radius:8px;font-size:13px}.suggested-next__icon[data-v-0e0e9b65]{font-size:15px;flex-shrink:0}.suggested-next__text[data-v-0e0e9b65]{flex:1;color:var(--el-text-color-regular)}.chat-message[data-v-af392c78]{display:flex;gap:10px;padding:12px 0}.chat-message.role-user[data-v-af392c78]{flex-direction:row-reverse}.message-avatar[data-v-af392c78]{width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:16px}.role-user .message-avatar[data-v-af392c78]{background:var(--el-color-primary);color:#fff}.role-assistant .message-avatar[data-v-af392c78]{background:var(--el-color-success);color:#fff}.message-body[data-v-af392c78]{max-width:80%;min-width:0}.role-user .message-body[data-v-af392c78]{background:var(--el-color-primary-light-9);padding:8px 14px;border-radius:12px 4px 12px 12px;box-shadow:0 0 10px #0000001a}.role-assistant .message-body[data-v-af392c78]{background:var(--el-fill-color-lighter);padding:8px 14px;border-radius:4px 12px 12px;display:flex;flex-direction:column;box-shadow:0 0 10px #0000001a}.message-user-text[data-v-af392c78]{font-size:14px;line-height:1.5;color:var(--el-text-color-primary);white-space:pre-wrap;word-break:break-word}.message-content[data-v-af392c78]{font-size:14px;line-height:1.6;color:var(--el-text-color-primary);white-space:pre-wrap;word-break:break-word;background:transparent;border:none;outline:none;box-shadow:none;height:auto}.message-cursor[data-v-af392c78]{display:inline-block;animation:blink-af392c78 .8s step-end infinite;color:var(--el-color-primary);font-size:16px}@keyframes blink-af392c78{50%{opacity:0}}.message-error[data-v-af392c78]{margin-top:4px;font-size:12px;color:var(--el-color-danger)}.message-reasoning[data-v-af392c78]{margin-bottom:8px}.message-reasoning details[data-v-af392c78]{font-size:13px}.message-reasoning summary[data-v-af392c78]{cursor:pointer;color:var(--el-color-info);font-size:12px}.message-reasoning pre[data-v-af392c78]{margin:6px 0 0;padding:8px;background:var(--el-fill-color);border-radius:6px;font-size:12px;white-space:pre-wrap;word-break:break-word;max-height:200px;overflow-y:auto}.message-files[data-v-af392c78]{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.message-file[data-v-af392c78]{display:flex;align-items:center;gap:8px;padding:6px 10px;border:1px solid var(--el-border-color);border-radius:8px;background:var(--el-bg-color);font-size:12px}.message-file.is-image[data-v-af392c78]{padding:4px;flex-direction:column;align-items:flex-start}.file-image[data-v-af392c78]{max-width:200px;max-height:200px;border-radius:6px;object-fit:contain;cursor:pointer}.file-info[data-v-af392c78]{display:flex;flex-direction:column;gap:2px}.file-name[data-v-af392c78]{color:var(--el-text-color-primary);font-weight:500;max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-size[data-v-af392c78]{color:var(--el-text-color-secondary);font-size:11px}.chat-input[data-v-8fcb870c]{padding:12px 16px;border-top:1px solid var(--el-border-color-lighter);background:var(--el-bg-color);display:flex;flex-direction:column}.chat-input__files[data-v-8fcb870c]{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}.chat-input__wrap[data-v-8fcb870c]{display:flex;align-items:flex-end;gap:8px;background:var(--el-fill-color-light);border:1px solid var(--el-border-color);border-radius:12px;padding:6px 6px 6px 12px;transition:border-color .2s,box-shadow .2s}.chat-input__wrap[data-v-8fcb870c]:focus-within{border-color:var(--el-color-primary);box-shadow:0 0 0 2px var(--el-color-primary-light-8)}.chat-input__wrap[data-v-8fcb870c] .el-textarea__inner{border:none;background:transparent;box-shadow:none;padding:4px 0;line-height:1.6;font-size:14px}.chat-input__wrap[data-v-8fcb870c] .el-textarea__inner:focus{box-shadow:none}.chat-input__actions[data-v-8fcb870c]{flex-shrink:0;display:flex;align-items:center;gap:2px;padding-bottom:2px}.form-tip[data-v-9634bbdc]{font-size:12px;color:var(--el-text-color-secondary);line-height:1.6;margin-top:4px}.form-tip-inline[data-v-9634bbdc]{margin-left:8px;font-size:12px;color:var(--el-text-color-secondary)}.temp-row[data-v-9634bbdc]{display:flex;align-items:center;gap:12px;width:100%}.temp-val[data-v-9634bbdc]{width:28px;text-align:right;font-size:13px;color:var(--el-text-color-secondary)}.chat-panel-root[data-v-d36abbf3]{position:absolute;bottom:100px;right:100px;z-index:1999}.ai-fab[data-v-d36abbf3]{position:fixed;right:22px;bottom:25px;z-index:2000;display:flex;align-items:center;gap:8px;height:52px;padding:0 22px 0 18px;border-radius:26px;color:#fff;font-size:15px;font-weight:600;cursor:pointer;background:linear-gradient(135deg,#009688,#2d8cf0);box-shadow:0 6px 24px #2d8cf080;transition:transform .25s cubic-bezier(.34,1.56,.64,1),box-shadow .25s;-webkit-user-select:none;user-select:none;overflow:hidden;isolation:isolate;animation:ai-fab-float-d36abbf3 3.6s ease-in-out infinite}@keyframes ai-fab-float-d36abbf3{0%,to{transform:translateY(0)}50%{transform:translateY(-6px)}}.ai-fab[data-v-d36abbf3]:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:inherit;background:linear-gradient(105deg,transparent 30%,rgba(255,255,255,.25) 50%,transparent 70%);background-size:200% 100%;background-position:100% 0;animation:ai-fab-shimmer-d36abbf3 4s ease-in-out infinite;z-index:-1;pointer-events:none}@keyframes ai-fab-shimmer-d36abbf3{0%,to{background-position:100% 0}50%{background-position:0 0}}.ai-fab[data-v-d36abbf3]:after{content:"";position:absolute;top:-4px;right:-4px;bottom:-4px;left:-4px;border-radius:inherit;border:2px solid rgba(45,140,240,.35);animation:ai-fab-pulse-d36abbf3 2.4s ease-in-out infinite;pointer-events:none;z-index:-2}@keyframes ai-fab-pulse-d36abbf3{0%,to{opacity:.6;transform:scale(1)}50%{opacity:0;transform:scale(1.12)}}.ai-fab__icon[data-v-d36abbf3]{font-size:22px;filter:drop-shadow(0 0 4px rgba(255,255,255,.4));transition:transform .3s cubic-bezier(.34,1.56,.64,1)}.ai-fab__label[data-v-d36abbf3]{line-height:1;text-shadow:0 1px 4px rgba(0,0,0,.15)}.ai-fab[data-v-d36abbf3]:hover{animation:none;transform:translateY(-4px) scale(1.04);box-shadow:0 12px 32px #2d8cf099}.ai-fab[data-v-d36abbf3]:hover:before{animation:none;background-position:0 0}.ai-fab--active[data-v-d36abbf3]{animation:none;box-shadow:0 4px 16px #2d8cf066}.ai-fab--active[data-v-d36abbf3]:after{animation:none;opacity:0}.ai-fab--active[data-v-d36abbf3]:before{animation:none}.ai-fab--active .ai-fab__icon[data-v-d36abbf3]{transform:rotate(45deg)}.chat-panel[data-v-d36abbf3]{position:fixed;bottom:25px;right:22px;z-index:9999;display:flex;flex-direction:column;height:680px;width:560px;min-height:400px;background:var(--el-bg-color);box-shadow:0 0 12px #0000006b;border-radius:8px}.chat-panel__header[data-v-d36abbf3]{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--el-border-color-lighter);flex-shrink:0}.chat-panel__title[data-v-d36abbf3]{display:flex;align-items:center;gap:8px;font-size:15px;font-weight:600;color:var(--el-text-color-primary)}.title-icon[data-v-d36abbf3]{color:var(--el-color-primary);font-size:18px}.chat-panel__ops[data-v-d36abbf3]{display:flex;gap:4px}.chat-panel__body[data-v-d36abbf3]{flex:1;overflow-y:auto;padding:0 16px;min-height:0;scrollbar-width:thin;scrollbar-color:var(--el-border-color-darker) transparent}.chat-panel__body[data-v-d36abbf3]::-webkit-scrollbar{width:8px}.chat-panel__body[data-v-d36abbf3]::-webkit-scrollbar-track{background:var(--el-fill-color-lighter);border-radius:4px}.chat-panel__body[data-v-d36abbf3]::-webkit-scrollbar-thumb{background:var(--el-border-color-darker);border-radius:4px;border:2px solid transparent;background-clip:content-box}.chat-panel__body[data-v-d36abbf3]::-webkit-scrollbar-thumb:hover{background:var(--el-text-color-secondary);background-clip:content-box}.chat-empty[data-v-d36abbf3]{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:20px;gap:14px}.chat-empty__logo[data-v-d36abbf3]{width:64px;height:64px;border-radius:18px;background:linear-gradient(135deg,#009688,#2d8cf0);color:#fff;display:flex;align-items:center;justify-content:center;font-size:32px;box-shadow:0 8px 24px #2d8cf04d}.chat-empty h3[data-v-d36abbf3]{margin:0;font-size:18px;color:var(--el-text-color-primary)}.chat-empty__desc[data-v-d36abbf3]{margin:0;font-size:13px;color:var(--el-text-color-secondary);line-height:1.6}.chat-empty__desc .hl[data-v-d36abbf3]{color:var(--el-color-primary);font-weight:600}.chat-panel__footer[data-v-d36abbf3]{flex-shrink:0}.chat-panel__stop[data-v-d36abbf3]{display:flex;justify-content:center;padding:6px 0 0}.chat-panel__error[data-v-d36abbf3]{padding:8px 16px 0}.fade-enter-active[data-v-d36abbf3],.fade-leave-active[data-v-d36abbf3]{transition:opacity .2s}.fade-enter-from[data-v-d36abbf3],.fade-leave-to[data-v-d36abbf3]{opacity:0}.chat-panel--fullscreen[data-v-d36abbf3]{position:fixed;top:5%;right:10%;bottom:5%;left:10%;z-index:9999;height:90vh!important;width:80%!important}
1
+ .render-block[data-v-dd314030]{margin:8px 0;padding:8px 0;width:100%}.render-block__component[data-v-dd314030]{border-radius:8px;background:var(--el-fill-color-lighter);box-shadow:0 0 10px #0000001a}.render-block__title[data-v-dd314030]{font-weight:600;font-size:14px;margin-bottom:6px;color:var(--el-text-color-primary)}.render-block__table[data-v-dd314030]{width:100%;max-width:100%}.render-block__cards[data-v-dd314030]{display:flex;flex-direction:column;gap:8px}.card-item[data-v-dd314030]{border:1px solid var(--el-border-color);border-radius:8px;padding:10px 14px;background:var(--el-fill-color-lighter)}.card-field[data-v-dd314030]{display:flex;gap:6px;font-size:13px;line-height:1.8}.card-label[data-v-dd314030]{font-weight:600;color:var(--el-text-color-secondary);min-width:80px}.card-value[data-v-dd314030]{color:var(--el-text-color-primary)}.render-block__list[data-v-dd314030]{display:flex;flex-direction:column;gap:4px}.list-item[data-v-dd314030]{padding:6px 10px;font-size:13px;border-left:3px solid var(--el-color-primary);background:var(--el-fill-color-lighter);border-radius:0 4px 4px 0}.suggested-next[data-v-0e0e9b65]{display:flex;align-items:center;gap:8px;padding:8px 12px;margin:6px 0;background:var(--el-color-primary-light-9);border:1px solid var(--el-color-primary-light-7);border-radius:8px;font-size:13px}.suggested-next__icon[data-v-0e0e9b65]{font-size:15px;flex-shrink:0}.suggested-next__text[data-v-0e0e9b65]{flex:1;color:var(--el-text-color-regular)}.chat-message[data-v-61b9c7d3]{display:flex;gap:10px;padding:12px 0}.chat-message.role-user[data-v-61b9c7d3]{flex-direction:row-reverse}.message-avatar[data-v-61b9c7d3]{width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:16px}.role-user .message-avatar[data-v-61b9c7d3]{background:var(--el-color-primary);color:#fff}.role-assistant .message-avatar[data-v-61b9c7d3]{background:var(--el-color-success);color:#fff}.message-body[data-v-61b9c7d3]{max-width:80%;min-width:0}.role-user .message-body[data-v-61b9c7d3]{background:var(--el-color-primary-light-9);padding:8px 14px;border-radius:12px 4px 12px 12px;box-shadow:0 0 10px #0000001a}.role-assistant .message-body[data-v-61b9c7d3]{background:var(--el-fill-color-lighter);padding:8px 14px;border-radius:4px 12px 12px;display:flex;flex-direction:column;box-shadow:0 0 10px #0000001a}.message-user-text[data-v-61b9c7d3]{font-size:14px;line-height:1.5;color:var(--el-text-color-primary);white-space:pre-wrap;word-break:break-word}.message-content[data-v-61b9c7d3]{font-size:14px;line-height:1.6;color:var(--el-text-color-primary);word-break:break-word;background:transparent;border:none;outline:none;box-shadow:none;height:auto;overflow-wrap:break-word}.message-content[data-v-61b9c7d3] p{margin:0 0 8px}.message-content[data-v-61b9c7d3] p:last-child{margin-bottom:0}.message-content[data-v-61b9c7d3] h1,.message-content[data-v-61b9c7d3] h2,.message-content[data-v-61b9c7d3] h3,.message-content[data-v-61b9c7d3] h4,.message-content[data-v-61b9c7d3] h5,.message-content[data-v-61b9c7d3] h6{margin:12px 0 8px;font-weight:600;line-height:1.4;color:var(--el-text-color-primary)}.message-content[data-v-61b9c7d3] h1{font-size:20px}.message-content[data-v-61b9c7d3] h2{font-size:18px;padding-bottom:4px;border-bottom:1px solid var(--el-border-color-lighter)}.message-content[data-v-61b9c7d3] h3{font-size:16px}.message-content[data-v-61b9c7d3] h4{font-size:15px}.message-content[data-v-61b9c7d3] h5,.message-content[data-v-61b9c7d3] h6{font-size:14px}.message-content[data-v-61b9c7d3] strong{font-weight:600}.message-content[data-v-61b9c7d3] em{font-style:italic}.message-content[data-v-61b9c7d3] ul,.message-content[data-v-61b9c7d3] ol{margin:0 0 8px;padding-left:20px}.message-content[data-v-61b9c7d3] ul:last-child,.message-content[data-v-61b9c7d3] ol:last-child{margin-bottom:0}.message-content[data-v-61b9c7d3] li{margin:2px 0}.message-content[data-v-61b9c7d3] li>ul,.message-content[data-v-61b9c7d3] li>ol{margin:0}.message-content[data-v-61b9c7d3] code{padding:1px 5px;margin:0 2px;font-size:12px;font-family:Consolas,Monaco,Courier New,monospace;background:var(--el-fill-color);color:var(--el-color-primary);border-radius:4px}.message-content[data-v-61b9c7d3] pre{margin:8px 0;padding:10px 12px;background:var(--el-bg-color);border:1px solid var(--el-border-color-lighter);border-radius:6px;overflow-x:auto}.message-content[data-v-61b9c7d3] pre code{display:block;padding:0;margin:0;font-size:12px;line-height:1.6;background:transparent;color:var(--el-text-color-primary);border-radius:0;white-space:pre}.message-content[data-v-61b9c7d3] blockquote{margin:8px 0;padding:4px 12px;border-left:3px solid var(--el-color-primary-light-5);background:var(--el-fill-color-lighter);border-radius:0 6px 6px 0;color:var(--el-text-color-regular)}.message-content[data-v-61b9c7d3] blockquote p{margin:0}.message-content[data-v-61b9c7d3] table{width:100%;margin:8px 0;border-collapse:collapse;font-size:13px}.message-content[data-v-61b9c7d3] th,.message-content[data-v-61b9c7d3] td{padding:6px 10px;border:1px solid var(--el-border-color-lighter);text-align:left}.message-content[data-v-61b9c7d3] th{background:var(--el-fill-color);font-weight:600;color:var(--el-text-color-primary)}.message-content[data-v-61b9c7d3] tbody tr:nth-child(2n){background:var(--el-fill-color-lighter)}.message-content[data-v-61b9c7d3] a{color:var(--el-color-primary);text-decoration:none}.message-content[data-v-61b9c7d3] a:hover{text-decoration:underline}.message-content[data-v-61b9c7d3] img{max-width:100%;border-radius:6px}.message-content[data-v-61b9c7d3] hr{margin:12px 0;border:none;border-top:1px solid var(--el-border-color-lighter)}.message-cursor[data-v-61b9c7d3]{display:inline-block;animation:blink-61b9c7d3 .8s step-end infinite;color:var(--el-color-primary);font-size:16px}@keyframes blink-61b9c7d3{50%{opacity:0}}.message-error[data-v-61b9c7d3]{margin-top:4px;font-size:12px;color:var(--el-color-danger)}.message-reasoning[data-v-61b9c7d3]{margin-bottom:8px}.message-reasoning details[data-v-61b9c7d3]{font-size:13px}.message-reasoning summary[data-v-61b9c7d3]{cursor:pointer;color:var(--el-color-info);font-size:12px}.message-reasoning pre[data-v-61b9c7d3]{margin:6px 0 0;padding:8px;background:var(--el-fill-color);border-radius:6px;font-size:12px;white-space:pre-wrap;word-break:break-word;max-height:200px;overflow-y:auto}.message-files[data-v-61b9c7d3]{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.message-file[data-v-61b9c7d3]{display:flex;align-items:center;gap:8px;padding:6px 10px;border:1px solid var(--el-border-color);border-radius:8px;background:var(--el-bg-color);font-size:12px}.message-file.is-image[data-v-61b9c7d3]{padding:4px;flex-direction:column;align-items:flex-start}.file-image[data-v-61b9c7d3]{max-width:200px;max-height:200px;border-radius:6px;object-fit:contain;cursor:pointer}.file-info[data-v-61b9c7d3]{display:flex;flex-direction:column;gap:2px}.file-name[data-v-61b9c7d3]{color:var(--el-text-color-primary);font-weight:500;max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-size[data-v-61b9c7d3]{color:var(--el-text-color-secondary);font-size:11px}.chat-input[data-v-fcb6ee4c]{padding:12px 16px;border-top:1px solid var(--el-border-color-lighter);background:var(--el-bg-color);display:flex;flex-direction:column}.chat-input__files[data-v-fcb6ee4c]{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}.chat-input__preview[data-v-fcb6ee4c]{margin-left:auto;height:24px;padding:0 8px}.chat-input__wrap[data-v-fcb6ee4c]{display:flex;align-items:flex-end;gap:8px;background:var(--el-fill-color-light);border:1px solid var(--el-border-color);border-radius:12px;padding:6px 6px 6px 12px;transition:border-color .2s,box-shadow .2s}.chat-input__wrap[data-v-fcb6ee4c]:focus-within{border-color:var(--el-color-primary);box-shadow:0 0 0 2px var(--el-color-primary-light-8)}.chat-input__wrap[data-v-fcb6ee4c] .el-textarea__inner{border:none;background:transparent;box-shadow:none;padding:4px 0;line-height:1.6;font-size:14px}.chat-input__wrap[data-v-fcb6ee4c] .el-textarea__inner:focus{box-shadow:none}.chat-input__actions[data-v-fcb6ee4c]{flex-shrink:0;display:flex;align-items:center;gap:2px;padding-bottom:2px}.form-tip[data-v-9634bbdc]{font-size:12px;color:var(--el-text-color-secondary);line-height:1.6;margin-top:4px}.form-tip-inline[data-v-9634bbdc]{margin-left:8px;font-size:12px;color:var(--el-text-color-secondary)}.temp-row[data-v-9634bbdc]{display:flex;align-items:center;gap:12px;width:100%}.temp-val[data-v-9634bbdc]{width:28px;text-align:right;font-size:13px;color:var(--el-text-color-secondary)}.chat-panel-root[data-v-9c108ff6]{position:absolute;bottom:100px;right:100px;z-index:1999}.ai-fab[data-v-9c108ff6]{position:fixed;right:22px;bottom:25px;z-index:2000;display:flex;align-items:center;gap:8px;height:52px;padding:0 22px 0 18px;border-radius:26px;color:#fff;font-size:15px;font-weight:600;cursor:pointer;background:linear-gradient(135deg,#009688,#2d8cf0);box-shadow:0 6px 24px #2d8cf080;transition:transform .25s cubic-bezier(.34,1.56,.64,1),box-shadow .25s;-webkit-user-select:none;user-select:none;overflow:hidden;isolation:isolate;animation:ai-fab-float-9c108ff6 3.6s ease-in-out infinite}@keyframes ai-fab-float-9c108ff6{0%,to{transform:translateY(0)}50%{transform:translateY(-6px)}}.ai-fab[data-v-9c108ff6]:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:inherit;background:linear-gradient(105deg,transparent 30%,rgba(255,255,255,.25) 50%,transparent 70%);background-size:200% 100%;background-position:100% 0;animation:ai-fab-shimmer-9c108ff6 4s ease-in-out infinite;z-index:-1;pointer-events:none}@keyframes ai-fab-shimmer-9c108ff6{0%,to{background-position:100% 0}50%{background-position:0 0}}.ai-fab[data-v-9c108ff6]:after{content:"";position:absolute;top:-4px;right:-4px;bottom:-4px;left:-4px;border-radius:inherit;border:2px solid rgba(45,140,240,.35);animation:ai-fab-pulse-9c108ff6 2.4s ease-in-out infinite;pointer-events:none;z-index:-2}@keyframes ai-fab-pulse-9c108ff6{0%,to{opacity:.6;transform:scale(1)}50%{opacity:0;transform:scale(1.12)}}.ai-fab__icon[data-v-9c108ff6]{font-size:22px;filter:drop-shadow(0 0 4px rgba(255,255,255,.4));transition:transform .3s cubic-bezier(.34,1.56,.64,1)}.ai-fab__label[data-v-9c108ff6]{line-height:1;text-shadow:0 1px 4px rgba(0,0,0,.15)}.ai-fab[data-v-9c108ff6]:hover{animation:none;transform:translateY(-4px) scale(1.04);box-shadow:0 12px 32px #2d8cf099}.ai-fab[data-v-9c108ff6]:hover:before{animation:none;background-position:0 0}.ai-fab--active[data-v-9c108ff6]{animation:none;box-shadow:0 4px 16px #2d8cf066}.ai-fab--active[data-v-9c108ff6]:after{animation:none;opacity:0}.ai-fab--active[data-v-9c108ff6]:before{animation:none}.ai-fab--active .ai-fab__icon[data-v-9c108ff6]{transform:rotate(45deg)}.chat-panel[data-v-9c108ff6]{position:fixed;bottom:25px;right:22px;z-index:9999;display:flex;flex-direction:column;height:680px;width:560px;min-height:400px;background:var(--el-bg-color);box-shadow:0 0 12px #0000006b;border-radius:8px}.chat-panel__header[data-v-9c108ff6]{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--el-border-color-lighter);flex-shrink:0}.chat-panel__title[data-v-9c108ff6]{display:flex;align-items:center;gap:8px;font-size:15px;font-weight:600;color:var(--el-text-color-primary)}.title-icon[data-v-9c108ff6]{color:var(--el-color-primary);font-size:18px}.chat-panel__ops[data-v-9c108ff6]{display:flex;gap:4px}.chat-panel__body[data-v-9c108ff6]{flex:1;overflow-y:auto;padding:0 16px;min-height:0;scrollbar-width:thin;scrollbar-color:var(--el-border-color-darker) transparent}.chat-panel__body[data-v-9c108ff6]::-webkit-scrollbar{width:8px}.chat-panel__body[data-v-9c108ff6]::-webkit-scrollbar-track{background:var(--el-fill-color-lighter);border-radius:4px}.chat-panel__body[data-v-9c108ff6]::-webkit-scrollbar-thumb{background:var(--el-border-color-darker);border-radius:4px;border:2px solid transparent;background-clip:content-box}.chat-panel__body[data-v-9c108ff6]::-webkit-scrollbar-thumb:hover{background:var(--el-text-color-secondary);background-clip:content-box}.chat-empty[data-v-9c108ff6]{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:14px}.chat-empty__logo[data-v-9c108ff6]{width:64px;height:64px;border-radius:18px;background:linear-gradient(135deg,#009688,#2d8cf0);color:#fff;display:flex;align-items:center;justify-content:center;font-size:32px;box-shadow:0 8px 24px #2d8cf04d}.chat-empty h3[data-v-9c108ff6]{margin:0;font-size:18px;color:var(--el-text-color-primary)}.chat-empty__desc[data-v-9c108ff6]{margin:0;font-size:13px;color:var(--el-text-color-secondary);line-height:1.6}.chat-empty__desc .hl[data-v-9c108ff6]{color:var(--el-color-primary);font-weight:600}.chat-empty__commands[data-v-9c108ff6]{display:flex;flex-wrap:wrap;justify-content:center;gap:8px}.chat-empty__commands .el-button[data-v-9c108ff6]{margin-left:0}.chat-panel__footer[data-v-9c108ff6]{flex-shrink:0}.chat-panel__stop[data-v-9c108ff6]{display:flex;justify-content:center;padding:6px 0 0}.chat-panel__error[data-v-9c108ff6]{padding:8px 16px 0}.fade-enter-active[data-v-9c108ff6],.fade-leave-active[data-v-9c108ff6]{transition:opacity .2s}.fade-enter-from[data-v-9c108ff6],.fade-leave-to[data-v-9c108ff6]{opacity:0}.chat-panel--fullscreen[data-v-9c108ff6]{position:fixed;top:5%;right:10%;bottom:5%;left:10%;z-index:9999;height:90vh!important;width:80%!important}
@@ -0,0 +1,5 @@
1
+ import { BUILTIN_TOOL_PACKAGE } from './modules/demo/tools';
2
+ export { BUILTIN_TOOL_PACKAGE };
3
+ declare const BUILTIN_HANDLERS: Record<string, (args: any) => any>;
4
+ export declare function runBuiltinToolHandler(name: string, args: any): any;
5
+ export type BuiltinToolName = keyof typeof BUILTIN_HANDLERS;
@@ -0,0 +1,3 @@
1
+ import { ToolPackage } from '../../../types';
2
+ export declare const BUILTIN_TOOL_PACKAGE: ToolPackage;
3
+ export declare function createBuiltinToolHandlers(): Record<string, (args: any) => any>;
@@ -1,4 +1,4 @@
1
- import { ChatMessage as ChatMessageType, ChatSettings as ChatSettingsType, ToolPackage, FileAttachment } from '../types';
1
+ import { ChatMessage as ChatMessageType, ChatSettings as ChatSettingsType, ToolPackage, ChatCommand, FileAttachment } from '../types';
2
2
  import { EventBus } from '../core/event-bus';
3
3
  export interface AgentChatAPI {
4
4
  messages: import('vue').Ref<ChatMessageType[]>;
@@ -15,14 +15,16 @@ export interface AgentChatAPI {
15
15
  stopGeneration: () => void;
16
16
  clearMessages: () => void;
17
17
  saveSettings: (s: ChatSettingsType) => void;
18
+ suggestedCommands: ChatCommand[];
18
19
  }
19
20
  type __VLS_Props = {
20
- chat: AgentChatAPI;
21
+ chat?: AgentChatAPI;
22
+ options?: import('../types').AgentChatOptions;
21
23
  showFab?: boolean;
22
24
  };
23
25
  declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
24
26
  showFab: boolean;
25
- }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
27
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {
26
28
  scrollRef: HTMLDivElement;
27
29
  }, HTMLDivElement>;
28
30
  export default _default;
@@ -1,5 +1,5 @@
1
1
  import { EventBus } from '../core/event-bus';
2
- import { AgentChatOptions, ChatMessage, ChatSettings, ToolPackage, FileAttachment } from '../types';
2
+ import { AgentChatOptions, ChatMessage, ChatSettings, ChatCommand, ToolPackage, FileAttachment } from '../types';
3
3
  export declare function useAgentChat(options: AgentChatOptions): {
4
4
  messages: import('vue').Ref<{
5
5
  id: string;
@@ -35,6 +35,15 @@ export declare function useAgentChat(options: AgentChatOptions): {
35
35
  size: number;
36
36
  type: string;
37
37
  data: string;
38
+ blob?: {
39
+ readonly size: number;
40
+ readonly type: string;
41
+ arrayBuffer: () => Promise<ArrayBuffer>;
42
+ bytes: () => Promise<Uint8Array<ArrayBuffer>>;
43
+ slice: (start?: number, end?: number, contentType?: string) => Blob;
44
+ stream: () => ReadableStream<Uint8Array<ArrayBuffer>>;
45
+ text: () => Promise<string>;
46
+ };
38
47
  }[];
39
48
  toolResults?: {
40
49
  callId: string;
@@ -78,6 +87,15 @@ export declare function useAgentChat(options: AgentChatOptions): {
78
87
  size: number;
79
88
  type: string;
80
89
  data: string;
90
+ blob?: {
91
+ readonly size: number;
92
+ readonly type: string;
93
+ arrayBuffer: () => Promise<ArrayBuffer>;
94
+ bytes: () => Promise<Uint8Array<ArrayBuffer>>;
95
+ slice: (start?: number, end?: number, contentType?: string) => Blob;
96
+ stream: () => ReadableStream<Uint8Array<ArrayBuffer>>;
97
+ text: () => Promise<string>;
98
+ };
81
99
  }[];
82
100
  toolResults?: {
83
101
  callId: string;
@@ -117,4 +135,5 @@ export declare function useAgentChat(options: AgentChatOptions): {
117
135
  stopGeneration: () => void;
118
136
  clearMessages: () => Promise<void>;
119
137
  saveSettings: (next: ChatSettings) => void;
138
+ suggestedCommands: ChatCommand[];
120
139
  };
@@ -1,2 +1,4 @@
1
1
  import { ToolPackage } from '../types';
2
+ export declare function buildPackageSection(pkg: ToolPackage): string;
2
3
  export declare function buildSystemPrompt(packages: ToolPackage[]): string;
4
+ export declare const REPEAT_COMMAND_RULE = "--- \u91CD\u590D\u6307\u4EE4\u5904\u7406\u89C4\u5219 ---\n\u5982\u679C\u7528\u6237\u518D\u6B21\u53D1\u9001\u76F8\u540C\u6216\u7C7B\u4F3C\u7684\u6307\u4EE4\uFF08\u5373\u4F7F\u4E4B\u524D\u5DF2\u7ECF\u6267\u884C\u8FC7\uFF09\uFF0C\u5FC5\u987B\u91CD\u65B0\u8C03\u7528\u5BF9\u5E94\u7684\u5DE5\u5177\u518D\u6B21\u6267\u884C\u3002\n\u4E0D\u5F97\u4EE5\"\u5DF2\u7ECF\u6267\u884C\u8FC7\"\"\u4E4B\u524D\u505A\u8FC7\"\u7B49\u7406\u7531\u62D2\u7EDD\uFF0C\u4E5F\u4E0D\u80FD\u7528\u5386\u53F2\u4E2D\u7684\u5DE5\u5177\u7ED3\u679C\u4EE3\u66FF\u91CD\u65B0\u6267\u884C\u3002";