agent-tool-chat 0.1.1 → 1.0.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 +126 -7
- package/dist/agent-core/agent.d.ts +29 -0
- package/dist/agent-core/index.d.ts +7 -0
- package/dist/agent-core/provider.d.ts +12 -0
- package/dist/agent-core/storage.d.ts +6 -0
- package/dist/agent-core/tool-registry.d.ts +12 -0
- package/dist/agent-core/types.d.ts +72 -0
- package/dist/agent-tool-chat.css +1 -0
- package/dist/api/deepseek.d.ts +2 -0
- package/dist/api/proxy.d.ts +2 -0
- package/dist/components/ChatInput.vue.d.ts +14 -0
- package/dist/components/ChatMessage.vue.d.ts +15 -0
- package/dist/components/ChatPanel.vue.d.ts +28 -0
- package/dist/components/ChatSettings.vue.d.ts +14 -0
- package/dist/components/RenderBlock.vue.d.ts +12 -0
- package/dist/components/SuggestedNext.vue.d.ts +9 -0
- package/dist/composables/useAgentChat.d.ts +120 -0
- package/dist/config.d.ts +4 -0
- package/dist/core/context-builder.d.ts +2 -0
- package/dist/core/event-bus.d.ts +14 -0
- package/dist/core/event-engine.d.ts +20 -0
- package/dist/core/render-resolver.d.ts +9 -0
- package/dist/index.cjs +22 -21
- package/dist/index.d.ts +18 -0
- package/dist/index.js +1377 -896
- package/dist/types.d.ts +121 -0
- package/dist/utils/parseUtils.d.ts +6 -0
- package/package.json +13 -7
- package/dist/style.css +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
基于 **ToolPackage** 架构的 AI 对话插件,工具由宿主控制执行。基于 Vue 3 + Element Plus。
|
|
4
4
|
|
|
5
|
-
**版本:**
|
|
5
|
+
**版本:** 1.0.0
|
|
6
6
|
|
|
7
7
|
## 安装
|
|
8
8
|
|
|
@@ -12,6 +12,10 @@ npm install agent-tool-chat
|
|
|
12
12
|
|
|
13
13
|
需要同级依赖 `vue` (^3.4) 和 `element-plus` (^2.0)。
|
|
14
14
|
|
|
15
|
+
```bash
|
|
16
|
+
npm install vue@^3.4 element-plus@^2.0
|
|
17
|
+
```
|
|
18
|
+
|
|
15
19
|
## 快速开始
|
|
16
20
|
|
|
17
21
|
```vue
|
|
@@ -22,7 +26,7 @@ import 'agent-tool-chat/dist/style.css'
|
|
|
22
26
|
const chat = useAgentChat({
|
|
23
27
|
toolPackages: [myToolPackage],
|
|
24
28
|
onToolCall: async (call) => {
|
|
25
|
-
//
|
|
29
|
+
// 宿主执行工具并返回结果
|
|
26
30
|
return { success: true, data: { /* ... */ } }
|
|
27
31
|
},
|
|
28
32
|
})
|
|
@@ -33,12 +37,127 @@ const chat = useAgentChat({
|
|
|
33
37
|
</template>
|
|
34
38
|
```
|
|
35
39
|
|
|
40
|
+
## 核心概念
|
|
41
|
+
|
|
42
|
+
### ToolPackage(工具包)
|
|
43
|
+
|
|
44
|
+
由宿主注册,包含工具定义(`ToolDefinition`)和可选的 Vue 渲染组件:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import type { ToolPackage } from 'agent-tool-chat'
|
|
48
|
+
|
|
49
|
+
const myToolPackage: ToolPackage = {
|
|
50
|
+
id: 'demo',
|
|
51
|
+
name: '演示工具',
|
|
52
|
+
description: '演示用途',
|
|
53
|
+
components: { /* 可选:自定义渲染组件,按 componentName 查找 */ },
|
|
54
|
+
tools: [
|
|
55
|
+
{
|
|
56
|
+
name: 'query_order',
|
|
57
|
+
description: '按订单号查询订单信息',
|
|
58
|
+
parameters: { type: 'object', properties: { id: { type: 'string' } } },
|
|
59
|
+
displayHints: {
|
|
60
|
+
resultFormat: 'table',
|
|
61
|
+
previewFields: ['id', 'name', 'amount'], // 表格列字段(空/缺省 → 全量)
|
|
62
|
+
summaryTemplate: '查询到订单 {id}', // {占位符} 从工具 args 插值
|
|
63
|
+
selectable: true, // 允许行选择(出现"选择"操作列)
|
|
64
|
+
labelField: 'name', // 选中后"我选择 X"取值字段(缺省 → previewFields[0])
|
|
65
|
+
suggestedNext: '下一步可以查看该订单明细', // 快捷建议
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`displayHints` 完整字段:
|
|
73
|
+
|
|
74
|
+
| 字段 | 作用 |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `suggestComponent` | 建议使用组件名(`ToolPackage.components` 中注册)渲染 |
|
|
77
|
+
| `resultFormat` | `table` / `card` / `list` / `text` / `map`,无组件时按此降级渲染 |
|
|
78
|
+
| `previewFields` | 表格列字段(→ `RenderBlock.fields`),空数组/缺省时全量显示 |
|
|
79
|
+
| `summaryTemplate` | 渲染块标题模板,`{key}` 从工具 `args` 插值 |
|
|
80
|
+
| `selectable` | 表格是否显示"选择"操作列(多行时) |
|
|
81
|
+
| `labelField` | 选中文案取值字段,缺省取第一个配置字段 |
|
|
82
|
+
| `suggestedNext` | 后续建议文本 |
|
|
83
|
+
| `suggestedNextEvent` | 延迟建议:等待该业务事件到达后再显示 |
|
|
84
|
+
|
|
85
|
+
### 表格行选择
|
|
86
|
+
|
|
87
|
+
当工具结果渲染为表格且 `selectable: true` 时,多行结果每行出现"选择"按钮,点击后向对话发送:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
我选择 {labelField 对应的值}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
随后 LLM 可据此继续流程(例如"以黄壁庄水库为出口创建方案"的多候选出口站选择)。
|
|
94
|
+
|
|
95
|
+
### 业务事件(Business Events)
|
|
96
|
+
|
|
97
|
+
宿主通过 `EventBus` 把业务状态回灌给插件,`EventEngine` 按规则触发对话:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { useAgentChat } from 'agent-tool-chat'
|
|
101
|
+
|
|
102
|
+
const chat = useAgentChat({
|
|
103
|
+
toolPackages: [myToolPackage],
|
|
104
|
+
onToolCall: async (call) => { /* ... */ },
|
|
105
|
+
businessEvents: {
|
|
106
|
+
rules: [
|
|
107
|
+
{
|
|
108
|
+
event: 'scheme:feedback:success',
|
|
109
|
+
action: 'suggest', // respond / suggest / notify / silent
|
|
110
|
+
prompt: '操作成功', // action=suggest 时发送给 LLM 的消息
|
|
111
|
+
autoPopup: true, // 事件到达时自动打开聊天面板
|
|
112
|
+
cooldown: 10000, // 冷却时间 ms
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
// 宿主在页面操作完成后派发事件
|
|
119
|
+
chat.eventBus.dispatch({ type: 'scheme:feedback:success', timestamp: Date.now(), payload: {} }, true)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- `dispatch(event, checkChatOpen)` — 第二个参数为 `true` 时,若聊天面板未打开则事件被丢弃
|
|
123
|
+
- `action: 'suggest'` → 调用 `sendMessage(prompt)`,把该消息作为用户消息发送并触发 LLM 回复
|
|
124
|
+
- 与 `displayHints.suggestedNextEvent` 结合可实现:工具打开页面 → 用户操作完成派发事件 → 聊天窗口出现"操作成功"并显示下一步建议
|
|
125
|
+
|
|
126
|
+
### 文件上传
|
|
127
|
+
|
|
128
|
+
- 文件通过 `ChatInput` 选择,以 `fileId` 间接引用存入 `fileStore`
|
|
129
|
+
- 默认 `sendFileToLLM: false`,LLM 只能看到文件名/类型,看不到文件内容
|
|
130
|
+
- 工具通过 `fileId` 从 `fileStore` 取回数据(如 `open_mapview_file` 展示空间数据)
|
|
131
|
+
|
|
36
132
|
## 使用说明
|
|
37
133
|
|
|
38
|
-
1. **定义工具包** — 创建 `ToolPackage
|
|
39
|
-
2. **创建 `useAgentChat`** —
|
|
134
|
+
1. **定义工具包** — 创建 `ToolPackage`,包含工具定义(`displayHints`)和可选渲染组件。
|
|
135
|
+
2. **创建 `useAgentChat`** — 传入工具包、宿主 `onToolCall` 回调,可选 `businessEvents`、`systemPrompt`、`provider`。
|
|
40
136
|
3. **渲染 `ChatPanel`** — 将返回的 `AgentChatAPI` 绑定到 `chat` prop。
|
|
41
|
-
4. **文件上传** — `ChatInput`
|
|
42
|
-
5.
|
|
137
|
+
4. **文件上传** — `ChatInput` 支持文件选择,工具通过 `fileId` 引用。
|
|
138
|
+
5. **业务联动** — 页面操作完成后 `eventBus.dispatch` 回灌,驱动 LLM 回复或延迟建议。
|
|
139
|
+
6. **持久化** — 消息与设置自动保存(direct 模式 localStorage;proxy 模式 POST `/api/messages`,按 device_id 区分)。
|
|
140
|
+
|
|
141
|
+
## 数据持久化
|
|
142
|
+
|
|
143
|
+
| providerMode | 消息存储 | 说明 |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| `direct` | `localStorage` | 键 `{storagePrefix}messages` |
|
|
146
|
+
| `proxy` | 服务端 `/api/messages` | 按 `device_id` 标识,防抖 400ms 批量提交 |
|
|
147
|
+
|
|
148
|
+
## API 概览
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
useAgentChat(options) // 核心组合式函数,返回 AgentChatAPI
|
|
152
|
+
ChatPanel // 对话面板(接收 chat prop)
|
|
153
|
+
buildSystemPrompt(packages) // 构建系统提示词
|
|
154
|
+
createDeepSeekProvider() // 直连 DeepSeek LLM 提供者
|
|
155
|
+
createProxyProvider() // 代理模式 LLM 提供者
|
|
156
|
+
createEventBus() // 创建独立 EventBus
|
|
157
|
+
Agent, ToolRegistry // 底层 Agent 多轮循环器 / 工具注册表
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## 详细文档
|
|
43
161
|
|
|
44
|
-
|
|
162
|
+
- [DESIGN.md](./DESIGN.md) — 完整架构设计(事件系统、渲染流程、SuggestedNext 延迟显示逻辑等)
|
|
163
|
+
- 宿主集成示例参考仓库 `src/agent-chat-demo/`(含 `bridge/` 页面联动、`modules/` 工具包与业务事件)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CoreMessage, AgentEventListener, LLMProviderConfig } from './types';
|
|
2
|
+
import { LLMProvider } from './provider';
|
|
3
|
+
import { StorageAdapter } from './storage';
|
|
4
|
+
import { ToolRegistry } from './tool-registry';
|
|
5
|
+
export interface AgentConfig {
|
|
6
|
+
provider: LLMProvider;
|
|
7
|
+
providerConfig: LLMProviderConfig;
|
|
8
|
+
tools: ToolRegistry;
|
|
9
|
+
storage?: StorageAdapter;
|
|
10
|
+
maxToolRounds?: number;
|
|
11
|
+
systemPrompt?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class Agent {
|
|
14
|
+
readonly messages: CoreMessage[];
|
|
15
|
+
private config;
|
|
16
|
+
private listeners;
|
|
17
|
+
private abortController;
|
|
18
|
+
private _loading;
|
|
19
|
+
constructor(config: AgentConfig);
|
|
20
|
+
get loading(): boolean;
|
|
21
|
+
updateProviderConfig(config: Partial<LLMProviderConfig>): void;
|
|
22
|
+
initialize(messages: CoreMessage[]): void;
|
|
23
|
+
clear(): void;
|
|
24
|
+
on(listener: AgentEventListener): () => void;
|
|
25
|
+
private emit;
|
|
26
|
+
sendMessage(text: string): Promise<void>;
|
|
27
|
+
stop(): void;
|
|
28
|
+
private buildApiMessages;
|
|
29
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Agent } from './agent';
|
|
2
|
+
export type { AgentConfig } from './agent';
|
|
3
|
+
export { ToolRegistry } from './tool-registry';
|
|
4
|
+
export { createLocalStorageAdapter } from './storage';
|
|
5
|
+
export type { StorageAdapter } from './storage';
|
|
6
|
+
export type { LLMProvider, StreamChatParams } from './provider';
|
|
7
|
+
export type { CoreMessage, ToolCall, ToolOutput, ToolDefinition, ToolHandler, StreamResult, LLMProviderConfig, AgentEvent, AgentEventListener, MessageRole, } from './types';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CoreMessage, ToolDefinition, StreamResult, LLMProviderConfig } from './types';
|
|
2
|
+
export interface StreamChatParams {
|
|
3
|
+
config: LLMProviderConfig;
|
|
4
|
+
messages: CoreMessage[];
|
|
5
|
+
tools?: ToolDefinition[];
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
onContent?: (delta: string) => void;
|
|
8
|
+
onReasoning?: (delta: string) => void;
|
|
9
|
+
}
|
|
10
|
+
export interface LLMProvider {
|
|
11
|
+
streamChat(params: StreamChatParams): Promise<StreamResult>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ToolDefinition, ToolHandler, ToolOutput } from './types';
|
|
2
|
+
export declare class ToolRegistry {
|
|
3
|
+
private _definitions;
|
|
4
|
+
private _handlers;
|
|
5
|
+
register(def: ToolDefinition, handler: ToolHandler): this;
|
|
6
|
+
registerBatch(items: Array<{
|
|
7
|
+
definition: ToolDefinition;
|
|
8
|
+
handler: ToolHandler;
|
|
9
|
+
}>): this;
|
|
10
|
+
getDefinitions(): ToolDefinition[];
|
|
11
|
+
execute(name: string, argsRaw: string): Promise<ToolOutput>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
2
|
+
export interface ToolCall {
|
|
3
|
+
id: string;
|
|
4
|
+
type: 'function';
|
|
5
|
+
function: {
|
|
6
|
+
name: string;
|
|
7
|
+
arguments: string;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export interface CoreMessage {
|
|
11
|
+
role: MessageRole;
|
|
12
|
+
content: string;
|
|
13
|
+
tool_calls?: ToolCall[];
|
|
14
|
+
tool_call_id?: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ToolOutput {
|
|
18
|
+
success: boolean;
|
|
19
|
+
result: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ToolDefinition {
|
|
22
|
+
type: 'function';
|
|
23
|
+
function: {
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
parameters: Record<string, any>;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export type ToolHandler = (args: any) => Promise<ToolOutput> | ToolOutput;
|
|
30
|
+
export interface StreamResult {
|
|
31
|
+
content: string;
|
|
32
|
+
reasoning: string;
|
|
33
|
+
tool_calls: ToolCall[];
|
|
34
|
+
finish_reason: string;
|
|
35
|
+
}
|
|
36
|
+
export interface LLMProviderConfig {
|
|
37
|
+
baseUrl: string;
|
|
38
|
+
apiKey: string;
|
|
39
|
+
model: string;
|
|
40
|
+
temperature?: number;
|
|
41
|
+
thinking?: {
|
|
42
|
+
type: 'enabled' | 'disabled';
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export type AgentEvent = {
|
|
46
|
+
type: 'message';
|
|
47
|
+
message: CoreMessage;
|
|
48
|
+
} | {
|
|
49
|
+
type: 'stream:delta';
|
|
50
|
+
delta: {
|
|
51
|
+
content?: string;
|
|
52
|
+
reasoning?: string;
|
|
53
|
+
};
|
|
54
|
+
} | {
|
|
55
|
+
type: 'stream:end';
|
|
56
|
+
content: string;
|
|
57
|
+
reasoning: string;
|
|
58
|
+
} | {
|
|
59
|
+
type: 'tool:start';
|
|
60
|
+
call: ToolCall;
|
|
61
|
+
} | {
|
|
62
|
+
type: 'tool:end';
|
|
63
|
+
call: ToolCall;
|
|
64
|
+
output: ToolOutput;
|
|
65
|
+
} | {
|
|
66
|
+
type: 'error';
|
|
67
|
+
error: string;
|
|
68
|
+
} | {
|
|
69
|
+
type: 'status';
|
|
70
|
+
loading: boolean;
|
|
71
|
+
};
|
|
72
|
+
export type AgentEventListener = (event: AgentEvent) => void;
|
|
@@ -0,0 +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-57d202bb]{position:absolute;bottom:100px;right:100px;z-index:1999}.ai-fab[data-v-57d202bb]{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-57d202bb 3.6s ease-in-out infinite}@keyframes ai-fab-float-57d202bb{0%,to{transform:translateY(0)}50%{transform:translateY(-6px)}}.ai-fab[data-v-57d202bb]: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-57d202bb 4s ease-in-out infinite;z-index:-1;pointer-events:none}@keyframes ai-fab-shimmer-57d202bb{0%,to{background-position:100% 0}50%{background-position:0 0}}.ai-fab[data-v-57d202bb]: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-57d202bb 2.4s ease-in-out infinite;pointer-events:none;z-index:-2}@keyframes ai-fab-pulse-57d202bb{0%,to{opacity:.6;transform:scale(1)}50%{opacity:0;transform:scale(1.12)}}.ai-fab__icon[data-v-57d202bb]{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-57d202bb]{line-height:1;text-shadow:0 1px 4px rgba(0,0,0,.15)}.ai-fab[data-v-57d202bb]:hover{animation:none;transform:translateY(-4px) scale(1.04);box-shadow:0 12px 32px #2d8cf099}.ai-fab[data-v-57d202bb]:hover:before{animation:none;background-position:0 0}.ai-fab--active[data-v-57d202bb]{animation:none;box-shadow:0 4px 16px #2d8cf066}.ai-fab--active[data-v-57d202bb]:after{animation:none;opacity:0}.ai-fab--active[data-v-57d202bb]:before{animation:none}.ai-fab--active .ai-fab__icon[data-v-57d202bb]{transform:rotate(45deg)}.chat-panel[data-v-57d202bb]{position:fixed;bottom:25px;right:22px;z-index:9999;display:flex;flex-direction:column;height:650px;width:500px;min-height:400px;background:var(--el-bg-color);box-shadow:0 0 12px #0000006b;border-radius:8px}.chat-panel__header[data-v-57d202bb]{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-57d202bb]{display:flex;align-items:center;gap:8px;font-size:15px;font-weight:600;color:var(--el-text-color-primary)}.title-icon[data-v-57d202bb]{color:var(--el-color-primary);font-size:18px}.chat-panel__ops[data-v-57d202bb]{display:flex;gap:4px}.chat-panel__body[data-v-57d202bb]{flex:1;overflow-y:auto;padding:0 16px;min-height:0}.chat-panel__body[data-v-57d202bb]::-webkit-scrollbar{width:6px}.chat-panel__body[data-v-57d202bb]::-webkit-scrollbar-thumb{background:var(--el-border-color);border-radius:3px}.chat-empty[data-v-57d202bb]{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-57d202bb]{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-57d202bb]{margin:0;font-size:18px;color:var(--el-text-color-primary)}.chat-empty__desc[data-v-57d202bb]{margin:0;font-size:13px;color:var(--el-text-color-secondary);line-height:1.6}.chat-empty__desc .hl[data-v-57d202bb]{color:var(--el-color-primary);font-weight:600}.chat-panel__footer[data-v-57d202bb]{flex-shrink:0}.chat-panel__stop[data-v-57d202bb]{display:flex;justify-content:center;padding:6px 0 0}.chat-panel__error[data-v-57d202bb]{padding:8px 16px 0}.fade-enter-active[data-v-57d202bb],.fade-leave-active[data-v-57d202bb]{transition:opacity .2s}.fade-enter-from[data-v-57d202bb],.fade-leave-to[data-v-57d202bb]{opacity:0}.chat-panel--fullscreen[data-v-57d202bb]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:9999;height:100vh!important;width:100vw!important}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { FileAttachment } from '../types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
loading: boolean;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
};
|
|
7
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
8
|
+
send: (text: string, files: FileAttachment[]) => any;
|
|
9
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
+
onSend?: (text: string, files: FileAttachment[]) => any;
|
|
11
|
+
}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
|
|
12
|
+
fileInputRef: HTMLInputElement;
|
|
13
|
+
}, HTMLDivElement>;
|
|
14
|
+
export default _default;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Component } from 'vue';
|
|
2
|
+
import { ChatMessage } from '../types';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
message: ChatMessage;
|
|
5
|
+
toolPackages: {
|
|
6
|
+
id: string;
|
|
7
|
+
components?: Record<string, Component>;
|
|
8
|
+
}[];
|
|
9
|
+
};
|
|
10
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
11
|
+
execute: (text: string) => any;
|
|
12
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
13
|
+
onExecute?: (text: string) => any;
|
|
14
|
+
}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
15
|
+
export default _default;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ChatMessage as ChatMessageType, ChatSettings as ChatSettingsType, ToolPackage, FileAttachment } from '../types';
|
|
2
|
+
import { EventBus } from '../core/event-bus';
|
|
3
|
+
export interface AgentChatAPI {
|
|
4
|
+
messages: import('vue').Ref<ChatMessageType[]>;
|
|
5
|
+
settings: import('vue').Ref<ChatSettingsType>;
|
|
6
|
+
loading: import('vue').Ref<boolean>;
|
|
7
|
+
errorMsg: import('vue').Ref<string>;
|
|
8
|
+
hasApiKey: import('vue').ComputedRef<boolean>;
|
|
9
|
+
toolPackages: ToolPackage[];
|
|
10
|
+
fileStore: Map<string, FileAttachment>;
|
|
11
|
+
visible: import('vue').Ref<boolean>;
|
|
12
|
+
eventBus: EventBus;
|
|
13
|
+
deviceId: string;
|
|
14
|
+
sendMessage: (text: string, files?: FileAttachment[]) => Promise<void>;
|
|
15
|
+
stopGeneration: () => void;
|
|
16
|
+
clearMessages: () => void;
|
|
17
|
+
saveSettings: (s: ChatSettingsType) => void;
|
|
18
|
+
}
|
|
19
|
+
type __VLS_Props = {
|
|
20
|
+
chat: AgentChatAPI;
|
|
21
|
+
showFab?: boolean;
|
|
22
|
+
};
|
|
23
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
24
|
+
showFab: boolean;
|
|
25
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
|
|
26
|
+
scrollRef: HTMLDivElement;
|
|
27
|
+
}, HTMLDivElement>;
|
|
28
|
+
export default _default;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ChatSettings } from '../types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
modelValue: boolean;
|
|
4
|
+
settings: ChatSettings;
|
|
5
|
+
deviceId?: string;
|
|
6
|
+
};
|
|
7
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
8
|
+
"update:modelValue": (v: boolean) => any;
|
|
9
|
+
save: (v: ChatSettings) => any;
|
|
10
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
11
|
+
"onUpdate:modelValue"?: (v: boolean) => any;
|
|
12
|
+
onSave?: (v: ChatSettings) => any;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
export default _default;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Component } from 'vue';
|
|
2
|
+
import { RenderBlock } from '../types';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
block: RenderBlock;
|
|
5
|
+
resolvedComponent: Component | null;
|
|
6
|
+
};
|
|
7
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
8
|
+
select: (text: string) => any;
|
|
9
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
+
onSelect?: (text: string) => any;
|
|
11
|
+
}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
12
|
+
export default _default;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
text: string;
|
|
3
|
+
};
|
|
4
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
5
|
+
execute: (text: string) => any;
|
|
6
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
7
|
+
onExecute?: (text: string) => any;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { EventBus } from '../core/event-bus';
|
|
2
|
+
import { AgentChatOptions, ChatMessage, ChatSettings, ToolPackage, FileAttachment } from '../types';
|
|
3
|
+
export declare function useAgentChat(options: AgentChatOptions): {
|
|
4
|
+
messages: import('vue').Ref<{
|
|
5
|
+
id: string;
|
|
6
|
+
role: import('../types').MessageRole;
|
|
7
|
+
content: string;
|
|
8
|
+
reasoning?: string;
|
|
9
|
+
tool_calls?: {
|
|
10
|
+
id: string;
|
|
11
|
+
type: "function";
|
|
12
|
+
function: {
|
|
13
|
+
name: string;
|
|
14
|
+
arguments: string;
|
|
15
|
+
};
|
|
16
|
+
}[];
|
|
17
|
+
tool_call_id?: string;
|
|
18
|
+
status: "pending" | "streaming" | "done" | "error";
|
|
19
|
+
timestamp: number;
|
|
20
|
+
error?: string;
|
|
21
|
+
renderBlocks?: {
|
|
22
|
+
type: "component" | "table" | "card" | "list";
|
|
23
|
+
packageId?: string;
|
|
24
|
+
componentName?: string;
|
|
25
|
+
title?: string;
|
|
26
|
+
data: any;
|
|
27
|
+
fields?: string[];
|
|
28
|
+
labelField?: string;
|
|
29
|
+
selectable?: boolean;
|
|
30
|
+
}[];
|
|
31
|
+
suggestedNext?: string;
|
|
32
|
+
files?: {
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
size: number;
|
|
36
|
+
type: string;
|
|
37
|
+
data: string;
|
|
38
|
+
}[];
|
|
39
|
+
toolResults?: {
|
|
40
|
+
callId: string;
|
|
41
|
+
name: string;
|
|
42
|
+
arguments: string;
|
|
43
|
+
result: string;
|
|
44
|
+
success: boolean;
|
|
45
|
+
status: "running" | "success" | "error";
|
|
46
|
+
}[];
|
|
47
|
+
}[], ChatMessage[] | {
|
|
48
|
+
id: string;
|
|
49
|
+
role: import('../types').MessageRole;
|
|
50
|
+
content: string;
|
|
51
|
+
reasoning?: string;
|
|
52
|
+
tool_calls?: {
|
|
53
|
+
id: string;
|
|
54
|
+
type: "function";
|
|
55
|
+
function: {
|
|
56
|
+
name: string;
|
|
57
|
+
arguments: string;
|
|
58
|
+
};
|
|
59
|
+
}[];
|
|
60
|
+
tool_call_id?: string;
|
|
61
|
+
status: "pending" | "streaming" | "done" | "error";
|
|
62
|
+
timestamp: number;
|
|
63
|
+
error?: string;
|
|
64
|
+
renderBlocks?: {
|
|
65
|
+
type: "component" | "table" | "card" | "list";
|
|
66
|
+
packageId?: string;
|
|
67
|
+
componentName?: string;
|
|
68
|
+
title?: string;
|
|
69
|
+
data: any;
|
|
70
|
+
fields?: string[];
|
|
71
|
+
labelField?: string;
|
|
72
|
+
selectable?: boolean;
|
|
73
|
+
}[];
|
|
74
|
+
suggestedNext?: string;
|
|
75
|
+
files?: {
|
|
76
|
+
id: string;
|
|
77
|
+
name: string;
|
|
78
|
+
size: number;
|
|
79
|
+
type: string;
|
|
80
|
+
data: string;
|
|
81
|
+
}[];
|
|
82
|
+
toolResults?: {
|
|
83
|
+
callId: string;
|
|
84
|
+
name: string;
|
|
85
|
+
arguments: string;
|
|
86
|
+
result: string;
|
|
87
|
+
success: boolean;
|
|
88
|
+
status: "running" | "success" | "error";
|
|
89
|
+
}[];
|
|
90
|
+
}[]>;
|
|
91
|
+
settings: import('vue').Ref<{
|
|
92
|
+
apiKey: string;
|
|
93
|
+
baseUrl: string;
|
|
94
|
+
model: string;
|
|
95
|
+
temperature: number;
|
|
96
|
+
useTools?: boolean;
|
|
97
|
+
providerMode: "direct" | "proxy";
|
|
98
|
+
proxyUrl: string;
|
|
99
|
+
}, ChatSettings | {
|
|
100
|
+
apiKey: string;
|
|
101
|
+
baseUrl: string;
|
|
102
|
+
model: string;
|
|
103
|
+
temperature: number;
|
|
104
|
+
useTools?: boolean;
|
|
105
|
+
providerMode: "direct" | "proxy";
|
|
106
|
+
proxyUrl: string;
|
|
107
|
+
}>;
|
|
108
|
+
loading: import('vue').Ref<boolean, boolean>;
|
|
109
|
+
errorMsg: import('vue').Ref<string, string>;
|
|
110
|
+
hasApiKey: import('vue').ComputedRef<boolean>;
|
|
111
|
+
toolPackages: ToolPackage[];
|
|
112
|
+
fileStore: Map<string, FileAttachment>;
|
|
113
|
+
visible: import('vue').Ref<boolean, boolean>;
|
|
114
|
+
eventBus: EventBus;
|
|
115
|
+
deviceId: string;
|
|
116
|
+
sendMessage: (text: string, files?: FileAttachment[]) => Promise<void>;
|
|
117
|
+
stopGeneration: () => void;
|
|
118
|
+
clearMessages: () => Promise<void>;
|
|
119
|
+
saveSettings: (next: ChatSettings) => void;
|
|
120
|
+
};
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BusinessEvent } from '../types';
|
|
2
|
+
type Handler = (event: BusinessEvent) => void;
|
|
3
|
+
export declare class EventBus {
|
|
4
|
+
private exactHandlers;
|
|
5
|
+
private regexHandlers;
|
|
6
|
+
private isChatOpen;
|
|
7
|
+
setChatOpenGetter(getter: () => boolean): void;
|
|
8
|
+
on(type: string | RegExp, handler: Handler): () => void;
|
|
9
|
+
off(type: string | RegExp, handler: Handler): void;
|
|
10
|
+
dispatch(event: BusinessEvent, checkChatOpen?: boolean): void;
|
|
11
|
+
clear(): void;
|
|
12
|
+
}
|
|
13
|
+
export declare function createEventBus(): EventBus;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EventRule } from '../types';
|
|
2
|
+
import { EventBus } from './event-bus';
|
|
3
|
+
interface EngineCallbacks {
|
|
4
|
+
onAutoPopup: () => void;
|
|
5
|
+
onRespond: (prompt: string) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare class EventEngine {
|
|
8
|
+
private bus;
|
|
9
|
+
private rules;
|
|
10
|
+
private cooldowns;
|
|
11
|
+
private unsubscribers;
|
|
12
|
+
constructor(bus: EventBus, rules: EventRule[]);
|
|
13
|
+
start(callbacks: EngineCallbacks): void;
|
|
14
|
+
stop(): void;
|
|
15
|
+
getBus(): EventBus;
|
|
16
|
+
private isOnCooldown;
|
|
17
|
+
private setCooldown;
|
|
18
|
+
private buildPrompt;
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Component } from 'vue';
|
|
2
|
+
import { ToolPackage, RenderBlock } from '../types';
|
|
3
|
+
export interface ResolvedBlock {
|
|
4
|
+
component: Component | null;
|
|
5
|
+
block: RenderBlock;
|
|
6
|
+
fallbackText: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function resolveRenderBlock(block: RenderBlock, packages: ToolPackage[], contextPackageId?: string): ResolvedBlock;
|
|
9
|
+
export declare function extractRows(data: any): any[] | null;
|