kimi-vercel-ai-sdk-provider 0.2.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/LICENSE +198 -0
- package/README.md +871 -0
- package/dist/index.d.mts +1317 -0
- package/dist/index.d.ts +1317 -0
- package/dist/index.js +2764 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2734 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +70 -0
- package/src/__tests__/caching.test.ts +97 -0
- package/src/__tests__/chat.test.ts +386 -0
- package/src/__tests__/code-integration.test.ts +562 -0
- package/src/__tests__/code-provider.test.ts +289 -0
- package/src/__tests__/code.test.ts +427 -0
- package/src/__tests__/core.test.ts +172 -0
- package/src/__tests__/files.test.ts +185 -0
- package/src/__tests__/integration.test.ts +457 -0
- package/src/__tests__/provider.test.ts +188 -0
- package/src/__tests__/tools.test.ts +519 -0
- package/src/chat/index.ts +42 -0
- package/src/chat/kimi-chat-language-model.ts +829 -0
- package/src/chat/kimi-chat-messages.ts +297 -0
- package/src/chat/kimi-chat-response.ts +84 -0
- package/src/chat/kimi-chat-settings.ts +216 -0
- package/src/code/index.ts +66 -0
- package/src/code/kimi-code-language-model.ts +669 -0
- package/src/code/kimi-code-messages.ts +303 -0
- package/src/code/kimi-code-provider.ts +239 -0
- package/src/code/kimi-code-settings.ts +193 -0
- package/src/code/kimi-code-types.ts +354 -0
- package/src/core/errors.ts +140 -0
- package/src/core/index.ts +36 -0
- package/src/core/types.ts +148 -0
- package/src/core/utils.ts +210 -0
- package/src/files/attachment-processor.ts +276 -0
- package/src/files/file-utils.ts +257 -0
- package/src/files/index.ts +24 -0
- package/src/files/kimi-file-client.ts +292 -0
- package/src/index.ts +122 -0
- package/src/kimi-provider.ts +263 -0
- package/src/tools/builtin-tools.ts +273 -0
- package/src/tools/index.ts +33 -0
- package/src/tools/prepare-tools.ts +306 -0
- package/src/version.ts +4 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for context caching configuration.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from 'vitest';
|
|
6
|
+
import { kimiCachingConfigSchema, kimiProviderOptionsSchema } from '../chat/kimi-chat-settings';
|
|
7
|
+
|
|
8
|
+
describe('context caching', () => {
|
|
9
|
+
describe('kimiCachingConfigSchema', () => {
|
|
10
|
+
it('should validate minimal config', () => {
|
|
11
|
+
const result = kimiCachingConfigSchema.safeParse({
|
|
12
|
+
enabled: true
|
|
13
|
+
});
|
|
14
|
+
expect(result.success).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should validate full config', () => {
|
|
18
|
+
const result = kimiCachingConfigSchema.safeParse({
|
|
19
|
+
enabled: true,
|
|
20
|
+
cacheKey: 'my-book-analysis',
|
|
21
|
+
ttlSeconds: 7200,
|
|
22
|
+
resetCache: false
|
|
23
|
+
});
|
|
24
|
+
expect(result.success).toBe(true);
|
|
25
|
+
if (result.success) {
|
|
26
|
+
expect(result.data.cacheKey).toBe('my-book-analysis');
|
|
27
|
+
expect(result.data.ttlSeconds).toBe(7200);
|
|
28
|
+
expect(result.data.resetCache).toBe(false);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should reject config without enabled', () => {
|
|
33
|
+
const result = kimiCachingConfigSchema.safeParse({
|
|
34
|
+
cacheKey: 'test'
|
|
35
|
+
});
|
|
36
|
+
expect(result.success).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should allow disabled config', () => {
|
|
40
|
+
const result = kimiCachingConfigSchema.safeParse({
|
|
41
|
+
enabled: false
|
|
42
|
+
});
|
|
43
|
+
expect(result.success).toBe(true);
|
|
44
|
+
if (result.success) {
|
|
45
|
+
expect(result.data.enabled).toBe(false);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('kimiProviderOptionsSchema with caching', () => {
|
|
51
|
+
it('should accept boolean caching option', () => {
|
|
52
|
+
const result = kimiProviderOptionsSchema.safeParse({
|
|
53
|
+
caching: true
|
|
54
|
+
});
|
|
55
|
+
expect(result.success).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should accept caching config object', () => {
|
|
59
|
+
const result = kimiProviderOptionsSchema.safeParse({
|
|
60
|
+
caching: {
|
|
61
|
+
enabled: true,
|
|
62
|
+
cacheKey: 'conversation-1',
|
|
63
|
+
ttlSeconds: 3600
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
expect(result.success).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should accept caching with other options', () => {
|
|
70
|
+
const result = kimiProviderOptionsSchema.safeParse({
|
|
71
|
+
user: 'user-123',
|
|
72
|
+
caching: {
|
|
73
|
+
enabled: true,
|
|
74
|
+
cacheKey: 'long-document'
|
|
75
|
+
},
|
|
76
|
+
webSearch: true
|
|
77
|
+
});
|
|
78
|
+
expect(result.success).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('kimiProviderOptionsSchema with toolChoicePolyfill', () => {
|
|
83
|
+
it('should accept toolChoicePolyfill boolean', () => {
|
|
84
|
+
const result = kimiProviderOptionsSchema.safeParse({
|
|
85
|
+
toolChoicePolyfill: true
|
|
86
|
+
});
|
|
87
|
+
expect(result.success).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should accept toolChoicePolyfill false', () => {
|
|
91
|
+
const result = kimiProviderOptionsSchema.safeParse({
|
|
92
|
+
toolChoicePolyfill: false
|
|
93
|
+
});
|
|
94
|
+
expect(result.success).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
convertKimiUsage,
|
|
4
|
+
convertToKimiChatMessages,
|
|
5
|
+
extractCodeInterpreterTokens,
|
|
6
|
+
extractMessageContent,
|
|
7
|
+
extractWebSearchTokens,
|
|
8
|
+
getKimiRequestId,
|
|
9
|
+
inferModelCapabilities,
|
|
10
|
+
mapKimiFinishReason
|
|
11
|
+
} from '../chat';
|
|
12
|
+
|
|
13
|
+
describe('inferModelCapabilities', () => {
|
|
14
|
+
it('should detect thinking model', () => {
|
|
15
|
+
const caps = inferModelCapabilities('kimi-k2.5-thinking');
|
|
16
|
+
expect(caps.thinking).toBe(true);
|
|
17
|
+
expect(caps.alwaysThinking).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should detect K2.5 model video support', () => {
|
|
21
|
+
const caps = inferModelCapabilities('kimi-k2.5');
|
|
22
|
+
expect(caps.videoInput).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should not enable video for K2 models', () => {
|
|
26
|
+
const caps = inferModelCapabilities('kimi-k2-turbo');
|
|
27
|
+
expect(caps.videoInput).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should enable image input for all models', () => {
|
|
31
|
+
expect(inferModelCapabilities('kimi-k2.5').imageInput).toBe(true);
|
|
32
|
+
expect(inferModelCapabilities('kimi-k2-turbo').imageInput).toBe(true);
|
|
33
|
+
expect(inferModelCapabilities('custom-model').imageInput).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should handle k2-5 variant', () => {
|
|
37
|
+
const caps = inferModelCapabilities('kimi-k2-5-thinking');
|
|
38
|
+
expect(caps.videoInput).toBe(true);
|
|
39
|
+
expect(caps.thinking).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('convertToKimiChatMessages', () => {
|
|
44
|
+
it('should convert system message', () => {
|
|
45
|
+
const result = convertToKimiChatMessages([{ role: 'system', content: 'You are a helpful assistant.' }]);
|
|
46
|
+
|
|
47
|
+
expect(result).toEqual([{ role: 'system', content: 'You are a helpful assistant.' }]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should convert simple user message', () => {
|
|
51
|
+
const result = convertToKimiChatMessages([{ role: 'user', content: [{ type: 'text', text: 'Hello!' }] }]);
|
|
52
|
+
|
|
53
|
+
expect(result).toEqual([{ role: 'user', content: 'Hello!' }]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should convert user message with image URL', () => {
|
|
57
|
+
const result = convertToKimiChatMessages([
|
|
58
|
+
{
|
|
59
|
+
role: 'user',
|
|
60
|
+
content: [
|
|
61
|
+
{ type: 'text', text: 'What is in this image?' },
|
|
62
|
+
{
|
|
63
|
+
type: 'file',
|
|
64
|
+
mediaType: 'image/png',
|
|
65
|
+
data: new URL('https://example.com/image.png')
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
expect(result).toEqual([
|
|
72
|
+
{
|
|
73
|
+
role: 'user',
|
|
74
|
+
content: [
|
|
75
|
+
{ type: 'text', text: 'What is in this image?' },
|
|
76
|
+
{ type: 'image_url', image_url: { url: 'https://example.com/image.png' } }
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
]);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should convert assistant message with text', () => {
|
|
83
|
+
const result = convertToKimiChatMessages([
|
|
84
|
+
{
|
|
85
|
+
role: 'assistant',
|
|
86
|
+
content: [{ type: 'text', text: 'Hello, how can I help?' }]
|
|
87
|
+
}
|
|
88
|
+
]);
|
|
89
|
+
|
|
90
|
+
expect(result).toEqual([
|
|
91
|
+
{
|
|
92
|
+
role: 'assistant',
|
|
93
|
+
content: 'Hello, how can I help?'
|
|
94
|
+
}
|
|
95
|
+
]);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should convert assistant message with reasoning', () => {
|
|
99
|
+
const result = convertToKimiChatMessages([
|
|
100
|
+
{
|
|
101
|
+
role: 'assistant',
|
|
102
|
+
content: [
|
|
103
|
+
{ type: 'reasoning', text: 'Let me think about this...' },
|
|
104
|
+
{ type: 'text', text: 'The answer is 42.' }
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
]);
|
|
108
|
+
|
|
109
|
+
expect(result).toEqual([
|
|
110
|
+
{
|
|
111
|
+
role: 'assistant',
|
|
112
|
+
content: 'The answer is 42.',
|
|
113
|
+
reasoning_content: 'Let me think about this...'
|
|
114
|
+
}
|
|
115
|
+
]);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should convert assistant message with tool calls', () => {
|
|
119
|
+
const result = convertToKimiChatMessages([
|
|
120
|
+
{
|
|
121
|
+
role: 'assistant',
|
|
122
|
+
content: [
|
|
123
|
+
{
|
|
124
|
+
type: 'tool-call',
|
|
125
|
+
toolCallId: 'call_123',
|
|
126
|
+
toolName: 'get_weather',
|
|
127
|
+
input: { location: 'Tokyo' }
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
]);
|
|
132
|
+
|
|
133
|
+
expect(result).toEqual([
|
|
134
|
+
{
|
|
135
|
+
role: 'assistant',
|
|
136
|
+
content: null,
|
|
137
|
+
tool_calls: [
|
|
138
|
+
{
|
|
139
|
+
id: 'call_123',
|
|
140
|
+
type: 'function',
|
|
141
|
+
function: {
|
|
142
|
+
name: 'get_weather',
|
|
143
|
+
arguments: '{"location":"Tokyo"}'
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
]);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should convert tool result message', () => {
|
|
152
|
+
const result = convertToKimiChatMessages([
|
|
153
|
+
{
|
|
154
|
+
role: 'tool',
|
|
155
|
+
content: [
|
|
156
|
+
{
|
|
157
|
+
type: 'tool-result',
|
|
158
|
+
toolCallId: 'call_123',
|
|
159
|
+
toolName: 'get_weather',
|
|
160
|
+
output: { type: 'text', value: 'Sunny, 25C' }
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
]);
|
|
165
|
+
|
|
166
|
+
expect(result).toEqual([
|
|
167
|
+
{
|
|
168
|
+
role: 'tool',
|
|
169
|
+
tool_call_id: 'call_123',
|
|
170
|
+
content: 'Sunny, 25C'
|
|
171
|
+
}
|
|
172
|
+
]);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe('mapKimiFinishReason', () => {
|
|
177
|
+
it('should map stop', () => {
|
|
178
|
+
expect(mapKimiFinishReason('stop')).toBe('stop');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should map length', () => {
|
|
182
|
+
expect(mapKimiFinishReason('length')).toBe('length');
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('should map content_filter', () => {
|
|
186
|
+
expect(mapKimiFinishReason('content_filter')).toBe('content-filter');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should map tool_calls', () => {
|
|
190
|
+
expect(mapKimiFinishReason('tool_calls')).toBe('tool-calls');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should map function_call', () => {
|
|
194
|
+
expect(mapKimiFinishReason('function_call')).toBe('tool-calls');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should map unknown to other', () => {
|
|
198
|
+
expect(mapKimiFinishReason('unknown')).toBe('other');
|
|
199
|
+
expect(mapKimiFinishReason(null)).toBe('other');
|
|
200
|
+
expect(mapKimiFinishReason(undefined)).toBe('other');
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
describe('convertKimiUsage', () => {
|
|
205
|
+
it('should handle null usage', () => {
|
|
206
|
+
const result = convertKimiUsage(null);
|
|
207
|
+
expect(result.inputTokens.total).toBeUndefined();
|
|
208
|
+
expect(result.outputTokens.total).toBeUndefined();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('should convert basic usage', () => {
|
|
212
|
+
const result = convertKimiUsage({
|
|
213
|
+
prompt_tokens: 100,
|
|
214
|
+
completion_tokens: 50,
|
|
215
|
+
total_tokens: 150
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
expect(result.inputTokens.total).toBe(100);
|
|
219
|
+
expect(result.outputTokens.total).toBe(50);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should handle cached tokens', () => {
|
|
223
|
+
const result = convertKimiUsage({
|
|
224
|
+
prompt_tokens: 100,
|
|
225
|
+
completion_tokens: 50,
|
|
226
|
+
total_tokens: 150,
|
|
227
|
+
prompt_tokens_details: { cached_tokens: 30 }
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
expect(result.inputTokens.total).toBe(100);
|
|
231
|
+
expect(result.inputTokens.cacheRead).toBe(30);
|
|
232
|
+
expect(result.inputTokens.noCache).toBe(70);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('should handle reasoning tokens', () => {
|
|
236
|
+
const result = convertKimiUsage({
|
|
237
|
+
prompt_tokens: 100,
|
|
238
|
+
completion_tokens: 50,
|
|
239
|
+
total_tokens: 150,
|
|
240
|
+
completion_tokens_details: { reasoning_tokens: 20 }
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
expect(result.outputTokens.total).toBe(50);
|
|
244
|
+
expect(result.outputTokens.reasoning).toBe(20);
|
|
245
|
+
expect(result.outputTokens.text).toBe(30);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should include web search tokens when provided', () => {
|
|
249
|
+
const result = convertKimiUsage({ prompt_tokens: 100, completion_tokens: 50, total_tokens: 150 }, 500);
|
|
250
|
+
|
|
251
|
+
expect(result.webSearchTokens).toBe(500);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('should include code interpreter tokens when provided', () => {
|
|
255
|
+
const result = convertKimiUsage({ prompt_tokens: 100, completion_tokens: 50, total_tokens: 150 }, undefined, 300);
|
|
256
|
+
|
|
257
|
+
expect(result.codeInterpreterTokens).toBe(300);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
describe('extractWebSearchTokens', () => {
|
|
262
|
+
it('should return undefined for null tool calls', () => {
|
|
263
|
+
expect(extractWebSearchTokens(null)).toBeUndefined();
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('should return undefined when no web search tool', () => {
|
|
267
|
+
expect(extractWebSearchTokens([{ function: { name: 'other_tool', arguments: '{}' } }])).toBeUndefined();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should extract tokens from web search tool', () => {
|
|
271
|
+
const result = extractWebSearchTokens([
|
|
272
|
+
{
|
|
273
|
+
function: {
|
|
274
|
+
name: '$web_search',
|
|
275
|
+
arguments: JSON.stringify({ total_tokens: 500 })
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
]);
|
|
279
|
+
expect(result).toBe(500);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('should sum tokens from multiple web search calls', () => {
|
|
283
|
+
const result = extractWebSearchTokens([
|
|
284
|
+
{
|
|
285
|
+
function: {
|
|
286
|
+
name: '$web_search',
|
|
287
|
+
arguments: JSON.stringify({ total_tokens: 200 })
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
function: {
|
|
292
|
+
name: '$web_search',
|
|
293
|
+
arguments: JSON.stringify({ total_tokens: 300 })
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
]);
|
|
297
|
+
expect(result).toBe(500);
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
describe('extractCodeInterpreterTokens', () => {
|
|
302
|
+
it('should return undefined for null tool calls', () => {
|
|
303
|
+
expect(extractCodeInterpreterTokens(null)).toBeUndefined();
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('should return undefined when no code interpreter tool', () => {
|
|
307
|
+
expect(extractCodeInterpreterTokens([{ function: { name: 'other_tool', arguments: '{}' } }])).toBeUndefined();
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('should extract tokens from code interpreter tool', () => {
|
|
311
|
+
const result = extractCodeInterpreterTokens([
|
|
312
|
+
{
|
|
313
|
+
function: {
|
|
314
|
+
name: '$code',
|
|
315
|
+
arguments: JSON.stringify({ total_tokens: 300 })
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
]);
|
|
319
|
+
expect(result).toBe(300);
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
describe('getKimiRequestId', () => {
|
|
324
|
+
it('should return undefined for undefined headers', () => {
|
|
325
|
+
expect(getKimiRequestId(undefined)).toBeUndefined();
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('should extract x-request-id', () => {
|
|
329
|
+
expect(getKimiRequestId({ 'x-request-id': 'req_123' })).toBe('req_123');
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('should extract X-Request-ID (case insensitive)', () => {
|
|
333
|
+
expect(getKimiRequestId({ 'X-Request-ID': 'req_456' })).toBe('req_456');
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it('should extract x-trace-id', () => {
|
|
337
|
+
expect(getKimiRequestId({ 'x-trace-id': 'trace_789' })).toBe('trace_789');
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('should extract x-moonshot-request-id', () => {
|
|
341
|
+
expect(getKimiRequestId({ 'x-moonshot-request-id': 'moonshot_abc' })).toBe('moonshot_abc');
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
describe('extractMessageContent', () => {
|
|
346
|
+
it('should extract string content', () => {
|
|
347
|
+
const result = extractMessageContent({ content: 'Hello!' });
|
|
348
|
+
expect(result.text).toBe('Hello!');
|
|
349
|
+
expect(result.reasoning).toBe('');
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('should extract text from array content', () => {
|
|
353
|
+
const result = extractMessageContent({
|
|
354
|
+
content: [{ type: 'text', text: 'Hello!' }]
|
|
355
|
+
});
|
|
356
|
+
expect(result.text).toBe('Hello!');
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it('should extract reasoning_content', () => {
|
|
360
|
+
const result = extractMessageContent({
|
|
361
|
+
content: 'Answer',
|
|
362
|
+
reasoning_content: 'Thinking...'
|
|
363
|
+
});
|
|
364
|
+
expect(result.text).toBe('Answer');
|
|
365
|
+
expect(result.reasoning).toBe('Thinking...');
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it('should extract reasoning field', () => {
|
|
369
|
+
const result = extractMessageContent({
|
|
370
|
+
content: 'Answer',
|
|
371
|
+
reasoning: 'Reasoning...'
|
|
372
|
+
});
|
|
373
|
+
expect(result.reasoning).toBe('Reasoning...');
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it('should handle thinking type in array', () => {
|
|
377
|
+
const result = extractMessageContent({
|
|
378
|
+
content: [
|
|
379
|
+
{ type: 'thinking', thinking: 'Let me think...' },
|
|
380
|
+
{ type: 'text', text: 'The answer is 42.' }
|
|
381
|
+
]
|
|
382
|
+
});
|
|
383
|
+
expect(result.reasoning).toBe('Let me think...');
|
|
384
|
+
expect(result.text).toBe('The answer is 42.');
|
|
385
|
+
});
|
|
386
|
+
});
|