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
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2734 @@
|
|
|
1
|
+
// src/kimi-provider.ts
|
|
2
|
+
import { NoSuchModelError } from "@ai-sdk/provider";
|
|
3
|
+
import {
|
|
4
|
+
loadApiKey,
|
|
5
|
+
loadOptionalSetting,
|
|
6
|
+
withUserAgentSuffix,
|
|
7
|
+
withoutTrailingSlash
|
|
8
|
+
} from "@ai-sdk/provider-utils";
|
|
9
|
+
|
|
10
|
+
// src/chat/kimi-chat-language-model.ts
|
|
11
|
+
import {
|
|
12
|
+
InvalidResponseDataError
|
|
13
|
+
} from "@ai-sdk/provider";
|
|
14
|
+
import {
|
|
15
|
+
combineHeaders,
|
|
16
|
+
createEventSourceResponseHandler,
|
|
17
|
+
createJsonResponseHandler,
|
|
18
|
+
generateId,
|
|
19
|
+
isParsableJson,
|
|
20
|
+
parseProviderOptions,
|
|
21
|
+
postJsonToApi,
|
|
22
|
+
removeUndefinedEntries
|
|
23
|
+
} from "@ai-sdk/provider-utils";
|
|
24
|
+
import { z as z3 } from "zod/v4";
|
|
25
|
+
|
|
26
|
+
// src/core/errors.ts
|
|
27
|
+
import { createJsonErrorResponseHandler } from "@ai-sdk/provider-utils";
|
|
28
|
+
import { z } from "zod/v4";
|
|
29
|
+
var kimiErrorSchema = z.union([
|
|
30
|
+
z.object({
|
|
31
|
+
error: z.object({
|
|
32
|
+
message: z.string(),
|
|
33
|
+
type: z.string().nullish(),
|
|
34
|
+
param: z.any().nullish(),
|
|
35
|
+
code: z.union([z.string(), z.number()]).nullish(),
|
|
36
|
+
request_id: z.string().nullish()
|
|
37
|
+
})
|
|
38
|
+
}),
|
|
39
|
+
z.object({
|
|
40
|
+
message: z.string()
|
|
41
|
+
})
|
|
42
|
+
]);
|
|
43
|
+
var kimiFailedResponseHandler = createJsonErrorResponseHandler({
|
|
44
|
+
errorSchema: kimiErrorSchema,
|
|
45
|
+
errorToMessage: (error) => {
|
|
46
|
+
if ("error" in error) {
|
|
47
|
+
return error.error.message;
|
|
48
|
+
}
|
|
49
|
+
return error.message;
|
|
50
|
+
},
|
|
51
|
+
isRetryable: (response) => response.status === 408 || response.status === 409 || response.status === 429 || response.status >= 500
|
|
52
|
+
});
|
|
53
|
+
var KimiError = class extends Error {
|
|
54
|
+
constructor(message, code, statusCode) {
|
|
55
|
+
super(message);
|
|
56
|
+
this.name = "KimiError";
|
|
57
|
+
this.code = code;
|
|
58
|
+
this.statusCode = statusCode;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var KimiAuthenticationError = class extends KimiError {
|
|
62
|
+
constructor(message = "Invalid API key or authentication failed") {
|
|
63
|
+
super(message, "authentication_error", 401);
|
|
64
|
+
this.name = "KimiAuthenticationError";
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
var KimiRateLimitError = class extends KimiError {
|
|
68
|
+
constructor(message = "Rate limit exceeded", retryAfter) {
|
|
69
|
+
super(message, "rate_limit_error", 429);
|
|
70
|
+
this.name = "KimiRateLimitError";
|
|
71
|
+
this.retryAfter = retryAfter;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var KimiValidationError = class extends KimiError {
|
|
75
|
+
constructor(message, param) {
|
|
76
|
+
super(param ? `${message} (param: ${param})` : message, "validation_error", 400);
|
|
77
|
+
this.name = "KimiValidationError";
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
var KimiModelNotFoundError = class extends KimiError {
|
|
81
|
+
constructor(modelId) {
|
|
82
|
+
super(`Model '${modelId}' not found`, "model_not_found", 404);
|
|
83
|
+
this.name = "KimiModelNotFoundError";
|
|
84
|
+
this.modelId = modelId;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var KimiContentFilterError = class extends KimiError {
|
|
88
|
+
constructor(message = "Content was filtered due to policy violation") {
|
|
89
|
+
super(message, "content_filter", 400);
|
|
90
|
+
this.name = "KimiContentFilterError";
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var KimiContextLengthError = class extends KimiError {
|
|
94
|
+
constructor(message = "Context length exceeded") {
|
|
95
|
+
super(message, "context_length_exceeded", 400);
|
|
96
|
+
this.name = "KimiContextLengthError";
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// src/core/types.ts
|
|
101
|
+
function inferModelCapabilities(modelId) {
|
|
102
|
+
const isThinkingModel = modelId.includes("-thinking");
|
|
103
|
+
const isK25Model = modelId.includes("k2.5") || modelId.includes("k2-5");
|
|
104
|
+
return {
|
|
105
|
+
thinking: isThinkingModel,
|
|
106
|
+
alwaysThinking: isThinkingModel,
|
|
107
|
+
imageInput: true,
|
|
108
|
+
// All Kimi models support images
|
|
109
|
+
videoInput: isK25Model,
|
|
110
|
+
// Only K2.5 models support video
|
|
111
|
+
maxContextSize: 256e3,
|
|
112
|
+
// 256k context window
|
|
113
|
+
toolCalling: true,
|
|
114
|
+
jsonMode: true,
|
|
115
|
+
structuredOutputs: true
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/core/utils.ts
|
|
120
|
+
function mapKimiFinishReason(finishReason) {
|
|
121
|
+
switch (finishReason) {
|
|
122
|
+
case "stop":
|
|
123
|
+
return "stop";
|
|
124
|
+
case "length":
|
|
125
|
+
return "length";
|
|
126
|
+
case "content_filter":
|
|
127
|
+
return "content-filter";
|
|
128
|
+
case "tool_calls":
|
|
129
|
+
case "function_call":
|
|
130
|
+
return "tool-calls";
|
|
131
|
+
default:
|
|
132
|
+
return "other";
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function convertKimiUsage(usage, webSearchTokens, codeInterpreterTokens) {
|
|
136
|
+
if (usage == null) {
|
|
137
|
+
return {
|
|
138
|
+
inputTokens: {
|
|
139
|
+
total: void 0,
|
|
140
|
+
noCache: void 0,
|
|
141
|
+
cacheRead: void 0,
|
|
142
|
+
cacheWrite: void 0
|
|
143
|
+
},
|
|
144
|
+
outputTokens: {
|
|
145
|
+
total: void 0,
|
|
146
|
+
text: void 0,
|
|
147
|
+
reasoning: void 0
|
|
148
|
+
},
|
|
149
|
+
raw: void 0,
|
|
150
|
+
...webSearchTokens != null ? { webSearchTokens } : {},
|
|
151
|
+
...codeInterpreterTokens != null ? { codeInterpreterTokens } : {}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const promptTokens = usage.prompt_tokens ?? 0;
|
|
155
|
+
const completionTokens = usage.completion_tokens ?? 0;
|
|
156
|
+
const cacheReadTokens = usage.prompt_tokens_details?.cached_tokens ?? 0;
|
|
157
|
+
const reasoningTokens = usage.completion_tokens_details?.reasoning_tokens ?? 0;
|
|
158
|
+
const rawUsage = {
|
|
159
|
+
prompt_tokens: usage.prompt_tokens ?? void 0,
|
|
160
|
+
completion_tokens: usage.completion_tokens ?? void 0,
|
|
161
|
+
total_tokens: usage.total_tokens ?? void 0,
|
|
162
|
+
...usage.prompt_tokens_details ? {
|
|
163
|
+
prompt_tokens_details: {
|
|
164
|
+
cached_tokens: usage.prompt_tokens_details.cached_tokens ?? void 0
|
|
165
|
+
}
|
|
166
|
+
} : {},
|
|
167
|
+
...usage.completion_tokens_details ? {
|
|
168
|
+
completion_tokens_details: {
|
|
169
|
+
reasoning_tokens: usage.completion_tokens_details.reasoning_tokens ?? void 0
|
|
170
|
+
}
|
|
171
|
+
} : {}
|
|
172
|
+
};
|
|
173
|
+
return {
|
|
174
|
+
inputTokens: {
|
|
175
|
+
total: promptTokens,
|
|
176
|
+
noCache: promptTokens - cacheReadTokens,
|
|
177
|
+
cacheRead: cacheReadTokens,
|
|
178
|
+
cacheWrite: void 0
|
|
179
|
+
},
|
|
180
|
+
outputTokens: {
|
|
181
|
+
total: completionTokens,
|
|
182
|
+
text: completionTokens - reasoningTokens,
|
|
183
|
+
reasoning: reasoningTokens
|
|
184
|
+
},
|
|
185
|
+
raw: rawUsage,
|
|
186
|
+
...webSearchTokens != null ? { webSearchTokens } : {},
|
|
187
|
+
...codeInterpreterTokens != null ? { codeInterpreterTokens } : {}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function getResponseMetadata(response) {
|
|
191
|
+
return {
|
|
192
|
+
id: response.id ?? void 0,
|
|
193
|
+
modelId: response.model ?? void 0,
|
|
194
|
+
timestamp: response.created != null ? new Date(response.created * 1e3) : void 0
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function getKimiRequestId(headers) {
|
|
198
|
+
if (!headers) {
|
|
199
|
+
return void 0;
|
|
200
|
+
}
|
|
201
|
+
const lowerHeaders = Object.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value]));
|
|
202
|
+
return lowerHeaders["x-request-id"] || lowerHeaders["x-trace-id"] || lowerHeaders["x-moonshot-request-id"];
|
|
203
|
+
}
|
|
204
|
+
function extractMessageContent(message) {
|
|
205
|
+
let text = "";
|
|
206
|
+
let reasoning = "";
|
|
207
|
+
if (typeof message.content === "string") {
|
|
208
|
+
text = message.content;
|
|
209
|
+
} else if (Array.isArray(message.content)) {
|
|
210
|
+
for (const part of message.content) {
|
|
211
|
+
if (part && typeof part === "object") {
|
|
212
|
+
const candidate = part;
|
|
213
|
+
if (candidate.type === "text" && typeof candidate.text === "string") {
|
|
214
|
+
text += candidate.text;
|
|
215
|
+
}
|
|
216
|
+
if (candidate.type === "thinking" && typeof candidate.thinking === "string") {
|
|
217
|
+
reasoning += candidate.thinking;
|
|
218
|
+
}
|
|
219
|
+
if (candidate.type === "reasoning" && typeof candidate.text === "string") {
|
|
220
|
+
reasoning += candidate.text;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (typeof message.reasoning_content === "string") {
|
|
226
|
+
reasoning += message.reasoning_content;
|
|
227
|
+
}
|
|
228
|
+
if (typeof message.reasoning === "string") {
|
|
229
|
+
reasoning += message.reasoning;
|
|
230
|
+
}
|
|
231
|
+
return { text, reasoning };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// src/tools/builtin-tools.ts
|
|
235
|
+
var KIMI_WEB_SEARCH_TOOL_NAME = "$web_search";
|
|
236
|
+
var KIMI_CODE_INTERPRETER_TOOL_NAME = "$code";
|
|
237
|
+
function createWebSearchTool(config) {
|
|
238
|
+
return {
|
|
239
|
+
type: "builtin_function",
|
|
240
|
+
function: {
|
|
241
|
+
name: KIMI_WEB_SEARCH_TOOL_NAME,
|
|
242
|
+
...config ? { config } : {}
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function createKimiWebSearchTool(config) {
|
|
247
|
+
return createWebSearchTool(config);
|
|
248
|
+
}
|
|
249
|
+
function createCodeInterpreterTool(config) {
|
|
250
|
+
return {
|
|
251
|
+
type: "builtin_function",
|
|
252
|
+
function: {
|
|
253
|
+
name: KIMI_CODE_INTERPRETER_TOOL_NAME,
|
|
254
|
+
...config ? { config } : {}
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
function isBuiltinToolName(toolName) {
|
|
259
|
+
return toolName.startsWith("$");
|
|
260
|
+
}
|
|
261
|
+
var kimiTools = {
|
|
262
|
+
/**
|
|
263
|
+
* Create a web search tool for use with Kimi models.
|
|
264
|
+
*
|
|
265
|
+
* @param config - Optional configuration
|
|
266
|
+
* @returns A provider tool definition
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```ts
|
|
270
|
+
* import { kimi, kimiTools } from 'ai-sdk-provider-kimi';
|
|
271
|
+
*
|
|
272
|
+
* const result = await generateText({
|
|
273
|
+
* model: kimi('kimi-k2.5'),
|
|
274
|
+
* tools: {
|
|
275
|
+
* webSearch: kimiTools.webSearch(),
|
|
276
|
+
* },
|
|
277
|
+
* prompt: 'What are the latest AI news?',
|
|
278
|
+
* });
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
webSearch: (config) => {
|
|
282
|
+
return {
|
|
283
|
+
type: "provider",
|
|
284
|
+
id: "kimi.webSearch",
|
|
285
|
+
args: createWebSearchTool(config)
|
|
286
|
+
};
|
|
287
|
+
},
|
|
288
|
+
/**
|
|
289
|
+
* Create a code interpreter tool for use with Kimi models.
|
|
290
|
+
*
|
|
291
|
+
* @param config - Optional configuration
|
|
292
|
+
* @returns A provider tool definition
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```ts
|
|
296
|
+
* import { kimi, kimiTools } from 'ai-sdk-provider-kimi';
|
|
297
|
+
*
|
|
298
|
+
* const result = await generateText({
|
|
299
|
+
* model: kimi('kimi-k2.5'),
|
|
300
|
+
* tools: {
|
|
301
|
+
* codeInterpreter: kimiTools.codeInterpreter(),
|
|
302
|
+
* },
|
|
303
|
+
* prompt: 'Calculate the factorial of 10',
|
|
304
|
+
* });
|
|
305
|
+
* ```
|
|
306
|
+
*/
|
|
307
|
+
codeInterpreter: (config) => {
|
|
308
|
+
return {
|
|
309
|
+
type: "provider",
|
|
310
|
+
id: "kimi.codeInterpreter",
|
|
311
|
+
args: createCodeInterpreterTool(config)
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
// src/tools/prepare-tools.ts
|
|
317
|
+
import {
|
|
318
|
+
UnsupportedFunctionalityError
|
|
319
|
+
} from "@ai-sdk/provider";
|
|
320
|
+
function prepareKimiTools({
|
|
321
|
+
tools,
|
|
322
|
+
toolChoice,
|
|
323
|
+
webSearch,
|
|
324
|
+
codeInterpreter,
|
|
325
|
+
toolChoicePolyfill = true
|
|
326
|
+
}) {
|
|
327
|
+
tools = tools?.length ? tools : void 0;
|
|
328
|
+
const toolWarnings = [];
|
|
329
|
+
const kimiTools2 = [];
|
|
330
|
+
if (webSearch) {
|
|
331
|
+
const config = typeof webSearch === "boolean" ? void 0 : webSearch.config;
|
|
332
|
+
kimiTools2.push(createWebSearchTool(config));
|
|
333
|
+
}
|
|
334
|
+
if (codeInterpreter) {
|
|
335
|
+
const config = typeof codeInterpreter === "boolean" ? void 0 : codeInterpreter.config;
|
|
336
|
+
kimiTools2.push(createCodeInterpreterTool(config));
|
|
337
|
+
}
|
|
338
|
+
if (tools != null) {
|
|
339
|
+
for (const tool of tools) {
|
|
340
|
+
if (tool.type === "provider") {
|
|
341
|
+
const builtinTool = tryConvertToKimiBuiltinTool(tool);
|
|
342
|
+
if (builtinTool) {
|
|
343
|
+
kimiTools2.push(builtinTool);
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
toolWarnings.push({
|
|
347
|
+
type: "unsupported",
|
|
348
|
+
feature: `provider-defined tool ${tool.id}`
|
|
349
|
+
});
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
kimiTools2.push({
|
|
353
|
+
type: "function",
|
|
354
|
+
function: {
|
|
355
|
+
name: tool.name,
|
|
356
|
+
description: tool.description,
|
|
357
|
+
parameters: tool.inputSchema,
|
|
358
|
+
...tool.strict != null ? { strict: tool.strict } : {}
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (kimiTools2.length === 0) {
|
|
364
|
+
return { tools: void 0, toolChoice: void 0, toolWarnings };
|
|
365
|
+
}
|
|
366
|
+
if (toolChoice == null) {
|
|
367
|
+
return { tools: kimiTools2, toolChoice: void 0, toolWarnings };
|
|
368
|
+
}
|
|
369
|
+
switch (toolChoice.type) {
|
|
370
|
+
case "auto":
|
|
371
|
+
case "none":
|
|
372
|
+
return { tools: kimiTools2, toolChoice: toolChoice.type, toolWarnings };
|
|
373
|
+
case "required": {
|
|
374
|
+
if (toolChoicePolyfill) {
|
|
375
|
+
const toolNames = kimiTools2.map((t) => t.type === "function" ? t.function.name : t.function.name).join(", ");
|
|
376
|
+
const systemMessage = generateRequiredToolMessage(toolNames);
|
|
377
|
+
toolWarnings.push({
|
|
378
|
+
type: "compatibility",
|
|
379
|
+
feature: "toolChoice.required",
|
|
380
|
+
details: "Using tool choice polyfill with system message injection."
|
|
381
|
+
});
|
|
382
|
+
return {
|
|
383
|
+
tools: kimiTools2,
|
|
384
|
+
toolChoice: "auto",
|
|
385
|
+
toolWarnings,
|
|
386
|
+
toolChoiceSystemMessage: systemMessage
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
toolWarnings.push({
|
|
390
|
+
type: "compatibility",
|
|
391
|
+
feature: "toolChoice.required",
|
|
392
|
+
details: "Moonshot does not support required tool choice. Falling back to auto."
|
|
393
|
+
});
|
|
394
|
+
return { tools: kimiTools2, toolChoice: "auto", toolWarnings };
|
|
395
|
+
}
|
|
396
|
+
case "tool": {
|
|
397
|
+
if (toolChoicePolyfill) {
|
|
398
|
+
const systemMessage = generateSpecificToolMessage(toolChoice.toolName);
|
|
399
|
+
toolWarnings.push({
|
|
400
|
+
type: "compatibility",
|
|
401
|
+
feature: `toolChoice.tool:${toolChoice.toolName}`,
|
|
402
|
+
details: "Using tool choice polyfill with system message injection."
|
|
403
|
+
});
|
|
404
|
+
return {
|
|
405
|
+
tools: kimiTools2,
|
|
406
|
+
toolChoice: "auto",
|
|
407
|
+
toolWarnings,
|
|
408
|
+
toolChoiceSystemMessage: systemMessage
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
toolWarnings.push({
|
|
412
|
+
type: "compatibility",
|
|
413
|
+
feature: `toolChoice.tool:${toolChoice.toolName}`,
|
|
414
|
+
details: "Moonshot does not support forcing a specific tool. Falling back to auto."
|
|
415
|
+
});
|
|
416
|
+
return { tools: kimiTools2, toolChoice: "auto", toolWarnings };
|
|
417
|
+
}
|
|
418
|
+
default: {
|
|
419
|
+
const _exhaustiveCheck = toolChoice;
|
|
420
|
+
throw new UnsupportedFunctionalityError({
|
|
421
|
+
functionality: `tool choice type: ${_exhaustiveCheck}`
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
function generateRequiredToolMessage(toolNames) {
|
|
427
|
+
return `IMPORTANT INSTRUCTION: You MUST use one of the available tools (${toolNames}) to respond to the user's request. Do NOT provide a direct text response without first calling a tool. Always invoke a tool to complete this task.`;
|
|
428
|
+
}
|
|
429
|
+
function generateSpecificToolMessage(toolName) {
|
|
430
|
+
return `IMPORTANT INSTRUCTION: You MUST use the "${toolName}" tool to respond to this request. Do NOT use any other tool or provide a direct text response. Call the "${toolName}" tool with appropriate parameters.`;
|
|
431
|
+
}
|
|
432
|
+
function tryConvertToKimiBuiltinTool(tool) {
|
|
433
|
+
if (!tool.id.startsWith("kimi.")) {
|
|
434
|
+
return void 0;
|
|
435
|
+
}
|
|
436
|
+
const args = tool.args;
|
|
437
|
+
if (args && typeof args === "object" && "type" in args && args.type === "builtin_function" && "function" in args && typeof args.function === "object") {
|
|
438
|
+
const fn = args.function;
|
|
439
|
+
if (typeof fn.name === "string") {
|
|
440
|
+
return {
|
|
441
|
+
type: "builtin_function",
|
|
442
|
+
function: {
|
|
443
|
+
name: fn.name,
|
|
444
|
+
...fn.config ? { config: fn.config } : {}
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return void 0;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// src/chat/kimi-chat-messages.ts
|
|
453
|
+
import {
|
|
454
|
+
UnsupportedFunctionalityError as UnsupportedFunctionalityError2
|
|
455
|
+
} from "@ai-sdk/provider";
|
|
456
|
+
import { convertToBase64 } from "@ai-sdk/provider-utils";
|
|
457
|
+
var SUPPORTED_IMAGE_TYPES = ["image/jpeg", "image/png", "image/gif", "image/webp", "image/*"];
|
|
458
|
+
var SUPPORTED_VIDEO_TYPES = ["video/mp4", "video/webm", "video/ogg", "video/*"];
|
|
459
|
+
function convertToKimiChatMessages(prompt) {
|
|
460
|
+
const messages = [];
|
|
461
|
+
for (const { role, content } of prompt) {
|
|
462
|
+
switch (role) {
|
|
463
|
+
case "system": {
|
|
464
|
+
messages.push({ role: "system", content });
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
467
|
+
case "user": {
|
|
468
|
+
if (content.length === 1 && content[0].type === "text") {
|
|
469
|
+
messages.push({ role: "user", content: content[0].text });
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
messages.push({
|
|
473
|
+
role: "user",
|
|
474
|
+
content: content.map((part) => {
|
|
475
|
+
switch (part.type) {
|
|
476
|
+
case "text":
|
|
477
|
+
return { type: "text", text: part.text };
|
|
478
|
+
case "file": {
|
|
479
|
+
if (isImageMediaType(part.mediaType)) {
|
|
480
|
+
return convertImagePart(part);
|
|
481
|
+
}
|
|
482
|
+
if (isVideoMediaType(part.mediaType)) {
|
|
483
|
+
return convertVideoPart(part);
|
|
484
|
+
}
|
|
485
|
+
if (part.mediaType.startsWith("text/")) {
|
|
486
|
+
const text = part.data instanceof URL ? part.data.toString() : typeof part.data === "string" ? part.data : new TextDecoder().decode(part.data);
|
|
487
|
+
return { type: "text", text };
|
|
488
|
+
}
|
|
489
|
+
throw new UnsupportedFunctionalityError2({
|
|
490
|
+
functionality: `file part media type ${part.mediaType}`
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
default: {
|
|
494
|
+
const _exhaustiveCheck = part;
|
|
495
|
+
throw new Error(`Unsupported part type: ${_exhaustiveCheck}`);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
})
|
|
499
|
+
});
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
case "assistant": {
|
|
503
|
+
let text = "";
|
|
504
|
+
let reasoning = "";
|
|
505
|
+
const toolCalls = [];
|
|
506
|
+
for (const part of content) {
|
|
507
|
+
switch (part.type) {
|
|
508
|
+
case "text": {
|
|
509
|
+
text += part.text;
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
case "reasoning": {
|
|
513
|
+
reasoning += part.text;
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
case "tool-call": {
|
|
517
|
+
toolCalls.push({
|
|
518
|
+
id: part.toolCallId,
|
|
519
|
+
type: "function",
|
|
520
|
+
function: {
|
|
521
|
+
name: part.toolName,
|
|
522
|
+
arguments: JSON.stringify(part.input)
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
break;
|
|
526
|
+
}
|
|
527
|
+
case "file": {
|
|
528
|
+
break;
|
|
529
|
+
}
|
|
530
|
+
case "tool-result": {
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
default: {
|
|
534
|
+
const _exhaustiveCheck = part;
|
|
535
|
+
throw new Error(`Unsupported assistant part: ${_exhaustiveCheck}`);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
messages.push({
|
|
540
|
+
role: "assistant",
|
|
541
|
+
content: text.length > 0 ? text : null,
|
|
542
|
+
...reasoning.length > 0 ? { reasoning_content: reasoning } : {},
|
|
543
|
+
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
544
|
+
});
|
|
545
|
+
break;
|
|
546
|
+
}
|
|
547
|
+
case "tool": {
|
|
548
|
+
for (const toolResponse of content) {
|
|
549
|
+
if (toolResponse.type === "tool-approval-response") {
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
messages.push({
|
|
553
|
+
role: "tool",
|
|
554
|
+
tool_call_id: toolResponse.toolCallId,
|
|
555
|
+
content: serializeToolResult(toolResponse)
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
break;
|
|
559
|
+
}
|
|
560
|
+
default: {
|
|
561
|
+
const _exhaustiveCheck = role;
|
|
562
|
+
throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return messages;
|
|
567
|
+
}
|
|
568
|
+
function isImageMediaType(mediaType) {
|
|
569
|
+
return mediaType.startsWith("image/") || SUPPORTED_IMAGE_TYPES.includes(mediaType);
|
|
570
|
+
}
|
|
571
|
+
function isVideoMediaType(mediaType) {
|
|
572
|
+
return mediaType.startsWith("video/") || SUPPORTED_VIDEO_TYPES.includes(mediaType);
|
|
573
|
+
}
|
|
574
|
+
function convertImagePart(part) {
|
|
575
|
+
const mediaType = part.mediaType === "image/*" ? "image/jpeg" : part.mediaType;
|
|
576
|
+
const url = part.data instanceof URL ? part.data.toString() : `data:${mediaType};base64,${convertToBase64(part.data)}`;
|
|
577
|
+
return { type: "image_url", image_url: { url } };
|
|
578
|
+
}
|
|
579
|
+
function convertVideoPart(part) {
|
|
580
|
+
if (!(part.data instanceof URL)) {
|
|
581
|
+
throw new UnsupportedFunctionalityError2({
|
|
582
|
+
functionality: "inline video data (video must be provided as a URL)"
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
return { type: "video_url", video_url: { url: part.data.toString() } };
|
|
586
|
+
}
|
|
587
|
+
function serializeToolResult(toolResponse) {
|
|
588
|
+
const { toolName } = toolResponse;
|
|
589
|
+
const output = toolResponse.output;
|
|
590
|
+
if (isBuiltinToolName(toolName)) {
|
|
591
|
+
return serializeBuiltinToolResult(output);
|
|
592
|
+
}
|
|
593
|
+
switch (output.type) {
|
|
594
|
+
case "text":
|
|
595
|
+
case "error-text":
|
|
596
|
+
return output.value;
|
|
597
|
+
case "execution-denied":
|
|
598
|
+
return output.reason ?? "Tool execution denied.";
|
|
599
|
+
case "json":
|
|
600
|
+
case "error-json":
|
|
601
|
+
case "content":
|
|
602
|
+
return JSON.stringify(output.value);
|
|
603
|
+
default: {
|
|
604
|
+
const _exhaustiveCheck = output;
|
|
605
|
+
return JSON.stringify(_exhaustiveCheck);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
function serializeBuiltinToolResult(output) {
|
|
610
|
+
switch (output.type) {
|
|
611
|
+
case "text":
|
|
612
|
+
case "error-text":
|
|
613
|
+
return output.value;
|
|
614
|
+
case "json":
|
|
615
|
+
case "error-json":
|
|
616
|
+
case "content":
|
|
617
|
+
return JSON.stringify(output.value);
|
|
618
|
+
case "execution-denied":
|
|
619
|
+
return output.reason ?? "Tool execution denied.";
|
|
620
|
+
default: {
|
|
621
|
+
const _exhaustiveCheck = output;
|
|
622
|
+
return JSON.stringify(_exhaustiveCheck);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// src/chat/kimi-chat-response.ts
|
|
628
|
+
function extractWebSearchTokens(toolCalls) {
|
|
629
|
+
return extractBuiltinToolTokens(toolCalls, KIMI_WEB_SEARCH_TOOL_NAME);
|
|
630
|
+
}
|
|
631
|
+
function extractCodeInterpreterTokens(toolCalls) {
|
|
632
|
+
return extractBuiltinToolTokens(toolCalls, KIMI_CODE_INTERPRETER_TOOL_NAME);
|
|
633
|
+
}
|
|
634
|
+
function extractBuiltinToolTokens(toolCalls, toolName) {
|
|
635
|
+
if (!toolCalls) {
|
|
636
|
+
return void 0;
|
|
637
|
+
}
|
|
638
|
+
let totalTokens = 0;
|
|
639
|
+
let foundTool = false;
|
|
640
|
+
for (const toolCall of toolCalls) {
|
|
641
|
+
if (toolCall.function.name === toolName) {
|
|
642
|
+
foundTool = true;
|
|
643
|
+
if (toolCall.function.arguments) {
|
|
644
|
+
try {
|
|
645
|
+
const args = JSON.parse(toolCall.function.arguments);
|
|
646
|
+
if (typeof args.total_tokens === "number") {
|
|
647
|
+
totalTokens += args.total_tokens;
|
|
648
|
+
}
|
|
649
|
+
} catch {
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return foundTool ? totalTokens : void 0;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// src/chat/kimi-chat-settings.ts
|
|
658
|
+
import { z as z2 } from "zod/v4";
|
|
659
|
+
var kimiCachingConfigSchema = z2.object({
|
|
660
|
+
enabled: z2.boolean(),
|
|
661
|
+
cacheKey: z2.string().optional(),
|
|
662
|
+
ttlSeconds: z2.number().optional(),
|
|
663
|
+
resetCache: z2.boolean().optional()
|
|
664
|
+
});
|
|
665
|
+
var kimiProviderOptionsSchema = z2.object({
|
|
666
|
+
/**
|
|
667
|
+
* A unique identifier representing your end-user.
|
|
668
|
+
*/
|
|
669
|
+
user: z2.string().optional(),
|
|
670
|
+
/**
|
|
671
|
+
* Whether to use strict JSON schema validation when supported.
|
|
672
|
+
*/
|
|
673
|
+
strictJsonSchema: z2.boolean().optional(),
|
|
674
|
+
/**
|
|
675
|
+
* Optional request ID to correlate logs.
|
|
676
|
+
*/
|
|
677
|
+
requestId: z2.string().optional(),
|
|
678
|
+
/**
|
|
679
|
+
* Optional extra headers for this call.
|
|
680
|
+
*/
|
|
681
|
+
extraHeaders: z2.record(z2.string(), z2.string()).optional(),
|
|
682
|
+
/**
|
|
683
|
+
* Whether the provider should allow parallel tool calls.
|
|
684
|
+
*/
|
|
685
|
+
parallelToolCalls: z2.boolean().optional(),
|
|
686
|
+
/**
|
|
687
|
+
* Enable or configure the built-in web search tool for this request.
|
|
688
|
+
* This allows Kimi to search the web to help answer questions.
|
|
689
|
+
*/
|
|
690
|
+
webSearch: z2.union([
|
|
691
|
+
z2.boolean(),
|
|
692
|
+
z2.object({
|
|
693
|
+
enabled: z2.boolean(),
|
|
694
|
+
config: z2.object({
|
|
695
|
+
search_result: z2.boolean().optional()
|
|
696
|
+
}).optional()
|
|
697
|
+
})
|
|
698
|
+
]).optional(),
|
|
699
|
+
/**
|
|
700
|
+
* Enable or configure the built-in code interpreter tool for this request.
|
|
701
|
+
* This allows Kimi to execute code to help solve problems.
|
|
702
|
+
*/
|
|
703
|
+
codeInterpreter: z2.union([
|
|
704
|
+
z2.boolean(),
|
|
705
|
+
z2.object({
|
|
706
|
+
enabled: z2.boolean(),
|
|
707
|
+
config: z2.object({
|
|
708
|
+
timeout: z2.number().optional(),
|
|
709
|
+
include_output: z2.boolean().optional()
|
|
710
|
+
}).optional()
|
|
711
|
+
})
|
|
712
|
+
]).optional(),
|
|
713
|
+
/**
|
|
714
|
+
* Enable or configure context caching for this request.
|
|
715
|
+
* Reduces costs for repeated long prompts.
|
|
716
|
+
*/
|
|
717
|
+
caching: z2.union([z2.boolean(), kimiCachingConfigSchema]).optional(),
|
|
718
|
+
/**
|
|
719
|
+
* Enable tool choice polyfill for this request.
|
|
720
|
+
*/
|
|
721
|
+
toolChoicePolyfill: z2.boolean().optional()
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
// src/chat/kimi-chat-language-model.ts
|
|
725
|
+
var KimiChatLanguageModel = class {
|
|
726
|
+
constructor(modelId, settings, config) {
|
|
727
|
+
this.specificationVersion = "v3";
|
|
728
|
+
this.modelId = modelId;
|
|
729
|
+
this.settings = settings;
|
|
730
|
+
this.config = config;
|
|
731
|
+
this.generateIdFn = config.generateId ?? generateId;
|
|
732
|
+
this.supportsStructuredOutputs = config.supportsStructuredOutputs ?? false;
|
|
733
|
+
}
|
|
734
|
+
get provider() {
|
|
735
|
+
return this.config.provider;
|
|
736
|
+
}
|
|
737
|
+
get providerOptionsName() {
|
|
738
|
+
return this.config.provider.split(".")[0].trim();
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Get the inferred or configured capabilities for this model.
|
|
742
|
+
*/
|
|
743
|
+
get capabilities() {
|
|
744
|
+
const inferred = inferModelCapabilities(this.modelId);
|
|
745
|
+
return {
|
|
746
|
+
...inferred,
|
|
747
|
+
...this.settings.capabilities
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
get supportedUrls() {
|
|
751
|
+
const caps = this.capabilities;
|
|
752
|
+
const patterns = {
|
|
753
|
+
"image/*": [/^https?:\/\/.*$/i]
|
|
754
|
+
};
|
|
755
|
+
if (caps.videoInput) {
|
|
756
|
+
patterns["video/*"] = [/^https?:\/\/.*$/i];
|
|
757
|
+
}
|
|
758
|
+
return this.settings.supportedUrls ?? this.config.supportedUrls ?? patterns;
|
|
759
|
+
}
|
|
760
|
+
async getArgs({
|
|
761
|
+
prompt,
|
|
762
|
+
maxOutputTokens,
|
|
763
|
+
temperature,
|
|
764
|
+
topP,
|
|
765
|
+
topK,
|
|
766
|
+
frequencyPenalty,
|
|
767
|
+
presencePenalty,
|
|
768
|
+
stopSequences,
|
|
769
|
+
responseFormat,
|
|
770
|
+
seed,
|
|
771
|
+
providerOptions,
|
|
772
|
+
tools,
|
|
773
|
+
toolChoice
|
|
774
|
+
}) {
|
|
775
|
+
const warnings = [];
|
|
776
|
+
const deprecatedOptions = await parseProviderOptions({
|
|
777
|
+
provider: "moonshot",
|
|
778
|
+
providerOptions,
|
|
779
|
+
schema: kimiProviderOptionsSchema
|
|
780
|
+
});
|
|
781
|
+
if (deprecatedOptions != null) {
|
|
782
|
+
warnings.push({
|
|
783
|
+
type: "other",
|
|
784
|
+
message: "The 'moonshot' key in providerOptions is deprecated. Use 'kimi' instead."
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
const providerOptionsName = this.providerOptionsName;
|
|
788
|
+
const kimiOptions = await parseProviderOptions({
|
|
789
|
+
provider: providerOptionsName,
|
|
790
|
+
providerOptions,
|
|
791
|
+
schema: kimiProviderOptionsSchema
|
|
792
|
+
});
|
|
793
|
+
const options = {
|
|
794
|
+
...deprecatedOptions ?? {},
|
|
795
|
+
...kimiOptions ?? {}
|
|
796
|
+
};
|
|
797
|
+
if (topK != null) {
|
|
798
|
+
warnings.push({ type: "unsupported", feature: "topK" });
|
|
799
|
+
}
|
|
800
|
+
const strictJsonSchema = options.strictJsonSchema ?? true;
|
|
801
|
+
if (responseFormat?.type === "json" && responseFormat.schema != null && !this.supportsStructuredOutputs) {
|
|
802
|
+
warnings.push({
|
|
803
|
+
type: "unsupported",
|
|
804
|
+
feature: "responseFormat",
|
|
805
|
+
details: "JSON schema response format requires structured outputs support."
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
const webSearch = resolveBuiltinToolConfig(this.settings.webSearch, options.webSearch);
|
|
809
|
+
const codeInterpreter = resolveBuiltinToolConfig(this.settings.codeInterpreter, options.codeInterpreter);
|
|
810
|
+
const toolChoicePolyfill = options.toolChoicePolyfill ?? this.settings.toolChoicePolyfill ?? true;
|
|
811
|
+
const {
|
|
812
|
+
tools: kimiTools2,
|
|
813
|
+
toolChoice: kimiToolChoice,
|
|
814
|
+
toolWarnings,
|
|
815
|
+
toolChoiceSystemMessage
|
|
816
|
+
} = prepareKimiTools({
|
|
817
|
+
tools,
|
|
818
|
+
toolChoice,
|
|
819
|
+
webSearch,
|
|
820
|
+
codeInterpreter,
|
|
821
|
+
toolChoicePolyfill
|
|
822
|
+
});
|
|
823
|
+
const caching = resolveCachingConfig(this.settings.caching, options.caching);
|
|
824
|
+
const cachingHeaders = buildCachingHeaders(caching);
|
|
825
|
+
const passthroughOptions = getPassthroughOptions({
|
|
826
|
+
providerOptions,
|
|
827
|
+
providerOptionsName,
|
|
828
|
+
deprecatedProviderOptionsName: "moonshot",
|
|
829
|
+
knownKeys: Object.keys(kimiProviderOptionsSchema.shape)
|
|
830
|
+
});
|
|
831
|
+
const messages = convertToKimiChatMessages(prompt);
|
|
832
|
+
if (toolChoiceSystemMessage) {
|
|
833
|
+
messages.unshift({ role: "system", content: toolChoiceSystemMessage });
|
|
834
|
+
}
|
|
835
|
+
const body = removeUndefinedEntries({
|
|
836
|
+
model: this.modelId,
|
|
837
|
+
messages,
|
|
838
|
+
max_tokens: maxOutputTokens,
|
|
839
|
+
temperature,
|
|
840
|
+
top_p: topP,
|
|
841
|
+
frequency_penalty: frequencyPenalty,
|
|
842
|
+
presence_penalty: presencePenalty,
|
|
843
|
+
stop: stopSequences,
|
|
844
|
+
seed,
|
|
845
|
+
response_format: responseFormat?.type === "json" ? this.supportsStructuredOutputs && responseFormat.schema != null ? {
|
|
846
|
+
type: "json_schema",
|
|
847
|
+
json_schema: {
|
|
848
|
+
schema: responseFormat.schema,
|
|
849
|
+
strict: strictJsonSchema,
|
|
850
|
+
name: responseFormat.name ?? "response",
|
|
851
|
+
description: responseFormat.description
|
|
852
|
+
}
|
|
853
|
+
} : { type: "json_object" } : void 0,
|
|
854
|
+
tools: kimiTools2,
|
|
855
|
+
tool_choice: kimiToolChoice,
|
|
856
|
+
user: options.user,
|
|
857
|
+
...kimiTools2 != null && options.parallelToolCalls != null ? { parallel_tool_calls: options.parallelToolCalls } : {},
|
|
858
|
+
...passthroughOptions
|
|
859
|
+
});
|
|
860
|
+
const requestHeaders = {
|
|
861
|
+
...options.requestId ? { "X-Request-ID": options.requestId } : {},
|
|
862
|
+
...options.extraHeaders ?? {},
|
|
863
|
+
...cachingHeaders
|
|
864
|
+
};
|
|
865
|
+
return {
|
|
866
|
+
body,
|
|
867
|
+
warnings: [...warnings, ...toolWarnings],
|
|
868
|
+
requestHeaders
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
async doGenerate(options) {
|
|
872
|
+
const { body, warnings, requestHeaders } = await this.getArgs(options);
|
|
873
|
+
const {
|
|
874
|
+
responseHeaders,
|
|
875
|
+
value: response,
|
|
876
|
+
rawValue
|
|
877
|
+
} = await postJsonToApi({
|
|
878
|
+
url: `${this.config.baseURL}/chat/completions`,
|
|
879
|
+
headers: combineHeaders(this.config.headers(), requestHeaders, options.headers),
|
|
880
|
+
body,
|
|
881
|
+
failedResponseHandler: kimiFailedResponseHandler,
|
|
882
|
+
successfulResponseHandler: createJsonResponseHandler(kimiChatResponseSchema),
|
|
883
|
+
abortSignal: options.abortSignal,
|
|
884
|
+
fetch: this.config.fetch
|
|
885
|
+
});
|
|
886
|
+
const choice = response.choices[0];
|
|
887
|
+
const content = [];
|
|
888
|
+
const { text, reasoning } = extractMessageContent(choice.message);
|
|
889
|
+
if (reasoning.length > 0) {
|
|
890
|
+
content.push({ type: "reasoning", text: reasoning });
|
|
891
|
+
}
|
|
892
|
+
if (text.length > 0) {
|
|
893
|
+
content.push({ type: "text", text });
|
|
894
|
+
}
|
|
895
|
+
if (choice.message.tool_calls != null) {
|
|
896
|
+
for (const toolCall of choice.message.tool_calls) {
|
|
897
|
+
content.push({
|
|
898
|
+
type: "tool-call",
|
|
899
|
+
toolCallId: toolCall.id ?? this.generateIdFn(),
|
|
900
|
+
toolName: toolCall.function.name,
|
|
901
|
+
input: toolCall.function.arguments ?? ""
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
const webSearchTokens = extractWebSearchTokens(choice.message.tool_calls);
|
|
906
|
+
const codeInterpreterTokens = extractCodeInterpreterTokens(choice.message.tool_calls);
|
|
907
|
+
const providerMetadata = buildProviderMetadata({
|
|
908
|
+
providerOptionsName: this.providerOptionsName,
|
|
909
|
+
responseHeaders,
|
|
910
|
+
webSearchTokens,
|
|
911
|
+
codeInterpreterTokens
|
|
912
|
+
});
|
|
913
|
+
return {
|
|
914
|
+
content,
|
|
915
|
+
finishReason: {
|
|
916
|
+
unified: mapKimiFinishReason(choice.finish_reason),
|
|
917
|
+
raw: choice.finish_reason ?? void 0
|
|
918
|
+
},
|
|
919
|
+
usage: convertKimiUsage(response.usage, webSearchTokens, codeInterpreterTokens),
|
|
920
|
+
...providerMetadata ? { providerMetadata } : {},
|
|
921
|
+
request: { body },
|
|
922
|
+
response: {
|
|
923
|
+
...getResponseMetadata(response),
|
|
924
|
+
headers: responseHeaders,
|
|
925
|
+
body: rawValue
|
|
926
|
+
},
|
|
927
|
+
warnings
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
async doStream(options) {
|
|
931
|
+
const { body, warnings, requestHeaders } = await this.getArgs(options);
|
|
932
|
+
const streamBody = {
|
|
933
|
+
...body,
|
|
934
|
+
stream: true,
|
|
935
|
+
stream_options: this.config.includeUsageInStream ? { include_usage: true } : void 0
|
|
936
|
+
};
|
|
937
|
+
const { responseHeaders, value: response } = await postJsonToApi({
|
|
938
|
+
url: `${this.config.baseURL}/chat/completions`,
|
|
939
|
+
headers: combineHeaders(this.config.headers(), requestHeaders, options.headers),
|
|
940
|
+
body: streamBody,
|
|
941
|
+
failedResponseHandler: kimiFailedResponseHandler,
|
|
942
|
+
successfulResponseHandler: createEventSourceResponseHandler(kimiChatChunkSchema),
|
|
943
|
+
abortSignal: options.abortSignal,
|
|
944
|
+
fetch: this.config.fetch
|
|
945
|
+
});
|
|
946
|
+
const requestId = getKimiRequestId(responseHeaders);
|
|
947
|
+
let finishReason = {
|
|
948
|
+
unified: "other",
|
|
949
|
+
raw: void 0
|
|
950
|
+
};
|
|
951
|
+
let usage;
|
|
952
|
+
let isFirstChunk = true;
|
|
953
|
+
let isActiveText = false;
|
|
954
|
+
let isActiveReasoning = false;
|
|
955
|
+
const toolCalls = [];
|
|
956
|
+
const providerOptionsName = this.providerOptionsName;
|
|
957
|
+
const _generateIdFn = this.generateIdFn;
|
|
958
|
+
return {
|
|
959
|
+
stream: response.pipeThrough(
|
|
960
|
+
new TransformStream({
|
|
961
|
+
start(controller) {
|
|
962
|
+
controller.enqueue({ type: "stream-start", warnings });
|
|
963
|
+
},
|
|
964
|
+
transform(chunk, controller) {
|
|
965
|
+
if (options.includeRawChunks) {
|
|
966
|
+
controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
|
|
967
|
+
}
|
|
968
|
+
if (!chunk.success) {
|
|
969
|
+
finishReason = { unified: "error", raw: void 0 };
|
|
970
|
+
controller.enqueue({ type: "error", error: chunk.error });
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
if ("error" in chunk.value) {
|
|
974
|
+
finishReason = { unified: "error", raw: void 0 };
|
|
975
|
+
const error = chunk.value.error;
|
|
976
|
+
controller.enqueue({
|
|
977
|
+
type: "error",
|
|
978
|
+
error: error?.message ?? chunk.value
|
|
979
|
+
});
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
const value = chunk.value;
|
|
983
|
+
if (isFirstChunk) {
|
|
984
|
+
isFirstChunk = false;
|
|
985
|
+
controller.enqueue({
|
|
986
|
+
type: "response-metadata",
|
|
987
|
+
...getResponseMetadata(value)
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
if (value.usage != null) {
|
|
991
|
+
usage = value.usage;
|
|
992
|
+
}
|
|
993
|
+
const choice = value.choices[0];
|
|
994
|
+
if (!choice) {
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
if (choice.finish_reason != null) {
|
|
998
|
+
finishReason = {
|
|
999
|
+
unified: mapKimiFinishReason(choice.finish_reason),
|
|
1000
|
+
raw: choice.finish_reason ?? void 0
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
const delta = choice.delta;
|
|
1004
|
+
if (!delta) {
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
const reasoningDelta = delta.reasoning_content ?? delta.reasoning;
|
|
1008
|
+
if (reasoningDelta) {
|
|
1009
|
+
if (!isActiveReasoning) {
|
|
1010
|
+
if (isActiveText) {
|
|
1011
|
+
controller.enqueue({ type: "text-end", id: "text-0" });
|
|
1012
|
+
isActiveText = false;
|
|
1013
|
+
}
|
|
1014
|
+
controller.enqueue({
|
|
1015
|
+
type: "reasoning-start",
|
|
1016
|
+
id: "reasoning-0"
|
|
1017
|
+
});
|
|
1018
|
+
isActiveReasoning = true;
|
|
1019
|
+
}
|
|
1020
|
+
controller.enqueue({
|
|
1021
|
+
type: "reasoning-delta",
|
|
1022
|
+
id: "reasoning-0",
|
|
1023
|
+
delta: reasoningDelta
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
if (delta.content) {
|
|
1027
|
+
if (isActiveReasoning) {
|
|
1028
|
+
controller.enqueue({ type: "reasoning-end", id: "reasoning-0" });
|
|
1029
|
+
isActiveReasoning = false;
|
|
1030
|
+
}
|
|
1031
|
+
if (!isActiveText) {
|
|
1032
|
+
controller.enqueue({ type: "text-start", id: "text-0" });
|
|
1033
|
+
isActiveText = true;
|
|
1034
|
+
}
|
|
1035
|
+
controller.enqueue({
|
|
1036
|
+
type: "text-delta",
|
|
1037
|
+
id: "text-0",
|
|
1038
|
+
delta: delta.content
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
if (delta.tool_calls != null) {
|
|
1042
|
+
if (isActiveReasoning) {
|
|
1043
|
+
controller.enqueue({ type: "reasoning-end", id: "reasoning-0" });
|
|
1044
|
+
isActiveReasoning = false;
|
|
1045
|
+
}
|
|
1046
|
+
for (const toolCallDelta of delta.tool_calls) {
|
|
1047
|
+
const index = toolCallDelta.index ?? toolCalls.length;
|
|
1048
|
+
if (toolCalls[index] == null) {
|
|
1049
|
+
if (toolCallDelta.id == null) {
|
|
1050
|
+
throw new InvalidResponseDataError({
|
|
1051
|
+
data: toolCallDelta,
|
|
1052
|
+
message: "Expected 'id' to be a string."
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
if (toolCallDelta.function?.name == null) {
|
|
1056
|
+
throw new InvalidResponseDataError({
|
|
1057
|
+
data: toolCallDelta,
|
|
1058
|
+
message: "Expected 'function.name' to be a string."
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
controller.enqueue({
|
|
1062
|
+
type: "tool-input-start",
|
|
1063
|
+
id: toolCallDelta.id,
|
|
1064
|
+
toolName: toolCallDelta.function.name
|
|
1065
|
+
});
|
|
1066
|
+
toolCalls[index] = {
|
|
1067
|
+
id: toolCallDelta.id,
|
|
1068
|
+
type: "function",
|
|
1069
|
+
function: {
|
|
1070
|
+
name: toolCallDelta.function.name,
|
|
1071
|
+
arguments: toolCallDelta.function.arguments ?? ""
|
|
1072
|
+
},
|
|
1073
|
+
hasFinished: false
|
|
1074
|
+
};
|
|
1075
|
+
const toolCall2 = toolCalls[index];
|
|
1076
|
+
if (toolCall2.function.arguments.length > 0) {
|
|
1077
|
+
controller.enqueue({
|
|
1078
|
+
type: "tool-input-delta",
|
|
1079
|
+
id: toolCall2.id,
|
|
1080
|
+
delta: toolCall2.function.arguments
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
if (isParsableJson(toolCall2.function.arguments)) {
|
|
1084
|
+
controller.enqueue({ type: "tool-input-end", id: toolCall2.id });
|
|
1085
|
+
controller.enqueue({
|
|
1086
|
+
type: "tool-call",
|
|
1087
|
+
toolCallId: toolCall2.id,
|
|
1088
|
+
toolName: toolCall2.function.name,
|
|
1089
|
+
input: toolCall2.function.arguments
|
|
1090
|
+
});
|
|
1091
|
+
toolCall2.hasFinished = true;
|
|
1092
|
+
}
|
|
1093
|
+
continue;
|
|
1094
|
+
}
|
|
1095
|
+
const toolCall = toolCalls[index];
|
|
1096
|
+
if (toolCall.hasFinished) {
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
if (toolCallDelta.function?.arguments != null) {
|
|
1100
|
+
toolCall.function.arguments += toolCallDelta.function.arguments;
|
|
1101
|
+
}
|
|
1102
|
+
controller.enqueue({
|
|
1103
|
+
type: "tool-input-delta",
|
|
1104
|
+
id: toolCall.id,
|
|
1105
|
+
delta: toolCallDelta.function?.arguments ?? ""
|
|
1106
|
+
});
|
|
1107
|
+
if (isParsableJson(toolCall.function.arguments)) {
|
|
1108
|
+
controller.enqueue({ type: "tool-input-end", id: toolCall.id });
|
|
1109
|
+
controller.enqueue({
|
|
1110
|
+
type: "tool-call",
|
|
1111
|
+
toolCallId: toolCall.id,
|
|
1112
|
+
toolName: toolCall.function.name,
|
|
1113
|
+
input: toolCall.function.arguments
|
|
1114
|
+
});
|
|
1115
|
+
toolCall.hasFinished = true;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
},
|
|
1120
|
+
flush(controller) {
|
|
1121
|
+
if (isActiveReasoning) {
|
|
1122
|
+
controller.enqueue({ type: "reasoning-end", id: "reasoning-0" });
|
|
1123
|
+
isActiveReasoning = false;
|
|
1124
|
+
}
|
|
1125
|
+
if (isActiveText) {
|
|
1126
|
+
controller.enqueue({ type: "text-end", id: "text-0" });
|
|
1127
|
+
isActiveText = false;
|
|
1128
|
+
}
|
|
1129
|
+
for (const toolCall of toolCalls.filter((call) => !call.hasFinished)) {
|
|
1130
|
+
controller.enqueue({ type: "tool-input-end", id: toolCall.id });
|
|
1131
|
+
controller.enqueue({
|
|
1132
|
+
type: "tool-call",
|
|
1133
|
+
toolCallId: toolCall.id,
|
|
1134
|
+
toolName: toolCall.function.name,
|
|
1135
|
+
input: toolCall.function.arguments
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1138
|
+
const webSearchTokens = extractWebSearchTokens(toolCalls);
|
|
1139
|
+
const codeInterpreterTokens = extractCodeInterpreterTokens(toolCalls);
|
|
1140
|
+
const providerMetadata = requestId || webSearchTokens != null || codeInterpreterTokens != null ? {
|
|
1141
|
+
[providerOptionsName]: {
|
|
1142
|
+
...requestId ? { requestId } : {},
|
|
1143
|
+
...webSearchTokens != null ? { webSearchTokens } : {},
|
|
1144
|
+
...codeInterpreterTokens != null ? { codeInterpreterTokens } : {}
|
|
1145
|
+
}
|
|
1146
|
+
} : void 0;
|
|
1147
|
+
controller.enqueue({
|
|
1148
|
+
type: "finish",
|
|
1149
|
+
finishReason,
|
|
1150
|
+
usage: convertKimiUsage(usage, webSearchTokens, codeInterpreterTokens),
|
|
1151
|
+
...providerMetadata ? { providerMetadata } : {}
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
})
|
|
1155
|
+
),
|
|
1156
|
+
request: { body: streamBody },
|
|
1157
|
+
response: { headers: responseHeaders }
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
};
|
|
1161
|
+
function buildProviderMetadata({
|
|
1162
|
+
providerOptionsName,
|
|
1163
|
+
responseHeaders,
|
|
1164
|
+
webSearchTokens,
|
|
1165
|
+
codeInterpreterTokens
|
|
1166
|
+
}) {
|
|
1167
|
+
const requestId = getKimiRequestId(responseHeaders);
|
|
1168
|
+
if (!requestId && webSearchTokens == null && codeInterpreterTokens == null) {
|
|
1169
|
+
return void 0;
|
|
1170
|
+
}
|
|
1171
|
+
return {
|
|
1172
|
+
[providerOptionsName]: {
|
|
1173
|
+
...requestId ? { requestId } : {},
|
|
1174
|
+
...webSearchTokens != null ? { webSearchTokens } : {},
|
|
1175
|
+
...codeInterpreterTokens != null ? { codeInterpreterTokens } : {}
|
|
1176
|
+
}
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
function getPassthroughOptions({
|
|
1180
|
+
providerOptions,
|
|
1181
|
+
providerOptionsName,
|
|
1182
|
+
deprecatedProviderOptionsName,
|
|
1183
|
+
knownKeys
|
|
1184
|
+
}) {
|
|
1185
|
+
const rawOptions = [providerOptions?.[deprecatedProviderOptionsName], providerOptions?.[providerOptionsName]].filter(
|
|
1186
|
+
(entry) => entry != null && typeof entry === "object"
|
|
1187
|
+
);
|
|
1188
|
+
const passthrough = {};
|
|
1189
|
+
for (const options of rawOptions) {
|
|
1190
|
+
for (const [key, value] of Object.entries(options ?? {})) {
|
|
1191
|
+
if (!knownKeys.includes(key)) {
|
|
1192
|
+
passthrough[key] = value;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
return passthrough;
|
|
1197
|
+
}
|
|
1198
|
+
function resolveBuiltinToolConfig(settingsConfig, optionsConfig) {
|
|
1199
|
+
if (optionsConfig != null) {
|
|
1200
|
+
if (typeof optionsConfig === "boolean") {
|
|
1201
|
+
return optionsConfig ? { enabled: true } : void 0;
|
|
1202
|
+
}
|
|
1203
|
+
const config = optionsConfig;
|
|
1204
|
+
return config.enabled ? optionsConfig : void 0;
|
|
1205
|
+
}
|
|
1206
|
+
if (settingsConfig != null) {
|
|
1207
|
+
if (typeof settingsConfig === "boolean") {
|
|
1208
|
+
return settingsConfig ? { enabled: true } : void 0;
|
|
1209
|
+
}
|
|
1210
|
+
const config = settingsConfig;
|
|
1211
|
+
return config.enabled ? settingsConfig : void 0;
|
|
1212
|
+
}
|
|
1213
|
+
return void 0;
|
|
1214
|
+
}
|
|
1215
|
+
function resolveCachingConfig(settingsConfig, optionsConfig) {
|
|
1216
|
+
const config = optionsConfig ?? settingsConfig;
|
|
1217
|
+
if (config == null) {
|
|
1218
|
+
return void 0;
|
|
1219
|
+
}
|
|
1220
|
+
if (typeof config === "boolean") {
|
|
1221
|
+
return config ? { enabled: true } : void 0;
|
|
1222
|
+
}
|
|
1223
|
+
return config.enabled ? config : void 0;
|
|
1224
|
+
}
|
|
1225
|
+
function buildCachingHeaders(caching) {
|
|
1226
|
+
if (!caching?.enabled) {
|
|
1227
|
+
return {};
|
|
1228
|
+
}
|
|
1229
|
+
const headers = {
|
|
1230
|
+
"X-Kimi-Cache": "enabled"
|
|
1231
|
+
};
|
|
1232
|
+
if (caching.cacheKey) {
|
|
1233
|
+
headers["X-Kimi-Cache-Key"] = caching.cacheKey;
|
|
1234
|
+
}
|
|
1235
|
+
if (caching.ttlSeconds) {
|
|
1236
|
+
headers["X-Kimi-Cache-TTL"] = String(caching.ttlSeconds);
|
|
1237
|
+
}
|
|
1238
|
+
if (caching.resetCache) {
|
|
1239
|
+
headers["X-Kimi-Cache-Reset"] = "true";
|
|
1240
|
+
}
|
|
1241
|
+
return headers;
|
|
1242
|
+
}
|
|
1243
|
+
var kimiTokenUsageSchema = z3.object({
|
|
1244
|
+
prompt_tokens: z3.number().nullish(),
|
|
1245
|
+
completion_tokens: z3.number().nullish(),
|
|
1246
|
+
total_tokens: z3.number().nullish(),
|
|
1247
|
+
prompt_tokens_details: z3.object({
|
|
1248
|
+
cached_tokens: z3.number().nullish()
|
|
1249
|
+
}).nullish(),
|
|
1250
|
+
completion_tokens_details: z3.object({
|
|
1251
|
+
reasoning_tokens: z3.number().nullish()
|
|
1252
|
+
}).nullish()
|
|
1253
|
+
}).nullish();
|
|
1254
|
+
var kimiChatResponseSchema = z3.looseObject({
|
|
1255
|
+
id: z3.string().nullish(),
|
|
1256
|
+
created: z3.number().nullish(),
|
|
1257
|
+
model: z3.string().nullish(),
|
|
1258
|
+
choices: z3.array(
|
|
1259
|
+
z3.object({
|
|
1260
|
+
message: z3.object({
|
|
1261
|
+
role: z3.string().nullish(),
|
|
1262
|
+
content: z3.union([z3.string(), z3.array(z3.any())]).nullish(),
|
|
1263
|
+
reasoning_content: z3.string().nullish(),
|
|
1264
|
+
reasoning: z3.string().nullish(),
|
|
1265
|
+
tool_calls: z3.array(
|
|
1266
|
+
z3.object({
|
|
1267
|
+
id: z3.string().nullish(),
|
|
1268
|
+
function: z3.object({
|
|
1269
|
+
name: z3.string(),
|
|
1270
|
+
arguments: z3.string().nullish()
|
|
1271
|
+
})
|
|
1272
|
+
})
|
|
1273
|
+
).nullish()
|
|
1274
|
+
}),
|
|
1275
|
+
finish_reason: z3.string().nullish()
|
|
1276
|
+
})
|
|
1277
|
+
),
|
|
1278
|
+
usage: kimiTokenUsageSchema
|
|
1279
|
+
});
|
|
1280
|
+
var kimiChatChunkBaseSchema = z3.looseObject({
|
|
1281
|
+
id: z3.string().nullish(),
|
|
1282
|
+
created: z3.number().nullish(),
|
|
1283
|
+
model: z3.string().nullish(),
|
|
1284
|
+
choices: z3.array(
|
|
1285
|
+
z3.object({
|
|
1286
|
+
delta: z3.object({
|
|
1287
|
+
role: z3.enum(["assistant"]).nullish(),
|
|
1288
|
+
content: z3.string().nullish(),
|
|
1289
|
+
reasoning_content: z3.string().nullish(),
|
|
1290
|
+
reasoning: z3.string().nullish(),
|
|
1291
|
+
tool_calls: z3.array(
|
|
1292
|
+
z3.object({
|
|
1293
|
+
index: z3.number().nullish(),
|
|
1294
|
+
id: z3.string().nullish(),
|
|
1295
|
+
function: z3.object({
|
|
1296
|
+
name: z3.string().nullish(),
|
|
1297
|
+
arguments: z3.string().nullish()
|
|
1298
|
+
})
|
|
1299
|
+
})
|
|
1300
|
+
).nullish()
|
|
1301
|
+
}).nullish(),
|
|
1302
|
+
finish_reason: z3.string().nullish()
|
|
1303
|
+
})
|
|
1304
|
+
),
|
|
1305
|
+
usage: kimiTokenUsageSchema
|
|
1306
|
+
});
|
|
1307
|
+
var kimiChatChunkSchema = z3.union([kimiChatChunkBaseSchema, kimiErrorSchema]);
|
|
1308
|
+
|
|
1309
|
+
// src/files/file-utils.ts
|
|
1310
|
+
var SUPPORTED_FILE_EXTENSIONS = [
|
|
1311
|
+
// Documents
|
|
1312
|
+
".pdf",
|
|
1313
|
+
".txt",
|
|
1314
|
+
".csv",
|
|
1315
|
+
".doc",
|
|
1316
|
+
".docx",
|
|
1317
|
+
".xls",
|
|
1318
|
+
".xlsx",
|
|
1319
|
+
".ppt",
|
|
1320
|
+
".pptx",
|
|
1321
|
+
".md",
|
|
1322
|
+
".epub",
|
|
1323
|
+
".mobi",
|
|
1324
|
+
".html",
|
|
1325
|
+
".json",
|
|
1326
|
+
".log",
|
|
1327
|
+
".dot",
|
|
1328
|
+
".ini",
|
|
1329
|
+
".conf",
|
|
1330
|
+
".yaml",
|
|
1331
|
+
".yml",
|
|
1332
|
+
// Images
|
|
1333
|
+
".jpeg",
|
|
1334
|
+
".jpg",
|
|
1335
|
+
".png",
|
|
1336
|
+
".bmp",
|
|
1337
|
+
".gif",
|
|
1338
|
+
".svg",
|
|
1339
|
+
".svgz",
|
|
1340
|
+
".webp",
|
|
1341
|
+
".ico",
|
|
1342
|
+
".xbm",
|
|
1343
|
+
".dib",
|
|
1344
|
+
".pjp",
|
|
1345
|
+
".tif",
|
|
1346
|
+
".tiff",
|
|
1347
|
+
".pjpeg",
|
|
1348
|
+
".avif",
|
|
1349
|
+
".apng",
|
|
1350
|
+
".jfif",
|
|
1351
|
+
// Code files
|
|
1352
|
+
".go",
|
|
1353
|
+
".h",
|
|
1354
|
+
".c",
|
|
1355
|
+
".cpp",
|
|
1356
|
+
".cxx",
|
|
1357
|
+
".cc",
|
|
1358
|
+
".cs",
|
|
1359
|
+
".java",
|
|
1360
|
+
".js",
|
|
1361
|
+
".css",
|
|
1362
|
+
".jsp",
|
|
1363
|
+
".php",
|
|
1364
|
+
".py",
|
|
1365
|
+
".py3",
|
|
1366
|
+
".asp",
|
|
1367
|
+
".ts",
|
|
1368
|
+
".tsx"
|
|
1369
|
+
];
|
|
1370
|
+
var SUPPORTED_MIME_TYPES = {
|
|
1371
|
+
// Documents
|
|
1372
|
+
"application/pdf": "file-extract",
|
|
1373
|
+
"text/plain": "file-extract",
|
|
1374
|
+
"text/csv": "file-extract",
|
|
1375
|
+
"application/msword": "file-extract",
|
|
1376
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "file-extract",
|
|
1377
|
+
"application/vnd.ms-excel": "file-extract",
|
|
1378
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "file-extract",
|
|
1379
|
+
"application/vnd.ms-powerpoint": "file-extract",
|
|
1380
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation": "file-extract",
|
|
1381
|
+
"text/markdown": "file-extract",
|
|
1382
|
+
"text/html": "file-extract",
|
|
1383
|
+
"application/json": "file-extract",
|
|
1384
|
+
"application/epub+zip": "file-extract",
|
|
1385
|
+
"text/yaml": "file-extract",
|
|
1386
|
+
"application/x-yaml": "file-extract",
|
|
1387
|
+
// Code files (treated as text)
|
|
1388
|
+
"text/javascript": "file-extract",
|
|
1389
|
+
"text/typescript": "file-extract",
|
|
1390
|
+
"text/x-python": "file-extract",
|
|
1391
|
+
"text/x-java": "file-extract",
|
|
1392
|
+
"text/x-c": "file-extract",
|
|
1393
|
+
"text/x-c++": "file-extract",
|
|
1394
|
+
"text/css": "file-extract",
|
|
1395
|
+
// Images
|
|
1396
|
+
"image/jpeg": "image",
|
|
1397
|
+
"image/png": "image",
|
|
1398
|
+
"image/gif": "image",
|
|
1399
|
+
"image/webp": "image",
|
|
1400
|
+
"image/svg+xml": "image",
|
|
1401
|
+
"image/bmp": "image",
|
|
1402
|
+
"image/tiff": "image",
|
|
1403
|
+
"image/avif": "image",
|
|
1404
|
+
"image/apng": "image",
|
|
1405
|
+
"image/x-icon": "image",
|
|
1406
|
+
// Videos
|
|
1407
|
+
"video/mp4": "video",
|
|
1408
|
+
"video/webm": "video",
|
|
1409
|
+
"video/ogg": "video",
|
|
1410
|
+
"video/quicktime": "video"
|
|
1411
|
+
};
|
|
1412
|
+
function isImageMediaType2(mediaType) {
|
|
1413
|
+
return mediaType.startsWith("image/");
|
|
1414
|
+
}
|
|
1415
|
+
function isVideoMediaType2(mediaType) {
|
|
1416
|
+
return mediaType.startsWith("video/");
|
|
1417
|
+
}
|
|
1418
|
+
function isFileExtractMediaType(mediaType) {
|
|
1419
|
+
if (mediaType in SUPPORTED_MIME_TYPES) {
|
|
1420
|
+
return SUPPORTED_MIME_TYPES[mediaType] === "file-extract";
|
|
1421
|
+
}
|
|
1422
|
+
if (mediaType.startsWith("text/") || mediaType === "application/pdf") {
|
|
1423
|
+
return true;
|
|
1424
|
+
}
|
|
1425
|
+
return false;
|
|
1426
|
+
}
|
|
1427
|
+
function isDocumentMediaType(mediaType) {
|
|
1428
|
+
const documentTypes = [
|
|
1429
|
+
"application/pdf",
|
|
1430
|
+
"application/msword",
|
|
1431
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
1432
|
+
"application/vnd.ms-excel",
|
|
1433
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
1434
|
+
"application/vnd.ms-powerpoint",
|
|
1435
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
1436
|
+
"application/epub+zip"
|
|
1437
|
+
];
|
|
1438
|
+
return documentTypes.includes(mediaType);
|
|
1439
|
+
}
|
|
1440
|
+
function getPurposeFromMediaType(mediaType) {
|
|
1441
|
+
if (isImageMediaType2(mediaType)) {
|
|
1442
|
+
return "image";
|
|
1443
|
+
}
|
|
1444
|
+
if (isVideoMediaType2(mediaType)) {
|
|
1445
|
+
return "video";
|
|
1446
|
+
}
|
|
1447
|
+
return "file-extract";
|
|
1448
|
+
}
|
|
1449
|
+
function getMediaTypeFromExtension(extension) {
|
|
1450
|
+
const ext = extension.toLowerCase().startsWith(".") ? extension.toLowerCase() : `.${extension.toLowerCase()}`;
|
|
1451
|
+
const extensionToMime = {
|
|
1452
|
+
// Documents
|
|
1453
|
+
".pdf": "application/pdf",
|
|
1454
|
+
".txt": "text/plain",
|
|
1455
|
+
".csv": "text/csv",
|
|
1456
|
+
".doc": "application/msword",
|
|
1457
|
+
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
1458
|
+
".xls": "application/vnd.ms-excel",
|
|
1459
|
+
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
1460
|
+
".ppt": "application/vnd.ms-powerpoint",
|
|
1461
|
+
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
1462
|
+
".md": "text/markdown",
|
|
1463
|
+
".html": "text/html",
|
|
1464
|
+
".json": "application/json",
|
|
1465
|
+
".epub": "application/epub+zip",
|
|
1466
|
+
".yaml": "text/yaml",
|
|
1467
|
+
".yml": "text/yaml",
|
|
1468
|
+
".log": "text/plain",
|
|
1469
|
+
".ini": "text/plain",
|
|
1470
|
+
".conf": "text/plain",
|
|
1471
|
+
// Code
|
|
1472
|
+
".js": "text/javascript",
|
|
1473
|
+
".ts": "text/typescript",
|
|
1474
|
+
".tsx": "text/typescript",
|
|
1475
|
+
".py": "text/x-python",
|
|
1476
|
+
".java": "text/x-java",
|
|
1477
|
+
".c": "text/x-c",
|
|
1478
|
+
".cpp": "text/x-c++",
|
|
1479
|
+
".h": "text/x-c",
|
|
1480
|
+
".css": "text/css",
|
|
1481
|
+
".go": "text/plain",
|
|
1482
|
+
".php": "text/plain",
|
|
1483
|
+
// Images
|
|
1484
|
+
".jpeg": "image/jpeg",
|
|
1485
|
+
".jpg": "image/jpeg",
|
|
1486
|
+
".png": "image/png",
|
|
1487
|
+
".gif": "image/gif",
|
|
1488
|
+
".webp": "image/webp",
|
|
1489
|
+
".svg": "image/svg+xml",
|
|
1490
|
+
".bmp": "image/bmp",
|
|
1491
|
+
".tif": "image/tiff",
|
|
1492
|
+
".tiff": "image/tiff",
|
|
1493
|
+
".avif": "image/avif",
|
|
1494
|
+
".apng": "image/apng",
|
|
1495
|
+
".ico": "image/x-icon",
|
|
1496
|
+
// Videos
|
|
1497
|
+
".mp4": "video/mp4",
|
|
1498
|
+
".webm": "video/webm",
|
|
1499
|
+
".ogg": "video/ogg",
|
|
1500
|
+
".mov": "video/quicktime"
|
|
1501
|
+
};
|
|
1502
|
+
return extensionToMime[ext] ?? "application/octet-stream";
|
|
1503
|
+
}
|
|
1504
|
+
function getExtensionFromPath(path) {
|
|
1505
|
+
const match = path.match(/\.([^./?#]+)(?:[?#]|$)/);
|
|
1506
|
+
return match ? `.${match[1].toLowerCase()}` : null;
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
// src/files/kimi-file-client.ts
|
|
1510
|
+
var KimiFileClient = class {
|
|
1511
|
+
constructor(config) {
|
|
1512
|
+
this.config = config;
|
|
1513
|
+
}
|
|
1514
|
+
/**
|
|
1515
|
+
* Upload a file to the Kimi API.
|
|
1516
|
+
*/
|
|
1517
|
+
async upload(options) {
|
|
1518
|
+
const { data, filename, mediaType, purpose } = options;
|
|
1519
|
+
const resolvedMediaType = mediaType ?? getMediaTypeFromExtension(getExtensionFromPath(filename) ?? "") ?? "application/octet-stream";
|
|
1520
|
+
const resolvedPurpose = purpose ?? getPurposeFromMediaType(resolvedMediaType);
|
|
1521
|
+
const formData = new FormData();
|
|
1522
|
+
const fileData = typeof data === "string" ? base64ToUint8Array(data) : data;
|
|
1523
|
+
const blob = new Blob([new Uint8Array(fileData).buffer], { type: resolvedMediaType });
|
|
1524
|
+
formData.append("file", blob, filename);
|
|
1525
|
+
formData.append("purpose", resolvedPurpose);
|
|
1526
|
+
const fetchFn = this.config.fetch ?? fetch;
|
|
1527
|
+
const headers = this.config.headers();
|
|
1528
|
+
const response = await fetchFn(`${this.config.baseURL}/files`, {
|
|
1529
|
+
method: "POST",
|
|
1530
|
+
headers: {
|
|
1531
|
+
...Object.fromEntries(
|
|
1532
|
+
Object.entries(headers).filter((entry) => entry[1] !== void 0)
|
|
1533
|
+
)
|
|
1534
|
+
// Don't set Content-Type - let the browser set it with boundary for FormData
|
|
1535
|
+
},
|
|
1536
|
+
body: formData
|
|
1537
|
+
});
|
|
1538
|
+
if (!response.ok) {
|
|
1539
|
+
const errorBody = await response.text();
|
|
1540
|
+
throw new Error(`Failed to upload file: ${response.status} ${response.statusText} - ${errorBody}`);
|
|
1541
|
+
}
|
|
1542
|
+
return await response.json();
|
|
1543
|
+
}
|
|
1544
|
+
/**
|
|
1545
|
+
* Get the content of an uploaded file (for file-extract purpose).
|
|
1546
|
+
*/
|
|
1547
|
+
async getContent(fileId) {
|
|
1548
|
+
const fetchFn = this.config.fetch ?? fetch;
|
|
1549
|
+
const headers = this.config.headers();
|
|
1550
|
+
const response = await fetchFn(`${this.config.baseURL}/files/${fileId}/content`, {
|
|
1551
|
+
method: "GET",
|
|
1552
|
+
headers: Object.fromEntries(
|
|
1553
|
+
Object.entries(headers).filter((entry) => entry[1] !== void 0)
|
|
1554
|
+
)
|
|
1555
|
+
});
|
|
1556
|
+
if (!response.ok) {
|
|
1557
|
+
const errorBody = await response.text();
|
|
1558
|
+
throw new Error(`Failed to get file content: ${response.status} ${response.statusText} - ${errorBody}`);
|
|
1559
|
+
}
|
|
1560
|
+
return response.text();
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* Upload a file and extract its content in one operation.
|
|
1564
|
+
* Only works for files with purpose="file-extract".
|
|
1565
|
+
*/
|
|
1566
|
+
async uploadAndExtract(options) {
|
|
1567
|
+
const file = await this.upload({
|
|
1568
|
+
...options,
|
|
1569
|
+
purpose: options.purpose ?? "file-extract"
|
|
1570
|
+
});
|
|
1571
|
+
let currentFile = file;
|
|
1572
|
+
let attempts = 0;
|
|
1573
|
+
const maxAttempts = 30;
|
|
1574
|
+
const pollInterval = 1e3;
|
|
1575
|
+
while (currentFile.status === "processing" && attempts < maxAttempts) {
|
|
1576
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
1577
|
+
currentFile = await this.getFile(file.id);
|
|
1578
|
+
attempts++;
|
|
1579
|
+
}
|
|
1580
|
+
if (currentFile.status === "error") {
|
|
1581
|
+
throw new Error(`File processing failed: ${currentFile.status_details ?? "Unknown error"}`);
|
|
1582
|
+
}
|
|
1583
|
+
if (currentFile.status === "processing") {
|
|
1584
|
+
throw new Error("File processing timed out");
|
|
1585
|
+
}
|
|
1586
|
+
let content;
|
|
1587
|
+
if (currentFile.purpose === "file-extract") {
|
|
1588
|
+
content = await this.getContent(file.id);
|
|
1589
|
+
}
|
|
1590
|
+
return { file: currentFile, content };
|
|
1591
|
+
}
|
|
1592
|
+
/**
|
|
1593
|
+
* Get file information.
|
|
1594
|
+
*/
|
|
1595
|
+
async getFile(fileId) {
|
|
1596
|
+
const fetchFn = this.config.fetch ?? fetch;
|
|
1597
|
+
const headers = this.config.headers();
|
|
1598
|
+
const response = await fetchFn(`${this.config.baseURL}/files/${fileId}`, {
|
|
1599
|
+
method: "GET",
|
|
1600
|
+
headers: Object.fromEntries(
|
|
1601
|
+
Object.entries(headers).filter((entry) => entry[1] !== void 0)
|
|
1602
|
+
)
|
|
1603
|
+
});
|
|
1604
|
+
if (!response.ok) {
|
|
1605
|
+
const errorBody = await response.text();
|
|
1606
|
+
throw new Error(`Failed to get file: ${response.status} ${response.statusText} - ${errorBody}`);
|
|
1607
|
+
}
|
|
1608
|
+
return await response.json();
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* List all uploaded files.
|
|
1612
|
+
*/
|
|
1613
|
+
async listFiles() {
|
|
1614
|
+
const fetchFn = this.config.fetch ?? fetch;
|
|
1615
|
+
const headers = this.config.headers();
|
|
1616
|
+
const response = await fetchFn(`${this.config.baseURL}/files`, {
|
|
1617
|
+
method: "GET",
|
|
1618
|
+
headers: Object.fromEntries(
|
|
1619
|
+
Object.entries(headers).filter((entry) => entry[1] !== void 0)
|
|
1620
|
+
)
|
|
1621
|
+
});
|
|
1622
|
+
if (!response.ok) {
|
|
1623
|
+
const errorBody = await response.text();
|
|
1624
|
+
throw new Error(`Failed to list files: ${response.status} ${response.statusText} - ${errorBody}`);
|
|
1625
|
+
}
|
|
1626
|
+
const result = await response.json();
|
|
1627
|
+
return result.data;
|
|
1628
|
+
}
|
|
1629
|
+
/**
|
|
1630
|
+
* Delete a file.
|
|
1631
|
+
*/
|
|
1632
|
+
async deleteFile(fileId) {
|
|
1633
|
+
const fetchFn = this.config.fetch ?? fetch;
|
|
1634
|
+
const headers = this.config.headers();
|
|
1635
|
+
const response = await fetchFn(`${this.config.baseURL}/files/${fileId}`, {
|
|
1636
|
+
method: "DELETE",
|
|
1637
|
+
headers: Object.fromEntries(
|
|
1638
|
+
Object.entries(headers).filter((entry) => entry[1] !== void 0)
|
|
1639
|
+
)
|
|
1640
|
+
});
|
|
1641
|
+
if (!response.ok) {
|
|
1642
|
+
const errorBody = await response.text();
|
|
1643
|
+
throw new Error(`Failed to delete file: ${response.status} ${response.statusText} - ${errorBody}`);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
};
|
|
1647
|
+
function base64ToUint8Array(base64) {
|
|
1648
|
+
const base64Data = base64.includes(",") ? base64.split(",")[1] : base64;
|
|
1649
|
+
const binaryString = atob(base64Data);
|
|
1650
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
1651
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
1652
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
1653
|
+
}
|
|
1654
|
+
return bytes;
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
// src/files/attachment-processor.ts
|
|
1658
|
+
async function processAttachments(options) {
|
|
1659
|
+
const {
|
|
1660
|
+
attachments,
|
|
1661
|
+
clientConfig,
|
|
1662
|
+
autoUploadDocuments = true,
|
|
1663
|
+
uploadImages = false,
|
|
1664
|
+
cleanupAfterExtract = false
|
|
1665
|
+
} = options;
|
|
1666
|
+
const results = [];
|
|
1667
|
+
const client = new KimiFileClient(clientConfig);
|
|
1668
|
+
for (const attachment of attachments) {
|
|
1669
|
+
try {
|
|
1670
|
+
const processed = await processAttachment(attachment, client, {
|
|
1671
|
+
autoUploadDocuments,
|
|
1672
|
+
uploadImages,
|
|
1673
|
+
cleanupAfterExtract
|
|
1674
|
+
});
|
|
1675
|
+
results.push(processed);
|
|
1676
|
+
} catch (error) {
|
|
1677
|
+
results.push({
|
|
1678
|
+
original: attachment,
|
|
1679
|
+
type: "skip",
|
|
1680
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
return results;
|
|
1685
|
+
}
|
|
1686
|
+
async function processAttachment(attachment, client, options) {
|
|
1687
|
+
const contentType = resolveContentType(attachment);
|
|
1688
|
+
if (isImageMediaType2(contentType)) {
|
|
1689
|
+
if (options.uploadImages && attachment.content) {
|
|
1690
|
+
const result = await client.upload({
|
|
1691
|
+
data: attachment.content,
|
|
1692
|
+
filename: attachment.name ?? "image.jpg",
|
|
1693
|
+
mediaType: contentType,
|
|
1694
|
+
purpose: "image"
|
|
1695
|
+
});
|
|
1696
|
+
return {
|
|
1697
|
+
original: attachment,
|
|
1698
|
+
type: "image-url",
|
|
1699
|
+
fileId: result.id,
|
|
1700
|
+
mediaUrl: attachment.url
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1703
|
+
return {
|
|
1704
|
+
original: attachment,
|
|
1705
|
+
type: "image-url",
|
|
1706
|
+
mediaUrl: attachment.url
|
|
1707
|
+
};
|
|
1708
|
+
}
|
|
1709
|
+
if (isVideoMediaType2(contentType)) {
|
|
1710
|
+
return {
|
|
1711
|
+
original: attachment,
|
|
1712
|
+
type: "video-url",
|
|
1713
|
+
mediaUrl: attachment.url
|
|
1714
|
+
};
|
|
1715
|
+
}
|
|
1716
|
+
if (options.autoUploadDocuments && (isDocumentMediaType(contentType) || isFileExtractMediaType(contentType))) {
|
|
1717
|
+
let data;
|
|
1718
|
+
if (attachment.content) {
|
|
1719
|
+
data = attachment.content;
|
|
1720
|
+
} else if (attachment.url) {
|
|
1721
|
+
const response = await fetch(attachment.url);
|
|
1722
|
+
if (!response.ok) {
|
|
1723
|
+
throw new Error(`Failed to fetch attachment: ${response.status}`);
|
|
1724
|
+
}
|
|
1725
|
+
data = new Uint8Array(await response.arrayBuffer());
|
|
1726
|
+
} else {
|
|
1727
|
+
return {
|
|
1728
|
+
original: attachment,
|
|
1729
|
+
type: "skip",
|
|
1730
|
+
error: "No content or URL provided for document attachment"
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
const result = await client.uploadAndExtract({
|
|
1734
|
+
data,
|
|
1735
|
+
filename: attachment.name ?? guessFilename(attachment, contentType),
|
|
1736
|
+
mediaType: contentType,
|
|
1737
|
+
purpose: "file-extract"
|
|
1738
|
+
});
|
|
1739
|
+
if (options.cleanupAfterExtract && result.file.id) {
|
|
1740
|
+
try {
|
|
1741
|
+
await client.deleteFile(result.file.id);
|
|
1742
|
+
} catch {
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
return {
|
|
1746
|
+
original: attachment,
|
|
1747
|
+
type: "text-inject",
|
|
1748
|
+
textContent: result.content,
|
|
1749
|
+
fileId: result.file.id
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
return {
|
|
1753
|
+
original: attachment,
|
|
1754
|
+
type: "skip",
|
|
1755
|
+
error: `Unsupported content type: ${contentType}`
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1758
|
+
function resolveContentType(attachment) {
|
|
1759
|
+
if (attachment.contentType) {
|
|
1760
|
+
return attachment.contentType;
|
|
1761
|
+
}
|
|
1762
|
+
const path = attachment.name ?? attachment.url;
|
|
1763
|
+
if (path) {
|
|
1764
|
+
const ext = getExtensionFromPath(path);
|
|
1765
|
+
if (ext) {
|
|
1766
|
+
return getMediaTypeFromExtension(ext);
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
return "application/octet-stream";
|
|
1770
|
+
}
|
|
1771
|
+
function guessFilename(attachment, contentType) {
|
|
1772
|
+
if (attachment.name) {
|
|
1773
|
+
return attachment.name;
|
|
1774
|
+
}
|
|
1775
|
+
if (attachment.url) {
|
|
1776
|
+
const urlPath = attachment.url.split("?")[0];
|
|
1777
|
+
const segments = urlPath.split("/");
|
|
1778
|
+
const lastSegment = segments[segments.length - 1];
|
|
1779
|
+
if (lastSegment && lastSegment.includes(".")) {
|
|
1780
|
+
return lastSegment;
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
const extensionMap = {
|
|
1784
|
+
"application/pdf": "document.pdf",
|
|
1785
|
+
"text/plain": "document.txt",
|
|
1786
|
+
"application/msword": "document.doc",
|
|
1787
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "document.docx",
|
|
1788
|
+
"image/jpeg": "image.jpg",
|
|
1789
|
+
"image/png": "image.png"
|
|
1790
|
+
};
|
|
1791
|
+
return extensionMap[contentType] ?? "file.bin";
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
// src/version.ts
|
|
1795
|
+
var VERSION = "0.2.0".length > 0 ? "0.2.0" : "0.0.0";
|
|
1796
|
+
|
|
1797
|
+
// src/kimi-provider.ts
|
|
1798
|
+
var GLOBAL_BASE_URL = "https://api.moonshot.ai/v1";
|
|
1799
|
+
var CN_BASE_URL = "https://api.moonshot.cn/v1";
|
|
1800
|
+
function createKimi(options = {}) {
|
|
1801
|
+
const resolvedBaseURL = loadOptionalSetting({
|
|
1802
|
+
settingValue: options.baseURL,
|
|
1803
|
+
environmentVariableName: "MOONSHOT_BASE_URL"
|
|
1804
|
+
}) ?? (options.endpoint === "cn" ? CN_BASE_URL : GLOBAL_BASE_URL);
|
|
1805
|
+
const baseURL = withoutTrailingSlash(resolvedBaseURL) ?? GLOBAL_BASE_URL;
|
|
1806
|
+
const getHeaders = () => withUserAgentSuffix(
|
|
1807
|
+
{
|
|
1808
|
+
Authorization: `Bearer ${loadApiKey({
|
|
1809
|
+
apiKey: options.apiKey,
|
|
1810
|
+
environmentVariableName: "MOONSHOT_API_KEY",
|
|
1811
|
+
description: "Moonshot"
|
|
1812
|
+
})}`,
|
|
1813
|
+
...options.headers
|
|
1814
|
+
},
|
|
1815
|
+
`ai-sdk/kimi/${VERSION}`
|
|
1816
|
+
);
|
|
1817
|
+
const createChatModel = (modelId, settings = {}) => new KimiChatLanguageModel(modelId, settings, {
|
|
1818
|
+
provider: "kimi.chat",
|
|
1819
|
+
baseURL,
|
|
1820
|
+
headers: getHeaders,
|
|
1821
|
+
fetch: options.fetch,
|
|
1822
|
+
generateId: options.generateId,
|
|
1823
|
+
supportsStructuredOutputs: settings.supportsStructuredOutputs ?? options.supportsStructuredOutputs,
|
|
1824
|
+
includeUsageInStream: settings.includeUsageInStream ?? options.includeUsageInStream,
|
|
1825
|
+
supportedUrls: settings.supportedUrls ?? options.supportedUrls
|
|
1826
|
+
});
|
|
1827
|
+
const provider = (modelId, settings) => {
|
|
1828
|
+
if (new.target) {
|
|
1829
|
+
throw new Error("The Kimi provider function cannot be called with new.");
|
|
1830
|
+
}
|
|
1831
|
+
return createChatModel(modelId, settings);
|
|
1832
|
+
};
|
|
1833
|
+
provider.specificationVersion = "v3";
|
|
1834
|
+
provider.languageModel = createChatModel;
|
|
1835
|
+
provider.chat = createChatModel;
|
|
1836
|
+
provider.tools = kimiTools;
|
|
1837
|
+
provider.files = new KimiFileClient({
|
|
1838
|
+
baseURL,
|
|
1839
|
+
headers: getHeaders,
|
|
1840
|
+
fetch: options.fetch
|
|
1841
|
+
});
|
|
1842
|
+
provider.embeddingModel = (modelId) => {
|
|
1843
|
+
throw new NoSuchModelError({ modelId, modelType: "embeddingModel" });
|
|
1844
|
+
};
|
|
1845
|
+
provider.imageModel = (modelId) => {
|
|
1846
|
+
throw new NoSuchModelError({ modelId, modelType: "imageModel" });
|
|
1847
|
+
};
|
|
1848
|
+
provider.rerankingModel = (modelId) => {
|
|
1849
|
+
throw new NoSuchModelError({ modelId, modelType: "rerankingModel" });
|
|
1850
|
+
};
|
|
1851
|
+
return provider;
|
|
1852
|
+
}
|
|
1853
|
+
var kimi = createKimi();
|
|
1854
|
+
|
|
1855
|
+
// src/code/kimi-code-language-model.ts
|
|
1856
|
+
import {
|
|
1857
|
+
combineHeaders as combineHeaders2,
|
|
1858
|
+
createEventSourceResponseHandler as createEventSourceResponseHandler2,
|
|
1859
|
+
createJsonErrorResponseHandler as createJsonErrorResponseHandler2,
|
|
1860
|
+
createJsonResponseHandler as createJsonResponseHandler2,
|
|
1861
|
+
generateId as generateId2,
|
|
1862
|
+
parseProviderOptions as parseProviderOptions2,
|
|
1863
|
+
postJsonToApi as postJsonToApi2,
|
|
1864
|
+
removeUndefinedEntries as removeUndefinedEntries2
|
|
1865
|
+
} from "@ai-sdk/provider-utils";
|
|
1866
|
+
import { z as z5 } from "zod/v4";
|
|
1867
|
+
|
|
1868
|
+
// src/code/kimi-code-messages.ts
|
|
1869
|
+
import { UnsupportedFunctionalityError as UnsupportedFunctionalityError3 } from "@ai-sdk/provider";
|
|
1870
|
+
import { convertToBase64 as convertToBase642 } from "@ai-sdk/provider-utils";
|
|
1871
|
+
async function convertToKimiCodePrompt(prompt) {
|
|
1872
|
+
let systemMessage;
|
|
1873
|
+
const messages = [];
|
|
1874
|
+
for (const message of prompt) {
|
|
1875
|
+
switch (message.role) {
|
|
1876
|
+
case "system": {
|
|
1877
|
+
const systemText = typeof message.content === "string" ? message.content : "";
|
|
1878
|
+
systemMessage = systemMessage ? `${systemMessage}
|
|
1879
|
+
|
|
1880
|
+
${systemText}` : systemText;
|
|
1881
|
+
break;
|
|
1882
|
+
}
|
|
1883
|
+
case "user": {
|
|
1884
|
+
const content = [];
|
|
1885
|
+
for (const part of message.content) {
|
|
1886
|
+
switch (part.type) {
|
|
1887
|
+
case "text":
|
|
1888
|
+
content.push({ type: "text", text: part.text });
|
|
1889
|
+
break;
|
|
1890
|
+
case "file":
|
|
1891
|
+
if (part.mediaType?.startsWith("image/")) {
|
|
1892
|
+
content.push(await convertFilePart(part));
|
|
1893
|
+
} else {
|
|
1894
|
+
throw new UnsupportedFunctionalityError3({
|
|
1895
|
+
functionality: `file type: ${part.mediaType}`
|
|
1896
|
+
});
|
|
1897
|
+
}
|
|
1898
|
+
break;
|
|
1899
|
+
default:
|
|
1900
|
+
throw new UnsupportedFunctionalityError3({
|
|
1901
|
+
functionality: `user content part type: ${part.type}`
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
messages.push({
|
|
1906
|
+
role: "user",
|
|
1907
|
+
content: content.length === 1 && content[0].type === "text" ? content[0].text : content
|
|
1908
|
+
});
|
|
1909
|
+
break;
|
|
1910
|
+
}
|
|
1911
|
+
case "assistant": {
|
|
1912
|
+
const content = [];
|
|
1913
|
+
for (const part of message.content) {
|
|
1914
|
+
switch (part.type) {
|
|
1915
|
+
case "text":
|
|
1916
|
+
content.push({ type: "text", text: part.text });
|
|
1917
|
+
break;
|
|
1918
|
+
case "tool-call":
|
|
1919
|
+
content.push({
|
|
1920
|
+
type: "tool_use",
|
|
1921
|
+
id: part.toolCallId,
|
|
1922
|
+
name: part.toolName,
|
|
1923
|
+
input: typeof part.input === "string" ? JSON.parse(part.input) : part.input
|
|
1924
|
+
});
|
|
1925
|
+
break;
|
|
1926
|
+
case "reasoning":
|
|
1927
|
+
if (part.text) {
|
|
1928
|
+
content.push({ type: "text", text: `<thinking>${part.text}</thinking>` });
|
|
1929
|
+
}
|
|
1930
|
+
break;
|
|
1931
|
+
default:
|
|
1932
|
+
throw new UnsupportedFunctionalityError3({
|
|
1933
|
+
functionality: `assistant content part type: ${part.type}`
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
if (content.length > 0) {
|
|
1938
|
+
messages.push({
|
|
1939
|
+
role: "assistant",
|
|
1940
|
+
content: content.length === 1 && content[0].type === "text" ? content[0].text : content
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
break;
|
|
1944
|
+
}
|
|
1945
|
+
case "tool": {
|
|
1946
|
+
const toolResults = [];
|
|
1947
|
+
for (const part of message.content) {
|
|
1948
|
+
if (part.type === "tool-result") {
|
|
1949
|
+
toolResults.push(convertToolResultPart(part));
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
if (messages.length > 0 && messages[messages.length - 1].role === "assistant") {
|
|
1953
|
+
messages.push({
|
|
1954
|
+
role: "user",
|
|
1955
|
+
content: toolResults
|
|
1956
|
+
});
|
|
1957
|
+
} else {
|
|
1958
|
+
const lastMessage = messages[messages.length - 1];
|
|
1959
|
+
if (lastMessage?.role === "user" && Array.isArray(lastMessage.content)) {
|
|
1960
|
+
lastMessage.content.push(...toolResults);
|
|
1961
|
+
} else {
|
|
1962
|
+
messages.push({
|
|
1963
|
+
role: "user",
|
|
1964
|
+
content: toolResults
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
break;
|
|
1969
|
+
}
|
|
1970
|
+
default:
|
|
1971
|
+
throw new UnsupportedFunctionalityError3({
|
|
1972
|
+
functionality: `message role: ${message.role}`
|
|
1973
|
+
});
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
return {
|
|
1977
|
+
system: systemMessage,
|
|
1978
|
+
messages
|
|
1979
|
+
};
|
|
1980
|
+
}
|
|
1981
|
+
async function convertFilePart(part) {
|
|
1982
|
+
const mediaType = part.mediaType ?? "image/png";
|
|
1983
|
+
if (part.data instanceof URL) {
|
|
1984
|
+
return {
|
|
1985
|
+
type: "image",
|
|
1986
|
+
source: {
|
|
1987
|
+
type: "url",
|
|
1988
|
+
url: part.data.toString()
|
|
1989
|
+
}
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
if (typeof part.data === "string") {
|
|
1993
|
+
if (part.data.startsWith("http://") || part.data.startsWith("https://")) {
|
|
1994
|
+
return {
|
|
1995
|
+
type: "image",
|
|
1996
|
+
source: {
|
|
1997
|
+
type: "url",
|
|
1998
|
+
url: part.data
|
|
1999
|
+
}
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
if (part.data.startsWith("data:")) {
|
|
2003
|
+
const [header, data] = part.data.split(",");
|
|
2004
|
+
const extractedMimeType = header.match(/data:([^;]+)/)?.[1] ?? mediaType;
|
|
2005
|
+
return {
|
|
2006
|
+
type: "image",
|
|
2007
|
+
source: {
|
|
2008
|
+
type: "base64",
|
|
2009
|
+
media_type: extractedMimeType,
|
|
2010
|
+
data
|
|
2011
|
+
}
|
|
2012
|
+
};
|
|
2013
|
+
}
|
|
2014
|
+
return {
|
|
2015
|
+
type: "image",
|
|
2016
|
+
source: {
|
|
2017
|
+
type: "base64",
|
|
2018
|
+
media_type: mediaType,
|
|
2019
|
+
data: part.data
|
|
2020
|
+
}
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
const base64 = convertToBase642(part.data);
|
|
2024
|
+
return {
|
|
2025
|
+
type: "image",
|
|
2026
|
+
source: {
|
|
2027
|
+
type: "base64",
|
|
2028
|
+
media_type: mediaType,
|
|
2029
|
+
data: base64
|
|
2030
|
+
}
|
|
2031
|
+
};
|
|
2032
|
+
}
|
|
2033
|
+
function convertToolResultPart(part) {
|
|
2034
|
+
const output = part.output;
|
|
2035
|
+
let content;
|
|
2036
|
+
let isError = false;
|
|
2037
|
+
switch (output.type) {
|
|
2038
|
+
case "text":
|
|
2039
|
+
content = String(output.value ?? "");
|
|
2040
|
+
break;
|
|
2041
|
+
case "error-text":
|
|
2042
|
+
content = String(output.value ?? "");
|
|
2043
|
+
isError = true;
|
|
2044
|
+
break;
|
|
2045
|
+
case "execution-denied":
|
|
2046
|
+
content = output.reason ?? "Tool execution denied.";
|
|
2047
|
+
isError = true;
|
|
2048
|
+
break;
|
|
2049
|
+
case "json":
|
|
2050
|
+
case "content":
|
|
2051
|
+
content = JSON.stringify(output.value);
|
|
2052
|
+
break;
|
|
2053
|
+
case "error-json":
|
|
2054
|
+
content = JSON.stringify(output.value);
|
|
2055
|
+
isError = true;
|
|
2056
|
+
break;
|
|
2057
|
+
default:
|
|
2058
|
+
content = JSON.stringify(output);
|
|
2059
|
+
}
|
|
2060
|
+
return {
|
|
2061
|
+
type: "tool_result",
|
|
2062
|
+
tool_use_id: part.toolCallId,
|
|
2063
|
+
content,
|
|
2064
|
+
is_error: isError || void 0
|
|
2065
|
+
};
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
// src/code/kimi-code-settings.ts
|
|
2069
|
+
import { z as z4 } from "zod/v4";
|
|
2070
|
+
var kimiCodeProviderOptionsSchema = z4.object({
|
|
2071
|
+
/**
|
|
2072
|
+
* Extended thinking configuration.
|
|
2073
|
+
*/
|
|
2074
|
+
extendedThinking: z4.union([
|
|
2075
|
+
z4.boolean(),
|
|
2076
|
+
z4.object({
|
|
2077
|
+
enabled: z4.boolean().optional(),
|
|
2078
|
+
effort: z4.enum(["low", "medium", "high"]).optional(),
|
|
2079
|
+
budgetTokens: z4.number().optional()
|
|
2080
|
+
})
|
|
2081
|
+
]).optional(),
|
|
2082
|
+
/**
|
|
2083
|
+
* System prompt to prepend.
|
|
2084
|
+
*/
|
|
2085
|
+
system: z4.string().optional(),
|
|
2086
|
+
/**
|
|
2087
|
+
* Custom stop sequences.
|
|
2088
|
+
*/
|
|
2089
|
+
stopSequences: z4.array(z4.string()).optional()
|
|
2090
|
+
});
|
|
2091
|
+
function normalizeExtendedThinkingConfig(config) {
|
|
2092
|
+
if (config === void 0) {
|
|
2093
|
+
return void 0;
|
|
2094
|
+
}
|
|
2095
|
+
if (typeof config === "boolean") {
|
|
2096
|
+
return config ? { enabled: true, effort: "medium" } : { enabled: false };
|
|
2097
|
+
}
|
|
2098
|
+
return {
|
|
2099
|
+
enabled: config.enabled ?? true,
|
|
2100
|
+
effort: config.effort ?? "medium",
|
|
2101
|
+
budgetTokens: config.budgetTokens
|
|
2102
|
+
};
|
|
2103
|
+
}
|
|
2104
|
+
function effortToBudgetTokens(effort) {
|
|
2105
|
+
switch (effort) {
|
|
2106
|
+
case "low":
|
|
2107
|
+
return 2048;
|
|
2108
|
+
case "medium":
|
|
2109
|
+
return 8192;
|
|
2110
|
+
case "high":
|
|
2111
|
+
return 16384;
|
|
2112
|
+
default:
|
|
2113
|
+
return 8192;
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
// src/code/kimi-code-types.ts
|
|
2118
|
+
var KIMI_CODE_BASE_URL = "https://api.kimi.com/coding/v1";
|
|
2119
|
+
var KIMI_CODE_DEFAULT_MODEL = "kimi-for-coding";
|
|
2120
|
+
var KIMI_CODE_THINKING_MODEL = "kimi-k2-thinking";
|
|
2121
|
+
var KIMI_CODE_DEFAULT_MAX_TOKENS = 32768;
|
|
2122
|
+
var KIMI_CODE_DEFAULT_CONTEXT_WINDOW = 262144;
|
|
2123
|
+
function inferKimiCodeCapabilities(modelId) {
|
|
2124
|
+
const isThinkingModel = modelId.includes("-thinking") || modelId.includes("k2-thinking");
|
|
2125
|
+
return {
|
|
2126
|
+
extendedThinking: isThinkingModel,
|
|
2127
|
+
maxOutputTokens: KIMI_CODE_DEFAULT_MAX_TOKENS,
|
|
2128
|
+
maxContextSize: KIMI_CODE_DEFAULT_CONTEXT_WINDOW,
|
|
2129
|
+
streaming: true,
|
|
2130
|
+
toolCalling: true,
|
|
2131
|
+
imageInput: true
|
|
2132
|
+
};
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
// src/code/kimi-code-language-model.ts
|
|
2136
|
+
var kimiCodeErrorSchema = z5.union([
|
|
2137
|
+
z5.object({
|
|
2138
|
+
error: z5.object({
|
|
2139
|
+
message: z5.string(),
|
|
2140
|
+
type: z5.string().nullish(),
|
|
2141
|
+
code: z5.union([z5.string(), z5.number()]).nullish()
|
|
2142
|
+
})
|
|
2143
|
+
}),
|
|
2144
|
+
z5.object({
|
|
2145
|
+
message: z5.string()
|
|
2146
|
+
})
|
|
2147
|
+
]);
|
|
2148
|
+
var kimiCodeTextContentSchema = z5.object({
|
|
2149
|
+
type: z5.literal("text"),
|
|
2150
|
+
text: z5.string()
|
|
2151
|
+
});
|
|
2152
|
+
var kimiCodeThinkingContentSchema = z5.object({
|
|
2153
|
+
type: z5.literal("thinking"),
|
|
2154
|
+
thinking: z5.string()
|
|
2155
|
+
});
|
|
2156
|
+
var kimiCodeToolUseContentSchema = z5.object({
|
|
2157
|
+
type: z5.literal("tool_use"),
|
|
2158
|
+
id: z5.string(),
|
|
2159
|
+
name: z5.string(),
|
|
2160
|
+
input: z5.record(z5.string(), z5.unknown())
|
|
2161
|
+
});
|
|
2162
|
+
var kimiCodeContentBlockSchema = z5.union([
|
|
2163
|
+
kimiCodeTextContentSchema,
|
|
2164
|
+
kimiCodeThinkingContentSchema,
|
|
2165
|
+
kimiCodeToolUseContentSchema
|
|
2166
|
+
]);
|
|
2167
|
+
var kimiCodeResponseSchema = z5.object({
|
|
2168
|
+
id: z5.string().optional(),
|
|
2169
|
+
type: z5.string().optional(),
|
|
2170
|
+
model: z5.string().optional(),
|
|
2171
|
+
stop_reason: z5.string().nullish(),
|
|
2172
|
+
stop_sequence: z5.string().nullish(),
|
|
2173
|
+
content: z5.array(kimiCodeContentBlockSchema),
|
|
2174
|
+
usage: z5.object({
|
|
2175
|
+
input_tokens: z5.number().optional(),
|
|
2176
|
+
output_tokens: z5.number().optional(),
|
|
2177
|
+
cache_read_input_tokens: z5.number().optional(),
|
|
2178
|
+
cache_creation_input_tokens: z5.number().optional()
|
|
2179
|
+
}).optional()
|
|
2180
|
+
});
|
|
2181
|
+
var kimiCodeStreamChunkSchema = z5.object({
|
|
2182
|
+
type: z5.string(),
|
|
2183
|
+
index: z5.number().optional(),
|
|
2184
|
+
message: z5.object({
|
|
2185
|
+
id: z5.string().optional(),
|
|
2186
|
+
type: z5.string().optional(),
|
|
2187
|
+
model: z5.string().optional(),
|
|
2188
|
+
content: z5.array(z5.unknown()).optional(),
|
|
2189
|
+
stop_reason: z5.string().nullish(),
|
|
2190
|
+
stop_sequence: z5.string().nullish(),
|
|
2191
|
+
usage: z5.object({
|
|
2192
|
+
input_tokens: z5.number().optional(),
|
|
2193
|
+
output_tokens: z5.number().optional()
|
|
2194
|
+
}).optional()
|
|
2195
|
+
}).optional(),
|
|
2196
|
+
content_block: z5.object({
|
|
2197
|
+
type: z5.string(),
|
|
2198
|
+
text: z5.string().optional(),
|
|
2199
|
+
thinking: z5.string().optional(),
|
|
2200
|
+
id: z5.string().optional(),
|
|
2201
|
+
name: z5.string().optional(),
|
|
2202
|
+
input: z5.record(z5.string(), z5.unknown()).optional()
|
|
2203
|
+
}).optional(),
|
|
2204
|
+
delta: z5.object({
|
|
2205
|
+
type: z5.string().optional(),
|
|
2206
|
+
text: z5.string().optional(),
|
|
2207
|
+
thinking: z5.string().optional(),
|
|
2208
|
+
partial_json: z5.string().optional(),
|
|
2209
|
+
stop_reason: z5.string().optional(),
|
|
2210
|
+
stop_sequence: z5.string().optional()
|
|
2211
|
+
}).optional(),
|
|
2212
|
+
usage: z5.object({
|
|
2213
|
+
input_tokens: z5.number().optional(),
|
|
2214
|
+
output_tokens: z5.number().optional()
|
|
2215
|
+
}).optional()
|
|
2216
|
+
});
|
|
2217
|
+
var kimiCodeFailedResponseHandler = createJsonErrorResponseHandler2({
|
|
2218
|
+
errorSchema: kimiCodeErrorSchema,
|
|
2219
|
+
errorToMessage: (error) => {
|
|
2220
|
+
if ("error" in error) {
|
|
2221
|
+
return error.error.message;
|
|
2222
|
+
}
|
|
2223
|
+
return error.message;
|
|
2224
|
+
},
|
|
2225
|
+
isRetryable: (response) => response.status === 408 || response.status === 409 || response.status === 429 || response.status >= 500
|
|
2226
|
+
});
|
|
2227
|
+
function mapStopReason(stopReason) {
|
|
2228
|
+
switch (stopReason) {
|
|
2229
|
+
case "end_turn":
|
|
2230
|
+
case "stop_sequence":
|
|
2231
|
+
return { unified: "stop", raw: stopReason };
|
|
2232
|
+
case "tool_use":
|
|
2233
|
+
return { unified: "tool-calls", raw: stopReason };
|
|
2234
|
+
case "max_tokens":
|
|
2235
|
+
return { unified: "length", raw: stopReason };
|
|
2236
|
+
default:
|
|
2237
|
+
return { unified: "other", raw: stopReason ?? void 0 };
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
function convertUsage(usage) {
|
|
2241
|
+
const inputTokens = usage?.input_tokens ?? 0;
|
|
2242
|
+
const outputTokens = usage?.output_tokens ?? 0;
|
|
2243
|
+
const cacheRead = usage?.cache_read_input_tokens ?? 0;
|
|
2244
|
+
return {
|
|
2245
|
+
inputTokens: {
|
|
2246
|
+
total: inputTokens,
|
|
2247
|
+
cacheRead,
|
|
2248
|
+
cacheWrite: usage?.cache_creation_input_tokens,
|
|
2249
|
+
noCache: inputTokens - cacheRead
|
|
2250
|
+
},
|
|
2251
|
+
outputTokens: {
|
|
2252
|
+
total: outputTokens,
|
|
2253
|
+
text: outputTokens,
|
|
2254
|
+
reasoning: 0
|
|
2255
|
+
},
|
|
2256
|
+
raw: usage
|
|
2257
|
+
};
|
|
2258
|
+
}
|
|
2259
|
+
function convertTools(tools) {
|
|
2260
|
+
if (!tools || tools.length === 0) {
|
|
2261
|
+
return void 0;
|
|
2262
|
+
}
|
|
2263
|
+
return tools.map((tool) => {
|
|
2264
|
+
return {
|
|
2265
|
+
name: tool.name,
|
|
2266
|
+
description: tool.description,
|
|
2267
|
+
input_schema: tool.inputSchema ?? { type: "object", properties: {} }
|
|
2268
|
+
};
|
|
2269
|
+
});
|
|
2270
|
+
}
|
|
2271
|
+
var KimiCodeLanguageModel = class {
|
|
2272
|
+
constructor(modelId, settings, config) {
|
|
2273
|
+
this.specificationVersion = "v3";
|
|
2274
|
+
this.modelId = modelId;
|
|
2275
|
+
this.settings = settings;
|
|
2276
|
+
this.config = config;
|
|
2277
|
+
this.generateIdFn = config.generateId ?? generateId2;
|
|
2278
|
+
}
|
|
2279
|
+
get provider() {
|
|
2280
|
+
return this.config.provider;
|
|
2281
|
+
}
|
|
2282
|
+
get providerOptionsName() {
|
|
2283
|
+
return "kimiCode";
|
|
2284
|
+
}
|
|
2285
|
+
/**
|
|
2286
|
+
* Get the inferred or configured capabilities for this model.
|
|
2287
|
+
*/
|
|
2288
|
+
get capabilities() {
|
|
2289
|
+
const inferred = inferKimiCodeCapabilities(this.modelId);
|
|
2290
|
+
return {
|
|
2291
|
+
...inferred,
|
|
2292
|
+
...this.settings.capabilities
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
get supportedUrls() {
|
|
2296
|
+
const patterns = {
|
|
2297
|
+
"image/*": [/^https?:\/\/.*$/i]
|
|
2298
|
+
};
|
|
2299
|
+
return this.settings.supportedUrls ?? this.config.supportedUrls ?? patterns;
|
|
2300
|
+
}
|
|
2301
|
+
/**
|
|
2302
|
+
* Build request arguments.
|
|
2303
|
+
*/
|
|
2304
|
+
async getArgs(options) {
|
|
2305
|
+
const { prompt, maxOutputTokens, temperature, topP, topK, stopSequences, tools, toolChoice, providerOptions } = options;
|
|
2306
|
+
const warnings = [];
|
|
2307
|
+
const kimiCodeOptions = await parseProviderOptions2({
|
|
2308
|
+
provider: this.providerOptionsName,
|
|
2309
|
+
providerOptions,
|
|
2310
|
+
schema: kimiCodeProviderOptionsSchema
|
|
2311
|
+
});
|
|
2312
|
+
const extendedThinking = normalizeExtendedThinkingConfig(kimiCodeOptions?.extendedThinking) ?? normalizeExtendedThinkingConfig(this.settings.extendedThinking);
|
|
2313
|
+
if (topK != null) {
|
|
2314
|
+
warnings.push({
|
|
2315
|
+
type: "unsupported",
|
|
2316
|
+
feature: "topK"
|
|
2317
|
+
});
|
|
2318
|
+
}
|
|
2319
|
+
const { system, messages } = await convertToKimiCodePrompt(prompt);
|
|
2320
|
+
let toolChoiceParam;
|
|
2321
|
+
if (toolChoice != null) {
|
|
2322
|
+
switch (toolChoice.type) {
|
|
2323
|
+
case "auto":
|
|
2324
|
+
toolChoiceParam = { type: "auto" };
|
|
2325
|
+
break;
|
|
2326
|
+
case "none":
|
|
2327
|
+
toolChoiceParam = { type: "none" };
|
|
2328
|
+
break;
|
|
2329
|
+
case "required":
|
|
2330
|
+
toolChoiceParam = { type: "any" };
|
|
2331
|
+
break;
|
|
2332
|
+
case "tool":
|
|
2333
|
+
toolChoiceParam = { type: "tool", name: toolChoice.toolName };
|
|
2334
|
+
break;
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
const functionTools = tools?.filter((t) => t.type === "function");
|
|
2338
|
+
const body = removeUndefinedEntries2({
|
|
2339
|
+
model: this.modelId,
|
|
2340
|
+
system: kimiCodeOptions?.system ?? system,
|
|
2341
|
+
messages,
|
|
2342
|
+
max_tokens: maxOutputTokens ?? this.capabilities.maxOutputTokens ?? 32768,
|
|
2343
|
+
temperature,
|
|
2344
|
+
top_p: topP,
|
|
2345
|
+
stop_sequences: kimiCodeOptions?.stopSequences ?? stopSequences,
|
|
2346
|
+
tools: convertTools(functionTools),
|
|
2347
|
+
tool_choice: toolChoiceParam,
|
|
2348
|
+
// Extended thinking parameters
|
|
2349
|
+
...extendedThinking?.enabled && {
|
|
2350
|
+
thinking: {
|
|
2351
|
+
type: "enabled",
|
|
2352
|
+
budget_tokens: extendedThinking.budgetTokens ?? effortToBudgetTokens(extendedThinking.effort ?? "medium")
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
});
|
|
2356
|
+
const requestHeaders = {
|
|
2357
|
+
...options.headers ?? {}
|
|
2358
|
+
};
|
|
2359
|
+
return {
|
|
2360
|
+
body,
|
|
2361
|
+
warnings,
|
|
2362
|
+
requestHeaders
|
|
2363
|
+
};
|
|
2364
|
+
}
|
|
2365
|
+
async doGenerate(options) {
|
|
2366
|
+
const { body, warnings, requestHeaders } = await this.getArgs(options);
|
|
2367
|
+
const {
|
|
2368
|
+
responseHeaders,
|
|
2369
|
+
value: rawResponse,
|
|
2370
|
+
rawValue
|
|
2371
|
+
} = await postJsonToApi2({
|
|
2372
|
+
url: `${this.config.baseURL}/messages`,
|
|
2373
|
+
headers: combineHeaders2(this.config.headers(), requestHeaders, options.headers),
|
|
2374
|
+
body,
|
|
2375
|
+
failedResponseHandler: kimiCodeFailedResponseHandler,
|
|
2376
|
+
successfulResponseHandler: createJsonResponseHandler2(kimiCodeResponseSchema),
|
|
2377
|
+
abortSignal: options.abortSignal,
|
|
2378
|
+
fetch: this.config.fetch
|
|
2379
|
+
});
|
|
2380
|
+
const response = rawResponse;
|
|
2381
|
+
const content = [];
|
|
2382
|
+
for (const block of response.content) {
|
|
2383
|
+
switch (block.type) {
|
|
2384
|
+
case "text":
|
|
2385
|
+
content.push({ type: "text", text: block.text });
|
|
2386
|
+
break;
|
|
2387
|
+
case "thinking":
|
|
2388
|
+
content.push({
|
|
2389
|
+
type: "reasoning",
|
|
2390
|
+
text: block.thinking
|
|
2391
|
+
});
|
|
2392
|
+
break;
|
|
2393
|
+
case "tool_use":
|
|
2394
|
+
content.push({
|
|
2395
|
+
type: "tool-call",
|
|
2396
|
+
toolCallId: block.id,
|
|
2397
|
+
toolName: block.name,
|
|
2398
|
+
input: JSON.stringify(block.input)
|
|
2399
|
+
});
|
|
2400
|
+
break;
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
const providerMetadata = {
|
|
2404
|
+
[this.providerOptionsName]: {
|
|
2405
|
+
requestId: responseHeaders?.["x-request-id"] ?? void 0,
|
|
2406
|
+
modelId: response.model,
|
|
2407
|
+
stopReason: response.stop_reason,
|
|
2408
|
+
stopSequence: response.stop_sequence
|
|
2409
|
+
}
|
|
2410
|
+
};
|
|
2411
|
+
return {
|
|
2412
|
+
content,
|
|
2413
|
+
finishReason: mapStopReason(response.stop_reason),
|
|
2414
|
+
usage: convertUsage(response.usage),
|
|
2415
|
+
providerMetadata,
|
|
2416
|
+
request: { body },
|
|
2417
|
+
response: {
|
|
2418
|
+
id: response.id,
|
|
2419
|
+
modelId: response.model,
|
|
2420
|
+
headers: responseHeaders,
|
|
2421
|
+
body: rawValue
|
|
2422
|
+
},
|
|
2423
|
+
warnings
|
|
2424
|
+
};
|
|
2425
|
+
}
|
|
2426
|
+
async doStream(options) {
|
|
2427
|
+
const { body, warnings, requestHeaders } = await this.getArgs(options);
|
|
2428
|
+
const streamBody = {
|
|
2429
|
+
...body,
|
|
2430
|
+
stream: true
|
|
2431
|
+
};
|
|
2432
|
+
const { responseHeaders, value: response } = await postJsonToApi2({
|
|
2433
|
+
url: `${this.config.baseURL}/messages`,
|
|
2434
|
+
headers: combineHeaders2(this.config.headers(), requestHeaders, options.headers),
|
|
2435
|
+
body: streamBody,
|
|
2436
|
+
failedResponseHandler: kimiCodeFailedResponseHandler,
|
|
2437
|
+
successfulResponseHandler: createEventSourceResponseHandler2(kimiCodeStreamChunkSchema),
|
|
2438
|
+
abortSignal: options.abortSignal,
|
|
2439
|
+
fetch: this.config.fetch
|
|
2440
|
+
});
|
|
2441
|
+
const providerOptionsName = this.providerOptionsName;
|
|
2442
|
+
const generateIdFn = this.generateIdFn;
|
|
2443
|
+
const capturedResponseHeaders = responseHeaders;
|
|
2444
|
+
let currentBlockType;
|
|
2445
|
+
let currentToolCallId;
|
|
2446
|
+
let currentToolName;
|
|
2447
|
+
let accumulatedToolInput = "";
|
|
2448
|
+
let finishReason = { unified: "other", raw: void 0 };
|
|
2449
|
+
let usage;
|
|
2450
|
+
let responseId;
|
|
2451
|
+
let responseModel;
|
|
2452
|
+
let isActiveText = false;
|
|
2453
|
+
let isActiveReasoning = false;
|
|
2454
|
+
let hasToolCallFinished = false;
|
|
2455
|
+
return {
|
|
2456
|
+
stream: response.pipeThrough(
|
|
2457
|
+
new TransformStream({
|
|
2458
|
+
start(controller) {
|
|
2459
|
+
controller.enqueue({ type: "stream-start", warnings });
|
|
2460
|
+
},
|
|
2461
|
+
transform(chunk, controller) {
|
|
2462
|
+
if (!chunk.success) {
|
|
2463
|
+
controller.enqueue({ type: "error", error: chunk.error });
|
|
2464
|
+
return;
|
|
2465
|
+
}
|
|
2466
|
+
const data = chunk.value;
|
|
2467
|
+
switch (data.type) {
|
|
2468
|
+
case "message_start":
|
|
2469
|
+
if (data.message) {
|
|
2470
|
+
responseId = data.message.id;
|
|
2471
|
+
responseModel = data.message.model;
|
|
2472
|
+
if (data.message.usage) {
|
|
2473
|
+
usage = convertUsage(data.message.usage);
|
|
2474
|
+
}
|
|
2475
|
+
controller.enqueue({
|
|
2476
|
+
type: "response-metadata",
|
|
2477
|
+
id: responseId,
|
|
2478
|
+
modelId: responseModel
|
|
2479
|
+
});
|
|
2480
|
+
}
|
|
2481
|
+
break;
|
|
2482
|
+
case "content_block_start":
|
|
2483
|
+
if (data.content_block) {
|
|
2484
|
+
currentBlockType = data.content_block.type;
|
|
2485
|
+
if (data.content_block.type === "tool_use") {
|
|
2486
|
+
currentToolCallId = data.content_block.id ?? generateIdFn();
|
|
2487
|
+
currentToolName = data.content_block.name;
|
|
2488
|
+
accumulatedToolInput = "";
|
|
2489
|
+
hasToolCallFinished = false;
|
|
2490
|
+
if (isActiveText) {
|
|
2491
|
+
controller.enqueue({ type: "text-end", id: "text-0" });
|
|
2492
|
+
isActiveText = false;
|
|
2493
|
+
}
|
|
2494
|
+
if (isActiveReasoning) {
|
|
2495
|
+
controller.enqueue({ type: "reasoning-end", id: "reasoning-0" });
|
|
2496
|
+
isActiveReasoning = false;
|
|
2497
|
+
}
|
|
2498
|
+
controller.enqueue({
|
|
2499
|
+
type: "tool-input-start",
|
|
2500
|
+
id: currentToolCallId,
|
|
2501
|
+
toolName: currentToolName ?? ""
|
|
2502
|
+
});
|
|
2503
|
+
} else if (data.content_block.type === "text") {
|
|
2504
|
+
if (!isActiveText) {
|
|
2505
|
+
if (isActiveReasoning) {
|
|
2506
|
+
controller.enqueue({ type: "reasoning-end", id: "reasoning-0" });
|
|
2507
|
+
isActiveReasoning = false;
|
|
2508
|
+
}
|
|
2509
|
+
controller.enqueue({ type: "text-start", id: "text-0" });
|
|
2510
|
+
isActiveText = true;
|
|
2511
|
+
}
|
|
2512
|
+
} else if (data.content_block.type === "thinking") {
|
|
2513
|
+
if (!isActiveReasoning) {
|
|
2514
|
+
if (isActiveText) {
|
|
2515
|
+
controller.enqueue({ type: "text-end", id: "text-0" });
|
|
2516
|
+
isActiveText = false;
|
|
2517
|
+
}
|
|
2518
|
+
controller.enqueue({ type: "reasoning-start", id: "reasoning-0" });
|
|
2519
|
+
isActiveReasoning = true;
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
break;
|
|
2524
|
+
case "content_block_delta":
|
|
2525
|
+
if (data.delta) {
|
|
2526
|
+
if (data.delta.type === "text_delta" && data.delta.text) {
|
|
2527
|
+
if (!isActiveText) {
|
|
2528
|
+
if (isActiveReasoning) {
|
|
2529
|
+
controller.enqueue({ type: "reasoning-end", id: "reasoning-0" });
|
|
2530
|
+
isActiveReasoning = false;
|
|
2531
|
+
}
|
|
2532
|
+
controller.enqueue({ type: "text-start", id: "text-0" });
|
|
2533
|
+
isActiveText = true;
|
|
2534
|
+
}
|
|
2535
|
+
controller.enqueue({
|
|
2536
|
+
type: "text-delta",
|
|
2537
|
+
id: "text-0",
|
|
2538
|
+
delta: data.delta.text
|
|
2539
|
+
});
|
|
2540
|
+
} else if (data.delta.type === "thinking_delta" && data.delta.thinking) {
|
|
2541
|
+
if (!isActiveReasoning) {
|
|
2542
|
+
if (isActiveText) {
|
|
2543
|
+
controller.enqueue({ type: "text-end", id: "text-0" });
|
|
2544
|
+
isActiveText = false;
|
|
2545
|
+
}
|
|
2546
|
+
controller.enqueue({ type: "reasoning-start", id: "reasoning-0" });
|
|
2547
|
+
isActiveReasoning = true;
|
|
2548
|
+
}
|
|
2549
|
+
controller.enqueue({
|
|
2550
|
+
type: "reasoning-delta",
|
|
2551
|
+
id: "reasoning-0",
|
|
2552
|
+
delta: data.delta.thinking
|
|
2553
|
+
});
|
|
2554
|
+
} else if (data.delta.type === "input_json_delta" && data.delta.partial_json) {
|
|
2555
|
+
accumulatedToolInput += data.delta.partial_json;
|
|
2556
|
+
controller.enqueue({
|
|
2557
|
+
type: "tool-input-delta",
|
|
2558
|
+
id: currentToolCallId ?? "",
|
|
2559
|
+
delta: data.delta.partial_json
|
|
2560
|
+
});
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
break;
|
|
2564
|
+
case "content_block_stop":
|
|
2565
|
+
if (currentBlockType === "tool_use" && currentToolCallId && !hasToolCallFinished) {
|
|
2566
|
+
controller.enqueue({ type: "tool-input-end", id: currentToolCallId });
|
|
2567
|
+
controller.enqueue({
|
|
2568
|
+
type: "tool-call",
|
|
2569
|
+
toolCallId: currentToolCallId,
|
|
2570
|
+
toolName: currentToolName ?? "",
|
|
2571
|
+
input: accumulatedToolInput
|
|
2572
|
+
});
|
|
2573
|
+
hasToolCallFinished = true;
|
|
2574
|
+
} else if (currentBlockType === "text" && isActiveText) {
|
|
2575
|
+
controller.enqueue({ type: "text-end", id: "text-0" });
|
|
2576
|
+
isActiveText = false;
|
|
2577
|
+
} else if (currentBlockType === "thinking" && isActiveReasoning) {
|
|
2578
|
+
controller.enqueue({ type: "reasoning-end", id: "reasoning-0" });
|
|
2579
|
+
isActiveReasoning = false;
|
|
2580
|
+
}
|
|
2581
|
+
currentBlockType = void 0;
|
|
2582
|
+
currentToolCallId = void 0;
|
|
2583
|
+
currentToolName = void 0;
|
|
2584
|
+
accumulatedToolInput = "";
|
|
2585
|
+
break;
|
|
2586
|
+
case "message_delta":
|
|
2587
|
+
if (data.delta?.stop_reason) {
|
|
2588
|
+
finishReason = mapStopReason(data.delta.stop_reason);
|
|
2589
|
+
}
|
|
2590
|
+
if (data.usage) {
|
|
2591
|
+
usage = convertUsage(data.usage);
|
|
2592
|
+
}
|
|
2593
|
+
break;
|
|
2594
|
+
case "message_stop":
|
|
2595
|
+
if (isActiveText) {
|
|
2596
|
+
controller.enqueue({ type: "text-end", id: "text-0" });
|
|
2597
|
+
}
|
|
2598
|
+
if (isActiveReasoning) {
|
|
2599
|
+
controller.enqueue({ type: "reasoning-end", id: "reasoning-0" });
|
|
2600
|
+
}
|
|
2601
|
+
controller.enqueue({
|
|
2602
|
+
type: "finish",
|
|
2603
|
+
finishReason,
|
|
2604
|
+
usage: usage ?? convertUsage({}),
|
|
2605
|
+
providerMetadata: {
|
|
2606
|
+
[providerOptionsName]: {
|
|
2607
|
+
requestId: capturedResponseHeaders?.["x-request-id"] ?? void 0,
|
|
2608
|
+
modelId: responseModel
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
});
|
|
2612
|
+
break;
|
|
2613
|
+
case "error":
|
|
2614
|
+
controller.enqueue({
|
|
2615
|
+
type: "error",
|
|
2616
|
+
error: new Error(
|
|
2617
|
+
data.error?.message ?? "Unknown streaming error"
|
|
2618
|
+
)
|
|
2619
|
+
});
|
|
2620
|
+
break;
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
})
|
|
2624
|
+
),
|
|
2625
|
+
request: { body: streamBody },
|
|
2626
|
+
response: {
|
|
2627
|
+
headers: responseHeaders
|
|
2628
|
+
}
|
|
2629
|
+
};
|
|
2630
|
+
}
|
|
2631
|
+
};
|
|
2632
|
+
|
|
2633
|
+
// src/code/kimi-code-provider.ts
|
|
2634
|
+
import { NoSuchModelError as NoSuchModelError2 } from "@ai-sdk/provider";
|
|
2635
|
+
import {
|
|
2636
|
+
loadOptionalSetting as loadOptionalSetting2,
|
|
2637
|
+
withUserAgentSuffix as withUserAgentSuffix2,
|
|
2638
|
+
withoutTrailingSlash as withoutTrailingSlash2
|
|
2639
|
+
} from "@ai-sdk/provider-utils";
|
|
2640
|
+
function createKimiCode(options = {}) {
|
|
2641
|
+
const resolvedBaseURL = loadOptionalSetting2({
|
|
2642
|
+
settingValue: options.baseURL,
|
|
2643
|
+
environmentVariableName: "KIMI_CODE_BASE_URL"
|
|
2644
|
+
}) ?? KIMI_CODE_BASE_URL;
|
|
2645
|
+
const baseURL = withoutTrailingSlash2(resolvedBaseURL) ?? KIMI_CODE_BASE_URL;
|
|
2646
|
+
const getHeaders = () => {
|
|
2647
|
+
let apiKey = options.apiKey;
|
|
2648
|
+
if (!apiKey) {
|
|
2649
|
+
apiKey = process.env.KIMI_CODE_API_KEY ?? process.env.KIMI_API_KEY;
|
|
2650
|
+
}
|
|
2651
|
+
if (!apiKey) {
|
|
2652
|
+
throw new Error(
|
|
2653
|
+
"Kimi Code API key is required. Set the KIMI_CODE_API_KEY or KIMI_API_KEY environment variable, or pass the apiKey option."
|
|
2654
|
+
);
|
|
2655
|
+
}
|
|
2656
|
+
return withUserAgentSuffix2(
|
|
2657
|
+
{
|
|
2658
|
+
"x-api-key": apiKey,
|
|
2659
|
+
"anthropic-version": "2023-06-01",
|
|
2660
|
+
...options.headers
|
|
2661
|
+
},
|
|
2662
|
+
`ai-sdk/kimi-code/${VERSION}`
|
|
2663
|
+
);
|
|
2664
|
+
};
|
|
2665
|
+
const createCodeModel = (modelId = KIMI_CODE_DEFAULT_MODEL, settings = {}) => new KimiCodeLanguageModel(modelId, settings, {
|
|
2666
|
+
provider: "kimi.code",
|
|
2667
|
+
baseURL,
|
|
2668
|
+
headers: getHeaders,
|
|
2669
|
+
fetch: options.fetch,
|
|
2670
|
+
generateId: options.generateId,
|
|
2671
|
+
includeUsageInStream: settings.includeUsageInStream ?? options.includeUsageInStream,
|
|
2672
|
+
supportedUrls: settings.supportedUrls ?? options.supportedUrls
|
|
2673
|
+
});
|
|
2674
|
+
const provider = (modelId = KIMI_CODE_DEFAULT_MODEL, settings) => {
|
|
2675
|
+
if (new.target) {
|
|
2676
|
+
throw new Error("The Kimi Code provider function cannot be called with new.");
|
|
2677
|
+
}
|
|
2678
|
+
return createCodeModel(modelId, settings);
|
|
2679
|
+
};
|
|
2680
|
+
provider.specificationVersion = "v3";
|
|
2681
|
+
provider.languageModel = createCodeModel;
|
|
2682
|
+
provider.chat = createCodeModel;
|
|
2683
|
+
provider.embeddingModel = (modelId) => {
|
|
2684
|
+
throw new NoSuchModelError2({ modelId, modelType: "embeddingModel" });
|
|
2685
|
+
};
|
|
2686
|
+
provider.imageModel = (modelId) => {
|
|
2687
|
+
throw new NoSuchModelError2({ modelId, modelType: "imageModel" });
|
|
2688
|
+
};
|
|
2689
|
+
provider.rerankingModel = (modelId) => {
|
|
2690
|
+
throw new NoSuchModelError2({ modelId, modelType: "rerankingModel" });
|
|
2691
|
+
};
|
|
2692
|
+
return provider;
|
|
2693
|
+
}
|
|
2694
|
+
var kimiCode = createKimiCode();
|
|
2695
|
+
export {
|
|
2696
|
+
KIMI_CODE_BASE_URL,
|
|
2697
|
+
KIMI_CODE_DEFAULT_MODEL,
|
|
2698
|
+
KIMI_CODE_INTERPRETER_TOOL_NAME,
|
|
2699
|
+
KIMI_CODE_THINKING_MODEL,
|
|
2700
|
+
KIMI_WEB_SEARCH_TOOL_NAME,
|
|
2701
|
+
KimiAuthenticationError,
|
|
2702
|
+
KimiChatLanguageModel,
|
|
2703
|
+
KimiCodeLanguageModel,
|
|
2704
|
+
KimiContentFilterError,
|
|
2705
|
+
KimiContextLengthError,
|
|
2706
|
+
KimiError,
|
|
2707
|
+
KimiFileClient,
|
|
2708
|
+
KimiModelNotFoundError,
|
|
2709
|
+
KimiRateLimitError,
|
|
2710
|
+
KimiValidationError,
|
|
2711
|
+
SUPPORTED_FILE_EXTENSIONS,
|
|
2712
|
+
SUPPORTED_MIME_TYPES,
|
|
2713
|
+
createCodeInterpreterTool,
|
|
2714
|
+
createKimi,
|
|
2715
|
+
createKimiCode,
|
|
2716
|
+
createKimiWebSearchTool,
|
|
2717
|
+
createWebSearchTool,
|
|
2718
|
+
getMediaTypeFromExtension,
|
|
2719
|
+
getPurposeFromMediaType,
|
|
2720
|
+
inferKimiCodeCapabilities,
|
|
2721
|
+
inferModelCapabilities,
|
|
2722
|
+
isDocumentMediaType,
|
|
2723
|
+
isFileExtractMediaType,
|
|
2724
|
+
isImageMediaType2 as isImageMediaType,
|
|
2725
|
+
isVideoMediaType2 as isVideoMediaType,
|
|
2726
|
+
kimi,
|
|
2727
|
+
kimiCachingConfigSchema,
|
|
2728
|
+
kimiCode,
|
|
2729
|
+
kimiCodeProviderOptionsSchema,
|
|
2730
|
+
kimiProviderOptionsSchema,
|
|
2731
|
+
kimiTools,
|
|
2732
|
+
processAttachments
|
|
2733
|
+
};
|
|
2734
|
+
//# sourceMappingURL=index.mjs.map
|