@opentiny/tiny-robot-kit 0.4.0 → 0.4.1-alpha.1
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 +59 -262
- package/dist/chunk-EES4JUCD.mjs +1 -0
- package/dist/core.d.mts +281 -0
- package/dist/core.d.ts +281 -0
- package/dist/core.js +1 -0
- package/dist/core.mjs +1 -0
- package/dist/index.d.mts +31 -245
- package/dist/index.d.ts +31 -245
- package/dist/index.js +3 -3
- package/dist/index.mjs +3 -3
- package/dist/types-CePh-Jcx.d.mts +212 -0
- package/dist/types-CePh-Jcx.d.ts +212 -0
- package/package.json +47 -5
package/README.md
CHANGED
|
@@ -1,289 +1,86 @@
|
|
|
1
1
|
# tiny-robot-kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
@opentiny/tiny-robot-kit 是 TinyRobot 提供的数据层工具包,用于统一处理 AI 大模型调用、消息状态与多会话管理。
|
|
4
|
+
它帮助你在任意 UI 上快速实现聊天、流式响应和会话持久化等常见 AI 交互能力。
|
|
4
5
|
|
|
5
|
-
##
|
|
6
|
+
## 功能概览
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
- **消息管理**:`useMessage` 管理消息状态与模型交互流程。
|
|
9
|
+
- **会话管理**:`useConversation` 在 useMessage 之上提供多会话能力。
|
|
10
|
+
- **工具函数(Utils)**:处理 SSE、消息格式与响应解析。
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
完整 API 请参考文档:
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
- `useMessage`:<https://docs.opentiny.design/tiny-robot/tools/message>
|
|
15
|
+
- `useConversation`:<https://docs.opentiny.design/tiny-robot/tools/conversation>
|
|
16
|
+
- 工具函数:<https://docs.opentiny.design/tiny-robot/tools/utils>
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
new AIClient(config: AIModelConfig)
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
#### 方法
|
|
18
|
-
|
|
19
|
-
- `chat(request: ChatCompletionRequest): Promise<ChatCompletionResponse>`
|
|
20
|
-
发送聊天请求并获取响应。
|
|
21
|
-
|
|
22
|
-
- `chatStream(request: ChatCompletionRequest, handler: StreamHandler): Promise<void>`
|
|
23
|
-
发送流式聊天请求并通过处理器处理响应。
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
## 基本用法
|
|
27
|
-
|
|
28
|
-
### 创建客户端并发送消息
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
import { AIClient } from '@opentiny/tiny-robot-kit';
|
|
32
|
-
|
|
33
|
-
// 创建客户端
|
|
34
|
-
const client = new AIClient({
|
|
35
|
-
provider: 'openai',
|
|
36
|
-
apiKey: 'your-api-key',
|
|
37
|
-
defaultModel: 'gpt-3.5-turbo'
|
|
38
|
-
});
|
|
18
|
+
## 安装
|
|
39
19
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{ role: 'system', content: '你是一个有用的助手。' },
|
|
46
|
-
{ role: 'user', content: '你好,请介绍一下自己。' }
|
|
47
|
-
],
|
|
48
|
-
options: {
|
|
49
|
-
temperature: 0.7
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
console.log(response.choices[0].message.content);
|
|
54
|
-
} catch (error) {
|
|
55
|
-
console.error('聊天出错:', error);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
chat();
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### 使用流式响应
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
import { AIClient } from '@opentiny/tiny-robot-kit';
|
|
66
|
-
|
|
67
|
-
const client = new AIClient({
|
|
68
|
-
provider: 'openai',
|
|
69
|
-
apiKey: 'your-api-key'
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
async function streamChat() {
|
|
73
|
-
try {
|
|
74
|
-
const controller: AbortController = new AbortController()
|
|
75
|
-
await client.chatStream({
|
|
76
|
-
messages: [
|
|
77
|
-
{ role: 'user', content: '写一个简短的故事。' }
|
|
78
|
-
],
|
|
79
|
-
options: {
|
|
80
|
-
stream: true, // 启用流式响应
|
|
81
|
-
signal: controller.signal // 传递 AbortController 的 signal用于中断请求
|
|
82
|
-
}
|
|
83
|
-
}, {
|
|
84
|
-
onData: (data) => {
|
|
85
|
-
// 处理流式数据
|
|
86
|
-
const content = data.choices[0]?.delta?.content || '';
|
|
87
|
-
process.stdout.write(content);
|
|
88
|
-
},
|
|
89
|
-
onError: (error) => {
|
|
90
|
-
console.error('流式响应错误:', error);
|
|
91
|
-
},
|
|
92
|
-
onDone: () => {
|
|
93
|
-
console.log('\n流式响应完成');
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
// controller.abort() // 中断请求
|
|
97
|
-
} catch (error) {
|
|
98
|
-
console.error('流式聊天出错:', error);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
streamChat();
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add @opentiny/tiny-robot-kit
|
|
22
|
+
# 或
|
|
23
|
+
npm install @opentiny/tiny-robot-kit
|
|
24
|
+
yarn add @opentiny/tiny-robot-kit
|
|
103
25
|
```
|
|
104
26
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
#### 选项
|
|
108
|
-
|
|
109
|
-
`useMessage` 接受以下选项:
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
interface UseMessageOptions {
|
|
113
|
-
/** AI客户端实例 */
|
|
114
|
-
client: AIClient;
|
|
115
|
-
/** 是否默认使用流式响应 */
|
|
116
|
-
useStreamByDefault?: boolean;
|
|
117
|
-
/** 错误消息模板 */
|
|
118
|
-
errorMessage?: string;
|
|
119
|
-
/** 初始消息列表 */
|
|
120
|
-
initialMessages?: ChatMessage[];
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
#### 返回值
|
|
125
|
-
|
|
126
|
-
`useMessage` 返回以下内容:
|
|
127
|
-
```typescript
|
|
128
|
-
interface UseMessageReturn {
|
|
129
|
-
messages: ChatMessage[];
|
|
130
|
-
/** 消息状态 */
|
|
131
|
-
messageState: Reactive<MessageState>;
|
|
132
|
-
/** 输入消息 */
|
|
133
|
-
inputMessage: Ref<string>;
|
|
134
|
-
/** 是否使用流式响应 */
|
|
135
|
-
useStream: Ref<boolean>;
|
|
136
|
-
/** 发送消息 */
|
|
137
|
-
sendMessage: (content?: string, clearInput?: boolean) => Promise<void>
|
|
138
|
-
/** 清空消息 */
|
|
139
|
-
clearMessages: () => void;
|
|
140
|
-
/** 添加消息 */
|
|
141
|
-
addMessage: (message: ChatMessage) => void;
|
|
142
|
-
/** 中止请求 */
|
|
143
|
-
abortRequest: () => void;
|
|
144
|
-
/** 重试请求 */
|
|
145
|
-
retryRequest: () => Promise<void>;
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
#### MessageState 接口
|
|
150
|
-
```typescript
|
|
151
|
-
interface MessageState {
|
|
152
|
-
status: STATUS
|
|
153
|
-
errorMsg: string | null
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
enum STATUS {
|
|
157
|
-
INIT = 'init', // 初始状态
|
|
158
|
-
PROCESSING = 'processing', // AI请求正在处理中, 还未响应,显示加载动画
|
|
159
|
-
STREAMING = 'streaming', // 流式响应中分块数据返回中
|
|
160
|
-
FINISHED = 'finished', // AI请求已完成
|
|
161
|
-
ABORTED = 'aborted', // 用户中止请求
|
|
162
|
-
ERROR = 'error', // AI请求发生错误
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### useConversation
|
|
167
|
-
|
|
168
|
-
对话管理与数据持久化
|
|
169
|
-
|
|
170
|
-
#### 基本用法
|
|
27
|
+
## 基本用法
|
|
171
28
|
|
|
172
|
-
|
|
173
|
-
import { useConversation, AIClient } from '@opentiny/tiny-robot-kit'
|
|
29
|
+
### useMessage —— 管理 AI 消息
|
|
174
30
|
|
|
175
|
-
|
|
176
|
-
provider: 'openai',
|
|
177
|
-
apiKey: 'your-api-key',
|
|
178
|
-
defaultModel: 'gpt-3.5-turbo'
|
|
179
|
-
});
|
|
31
|
+
`useMessage` 管理消息列表、请求/处理状态、流式响应、插件体系以及工具调用逻辑,而真正的 HTTP 请求由你提供的 `responseProvider` 负责。
|
|
180
32
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
messageManager, // 与 useMessage 返回一致,具体查看useMessage
|
|
184
|
-
createConversation,
|
|
185
|
-
switchConversation,
|
|
186
|
-
deleteConversation,
|
|
187
|
-
// ...
|
|
188
|
-
} = useConversation({ client })
|
|
33
|
+
```ts
|
|
34
|
+
import { useMessage } from '@opentiny/tiny-robot-kit'
|
|
189
35
|
|
|
190
|
-
const
|
|
36
|
+
const message = useMessage({
|
|
37
|
+
// responseProvider 负责调用你的后端 / 模型接口
|
|
38
|
+
async responseProvider(requestBody, abortSignal) {
|
|
39
|
+
const res = await fetch('/api/chat', {
|
|
40
|
+
method: 'POST',
|
|
41
|
+
body: JSON.stringify(requestBody),
|
|
42
|
+
signal: abortSignal,
|
|
43
|
+
headers: { 'Content-Type': 'application/json' },
|
|
44
|
+
})
|
|
191
45
|
|
|
192
|
-
|
|
46
|
+
return await res.json()
|
|
47
|
+
},
|
|
48
|
+
})
|
|
193
49
|
```
|
|
194
50
|
|
|
195
|
-
|
|
51
|
+
更多进阶用法(流式响应、插件、自定义分块(chunk)处理、工具调用等),请查看 <https://docs.opentiny.design/tiny-robot/tools/message>。
|
|
196
52
|
|
|
197
|
-
|
|
53
|
+
### useConversation —— 管理多会话
|
|
198
54
|
|
|
199
|
-
|
|
200
|
-
interface UseConversationReturn {
|
|
201
|
-
/** 会话状态 */
|
|
202
|
-
state: ConversationState;
|
|
203
|
-
/** 消息管理 */
|
|
204
|
-
messageManager: UseMessageReturn;
|
|
205
|
-
/** 创建新会话 */
|
|
206
|
-
createConversation: (title?: string, metadata?: Record<string, any>) => string;
|
|
207
|
-
/** 切换会话 */
|
|
208
|
-
switchConversation: (id: string) => void;
|
|
209
|
-
/** 删除会话 */
|
|
210
|
-
deleteConversation: (id: string) => void;
|
|
211
|
-
/** 更新会话标题 */
|
|
212
|
-
updateTitle: (id: string, title: string) => void;
|
|
213
|
-
/** 更新会话元数据 */
|
|
214
|
-
updateMetadata: (id: string, metadata: Record<string, any>) => void;
|
|
215
|
-
/** 保存会话 */
|
|
216
|
-
saveConversations: () => Promise<void>;
|
|
217
|
-
/** 加载会话 */
|
|
218
|
-
loadConversations: () => Promise<void>;
|
|
219
|
-
/** 生成会话标题 */
|
|
220
|
-
generateTitle: (id: string) => Promise<string>;
|
|
221
|
-
/** 获取当前会话 */
|
|
222
|
-
getCurrentConversation: () => Conversation | null;
|
|
223
|
-
}
|
|
224
|
-
```
|
|
55
|
+
`useConversation` 基于 `useMessage` 之上,提供多会话管理能力,并支持多种存储策略(LocalStorage、IndexedDB、自定义等)。
|
|
225
56
|
|
|
226
|
-
|
|
57
|
+
```ts
|
|
58
|
+
import { useConversation } from '@opentiny/tiny-robot-kit'
|
|
227
59
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
60
|
+
const { conversations, activeConversation, createConversation, switchConversation } = useConversation({
|
|
61
|
+
useMessageOptions: {
|
|
62
|
+
async responseProvider(requestBody, abortSignal) {
|
|
63
|
+
const res = await fetch('/api/chat', {
|
|
64
|
+
method: 'POST',
|
|
65
|
+
body: JSON.stringify(requestBody),
|
|
66
|
+
signal: abortSignal,
|
|
67
|
+
headers: { 'Content-Type': 'application/json' },
|
|
68
|
+
})
|
|
69
|
+
return await res.json()
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
})
|
|
237
73
|
```
|
|
238
74
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
```typescript
|
|
242
|
-
|
|
243
|
-
interface Conversation {
|
|
244
|
-
/** 会话ID */
|
|
245
|
-
id: string;
|
|
246
|
-
/** 会话标题 */
|
|
247
|
-
title: string;
|
|
248
|
-
/** 创建时间 */
|
|
249
|
-
createdAt: number;
|
|
250
|
-
/** 更新时间 */
|
|
251
|
-
updatedAt: number;
|
|
252
|
-
/** 自定义元数据 */
|
|
253
|
-
metadata?: Record<string, any>;
|
|
254
|
-
/** 消息 */
|
|
255
|
-
messages: ChatMessage[];
|
|
256
|
-
}
|
|
257
|
-
```
|
|
75
|
+
例如 `localStorageStrategyFactory` 和 `indexedDBStorageStrategyFactory` 等存储策略的详细用法,请参考 <https://docs.opentiny.design/tiny-robot/tools/conversation>。
|
|
258
76
|
|
|
259
|
-
|
|
77
|
+
### 工具函数 Utils —— 处理 SSE 与响应
|
|
260
78
|
|
|
261
|
-
|
|
79
|
+
Utils 模块提供了一些与 `useMessage` 搭配使用的常用工具函数:
|
|
262
80
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
/** 加载会话列表 */
|
|
268
|
-
loadConversations: () => Promise<Conversation[]> | Conversation[];
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// 自定义存储策略示例
|
|
272
|
-
class CustomStorageStrategy implements ConversationStorageStrategy {
|
|
273
|
-
async saveConversations(conversations: Conversation[]) {
|
|
274
|
-
// 实现自定义存储逻辑
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
async loadConversations(): Promise<Conversation[]> {
|
|
278
|
-
// 实现自定义加载逻辑
|
|
279
|
-
return [];
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// 使用自定义存储策略
|
|
284
|
-
const conversationManager = useConversation({
|
|
285
|
-
client,
|
|
286
|
-
storage: new CustomStorageStrategy(),
|
|
287
|
-
});
|
|
288
|
-
```
|
|
81
|
+
- `sseStreamToGenerator`:把 SSE `Response` 转换为异步生成器。
|
|
82
|
+
- `formatMessages`:将多种形式的消息统一为 `ChatMessage[]`。
|
|
83
|
+
- `extractTextFromResponse`:从大模型响应中提取纯文本内容。
|
|
84
|
+
- `handleSSEStream`:通过回调方式消费 SSE 流式响应。
|
|
289
85
|
|
|
86
|
+
详细函数签名与行为说明,请查看 <https://docs.opentiny.design/tiny-robot/tools/utils>。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{computed as ce,isProxy as ue,reactive as ge,ref as L,toRaw as fe}from"vue";var le=e=>typeof e=="function"?null:Array.isArray(e)?e.length>0?new Set(e):null:new Set([e]),ee=e=>{let t=new Set,s=(o,f)=>{try{o.listener(f)}catch(m){console.error("Error in message state subscriber:",m)}};return{notify:o=>{let f=new Set(Array.isArray(o)?o:[o]),m=e(),p=Array.from(t);for(let a of p){if(a.kinds){let c=!1;for(let y of a.kinds)if(f.has(y)){c=!0;break}if(!c)continue}s(a,m)}},subscribe:(o,f)=>{let m=typeof o=="function"?o:f;if(!m)throw new Error("subscribe listener is required");let p={kinds:le(o),listener:m};return t.add(p),s(p,e()),()=>{t.delete(p)}}}};var te=e=>ge(e),$=e=>{let t=ue(e)?fe(e):e;if(Array.isArray(t))return t.map(s=>$(s));if(t&&typeof t=="object"){let s={};for(let[n,i]of Object.entries(t))s[n]=$(i);return s}return t},xe=()=>{let e=!1,t=L("idle"),s=L(void 0),n=L([]),i=ce(()=>t.value==="processing"),o=c=>{if(e)throw new Error("Message state adapter is already initialized");t.value=c.requestState,s.value=c.processingState,n.value=c.messages.map(te),e=!0},f=c=>te(c),m=()=>{if(!e)throw new Error("Message state adapter is not initialized");return{requestState:t.value,processingState:s.value,messages:$(n.value),isProcessing:i.value}},p=ee(m);return{requestState:t,processingState:s,messages:n,isProcessing:i,initialize:o,getState:m,createMessage:f,mutate:(c,y)=>{if(!e)throw new Error("Message state adapter is not initialized");let A={get requestState(){return t.value},set requestState(S){t.value=S},get processingState(){return s.value},set processingState(S){s.value=S},get messages(){return n.value},set messages(S){n.value=S.map(f)}},d=!1;if(y(A,()=>{d=!0}),d)return;(Array.isArray(c)?c:[c]).includes("messages")&&(n.value=[...n.value]),p.notify(c)},subscribe:p.subscribe}};var H=(e={})=>{let{continueContent:t="Please continue with your previous answer.",...s}=e;return{name:"length",...s,onAfterRequest:async n=>{let{lastChoice:i,appendMessage:o,requestNext:f}=n;return i?.finish_reason==="length"&&(o({role:"user",content:t}),f()),s.onAfterRequest?.(n)}}};var Q=(e={})=>{let t=(s,n)=>!!s.thinking!==n||!!s.open!==n;return{name:"thinking",...e,onCompletionChunk(s){let{choice:n,currentMessage:i,updateCurrentMessage:o}=s,f=n,m=f?.message?.reasoning_content||f?.delta?.reasoning_content,p=typeof m=="string"&&m.trim()!=="";return p?i.state&&typeof i.state=="object"?t(i.state,p)&&o(a=>{a.state.thinking=!0,a.state.open=!0}):o(a=>{a.state={thinking:p,open:p}}):i.state&&typeof i.state=="object"&&"thinking"in i.state&&t(i.state,p)&&o(a=>{a.state.thinking=!1,a.state.open=!1}),e.onCompletionChunk?.(s)},onTurnEnd(s){let{currentTurn:n,mutate:i}=s,o=n.at(-1);return o?.state&&typeof o.state=="object"&&"thinking"in o.state&&t(o.state,!1)&&i("messages",()=>{o.state.thinking=!1,o.state.open=!1}),e.onTurnEnd?.(s)}}};var D=class extends Error{constructor(t){super(t),this.name="AbortError"}};function de(e){if(e.aborted)return{promise:Promise.reject(new D(String(e.reason??"Aborted"))),cleanup:()=>{}};let t=null;return{promise:new Promise((i,o)=>{t=()=>{o(new D(String(e.reason??"Aborted")))},e.addEventListener("abort",t,{once:!0})}),cleanup:()=>{t&&(e.removeEventListener("abort",t),t=null)}}}function oe(e,t){let{promise:s,cleanup:n}=de(t);return Promise.race([e,s]).finally(n)}function ae(e,t){let s={};for(let n in e)t.includes(n)&&(s[n]=e[n]);return s}function re(e,t){let s={};for(let n in e)t.includes(n)||(s[n]=e[n]);return s}async function*J(e){if(se(e)){yield*e;return}let t=await e;if(se(t)){yield*t;return}yield t}function se(e){return e&&typeof e=="object"&&typeof e[Symbol.asyncIterator]=="function"}var X=e=>typeof e=="object"&&e!==null,ne=e=>X(e)&&typeof e.index=="number",O=(e,t)=>{for(let[s,n]of Object.entries(t)){let i=e[s];if(i)if(typeof i=="string"&&typeof n=="string")s==="type"&&i||(e[s]=i+n);else if(Array.isArray(i)&&Array.isArray(n))if(i.every(o=>ne(o))&&n.every(o=>ne(o))){let o=new Map(i.map(a=>[a.index,a])),f=new Map(n.map(a=>[a.index,a]));for(let[a,c]of f)if(o.has(a)){let y=o.get(a);o.set(a,O(y,c))}else o.set(a,c);let m=Math.max(...Array.from(o.keys()),-1)+1,p=m>i.length?Array.from({length:m}):i;for(let[a,c]of o)p[a]=c;e[s]=p}else e[s]=[...i,...n];else X(i)&&X(n)&&(e[s]=O(i,n));else e[s]=n}return e};function pe({messages:e,cancelledContent:t,createMessage:s,mutate:n}){let i=[];for(let o=0;o<e.length;o++){let f=e[o];if(f.role==="assistant"&&f.tool_calls&&f.tool_calls.length>0){let m=new Set(f.tool_calls.map(c=>c.id)),p=new Set;for(let c=o+1;c<e.length;c++){let y=e[c];y.role==="tool"&&y.tool_call_id&&m.has(y.tool_call_id)&&p.add(y.tool_call_id)}let a=f.tool_calls.map(c=>c.id).filter(c=>!p.has(c));a.length>0&&i.push({insertAfterIndex:o,missingToolCallIds:a})}}i.length!==0&&n("messages",o=>{for(let f=i.length-1;f>=0;f--){let{insertAfterIndex:m,missingToolCallIds:p}=i[f],a=p.map(c=>s({role:"tool",tool_call_id:c,content:t}));o.messages.splice(m+1,0,...a)}})}var me=e=>{let{getTools:t,beforeCallTools:s,callTool:n,onToolCallStart:i,onToolCallEnd:o,toolCallCancelledContent:f="Tool call cancelled.",toolCallFailedContent:m="Tool call failed.",autoFillMissingToolMessages:p=!1,...a}=e,c=(d,C)=>{var M,S;return d.state??(d.state={}),(M=d.state).toolCall??(M.toolCall={}),(S=d.state.toolCall)[C]??(S[C]={}),d},y=(...d)=>{let[C,{assistantMessage:M,mutate:S}]=d;S("messages",()=>{let w=c(M,C.id);w.state.toolCall[C.id].status="running"}),i?.(...d)},A=(...d)=>{let[C,{status:M,assistantMessage:S,mutate:w}]=d;w("messages",()=>{let W=c(S,C.id);W.state.toolCall[C.id].status=M}),o?.(...d)};return{name:"tool",...a,onTurnStart:d=>{let{getState:C,createMessage:M,mutate:S}=d,w=C().messages;return p&&pe({messages:w,cancelledContent:f,createMessage:M,mutate:S}),a.onTurnStart?.(d)},onBeforeRequest:async d=>{let{requestBody:C}=d,M=await t();return M&&M.length>0&&(C.tools=M),a.onBeforeRequest?.(d)},onAfterRequest:async d=>{let{currentMessage:C,lastChoice:M,appendMessage:S,abortSignal:w,setRequestState:W,requestNext:v,mutate:j,createMessage:R}=d;if(M?.finish_reason!=="tool_calls"||!C.tool_calls?.length)return;W("processing","calling-tools"),await s?.(C.tool_calls,{...d,assistantMessage:C});let G=C.tool_calls.map(async I=>{let z=Math.floor(Date.now()/1e3),V=!1,x=R({role:"tool",tool_call_id:I.id,content:"",metadata:{createdAt:z,updatedAt:z}});S(x);let B={...d,assistantMessage:C,toolMessage:x};y(I,B);try{let r=n(I,B),l=J(r);for await(let g of l)j("messages",()=>{if((typeof g=="string"&&g.length>0||g&&typeof g=="object"&&Object.keys(g).length>0)&&(V=!0),typeof g=="string")x.content+=g;else{let h={};try{let b=Array.isArray(x.content)?x.content.map(u=>u.text).join(""):x.content;h=JSON.parse(b||"{}")}catch(b){console.warn(b)}x.content=JSON.stringify(O(h,g))}x.metadata.updatedAt=Math.floor(Date.now()/1e3)});A(I,{...B,status:"success"})}catch(r){let l=r instanceof Error?r:new Error(String(r));if(w.aborted){A(I,{...B,status:"cancelled",error:l});return}console.error(r),V||j("messages",()=>{x.content=m,x.metadata.updatedAt=Math.floor(Date.now()/1e3)}),A(I,{...B,status:"failed",error:l})}});return await Promise.all(G),w.aborted||v(),a.onAfterRequest?.(d)}}};var Ce=async()=>{throw new Error("Response provider is not set")},Me=e=>{let t=[];for(let s of e){if(s.name){let n=t.findIndex(i=>i.name===s.name);n!==-1&&t.splice(n,1)}t.push(s)}return t},K=(e,t)=>typeof e.disabled=="function"?e.disabled(t):!!e.disabled,he=(e,t={})=>{let{initialMessages:s=[],requestMessageFields:n=[],requestMessageFieldsExclude:i=["state","metadata","loading"],responseProvider:o=Ce,onCompletionChunk:f,plugins:m=[]}=t,p={requestState:"idle",processingState:void 0,messages:[...s]};e.initialize(p);let a={currentTurn:[],customContext:{},abortController:null,responseProvider:o},c=[Q(),H()],y=Me(c.concat(m)),A=()=>e.getState(),d=r=>e.createMessage(r),C=e.subscribe,M=e.mutate,S=r=>!r||Object.keys(r).length===0?!1:Object.values(r).some(l=>!!l),w=r=>{let l=r;return n.length&&(l=l.map(g=>ae(g,n))),i.length&&(l=l.map(g=>re(g,i))),l},W=r=>{Object.assign(a.customContext,r)},v=(r,l)=>{M("requestState",(g,h)=>{if(g.requestState===r&&g.processingState===l){h();return}g.requestState=r,g.processingState=r==="processing"?l??"requesting":void 0})},j=(...r)=>{let l=r.map(g=>d(g));return M("messages",g=>{g.messages.push(...l)}),a.currentTurn.push(...l),l},R=r=>({getState:A,createMessage:d,mutate:M,abortSignal:r,currentTurn:a.currentTurn,customContext:a.customContext,setRequestState:v,setCustomContext:W});async function G(r,l,g={}){v("processing","requesting");let h={messages:A().messages},b=R(l);for(let _ of y.filter(T=>!K(T,b)))await _.onBeforeRequest?.({...b,requestBody:h});h.messages=w(h.messages);let u={role:"assistant",content:"",loading:!0};[u]=j(u),g.setAssistantMessage?.(u);let P=r(h,l),q=J(P),k;for await(let _ of q){v("processing","completing"),M("messages",(E,N)=>{u.loading?u.loading=void 0:N()});let T=(_.choices||[]).find(E=>E.index===0)??_.choices?.[0];if(!T)continue;k=T;let F=()=>{M("messages",()=>{u.metadata||(u.metadata={});let{created:E,...N}=_;u.metadata.createdAt=E,u.metadata.updatedAt=Math.floor(Date.now()/1e3),Object.assign(u.metadata,N);let U="delta"in T&&S(T.delta)&&T.delta||"message"in T&&S(T.message)&&T.message||null;if(U?.role&&(u.role=U.role),U){let{role:ye,...ie}=U;O(u,ie)}})},Y=E=>{M("messages",()=>{E(u)})};if(f){let E=R(l);f({...E,chunk:_,choice:T,currentMessage:u,updateCurrentMessage:Y},F)}else F();let Z=R(l);for(let E of y.filter(N=>!K(N,Z)))E.onCompletionChunk?.({...Z,abortSignal:l,chunk:_,choice:T,currentMessage:u,updateCurrentMessage:Y})}await I(u,r,l,k,g)}async function I(r,l,g,h,b){let u=!1,P=R(g),q=y.filter(k=>!K(k,P)).map(k=>{if(!k.onAfterRequest)return null;let _=F=>{j(...Array.isArray(F)?F:[F])},T=()=>{u=!0};return k.onAfterRequest({...P,currentMessage:r,lastChoice:h,appendMessage:_,requestNext:T})}).filter(k=>k!==null);await oe(Promise.all(q),g),u&&await G(l,g,b)}async function z(){let r=new AbortController;a.abortController=r,a.customContext={};let l=null,g=h=>{l=h};try{v("processing","requesting");let h=R(r.signal);for(let P of y.filter(q=>!K(q,h)))await P.onTurnStart?.(h);let b=a.responseProvider;try{await G(b,r.signal,{setAssistantMessage:g}),v("completed")}catch(P){if(r.signal.aborted||P instanceof D||P instanceof Error&&P.name==="AbortError")v("aborted");else throw P}let u=R(r.signal);for(let P of y.filter(q=>!K(q,u)))await P.onTurnEnd?.(u)}catch(h){v("error");let b=!1,u=R(r.signal);for(let P of y.filter(q=>!K(q,u)))P.onError&&(b=!0,P.onError({...u,error:h}));if(!b)throw h}finally{let h=R(r.signal);for(let b of y.filter(u=>!K(u,h)))try{b.onFinally?.(h)}catch(u){console.error(`Error in onFinally hook for plugin [${b.name||"Anonymous"}]:`,u)}a.abortController=null,a.currentTurn=[],M("messages",(b,u)=>{l?.loading?l.loading=void 0:u()})}}async function V(r){if(!r||!r.trim()){console.warn("Cannot send empty message");return}if(A().requestState==="processing"){console.warn("Cannot send message while processing is in progress");return}let l=Math.floor(Date.now()/1e3);j({role:"user",content:r.trim(),metadata:{createdAt:l,updatedAt:l}}),await z()}async function x(...r){if(A().requestState==="processing"){console.warn("Cannot send message while processing is in progress");return}j(...r),await z()}async function B(){a.abortController?.abort(),A().isProcessing&&await new Promise(r=>{let l=()=>{};l=C("requestState",g=>{g.isProcessing||(l(),r())})})}return{getState:A,subscribe:C,sendMessage:V,send:x,abort:B,setResponseProvider(r){a.responseProvider=r}}};export{ee as a,xe as b,H as c,Q as d,J as e,O as f,me as g,he as h};
|
package/dist/core.d.mts
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { ChatCompletionMessageParam, ChatCompletionMessageToolCall, ChatCompletion, ChatCompletionChunk, ChatCompletionTool } from 'openai/resources/index';
|
|
2
|
+
import { M as MaybePromise } from './types-CePh-Jcx.mjs';
|
|
3
|
+
import { Ref, ComputedRef } from 'vue';
|
|
4
|
+
|
|
5
|
+
type DeepReadonly<T> = T extends (...args: any[]) => any ? T : T extends Array<infer U> ? ReadonlyArray<DeepReadonly<U>> : T extends object ? {
|
|
6
|
+
readonly [K in keyof T]: DeepReadonly<T[K]>;
|
|
7
|
+
} : T;
|
|
8
|
+
type RequestState = 'idle' | 'processing' | 'completed' | 'aborted' | 'error';
|
|
9
|
+
type RequestProcessingState = 'requesting' | 'completing' | string;
|
|
10
|
+
type ChatMessage<Metadata extends object = Record<string, unknown>, State extends object = Record<string, unknown>> = ChatCompletionMessageParam & {
|
|
11
|
+
tool_calls?: Array<ChatCompletionMessageToolCall>;
|
|
12
|
+
loading?: boolean;
|
|
13
|
+
metadata?: Metadata;
|
|
14
|
+
state?: State;
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
};
|
|
17
|
+
interface MessageRequestBody {
|
|
18
|
+
messages: Array<ChatMessage>;
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
}
|
|
21
|
+
type ResponseProvider<T extends ChatCompletion | ChatCompletionChunk = ChatCompletion | ChatCompletionChunk> = (requestBody: MessageRequestBody, abortSignal: AbortSignal) => Promise<T> | AsyncGenerator<T> | Promise<AsyncGenerator<T>>;
|
|
22
|
+
interface PublicMessageState {
|
|
23
|
+
requestState: RequestState;
|
|
24
|
+
processingState?: RequestProcessingState;
|
|
25
|
+
messages: ChatMessage[];
|
|
26
|
+
isProcessing: boolean;
|
|
27
|
+
}
|
|
28
|
+
interface InternalMessageState {
|
|
29
|
+
requestState: RequestState;
|
|
30
|
+
processingState?: RequestProcessingState;
|
|
31
|
+
messages: ChatMessage[];
|
|
32
|
+
}
|
|
33
|
+
interface MessageRuntime {
|
|
34
|
+
currentTurn: ChatMessage[];
|
|
35
|
+
customContext: Record<string, unknown>;
|
|
36
|
+
abortController: AbortController | null;
|
|
37
|
+
responseProvider: ResponseProvider;
|
|
38
|
+
}
|
|
39
|
+
interface MessageEngine {
|
|
40
|
+
getState(): PublicMessageState;
|
|
41
|
+
subscribe(listener: (state: PublicMessageState) => void): () => void;
|
|
42
|
+
subscribe(kinds: MessageUpdateKinds, listener: (state: PublicMessageState) => void): () => void;
|
|
43
|
+
sendMessage(content: string): Promise<void>;
|
|
44
|
+
send(...msgs: ChatMessage[]): Promise<void>;
|
|
45
|
+
abort(): Promise<void>;
|
|
46
|
+
setResponseProvider(provider: ResponseProvider): void;
|
|
47
|
+
}
|
|
48
|
+
type MessageUpdateKind = 'messages' | 'requestState';
|
|
49
|
+
type MessageUpdateKinds = MessageUpdateKind | MessageUpdateKind[];
|
|
50
|
+
type MessageMutationRecipe = (draft: InternalMessageState, skipNotify: () => void) => void;
|
|
51
|
+
interface MutateMessageStateFn {
|
|
52
|
+
/**
|
|
53
|
+
* 在受控上下文中修改消息状态,并按声明的更新类型分发状态变更通知。
|
|
54
|
+
*
|
|
55
|
+
* 这里的“通知”语义对应 `subscribe` 订阅链路,用于驱动依赖 engine 状态快照的观察者;
|
|
56
|
+
* 它并不等同于具体框架的响应式更新机制。对于 Vue 等运行时,界面更新可能同时依赖
|
|
57
|
+
* 框架自身的响应式追踪与 `subscribe` 侧的状态通知,两者职责不同,不应混用。
|
|
58
|
+
*/
|
|
59
|
+
(kinds: MessageUpdateKinds, recipe: MessageMutationRecipe): void;
|
|
60
|
+
}
|
|
61
|
+
interface MessageStateAdapter {
|
|
62
|
+
initialize(initialState: InternalMessageState): void;
|
|
63
|
+
getState(): PublicMessageState;
|
|
64
|
+
/**
|
|
65
|
+
* 创建一条适配当前运行时的消息对象。
|
|
66
|
+
*
|
|
67
|
+
* engine 和 core 插件里凡是“新建消息”的入口,都应统一走这个方法,
|
|
68
|
+
* 以便不同平台注入各自的运行时能力。
|
|
69
|
+
*
|
|
70
|
+
* 例如:
|
|
71
|
+
* - native/纯 TS 场景:直接返回原对象即可
|
|
72
|
+
* `createMessage(message) { return message }`
|
|
73
|
+
* - Vue 场景:返回 reactive proxy,使后续对 message.content / message.state 的原地修改能够被追踪
|
|
74
|
+
* `createMessage(message) { return reactive(message) }`
|
|
75
|
+
*/
|
|
76
|
+
createMessage<T extends ChatMessage>(message: T): T;
|
|
77
|
+
mutate: MutateMessageStateFn;
|
|
78
|
+
subscribe(listener: (state: PublicMessageState) => void): () => void;
|
|
79
|
+
subscribe(kinds: MessageUpdateKinds, listener: (state: PublicMessageState) => void): () => void;
|
|
80
|
+
}
|
|
81
|
+
interface BasePluginContext {
|
|
82
|
+
getState(): PublicMessageState;
|
|
83
|
+
/**
|
|
84
|
+
* 创建一条适配当前运行时的消息对象。
|
|
85
|
+
*
|
|
86
|
+
* 插件在运行过程中如果需要主动创建并追加消息,应统一通过此接口构造消息实例,
|
|
87
|
+
* 而不是直接持有普通对象字面量。这样可以确保消息对象具备当前平台所要求的运行时能力。
|
|
88
|
+
*
|
|
89
|
+
* 对于采用响应式机制的平台(例如 Vue),该接口通常会返回带有响应式包装的消息实例。
|
|
90
|
+
* 如果插件绕过此接口直接创建普通对象,再参与后续的状态更新或原地字段修改,
|
|
91
|
+
* 可能导致消息内容、状态字段等变更无法被正确追踪。
|
|
92
|
+
*/
|
|
93
|
+
createMessage<T extends ChatMessage>(message: T): T;
|
|
94
|
+
/**
|
|
95
|
+
* 在受控上下文中修改状态,并触发与 `subscribe` 对应的状态更新通知。
|
|
96
|
+
*
|
|
97
|
+
* 该通知机制面向 engine 的订阅接口,而不是具体框架的响应式系统本身。
|
|
98
|
+
* 因此,在需要让 `subscribe` 观察者感知到变更时,应通过此接口完成状态写入。
|
|
99
|
+
*/
|
|
100
|
+
mutate: MutateMessageStateFn;
|
|
101
|
+
abortSignal: AbortSignal;
|
|
102
|
+
currentTurn: ChatMessage[];
|
|
103
|
+
customContext: Record<string, unknown>;
|
|
104
|
+
setRequestState: (state: RequestState, processingState?: RequestProcessingState) => void;
|
|
105
|
+
setCustomContext: (data: Record<string, unknown>) => void;
|
|
106
|
+
}
|
|
107
|
+
interface BeforeRequestContext extends BasePluginContext {
|
|
108
|
+
requestBody: MessageRequestBody;
|
|
109
|
+
}
|
|
110
|
+
interface AfterRequestContext extends BasePluginContext {
|
|
111
|
+
currentMessage: DeepReadonly<ChatMessage>;
|
|
112
|
+
lastChoice?: ChatCompletion.Choice | ChatCompletionChunk.Choice;
|
|
113
|
+
/**
|
|
114
|
+
* 使用 appendMessage 函数追加消息,可触发消息更新通知。
|
|
115
|
+
*/
|
|
116
|
+
appendMessage: (message: ChatMessage | ChatMessage[]) => void;
|
|
117
|
+
requestNext: () => void;
|
|
118
|
+
}
|
|
119
|
+
interface CompletionChunkContext extends BasePluginContext {
|
|
120
|
+
/**
|
|
121
|
+
* 当前消息,只读。需要使用 updateCurrentMessage 函数修改当前消息,才能正常触发消息更新通知。
|
|
122
|
+
*/
|
|
123
|
+
currentMessage: DeepReadonly<ChatMessage>;
|
|
124
|
+
/**
|
|
125
|
+
* 使用 updateCurrentMessage 函数修改当前消息,才能正常触发消息更新通知。
|
|
126
|
+
*/
|
|
127
|
+
updateCurrentMessage: (recipe: (message: ChatMessage) => void) => void;
|
|
128
|
+
choice: ChatCompletion.Choice | ChatCompletionChunk.Choice;
|
|
129
|
+
chunk: ChatCompletion | ChatCompletionChunk;
|
|
130
|
+
}
|
|
131
|
+
interface MessageEnginePlugin {
|
|
132
|
+
/**
|
|
133
|
+
* 插件名称。
|
|
134
|
+
*/
|
|
135
|
+
name?: string;
|
|
136
|
+
/**
|
|
137
|
+
* 是否禁用插件。
|
|
138
|
+
*/
|
|
139
|
+
disabled?: boolean | ((context: BasePluginContext) => boolean);
|
|
140
|
+
/**
|
|
141
|
+
* 一次对话回合(turn)开始钩子:用户消息入队后、正式发起请求之前触发。
|
|
142
|
+
* 按插件注册顺序串行执行,便于做有序初始化/校验;出错则中断流程。
|
|
143
|
+
*/
|
|
144
|
+
onTurnStart?: (context: BasePluginContext) => MaybePromise<void>;
|
|
145
|
+
/**
|
|
146
|
+
* 一次对话回合(turn)结束的生命周期钩子。
|
|
147
|
+
* 触发时机:本轮对话完成(成功、被中止)后。
|
|
148
|
+
* 执行策略:按插件注册顺序串行执行,有错误则中断流程。
|
|
149
|
+
*/
|
|
150
|
+
onTurnEnd?: (context: BasePluginContext) => MaybePromise<void>;
|
|
151
|
+
/**
|
|
152
|
+
* 请求开始前的生命周期钩子。
|
|
153
|
+
* 触发时机:已组装 requestBody,正式发起请求之前。
|
|
154
|
+
* 执行策略:按插件注册顺序串行执行,避免并发修改 requestBody 产生冲突。
|
|
155
|
+
*/
|
|
156
|
+
onBeforeRequest?: (context: BeforeRequestContext) => MaybePromise<void>;
|
|
157
|
+
/**
|
|
158
|
+
* 请求完成后的生命周期钩子。
|
|
159
|
+
* 触发时机:本次请求(含流式)结束后。
|
|
160
|
+
* 执行策略:并行执行(Promise.all)。
|
|
161
|
+
*/
|
|
162
|
+
onAfterRequest?: (context: AfterRequestContext) => MaybePromise<void>;
|
|
163
|
+
/**
|
|
164
|
+
* 数据块处理钩子,在接收到每个响应数据块时触发。
|
|
165
|
+
* 无论是流式响应(多个增量数据块)还是非流式响应(单个完整数据块),都会触发此钩子。
|
|
166
|
+
*/
|
|
167
|
+
onCompletionChunk?: (context: CompletionChunkContext) => void;
|
|
168
|
+
onError?: (context: BasePluginContext & {
|
|
169
|
+
error: unknown;
|
|
170
|
+
}) => void;
|
|
171
|
+
onFinally?: (context: BasePluginContext) => void;
|
|
172
|
+
}
|
|
173
|
+
interface CreateMessageEngineOptions {
|
|
174
|
+
initialMessages?: ChatMessage[];
|
|
175
|
+
/**
|
|
176
|
+
* 请求消息时,要包含的字段(白名单)。默认包含所有字段。
|
|
177
|
+
* 如果 `requestMessageFieldsExclude` 存在,会先取 `requestMessageFields` 中的字段,再排除 `requestMessageFieldsExclude` 中的字段
|
|
178
|
+
*/
|
|
179
|
+
requestMessageFields?: string[];
|
|
180
|
+
/**
|
|
181
|
+
* 请求消息时,要排除的字段(黑名单)。默认会排除 `state`、`metadata`、`loading` 字段(这几个字段是给UI展示用的)。
|
|
182
|
+
* 如果 `requestMessageFields` 存在,会先取 `requestMessageFields` 中的字段,再排除 `requestMessageFieldsExclude` 中的字段
|
|
183
|
+
*/
|
|
184
|
+
requestMessageFieldsExclude?: string[];
|
|
185
|
+
responseProvider?: ResponseProvider;
|
|
186
|
+
/**
|
|
187
|
+
* 全局的数据块处理钩子,在接收到每个响应数据块时触发。
|
|
188
|
+
* 注意:此钩子与插件中的 onCompletionChunk 有区别。
|
|
189
|
+
* 如果传入了此参数,默认的 chunk 处理逻辑不会自动执行,需要手动调用 runDefault 来执行默认处理逻辑。
|
|
190
|
+
*/
|
|
191
|
+
onCompletionChunk?: (context: CompletionChunkContext, runDefault: () => void) => void;
|
|
192
|
+
plugins?: MessageEnginePlugin[];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
declare const createNativeMessageAdapter: () => MessageStateAdapter;
|
|
196
|
+
|
|
197
|
+
interface VueMessageStateAdapter extends MessageStateAdapter {
|
|
198
|
+
requestState: Ref<RequestState>;
|
|
199
|
+
processingState: Ref<RequestProcessingState | undefined>;
|
|
200
|
+
messages: Ref<ChatMessage[]>;
|
|
201
|
+
isProcessing: ComputedRef<boolean>;
|
|
202
|
+
}
|
|
203
|
+
declare const createVueMessageAdapter: () => VueMessageStateAdapter;
|
|
204
|
+
|
|
205
|
+
declare const createMessageEngine: (adapter: MessageStateAdapter, options?: CreateMessageEngineOptions) => MessageEngine;
|
|
206
|
+
|
|
207
|
+
declare const lengthPlugin: (options?: MessageEnginePlugin & {
|
|
208
|
+
continueContent?: string;
|
|
209
|
+
}) => MessageEnginePlugin;
|
|
210
|
+
|
|
211
|
+
declare const thinkingPlugin: (options?: MessageEnginePlugin) => MessageEnginePlugin;
|
|
212
|
+
|
|
213
|
+
type AssistantMessageWithState = ChatMessage<Record<string, unknown>, {
|
|
214
|
+
toolCall?: Record<string, Record<string, unknown>>;
|
|
215
|
+
}>;
|
|
216
|
+
type ToolCallContext = BasePluginContext & {
|
|
217
|
+
assistantMessage: AssistantMessageWithState;
|
|
218
|
+
toolMessage: ChatMessage;
|
|
219
|
+
};
|
|
220
|
+
declare const toolPlugin: (options: MessageEnginePlugin & {
|
|
221
|
+
/**
|
|
222
|
+
* 获取工具列表的函数。会在请求大模型前调用。
|
|
223
|
+
*/
|
|
224
|
+
getTools: () => Promise<ChatCompletionTool[]>;
|
|
225
|
+
/**
|
|
226
|
+
* 在处理包含 tool_calls 的响应前调用。
|
|
227
|
+
*/
|
|
228
|
+
beforeCallTools?: (toolCalls: ChatCompletionMessageToolCall[], context: BasePluginContext & {
|
|
229
|
+
assistantMessage: AssistantMessageWithState;
|
|
230
|
+
}) => Promise<void>;
|
|
231
|
+
/**
|
|
232
|
+
* 执行单个工具调用并返回其文本结果的函数。
|
|
233
|
+
*/
|
|
234
|
+
callTool: (toolCall: ChatCompletionMessageToolCall, context: ToolCallContext) => Promise<string | Record<string, any>> | AsyncGenerator<string | Record<string, any>>;
|
|
235
|
+
/**
|
|
236
|
+
* 工具调用开始时的回调函数。
|
|
237
|
+
* 触发时机:工具消息已创建并追加后,调用 callTool 之前触发。
|
|
238
|
+
* @param toolCall - 工具调用对象
|
|
239
|
+
* @param context - 插件上下文,包含当前工具消息
|
|
240
|
+
*/
|
|
241
|
+
onToolCallStart?: (toolCall: ChatCompletionMessageToolCall, context: ToolCallContext) => void;
|
|
242
|
+
/**
|
|
243
|
+
* 工具调用结束时的回调函数。
|
|
244
|
+
* 触发时机:工具调用完成(成功、失败或取消)时触发。
|
|
245
|
+
* @param toolCall - 工具调用对象
|
|
246
|
+
* @param context - 插件上下文,包含当前工具消息、状态和错误信息
|
|
247
|
+
* @param context.status - 工具调用状态:'success' | 'failed' | 'cancelled'
|
|
248
|
+
* @param context.error - 当状态为 'failed' 或 'cancelled' 时,可能包含错误信息
|
|
249
|
+
*/
|
|
250
|
+
onToolCallEnd?: (toolCall: ChatCompletionMessageToolCall, context: ToolCallContext & {
|
|
251
|
+
status: "success" | "failed" | "cancelled";
|
|
252
|
+
error?: Error;
|
|
253
|
+
}) => void;
|
|
254
|
+
/**
|
|
255
|
+
* 当请求被中止时用于工具调用取消的消息内容。
|
|
256
|
+
*/
|
|
257
|
+
toolCallCancelledContent?: string;
|
|
258
|
+
/**
|
|
259
|
+
* 当工具调用执行失败(抛错或拒绝)时使用的消息内容。
|
|
260
|
+
*/
|
|
261
|
+
toolCallFailedContent?: string;
|
|
262
|
+
/**
|
|
263
|
+
* 是否在请求前自动补充缺失的 tool 消息。
|
|
264
|
+
* 当 assistant 响应了 tool_calls 但未追加对应的 tool 消息时,
|
|
265
|
+
* 插件将自动补充"工具调用已取消"的 tool 消息。默认:false。
|
|
266
|
+
*/
|
|
267
|
+
autoFillMissingToolMessages?: boolean;
|
|
268
|
+
}) => MessageEnginePlugin;
|
|
269
|
+
|
|
270
|
+
declare function normalizeToAsyncGenerator<T>(result: Promise<T> | AsyncGenerator<T> | Promise<AsyncGenerator<T>>): AsyncGenerator<T>;
|
|
271
|
+
/**
|
|
272
|
+
* Merge delta data from completion responses
|
|
273
|
+
* Handles string concatenation, object merging, and array merging by index
|
|
274
|
+
*
|
|
275
|
+
* @param target - Target object to merge into
|
|
276
|
+
* @param source - Source object to merge from
|
|
277
|
+
* @returns Merged target object
|
|
278
|
+
*/
|
|
279
|
+
declare const combineDeltaData: (target: Record<string, any>, source: Record<string, any>) => Record<string, any>;
|
|
280
|
+
|
|
281
|
+
export { type AfterRequestContext, type BasePluginContext, type BeforeRequestContext, type ChatMessage, type CompletionChunkContext, type CreateMessageEngineOptions, type DeepReadonly, type InternalMessageState, type MessageEngine, type MessageEnginePlugin, type MessageMutationRecipe, type MessageRequestBody, type MessageRuntime, type MessageStateAdapter, type MessageUpdateKind, type MessageUpdateKinds, type MutateMessageStateFn, type PublicMessageState, type RequestProcessingState, type RequestState, type ResponseProvider, type VueMessageStateAdapter, combineDeltaData, createMessageEngine, createNativeMessageAdapter, createVueMessageAdapter, lengthPlugin, normalizeToAsyncGenerator, thinkingPlugin, toolPlugin };
|