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.
Files changed (44) hide show
  1. package/LICENSE +198 -0
  2. package/README.md +871 -0
  3. package/dist/index.d.mts +1317 -0
  4. package/dist/index.d.ts +1317 -0
  5. package/dist/index.js +2764 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/index.mjs +2734 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +70 -0
  10. package/src/__tests__/caching.test.ts +97 -0
  11. package/src/__tests__/chat.test.ts +386 -0
  12. package/src/__tests__/code-integration.test.ts +562 -0
  13. package/src/__tests__/code-provider.test.ts +289 -0
  14. package/src/__tests__/code.test.ts +427 -0
  15. package/src/__tests__/core.test.ts +172 -0
  16. package/src/__tests__/files.test.ts +185 -0
  17. package/src/__tests__/integration.test.ts +457 -0
  18. package/src/__tests__/provider.test.ts +188 -0
  19. package/src/__tests__/tools.test.ts +519 -0
  20. package/src/chat/index.ts +42 -0
  21. package/src/chat/kimi-chat-language-model.ts +829 -0
  22. package/src/chat/kimi-chat-messages.ts +297 -0
  23. package/src/chat/kimi-chat-response.ts +84 -0
  24. package/src/chat/kimi-chat-settings.ts +216 -0
  25. package/src/code/index.ts +66 -0
  26. package/src/code/kimi-code-language-model.ts +669 -0
  27. package/src/code/kimi-code-messages.ts +303 -0
  28. package/src/code/kimi-code-provider.ts +239 -0
  29. package/src/code/kimi-code-settings.ts +193 -0
  30. package/src/code/kimi-code-types.ts +354 -0
  31. package/src/core/errors.ts +140 -0
  32. package/src/core/index.ts +36 -0
  33. package/src/core/types.ts +148 -0
  34. package/src/core/utils.ts +210 -0
  35. package/src/files/attachment-processor.ts +276 -0
  36. package/src/files/file-utils.ts +257 -0
  37. package/src/files/index.ts +24 -0
  38. package/src/files/kimi-file-client.ts +292 -0
  39. package/src/index.ts +122 -0
  40. package/src/kimi-provider.ts +263 -0
  41. package/src/tools/builtin-tools.ts +273 -0
  42. package/src/tools/index.ts +33 -0
  43. package/src/tools/prepare-tools.ts +306 -0
  44. package/src/version.ts +4 -0
