@lobehub/chat 1.1.7 → 1.1.8
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/CHANGELOG.md +25 -0
- package/docs/usage/providers/01ai.mdx +1 -1
- package/docs/usage/providers/01ai.zh-CN.mdx +1 -1
- package/docs/usage/providers/anthropic.mdx +1 -1
- package/docs/usage/providers/anthropic.zh-CN.mdx +1 -1
- package/docs/usage/providers/azure.mdx +1 -1
- package/docs/usage/providers/azure.zh-CN.mdx +1 -1
- package/docs/usage/providers/bedrock.mdx +1 -1
- package/docs/usage/providers/bedrock.zh-CN.mdx +1 -1
- package/docs/usage/providers/deepseek.mdx +1 -1
- package/docs/usage/providers/deepseek.zh-CN.mdx +1 -1
- package/docs/usage/providers/gemini.mdx +1 -1
- package/docs/usage/providers/gemini.zh-CN.mdx +1 -1
- package/docs/usage/providers/groq.mdx +1 -1
- package/docs/usage/providers/groq.zh-CN.mdx +1 -1
- package/docs/usage/providers/minimax.mdx +1 -1
- package/docs/usage/providers/minimax.zh-CN.mdx +1 -1
- package/docs/usage/providers/mistral.mdx +1 -1
- package/docs/usage/providers/mistral.zh-CN.mdx +1 -1
- package/docs/usage/providers/moonshot.mdx +1 -1
- package/docs/usage/providers/moonshot.zh-CN.mdx +1 -1
- package/docs/usage/providers/openai.mdx +1 -1
- package/docs/usage/providers/openai.zh-CN.mdx +1 -1
- package/docs/usage/providers/openrouter.mdx +1 -1
- package/docs/usage/providers/openrouter.zh-CN.mdx +2 -2
- package/docs/usage/providers/perplexity.mdx +1 -1
- package/docs/usage/providers/perplexity.zh-CN.mdx +1 -1
- package/docs/usage/providers/qwen.mdx +1 -1
- package/docs/usage/providers/qwen.zh-CN.mdx +1 -1
- package/docs/usage/providers/stepfun.mdx +1 -1
- package/docs/usage/providers/stepfun.zh-CN.mdx +2 -2
- package/docs/usage/providers/togetherai.mdx +1 -1
- package/docs/usage/providers/togetherai.zh-CN.mdx +2 -2
- package/docs/usage/providers/zhipu.mdx +1 -1
- package/docs/usage/providers/zhipu.zh-CN.mdx +2 -2
- package/docs/usage/tools-calling/anthropic.zh-CN.mdx +935 -2
- package/docs/usage/tools-calling/openai.zh-CN.mdx +4 -2
- package/docs/usage/tools-calling.zh-CN.mdx +15 -1
- package/package.json +1 -1
- package/src/libs/agent-runtime/utils/anthropicHelpers.test.ts +104 -0
- package/src/libs/agent-runtime/utils/anthropicHelpers.ts +28 -7
- package/src/libs/agent-runtime/utils/streams/anthropic.test.ts +156 -0
- package/src/libs/agent-runtime/utils/streams/anthropic.ts +12 -3
- package/src/libs/agent-runtime/utils/streams/protocol.ts +1 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: OpenAI GPT 系列 Tools Calling
|
|
3
|
-
description:
|
|
2
|
+
title: OpenAI GPT 系列 Tools Calling 评测
|
|
3
|
+
description: >-
|
|
4
|
+
使用 LobeChat 测试 OpenAI GPT 系列模型(GPT 3.5-turbo / GPT-4 /GPT-4o) 的工具调用(Function
|
|
5
|
+
Calling)能力,并展现评测结果
|
|
4
6
|
tags:
|
|
5
7
|
- Tools Calling
|
|
6
8
|
- Benchmark
|
|
@@ -4,7 +4,7 @@ description: 基于 LobeChat 测试主流支持工具调用(Tool Calling)
|
|
|
4
4
|
tags:
|
|
5
5
|
- Tools Calling
|
|
6
6
|
- Benchmark
|
|
7
|
-
- Function Calling
|
|
7
|
+
- Function Calling 评测
|
|
8
8
|
- 工具调用
|
|
9
9
|
- LobeChat 插件
|
|
10
10
|
---
|
|
@@ -238,4 +238,18 @@ Create images from a text-only prompt.
|
|
|
238
238
|
|
|
239
239
|
## 评测结果
|
|
240
240
|
|
|
241
|
+
各模型的评测细节可以点击查看:
|
|
242
|
+
|
|
243
|
+
<Cards>
|
|
244
|
+
<Card href={'/docs/usage/tools-calling/openai'} title={'OpenAI GPT 系列'} />
|
|
245
|
+
<Card href={'/docs/usage/tools-calling/anthropic'} title={'Anthropic Claude 系列'} />
|
|
246
|
+
<Card href={'/docs/usage/tools-calling/google'} title={'【TODO】Google Gemini 系列'} />
|
|
247
|
+
<Card
|
|
248
|
+
href={'/docs/usage/tools-calling/groq'}
|
|
249
|
+
title={'【TODO】Groq 部署的开源模型(Llama 3/Qwen2/Mistral 等)'}
|
|
250
|
+
/>
|
|
251
|
+
</Cards>
|
|
252
|
+
|
|
253
|
+
### 结果汇总
|
|
254
|
+
|
|
241
255
|
TODO
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -192,6 +192,110 @@ describe('anthropicHelpers', () => {
|
|
|
192
192
|
{ content: '你好', role: 'user' },
|
|
193
193
|
]);
|
|
194
194
|
});
|
|
195
|
+
|
|
196
|
+
it('should correctly convert OpenAI tool message to Anthropic format', () => {
|
|
197
|
+
const messages: OpenAIChatMessage[] = [
|
|
198
|
+
{
|
|
199
|
+
content: '告诉我杭州和北京的天气,先回答我好的',
|
|
200
|
+
role: 'user',
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
content:
|
|
204
|
+
'好的,我会为您查询杭州和北京的天气信息。我现在就开始查询这两个城市的当前天气情况。',
|
|
205
|
+
role: 'assistant',
|
|
206
|
+
tool_calls: [
|
|
207
|
+
{
|
|
208
|
+
function: {
|
|
209
|
+
arguments: '{"city": "\\u676d\\u5dde"}',
|
|
210
|
+
name: 'realtime-weather____fetchCurrentWeather',
|
|
211
|
+
},
|
|
212
|
+
id: 'toolu_018PNQkH8ChbjoJz4QBiFVod',
|
|
213
|
+
type: 'function',
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
function: {
|
|
217
|
+
arguments: '{"city": "\\u5317\\u4eac"}',
|
|
218
|
+
name: 'realtime-weather____fetchCurrentWeather',
|
|
219
|
+
},
|
|
220
|
+
id: 'toolu_018VQTQ6fwAEC3eppuEfMxPp',
|
|
221
|
+
type: 'function',
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
content:
|
|
227
|
+
'[{"city":"杭州市","adcode":"330100","province":"浙江","reporttime":"2024-06-24 17:02:14","casts":[{"date":"2024-06-24","week":"1","dayweather":"小雨","nightweather":"中雨","daytemp":"26","nighttemp":"20","daywind":"西","nightwind":"西","daypower":"1-3","nightpower":"1-3","daytemp_float":"26.0","nighttemp_float":"20.0"},{"date":"2024-06-25","week":"2","dayweather":"大雨","nightweather":"中雨","daytemp":"23","nighttemp":"19","daywind":"东","nightwind":"东","daypower":"1-3","nightpower":"1-3","daytemp_float":"23.0","nighttemp_float":"19.0"},{"date":"2024-06-26","week":"3","dayweather":"中雨","nightweather":"中雨","daytemp":"24","nighttemp":"21","daywind":"东南","nightwind":"东南","daypower":"1-3","nightpower":"1-3","daytemp_float":"24.0","nighttemp_float":"21.0"},{"date":"2024-06-27","week":"4","dayweather":"中雨-大雨","nightweather":"中雨","daytemp":"24","nighttemp":"22","daywind":"南","nightwind":"南","daypower":"1-3","nightpower":"1-3","daytemp_float":"24.0","nighttemp_float":"22.0"}]}]',
|
|
228
|
+
name: 'realtime-weather____fetchCurrentWeather',
|
|
229
|
+
role: 'tool',
|
|
230
|
+
tool_call_id: 'toolu_018PNQkH8ChbjoJz4QBiFVod',
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
content:
|
|
234
|
+
'[{"city":"北京市","adcode":"110000","province":"北京","reporttime":"2024-06-24 17:03:11","casts":[{"date":"2024-06-24","week":"1","dayweather":"晴","nightweather":"晴","daytemp":"33","nighttemp":"20","daywind":"北","nightwind":"北","daypower":"1-3","nightpower":"1-3","daytemp_float":"33.0","nighttemp_float":"20.0"},{"date":"2024-06-25","week":"2","dayweather":"晴","nightweather":"晴","daytemp":"35","nighttemp":"21","daywind":"东南","nightwind":"东南","daypower":"1-3","nightpower":"1-3","daytemp_float":"35.0","nighttemp_float":"21.0"},{"date":"2024-06-26","week":"3","dayweather":"晴","nightweather":"晴","daytemp":"35","nighttemp":"23","daywind":"西南","nightwind":"西南","daypower":"1-3","nightpower":"1-3","daytemp_float":"35.0","nighttemp_float":"23.0"},{"date":"2024-06-27","week":"4","dayweather":"多云","nightweather":"多云","daytemp":"35","nighttemp":"23","daywind":"西南","nightwind":"西南","daypower":"1-3","nightpower":"1-3","daytemp_float":"35.0","nighttemp_float":"23.0"}]}]',
|
|
235
|
+
name: 'realtime-weather____fetchCurrentWeather',
|
|
236
|
+
role: 'tool',
|
|
237
|
+
tool_call_id: 'toolu_018VQTQ6fwAEC3eppuEfMxPp',
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
content: '继续',
|
|
241
|
+
role: 'user',
|
|
242
|
+
},
|
|
243
|
+
];
|
|
244
|
+
|
|
245
|
+
const contents = buildAnthropicMessages(messages);
|
|
246
|
+
|
|
247
|
+
expect(contents).toEqual([
|
|
248
|
+
{ content: '告诉我杭州和北京的天气,先回答我好的', role: 'user' },
|
|
249
|
+
{
|
|
250
|
+
content: [
|
|
251
|
+
{
|
|
252
|
+
text: '好的,我会为您查询杭州和北京的天气信息。我现在就开始查询这两个城市的当前天气情况。',
|
|
253
|
+
type: 'text',
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
id: 'toolu_018PNQkH8ChbjoJz4QBiFVod',
|
|
257
|
+
input: { city: '杭州' },
|
|
258
|
+
name: 'realtime-weather____fetchCurrentWeather',
|
|
259
|
+
type: 'tool_use',
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
id: 'toolu_018VQTQ6fwAEC3eppuEfMxPp',
|
|
263
|
+
input: { city: '北京' },
|
|
264
|
+
name: 'realtime-weather____fetchCurrentWeather',
|
|
265
|
+
type: 'tool_use',
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
role: 'assistant',
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
content: [
|
|
272
|
+
{
|
|
273
|
+
content: [
|
|
274
|
+
{
|
|
275
|
+
text: '[{"city":"杭州市","adcode":"330100","province":"浙江","reporttime":"2024-06-24 17:02:14","casts":[{"date":"2024-06-24","week":"1","dayweather":"小雨","nightweather":"中雨","daytemp":"26","nighttemp":"20","daywind":"西","nightwind":"西","daypower":"1-3","nightpower":"1-3","daytemp_float":"26.0","nighttemp_float":"20.0"},{"date":"2024-06-25","week":"2","dayweather":"大雨","nightweather":"中雨","daytemp":"23","nighttemp":"19","daywind":"东","nightwind":"东","daypower":"1-3","nightpower":"1-3","daytemp_float":"23.0","nighttemp_float":"19.0"},{"date":"2024-06-26","week":"3","dayweather":"中雨","nightweather":"中雨","daytemp":"24","nighttemp":"21","daywind":"东南","nightwind":"东南","daypower":"1-3","nightpower":"1-3","daytemp_float":"24.0","nighttemp_float":"21.0"},{"date":"2024-06-27","week":"4","dayweather":"中雨-大雨","nightweather":"中雨","daytemp":"24","nighttemp":"22","daywind":"南","nightwind":"南","daypower":"1-3","nightpower":"1-3","daytemp_float":"24.0","nighttemp_float":"22.0"}]}]',
|
|
276
|
+
type: 'text',
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
tool_use_id: 'toolu_018PNQkH8ChbjoJz4QBiFVod',
|
|
280
|
+
type: 'tool_result',
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
content: [
|
|
284
|
+
{
|
|
285
|
+
text: '[{"city":"北京市","adcode":"110000","province":"北京","reporttime":"2024-06-24 17:03:11","casts":[{"date":"2024-06-24","week":"1","dayweather":"晴","nightweather":"晴","daytemp":"33","nighttemp":"20","daywind":"北","nightwind":"北","daypower":"1-3","nightpower":"1-3","daytemp_float":"33.0","nighttemp_float":"20.0"},{"date":"2024-06-25","week":"2","dayweather":"晴","nightweather":"晴","daytemp":"35","nighttemp":"21","daywind":"东南","nightwind":"东南","daypower":"1-3","nightpower":"1-3","daytemp_float":"35.0","nighttemp_float":"21.0"},{"date":"2024-06-26","week":"3","dayweather":"晴","nightweather":"晴","daytemp":"35","nighttemp":"23","daywind":"西南","nightwind":"西南","daypower":"1-3","nightpower":"1-3","daytemp_float":"35.0","nighttemp_float":"23.0"},{"date":"2024-06-27","week":"4","dayweather":"多云","nightweather":"多云","daytemp":"35","nighttemp":"23","daywind":"西南","nightwind":"西南","daypower":"1-3","nightpower":"1-3","daytemp_float":"35.0","nighttemp_float":"23.0"}]}]',
|
|
286
|
+
type: 'text',
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
tool_use_id: 'toolu_018VQTQ6fwAEC3eppuEfMxPp',
|
|
290
|
+
type: 'tool_result',
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
role: 'user',
|
|
294
|
+
},
|
|
295
|
+
{ content: '_', role: 'assistant' },
|
|
296
|
+
{ content: '继续', role: 'user' },
|
|
297
|
+
]);
|
|
298
|
+
});
|
|
195
299
|
});
|
|
196
300
|
|
|
197
301
|
describe('buildAnthropicTools', () => {
|
|
@@ -95,16 +95,37 @@ export const buildAnthropicMessages = (
|
|
|
95
95
|
): Anthropic.Messages.MessageParam[] => {
|
|
96
96
|
const messages: Anthropic.Messages.MessageParam[] = [];
|
|
97
97
|
let lastRole = 'assistant';
|
|
98
|
+
let pendingToolResults: Anthropic.ToolResultBlockParam[] = [];
|
|
99
|
+
|
|
100
|
+
oaiMessages.forEach((message, index) => {
|
|
101
|
+
// refs: https://docs.anthropic.com/claude/docs/tool-use#tool-use-and-tool-result-content-blocks
|
|
102
|
+
if (message.role === 'tool') {
|
|
103
|
+
pendingToolResults.push({
|
|
104
|
+
content: [{ text: message.content as string, type: 'text' }],
|
|
105
|
+
tool_use_id: message.tool_call_id!,
|
|
106
|
+
type: 'tool_result',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// If this is the last message or the next message is not a 'tool' message,
|
|
110
|
+
// we add the accumulated tool results as a single 'user' message
|
|
111
|
+
if (index === oaiMessages.length - 1 || oaiMessages[index + 1].role !== 'tool') {
|
|
112
|
+
messages.push({
|
|
113
|
+
content: pendingToolResults,
|
|
114
|
+
role: 'user',
|
|
115
|
+
});
|
|
116
|
+
pendingToolResults = [];
|
|
117
|
+
lastRole = 'user';
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
const anthropicMessage = buildAnthropicMessage(message);
|
|
98
121
|
|
|
99
|
-
|
|
100
|
-
|
|
122
|
+
if (lastRole === anthropicMessage.role) {
|
|
123
|
+
messages.push({ content: '_', role: lastRole === 'user' ? 'assistant' : 'user' });
|
|
124
|
+
}
|
|
101
125
|
|
|
102
|
-
|
|
103
|
-
messages.push(
|
|
126
|
+
lastRole = anthropicMessage.role;
|
|
127
|
+
messages.push(anthropicMessage);
|
|
104
128
|
}
|
|
105
|
-
|
|
106
|
-
lastRole = anthropicMessage.role;
|
|
107
|
-
messages.push(anthropicMessage);
|
|
108
129
|
});
|
|
109
130
|
|
|
110
131
|
return messages;
|
|
@@ -227,6 +227,162 @@ describe('AnthropicStream', () => {
|
|
|
227
227
|
|
|
228
228
|
expect(onToolCallMock).toHaveBeenCalledTimes(5);
|
|
229
229
|
});
|
|
230
|
+
it('should handle parallel tools use event and ReadableStream input', async () => {
|
|
231
|
+
const streams = [
|
|
232
|
+
{
|
|
233
|
+
type: 'message_start',
|
|
234
|
+
message: {
|
|
235
|
+
id: 'msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
236
|
+
type: 'message',
|
|
237
|
+
role: 'assistant',
|
|
238
|
+
model: 'claude-3-5-sonnet-20240620',
|
|
239
|
+
content: [],
|
|
240
|
+
stop_reason: null,
|
|
241
|
+
stop_sequence: null,
|
|
242
|
+
usage: { input_tokens: 485, output_tokens: 4 },
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
{ type: 'content_block_start', index: 0, content_block: { type: 'text', text: '' } },
|
|
246
|
+
{
|
|
247
|
+
type: 'content_block_delta',
|
|
248
|
+
index: 0,
|
|
249
|
+
delta: { type: 'text_delta', text: '好的,我会为您查询杭州和北京的天气情况。' },
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
type: 'content_block_delta',
|
|
253
|
+
index: 0,
|
|
254
|
+
delta: { type: 'text_delta', text: '请稍等,我现在开始获取这两个城市的天气信息。' },
|
|
255
|
+
},
|
|
256
|
+
{ type: 'content_block_stop', index: 0 },
|
|
257
|
+
{
|
|
258
|
+
type: 'content_block_start',
|
|
259
|
+
index: 1,
|
|
260
|
+
content_block: {
|
|
261
|
+
type: 'tool_use',
|
|
262
|
+
id: 'toolu_011NuszmBcxskstLWe4z4z5B',
|
|
263
|
+
name: 'realtime-weather____fetchCurrentWeather',
|
|
264
|
+
input: {},
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
type: 'content_block_delta',
|
|
269
|
+
index: 1,
|
|
270
|
+
delta: { type: 'input_json_delta', partial_json: '' },
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
type: 'content_block_delta',
|
|
274
|
+
index: 1,
|
|
275
|
+
delta: { type: 'input_json_delta', partial_json: '{"city": "杭州"}' },
|
|
276
|
+
},
|
|
277
|
+
{ type: 'content_block_stop', index: 1 },
|
|
278
|
+
{
|
|
279
|
+
type: 'content_block_start',
|
|
280
|
+
index: 2,
|
|
281
|
+
content_block: {
|
|
282
|
+
type: 'tool_use',
|
|
283
|
+
id: 'toolu_01HojNiibMiKnYFvLrJyfX3B',
|
|
284
|
+
name: 'realtime-weather____fetchCurrentWeather',
|
|
285
|
+
input: {},
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
type: 'content_block_delta',
|
|
290
|
+
index: 2,
|
|
291
|
+
delta: { type: 'input_json_delta', partial_json: '' },
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
type: 'content_block_delta',
|
|
295
|
+
index: 2,
|
|
296
|
+
delta: { type: 'input_json_delta', partial_json: '{"city": "北京"}' },
|
|
297
|
+
},
|
|
298
|
+
{ type: 'content_block_stop', index: 2 },
|
|
299
|
+
{
|
|
300
|
+
type: 'message_delta',
|
|
301
|
+
delta: { stop_reason: 'tool_use', stop_sequence: null },
|
|
302
|
+
usage: { output_tokens: 150 },
|
|
303
|
+
},
|
|
304
|
+
{ type: 'message_stop' },
|
|
305
|
+
];
|
|
306
|
+
|
|
307
|
+
const mockReadableStream = new ReadableStream({
|
|
308
|
+
start(controller) {
|
|
309
|
+
streams.forEach((chunk) => {
|
|
310
|
+
controller.enqueue(chunk);
|
|
311
|
+
});
|
|
312
|
+
controller.close();
|
|
313
|
+
},
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const onToolCallMock = vi.fn();
|
|
317
|
+
|
|
318
|
+
const protocolStream = AnthropicStream(mockReadableStream, {
|
|
319
|
+
onToolCall: onToolCallMock,
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
const decoder = new TextDecoder();
|
|
323
|
+
const chunks = [];
|
|
324
|
+
|
|
325
|
+
// @ts-ignore
|
|
326
|
+
for await (const chunk of protocolStream) {
|
|
327
|
+
chunks.push(decoder.decode(chunk, { stream: true }));
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
expect(chunks).toEqual(
|
|
331
|
+
[
|
|
332
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
333
|
+
'event: data',
|
|
334
|
+
'data: {"id":"msg_0175ryA67RbGrnRrGBXFQEYK","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":485,"output_tokens":4}}\n',
|
|
335
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
336
|
+
'event: data',
|
|
337
|
+
'data: ""\n',
|
|
338
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
339
|
+
'event: text',
|
|
340
|
+
'data: "好的,我会为您查询杭州和北京的天气情况。"\n',
|
|
341
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
342
|
+
'event: text',
|
|
343
|
+
'data: "请稍等,我现在开始获取这两个城市的天气信息。"\n',
|
|
344
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
345
|
+
'event: data',
|
|
346
|
+
'data: {"type":"content_block_stop","index":0}\n',
|
|
347
|
+
// Tool calls
|
|
348
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
349
|
+
'event: tool_calls',
|
|
350
|
+
`data: [{"function":{"arguments":"","name":"realtime-weather____fetchCurrentWeather"},"id":"toolu_011NuszmBcxskstLWe4z4z5B","index":0,"type":"function"}]\n`,
|
|
351
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
352
|
+
'event: tool_calls',
|
|
353
|
+
`data: [{"function":{"arguments":""},"index":0,"type":"function"}]\n`,
|
|
354
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
355
|
+
'event: tool_calls',
|
|
356
|
+
`data: [{"function":{"arguments":"{\\"city\\": \\"杭州\\"}"},"index":0,"type":"function"}]\n`,
|
|
357
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
358
|
+
'event: data',
|
|
359
|
+
`data: {"type":"content_block_stop","index":1}\n`,
|
|
360
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
361
|
+
'event: tool_calls',
|
|
362
|
+
`data: [{"function":{"arguments":"","name":"realtime-weather____fetchCurrentWeather"},"id":"toolu_01HojNiibMiKnYFvLrJyfX3B","index":1,"type":"function"}]\n`,
|
|
363
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
364
|
+
'event: tool_calls',
|
|
365
|
+
`data: [{"function":{"arguments":""},"index":1,"type":"function"}]\n`,
|
|
366
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
367
|
+
'event: tool_calls',
|
|
368
|
+
`data: [{"function":{"arguments":"{\\"city\\": \\"北京\\"}"},"index":1,"type":"function"}]\n`,
|
|
369
|
+
|
|
370
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
371
|
+
'event: data',
|
|
372
|
+
'data: {"type":"content_block_stop","index":2}\n',
|
|
373
|
+
|
|
374
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
375
|
+
'event: stop',
|
|
376
|
+
'data: "tool_use"\n',
|
|
377
|
+
|
|
378
|
+
'id: msg_0175ryA67RbGrnRrGBXFQEYK',
|
|
379
|
+
'event: stop',
|
|
380
|
+
'data: "message_stop"\n',
|
|
381
|
+
].map((item) => `${item}\n`),
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
expect(onToolCallMock).toHaveBeenCalledTimes(6);
|
|
385
|
+
});
|
|
230
386
|
|
|
231
387
|
it('should handle ReadableStream input', async () => {
|
|
232
388
|
const mockReadableStream = new ReadableStream({
|
|
@@ -26,17 +26,26 @@ export const transformAnthropicStream = (
|
|
|
26
26
|
if (chunk.content_block.type === 'tool_use') {
|
|
27
27
|
const toolChunk = chunk.content_block;
|
|
28
28
|
|
|
29
|
+
// if toolIndex is not defined, set it to 0
|
|
30
|
+
if (typeof stack.toolIndex === 'undefined') {
|
|
31
|
+
stack.toolIndex = 0;
|
|
32
|
+
}
|
|
33
|
+
// if toolIndex is defined, increment it
|
|
34
|
+
else {
|
|
35
|
+
stack.toolIndex += 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
29
38
|
const toolCall: StreamToolCallChunkData = {
|
|
30
39
|
function: {
|
|
31
40
|
arguments: '',
|
|
32
41
|
name: toolChunk.name,
|
|
33
42
|
},
|
|
34
43
|
id: toolChunk.id,
|
|
35
|
-
index:
|
|
44
|
+
index: stack.toolIndex,
|
|
36
45
|
type: 'function',
|
|
37
46
|
};
|
|
38
47
|
|
|
39
|
-
stack.tool = { id: toolChunk.id, index:
|
|
48
|
+
stack.tool = { id: toolChunk.id, index: stack.toolIndex, name: toolChunk.name };
|
|
40
49
|
|
|
41
50
|
return { data: [toolCall], id: stack.id, type: 'tool_calls' };
|
|
42
51
|
}
|
|
@@ -55,7 +64,7 @@ export const transformAnthropicStream = (
|
|
|
55
64
|
|
|
56
65
|
const toolCall: StreamToolCallChunkData = {
|
|
57
66
|
function: { arguments: delta },
|
|
58
|
-
index: 0,
|
|
67
|
+
index: stack.toolIndex || 0,
|
|
59
68
|
type: 'function',
|
|
60
69
|
};
|
|
61
70
|
|