@@ -0,0 +1,519 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ KIMI_CODE_INTERPRETER_TOOL_NAME,
4
+ KIMI_WEB_SEARCH_TOOL_NAME,
5
+ createCodeInterpreterTool,
6
+ createKimiWebSearchTool,
7
+ createWebSearchTool,
8
+ isBuiltinToolName,
9
+ isCodeInterpreterTool,
10
+ isWebSearchTool,
11
+ kimiTools,
12
+ prepareKimiTools
13
+ } from '../tools';
14
+
15
+ describe('builtin-tools', () => {
16
+ describe('constants', () => {
17
+ it('should have correct web search tool name', () => {
18
+ expect(KIMI_WEB_SEARCH_TOOL_NAME).toBe('$web_search');
19
+ });
20
+
21
+ it('should have correct code interpreter tool name', () => {
22
+ expect(KIMI_CODE_INTERPRETER_TOOL_NAME).toBe('$code');
23
+ });
24
+ });
25
+
26
+ describe('createWebSearchTool', () => {
27
+ it('should create basic web search tool', () => {
28
+ const tool = createWebSearchTool();
29
+ expect(tool).toEqual({
30
+ type: 'builtin_function',
31
+ function: {
32
+ name: '$web_search'
33
+ }
34
+ });
35
+ });
36
+
37
+ it('should create web search tool with config', () => {
38
+ const tool = createWebSearchTool({ search_result: true });
39
+ expect(tool).toEqual({
40
+ type: 'builtin_function',
41
+ function: {
42
+ name: '$web_search',
43
+ config: { search_result: true }
44
+ }
45
+ });
46
+ });
47
+ });
48
+
49
+ describe('createKimiWebSearchTool', () => {
50
+ it('should create web search tool (alias)', () => {
51
+ const tool = createKimiWebSearchTool();
52
+ expect(tool).toEqual({
53
+ type: 'builtin_function',
54
+ function: {
55
+ name: '$web_search'
56
+ }
57
+ });
58
+ });
59
+ });
60
+
61
+ describe('createCodeInterpreterTool', () => {
62
+ it('should create basic code interpreter tool', () => {
63
+ const tool = createCodeInterpreterTool();
64
+ expect(tool).toEqual({
65
+ type: 'builtin_function',
66
+ function: {
67
+ name: '$code'
68
+ }
69
+ });
70
+ });
71
+
72
+ it('should create code interpreter tool with config', () => {
73
+ const tool = createCodeInterpreterTool({
74
+ timeout: 30,
75
+ include_output: true
76
+ });
77
+ expect(tool).toEqual({
78
+ type: 'builtin_function',
79
+ function: {
80
+ name: '$code',
81
+ config: { timeout: 30, include_output: true }
82
+ }
83
+ });
84
+ });
85
+ });
86
+
87
+ describe('isBuiltinToolName', () => {
88
+ it('should return true for $web_search', () => {
89
+ expect(isBuiltinToolName('$web_search')).toBe(true);
90
+ });
91
+
92
+ it('should return true for $code', () => {
93
+ expect(isBuiltinToolName('$code')).toBe(true);
94
+ });
95
+
96
+ it('should return true for any tool starting with $', () => {
97
+ expect(isBuiltinToolName('$custom_tool')).toBe(true);
98
+ });
99
+
100
+ it('should return false for regular tool names', () => {
101
+ expect(isBuiltinToolName('get_weather')).toBe(false);
102
+ expect(isBuiltinToolName('web_search')).toBe(false);
103
+ expect(isBuiltinToolName('code')).toBe(false);
104
+ });
105
+ });
106
+
107
+ describe('isWebSearchTool', () => {
108
+ it('should return true for $web_search', () => {
109
+ expect(isWebSearchTool('$web_search')).toBe(true);
110
+ });
111
+
112
+ it('should return false for other tools', () => {
113
+ expect(isWebSearchTool('$code')).toBe(false);
114
+ expect(isWebSearchTool('web_search')).toBe(false);
115
+ });
116
+ });
117
+
118
+ describe('isCodeInterpreterTool', () => {
119
+ it('should return true for $code', () => {
120
+ expect(isCodeInterpreterTool('$code')).toBe(true);
121
+ });
122
+
123
+ it('should return false for other tools', () => {
124
+ expect(isCodeInterpreterTool('$web_search')).toBe(false);
125
+ expect(isCodeInterpreterTool('code')).toBe(false);
126
+ });
127
+ });
128
+
129
+ describe('kimiTools', () => {
130
+ describe('webSearch', () => {
131
+ it('should create a provider tool for web search', () => {
132
+ const tool = kimiTools.webSearch();
133
+ expect(tool.type).toBe('provider');
134
+ expect(tool.id).toBe('kimi.webSearch');
135
+ expect(tool.args).toEqual({
136
+ type: 'builtin_function',
137
+ function: { name: '$web_search' }
138
+ });
139
+ });
140
+
141
+ it('should create a provider tool with config', () => {
142
+ const tool = kimiTools.webSearch({ search_result: true });
143
+ expect(tool.args).toEqual({
144
+ type: 'builtin_function',
145
+ function: {
146
+ name: '$web_search',
147
+ config: { search_result: true }
148
+ }
149
+ });
150
+ });
151
+ });
152
+
153
+ describe('codeInterpreter', () => {
154
+ it('should create a provider tool for code interpreter', () => {
155
+ const tool = kimiTools.codeInterpreter();
156
+ expect(tool.type).toBe('provider');
157
+ expect(tool.id).toBe('kimi.codeInterpreter');
158
+ expect(tool.args).toEqual({
159
+ type: 'builtin_function',
160
+ function: { name: '$code' }
161
+ });
162
+ });
163
+
164
+ it('should create a provider tool with config', () => {
165
+ const tool = kimiTools.codeInterpreter({ timeout: 60 });
166
+ expect(tool.args).toEqual({
167
+ type: 'builtin_function',
168
+ function: {
169
+ name: '$code',
170
+ config: { timeout: 60 }
171
+ }
172
+ });
173
+ });
174
+ });
175
+ });
176
+ });
177
+
178
+ describe('prepareKimiTools', () => {
179
+ describe('with no tools', () => {
180
+ it('should return undefined when tools is undefined', () => {
181
+ const result = prepareKimiTools({ tools: undefined });
182
+ expect(result.tools).toBeUndefined();
183
+ expect(result.toolChoice).toBeUndefined();
184
+ expect(result.toolWarnings).toEqual([]);
185
+ });
186
+
187
+ it('should return undefined when tools is empty array', () => {
188
+ const result = prepareKimiTools({ tools: [] });
189
+ expect(result.tools).toBeUndefined();
190
+ expect(result.toolChoice).toBeUndefined();
191
+ });
192
+ });
193
+
194
+ describe('with function tools', () => {
195
+ it('should convert function tools to Kimi format', () => {
196
+ const result = prepareKimiTools({
197
+ tools: [
198
+ {
199
+ type: 'function',
200
+ name: 'get_weather',
201
+ description: 'Get weather for a location',
202
+ inputSchema: {
203
+ type: 'object',
204
+ properties: {
205
+ location: { type: 'string' }
206
+ }
207
+ }
208
+ }
209
+ ]
210
+ });
211
+
212
+ expect(result.tools).toHaveLength(1);
213
+ expect(result.tools?.[0]).toEqual({
214
+ type: 'function',
215
+ function: {
216
+ name: 'get_weather',
217
+ description: 'Get weather for a location',
218
+ parameters: {
219
+ type: 'object',
220
+ properties: {
221
+ location: { type: 'string' }
222
+ }
223
+ }
224
+ }
225
+ });
226
+ });
227
+
228
+ it('should include strict when provided', () => {
229
+ const result = prepareKimiTools({
230
+ tools: [
231
+ {
232
+ type: 'function',
233
+ name: 'test',
234
+ description: 'Test tool',
235
+ inputSchema: {},
236
+ strict: true
237
+ }
238
+ ]
239
+ });
240
+
241
+ expect(result.tools?.[0]).toMatchObject({
242
+ type: 'function',
243
+ function: {
244
+ name: 'test',
245
+ strict: true
246
+ }
247
+ });
248
+ });
249
+ });
250
+
251
+ describe('with web search', () => {
252
+ it('should add web search tool when webSearch is true', () => {
253
+ const result = prepareKimiTools({
254
+ tools: undefined,
255
+ webSearch: true
256
+ });
257
+
258
+ expect(result.tools).toHaveLength(1);
259
+ expect(result.tools?.[0]).toEqual({
260
+ type: 'builtin_function',
261
+ function: {
262
+ name: '$web_search'
263
+ }
264
+ });
265
+ });
266
+
267
+ it('should add web search tool with config', () => {
268
+ const result = prepareKimiTools({
269
+ tools: undefined,
270
+ webSearch: {
271
+ enabled: true,
272
+ config: { search_result: true }
273
+ }
274
+ });
275
+
276
+ expect(result.tools).toHaveLength(1);
277
+ expect(result.tools?.[0]).toEqual({
278
+ type: 'builtin_function',
279
+ function: {
280
+ name: '$web_search',
281
+ config: { search_result: true }
282
+ }
283
+ });
284
+ });
285
+
286
+ it('should combine web search with function tools', () => {
287
+ const result = prepareKimiTools({
288
+ tools: [
289
+ {
290
+ type: 'function',
291
+ name: 'get_data',
292
+ description: 'Get data',
293
+ inputSchema: {}
294
+ }
295
+ ],
296
+ webSearch: true
297
+ });
298
+
299
+ expect(result.tools).toHaveLength(2);
300
+ expect(result.tools?.[0].type).toBe('builtin_function');
301
+ expect(result.tools?.[1].type).toBe('function');
302
+ });
303
+ });
304
+
305
+ describe('with code interpreter', () => {
306
+ it('should add code interpreter tool when codeInterpreter is true', () => {
307
+ const result = prepareKimiTools({
308
+ tools: undefined,
309
+ codeInterpreter: true
310
+ });
311
+
312
+ expect(result.tools).toHaveLength(1);
313
+ expect(result.tools?.[0]).toEqual({
314
+ type: 'builtin_function',
315
+ function: {
316
+ name: '$code'
317
+ }
318
+ });
319
+ });
320
+
321
+ it('should add code interpreter tool with config', () => {
322
+ const result = prepareKimiTools({
323
+ tools: undefined,
324
+ codeInterpreter: {
325
+ enabled: true,
326
+ config: { timeout: 30, include_output: true }
327
+ }
328
+ });
329
+
330
+ expect(result.tools).toHaveLength(1);
331
+ expect(result.tools?.[0]).toEqual({
332
+ type: 'builtin_function',
333
+ function: {
334
+ name: '$code',
335
+ config: { timeout: 30, include_output: true }
336
+ }
337
+ });
338
+ });
339
+
340
+ it('should combine both web search and code interpreter', () => {
341
+ const result = prepareKimiTools({
342
+ tools: undefined,
343
+ webSearch: true,
344
+ codeInterpreter: true
345
+ });
346
+
347
+ expect(result.tools).toHaveLength(2);
348
+ expect(result.tools?.[0]).toEqual({
349
+ type: 'builtin_function',
350
+ function: { name: '$web_search' }
351
+ });
352
+ expect(result.tools?.[1]).toEqual({
353
+ type: 'builtin_function',
354
+ function: { name: '$code' }
355
+ });
356
+ });
357
+ });
358
+
359
+ describe('with tool choice', () => {
360
+ const basicTools = [
361
+ {
362
+ type: 'function' as const,
363
+ name: 'test',
364
+ description: 'Test',
365
+ inputSchema: {}
366
+ }
367
+ ];
368
+
369
+ it('should pass through auto tool choice', () => {
370
+ const result = prepareKimiTools({
371
+ tools: basicTools,
372
+ toolChoice: { type: 'auto' }
373
+ });
374
+ expect(result.toolChoice).toBe('auto');
375
+ });
376
+
377
+ it('should pass through none tool choice', () => {
378
+ const result = prepareKimiTools({
379
+ tools: basicTools,
380
+ toolChoice: { type: 'none' }
381
+ });
382
+ expect(result.toolChoice).toBe('none');
383
+ });
384
+
385
+ it('should warn and fallback to auto for required tool choice with polyfill', () => {
386
+ const result = prepareKimiTools({
387
+ tools: basicTools,
388
+ toolChoice: { type: 'required' }
389
+ });
390
+ expect(result.toolChoice).toBe('auto');
391
+ expect(result.toolWarnings).toContainEqual({
392
+ type: 'compatibility',
393
+ feature: 'toolChoice.required',
394
+ details: 'Using tool choice polyfill with system message injection.'
395
+ });
396
+ expect(result.toolChoiceSystemMessage).toBeDefined();
397
+ expect(result.toolChoiceSystemMessage).toContain('MUST use one of the available tools');
398
+ });
399
+
400
+ it('should warn and fallback to auto for required tool choice without polyfill', () => {
401
+ const result = prepareKimiTools({
402
+ tools: basicTools,
403
+ toolChoice: { type: 'required' },
404
+ toolChoicePolyfill: false
405
+ });
406
+ expect(result.toolChoice).toBe('auto');
407
+ expect(result.toolWarnings).toContainEqual({
408
+ type: 'compatibility',
409
+ feature: 'toolChoice.required',
410
+ details: 'Moonshot does not support required tool choice. Falling back to auto.'
411
+ });
412
+ expect(result.toolChoiceSystemMessage).toBeUndefined();
413
+ });
414
+
415
+ it('should warn and fallback to auto for specific tool choice with polyfill', () => {
416
+ const result = prepareKimiTools({
417
+ tools: basicTools,
418
+ toolChoice: { type: 'tool', toolName: 'test' }
419
+ });
420
+ expect(result.toolChoice).toBe('auto');
421
+ expect(result.toolWarnings).toContainEqual({
422
+ type: 'compatibility',
423
+ feature: 'toolChoice.tool:test',
424
+ details: 'Using tool choice polyfill with system message injection.'
425
+ });
426
+ expect(result.toolChoiceSystemMessage).toBeDefined();
427
+ expect(result.toolChoiceSystemMessage).toContain('MUST use the "test" tool');
428
+ });
429
+
430
+ it('should warn and fallback to auto for specific tool choice without polyfill', () => {
431
+ const result = prepareKimiTools({
432
+ tools: basicTools,
433
+ toolChoice: { type: 'tool', toolName: 'test' },
434
+ toolChoicePolyfill: false
435
+ });
436
+ expect(result.toolChoice).toBe('auto');
437
+ expect(result.toolWarnings).toContainEqual({
438
+ type: 'compatibility',
439
+ feature: 'toolChoice.tool:test',
440
+ details: 'Moonshot does not support forcing a specific tool. Falling back to auto.'
441
+ });
442
+ expect(result.toolChoiceSystemMessage).toBeUndefined();
443
+ });
444
+ });
445
+
446
+ describe('with provider tools', () => {
447
+ it('should warn for unsupported provider tools', () => {
448
+ const result = prepareKimiTools({
449
+ tools: [
450
+ {
451
+ type: 'provider',
452
+ id: 'other.tool' as `${string}.${string}`,
453
+ name: 'other_tool',
454
+ args: {}
455
+ }
456
+ ]
457
+ });
458
+
459
+ expect(result.toolWarnings).toContainEqual({
460
+ type: 'unsupported',
461
+ feature: 'provider-defined tool other.tool'
462
+ });
463
+ });
464
+
465
+ it('should convert Kimi builtin provider tools', () => {
466
+ const result = prepareKimiTools({
467
+ tools: [
468
+ {
469
+ type: 'provider',
470
+ id: 'kimi.web_search' as `${string}.${string}`,
471
+ name: 'web_search',
472
+ args: {
473
+ type: 'builtin_function',
474
+ function: {
475
+ name: '$web_search',
476
+ config: { search_result: true }
477
+ }
478
+ }
479
+ }
480
+ ]
481
+ });
482
+
483
+ expect(result.tools).toHaveLength(1);
484
+ expect(result.tools?.[0]).toEqual({
485
+ type: 'builtin_function',
486
+ function: {
487
+ name: '$web_search',
488
+ config: { search_result: true }
489
+ }
490
+ });
491
+ });
492
+
493
+ it('should convert Kimi code interpreter provider tool', () => {
494
+ const result = prepareKimiTools({
495
+ tools: [
496
+ {
497
+ type: 'provider',
498
+ id: 'kimi.code_interpreter' as `${string}.${string}`,
499
+ name: 'code_interpreter',
500
+ args: {
501
+ type: 'builtin_function',
502
+ function: {
503
+ name: '$code'
504
+ }
505
+ }
506
+ }
507
+ ]
508
+ });
509
+
510
+ expect(result.tools).toHaveLength(1);
511
+ expect(result.tools?.[0]).toEqual({
512
+ type: 'builtin_function',
513
+ function: {
514
+ name: '$code'
515
+ }
516
+ });
517
+ });
518
+ });
519
+ });
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Chat module exports.
3
+ * @module
4
+ */
5
+
6
+ // Messages
7
+ export type {
8
+ KimiChatContentPart,
9
+ KimiChatMessage,
10
+ KimiChatPrompt
11
+ } from './kimi-chat-messages';
12
+ // Response utilities
13
+ export type {
14
+ KimiExtendedUsage,
15
+ KimiTokenUsage
16
+ } from './kimi-chat-response';
17
+ // Settings and configuration
18
+ export type {
19
+ KimiCachingConfig,
20
+ KimiChatConfig,
21
+ KimiChatModelId,
22
+ KimiChatSettings,
23
+ KimiModelCapabilities,
24
+ KimiProviderOptions
25
+ } from './kimi-chat-settings';
26
+ // Language model
27
+ export { KimiChatLanguageModel } from './kimi-chat-language-model';
28
+ export { convertToKimiChatMessages } from './kimi-chat-messages';
29
+ export {
30
+ convertKimiUsage,
31
+ extractCodeInterpreterTokens,
32
+ extractMessageContent,
33
+ extractWebSearchTokens,
34
+ getKimiRequestId,
35
+ getResponseMetadata,
36
+ mapKimiFinishReason
37
+ } from './kimi-chat-response';
38
+ export {
39
+ inferModelCapabilities,
40
+ kimiCachingConfigSchema,
41
+ kimiProviderOptionsSchema
42
+ } from './kimi-chat-settings';