@ai-sdk/moonshotai 2.0.49 → 2.0.53

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.
@@ -31,13 +31,16 @@ import {
31
31
  moonshotAIChatChunkSchema,
32
32
  moonshotAIChatResponseSchema,
33
33
  moonshotAIErrorSchema,
34
+ type MoonshotAIChatLogprob,
34
35
  type MoonshotAIChatTokenUsage,
35
36
  } from './moonshotai-chat-api-types';
36
37
  import {
37
- getModelThinkingKeepSupport,
38
+ getMoonshotAIModelFamily,
39
+ isMoonshotAIKimiModel,
38
40
  moonshotaiLanguageModelOptions,
39
41
  type MoonshotAIChatModelId,
40
42
  } from './moonshotai-chat-options';
43
+ import { normalizeJsonSchemaForMFJS } from './normalize-json-schema-for-mfjs';
41
44
  import { prepareTools } from './moonshotai-prepare-tools';
42
45
 
43
46
  export type MoonshotAIChatConfig = {
@@ -105,8 +108,6 @@ export class MoonshotAIChatLanguageModel implements LanguageModelV3 {
105
108
  schema: moonshotaiLanguageModelOptions,
106
109
  })) ?? {};
107
110
 
108
- const messages = convertToMoonshotAIChatMessages(prompt);
109
-
110
111
  const allWarnings: SharedV3Warning[] = [];
111
112
  if (topK != null) {
112
113
  allWarnings.push({ type: 'unsupported', feature: 'topK' });
@@ -115,30 +116,150 @@ export class MoonshotAIChatLanguageModel implements LanguageModelV3 {
115
116
  allWarnings.push({ type: 'unsupported', feature: 'seed' });
116
117
  }
117
118
 
119
+ const supportsSamplingOptions = !isMoonshotAIKimiModel(this.modelId);
120
+
121
+ if (!supportsSamplingOptions && temperature != null) {
122
+ allWarnings.push({
123
+ type: 'unsupported',
124
+ feature: 'temperature',
125
+ details: `temperature is fixed by model "${this.modelId}" and has been omitted.`,
126
+ });
127
+ }
128
+ if (!supportsSamplingOptions && topP != null) {
129
+ allWarnings.push({
130
+ type: 'unsupported',
131
+ feature: 'topP',
132
+ details: `topP is fixed by model "${this.modelId}" and has been omitted.`,
133
+ });
134
+ }
135
+ if (!supportsSamplingOptions && frequencyPenalty != null) {
136
+ allWarnings.push({
137
+ type: 'unsupported',
138
+ feature: 'frequencyPenalty',
139
+ details: `frequencyPenalty is fixed by model "${this.modelId}" and has been omitted.`,
140
+ });
141
+ }
142
+ if (!supportsSamplingOptions && presencePenalty != null) {
143
+ allWarnings.push({
144
+ type: 'unsupported',
145
+ feature: 'presencePenalty',
146
+ details: `presencePenalty is fixed by model "${this.modelId}" and has been omitted.`,
147
+ });
148
+ }
149
+
118
150
  const {
119
151
  tools: moonshotTools,
120
152
  toolChoice: moonshotToolChoice,
121
153
  toolWarnings,
122
- } = prepareTools({ tools, toolChoice });
123
-
124
- // Thinking is configured through explicit provider options only.
125
- const thinking = moonshotOptions.thinking;
126
-
127
- // Moonshot has no reasoning_history field; the API silently ignores it
128
- // (verified against the live API). Preserved Thinking maps to
129
- // thinking.keep, which only accepts 'all' and only on some models
130
- // (verified: k2.6, k2.7-code, k3 accept it; k2.5 rejects it). Other
131
- // reasoningHistory values use the server default.
132
- let keep: 'all' | undefined;
133
- if (moonshotOptions.reasoningHistory === 'preserved') {
134
- if (getModelThinkingKeepSupport(this.modelId)) {
135
- keep = 'all';
136
- } else {
154
+ } = prepareTools({ tools, toolChoice, modelId: this.modelId });
155
+
156
+ const modelFamily = getMoonshotAIModelFamily(this.modelId);
157
+ const requestedThinking = moonshotOptions.thinking;
158
+ const requestedReasoningEffort = moonshotOptions.reasoningEffort;
159
+ const preserveReasoning = moonshotOptions.reasoningHistory === 'preserved';
160
+
161
+ if (requestedThinking?.budgetTokens != null) {
162
+ allWarnings.push({
163
+ type: 'other',
164
+ message:
165
+ 'providerOptions.moonshotai.thinking.budgetTokens is deprecated because Moonshot Chat Completions does not support budget_tokens. The option has been omitted.',
166
+ });
167
+ }
168
+
169
+ let thinking: { type: 'enabled' | 'disabled'; keep?: 'all' } | undefined;
170
+ let reasoningEffort: 'low' | 'high' | 'max' | undefined;
171
+
172
+ const warnUnsupportedReasoningEffort = () => {
173
+ if (requestedReasoningEffort != null) {
137
174
  allWarnings.push({
138
175
  type: 'unsupported',
139
- feature: `reasoningHistory 'preserved' is not supported by model "${this.modelId}"`,
176
+ feature: 'reasoningEffort',
177
+ details: `reasoningEffort is only supported by Kimi K3 and has been omitted for model "${this.modelId}".`,
140
178
  });
141
179
  }
180
+ };
181
+
182
+ switch (modelFamily) {
183
+ case 'kimi-k3': {
184
+ if (requestedThinking != null) {
185
+ allWarnings.push({
186
+ type: 'unsupported',
187
+ feature: 'thinking',
188
+ details:
189
+ 'Kimi K3 always reasons and does not accept the thinking field. The option has been omitted.',
190
+ });
191
+ }
192
+ reasoningEffort = requestedReasoningEffort;
193
+ break;
194
+ }
195
+ case 'kimi-k2.7': {
196
+ warnUnsupportedReasoningEffort();
197
+ if (requestedThinking?.type === 'disabled') {
198
+ allWarnings.push({
199
+ type: 'unsupported',
200
+ feature: 'thinking.type "disabled"',
201
+ details: 'Kimi K2.7 thinking cannot be disabled.',
202
+ });
203
+ } else if (requestedThinking?.type === 'enabled') {
204
+ thinking = { type: 'enabled' };
205
+ }
206
+ break;
207
+ }
208
+ case 'kimi-k2.6': {
209
+ warnUnsupportedReasoningEffort();
210
+ const thinkingType = requestedThinking?.type;
211
+ if (thinkingType != null || preserveReasoning) {
212
+ thinking = {
213
+ type: thinkingType ?? 'enabled',
214
+ ...(preserveReasoning ? { keep: 'all' as const } : {}),
215
+ };
216
+ }
217
+ break;
218
+ }
219
+ case 'kimi-k2.5': {
220
+ warnUnsupportedReasoningEffort();
221
+ const thinkingType = requestedThinking?.type;
222
+ if (thinkingType != null) {
223
+ thinking = { type: thinkingType };
224
+ }
225
+ if (preserveReasoning) {
226
+ allWarnings.push({
227
+ type: 'unsupported',
228
+ feature: `reasoningHistory 'preserved' is not supported by model "${this.modelId}"`,
229
+ });
230
+ }
231
+ break;
232
+ }
233
+ case 'moonshot-v1': {
234
+ warnUnsupportedReasoningEffort();
235
+ if (requestedThinking != null) {
236
+ allWarnings.push({
237
+ type: 'unsupported',
238
+ feature: 'thinking',
239
+ details: `thinking is not supported by model "${this.modelId}" and has been omitted.`,
240
+ });
241
+ }
242
+ if (preserveReasoning) {
243
+ allWarnings.push({
244
+ type: 'unsupported',
245
+ feature: `reasoningHistory 'preserved' is not supported by model "${this.modelId}"`,
246
+ });
247
+ }
248
+ break;
249
+ }
250
+ case 'unknown': {
251
+ reasoningEffort = requestedReasoningEffort;
252
+ if (requestedThinking?.type != null) {
253
+ thinking = { type: requestedThinking.type };
254
+ }
255
+ if (preserveReasoning) {
256
+ allWarnings.push({
257
+ type: 'unsupported',
258
+ feature: `reasoningHistory 'preserved' is not supported by model "${this.modelId}"`,
259
+ });
260
+ }
261
+ break;
262
+ }
142
263
  }
143
264
 
144
265
  let response_format: Record<string, unknown> | undefined;
@@ -158,10 +279,8 @@ export class MoonshotAIChatLanguageModel implements LanguageModelV3 {
158
279
  type: 'json_schema',
159
280
  json_schema: {
160
281
  name: responseFormat.name ?? 'response',
161
- schema: schemaWithoutDollarSchema,
162
- ...(responseFormat.description != null && {
163
- description: responseFormat.description,
164
- }),
282
+ strict: moonshotOptions.strictJsonSchema ?? true,
283
+ schema: normalizeJsonSchemaForMFJS(schemaWithoutDollarSchema),
165
284
  },
166
285
  };
167
286
  } else {
@@ -169,32 +288,41 @@ export class MoonshotAIChatLanguageModel implements LanguageModelV3 {
169
288
  }
170
289
  }
171
290
 
291
+ const { messages, warnings: messageWarnings } =
292
+ convertToMoonshotAIChatMessages({
293
+ modelId: this.modelId,
294
+ prompt,
295
+ providerOptionsName: this.providerOptionsName,
296
+ responseFormat: response_format,
297
+ });
298
+ allWarnings.push(...messageWarnings);
299
+
172
300
  return {
173
301
  args: {
174
302
  model: this.modelId,
175
- max_tokens: maxOutputTokens,
176
- temperature,
177
- top_p: topP,
178
- frequency_penalty: frequencyPenalty,
179
- presence_penalty: presencePenalty,
303
+ ...((moonshotOptions.logprobs === true ||
304
+ moonshotOptions.topLogprobs != null) && { logprobs: true }),
305
+ ...(moonshotOptions.topLogprobs != null && {
306
+ top_logprobs: moonshotOptions.topLogprobs,
307
+ }),
308
+ max_completion_tokens: maxOutputTokens,
309
+ temperature: supportsSamplingOptions ? temperature : undefined,
310
+ top_p: supportsSamplingOptions ? topP : undefined,
311
+ frequency_penalty: supportsSamplingOptions
312
+ ? frequencyPenalty
313
+ : undefined,
314
+ presence_penalty: supportsSamplingOptions ? presencePenalty : undefined,
180
315
  response_format,
181
316
  stop: stopSequences,
182
317
  messages,
183
318
  tools: moonshotTools,
184
319
  tool_choice: moonshotToolChoice,
185
- ...(thinking != null || keep != null
186
- ? {
187
- thinking: {
188
- ...(thinking?.type != null && { type: thinking.type }),
189
- ...(thinking?.budgetTokens !== undefined && {
190
- budget_tokens: thinking.budgetTokens,
191
- }),
192
- ...(keep != null && { keep }),
193
- },
194
- }
195
- : {}),
196
- ...(moonshotOptions.reasoningEffort != null && {
197
- reasoning_effort: moonshotOptions.reasoningEffort,
320
+ ...(moonshotOptions.prediction != null && {
321
+ prediction: moonshotOptions.prediction,
322
+ }),
323
+ ...(thinking != null ? { thinking } : {}),
324
+ ...(reasoningEffort != null && {
325
+ reasoning_effort: reasoningEffort,
198
326
  }),
199
327
  ...(moonshotOptions.promptCacheKey != null && {
200
328
  prompt_cache_key: moonshotOptions.promptCacheKey,
@@ -265,6 +393,23 @@ export class MoonshotAIChatLanguageModel implements LanguageModelV3 {
265
393
  raw: choice.finish_reason ?? undefined,
266
394
  },
267
395
  usage: convertMoonshotAIChatUsage(responseBody.usage),
396
+ providerMetadata: {
397
+ [this.providerOptionsName]: {
398
+ ...(responseBody.object != null && {
399
+ responseObject: responseBody.object,
400
+ }),
401
+ ...(choice.index != null && { choiceIndex: choice.index }),
402
+ ...(choice.message.role != null && {
403
+ messageRole: choice.message.role,
404
+ }),
405
+ ...(choice.message.tool_calls != null && {
406
+ toolCallTypes: choice.message.tool_calls
407
+ .map(toolCall => toolCall.type)
408
+ .filter(type => type != null),
409
+ }),
410
+ ...(choice.logprobs != null && { logprobs: choice.logprobs }),
411
+ },
412
+ },
268
413
  request: { body: args },
269
414
  response: {
270
415
  ...getResponseMetadata(responseBody),
@@ -314,10 +459,17 @@ export class MoonshotAIChatLanguageModel implements LanguageModelV3 {
314
459
  unified: 'other',
315
460
  raw: undefined,
316
461
  };
317
- let usage: MoonshotAIChatTokenUsage | undefined = undefined;
462
+ let topLevelUsage: MoonshotAIChatTokenUsage | undefined = undefined;
463
+ let choiceUsage: MoonshotAIChatTokenUsage | undefined = undefined;
464
+ const contentLogprobs: MoonshotAIChatLogprob[] = [];
465
+ const providerOptionsName = this.providerOptionsName;
318
466
  let isFirstChunk = true;
319
467
  let isActiveReasoning = false;
320
468
  let isActiveText = false;
469
+ let responseObject: 'chat.completion.chunk' | undefined;
470
+ let choiceIndex: number | undefined;
471
+ let messageRole: 'assistant' | undefined;
472
+ const toolCallTypes = new Map<number, 'function'>();
321
473
 
322
474
  return {
323
475
  stream: response.pipeThrough(
@@ -346,7 +498,7 @@ export class MoonshotAIChatLanguageModel implements LanguageModelV3 {
346
498
  // handle error chunks:
347
499
  if ('error' in value) {
348
500
  finishReason = { unified: 'error', raw: undefined };
349
- controller.enqueue({ type: 'error', error: value.error.message });
501
+ controller.enqueue({ type: 'error', error: value.error });
350
502
  return;
351
503
  }
352
504
 
@@ -360,11 +512,23 @@ export class MoonshotAIChatLanguageModel implements LanguageModelV3 {
360
512
  }
361
513
 
362
514
  if (value.usage != null) {
363
- usage = value.usage;
515
+ topLevelUsage = value.usage;
516
+ }
517
+
518
+ if (value.object != null) {
519
+ responseObject = value.object;
364
520
  }
365
521
 
366
522
  const choice = value.choices[0];
367
523
 
524
+ if (choice?.usage != null) {
525
+ choiceUsage = choice.usage;
526
+ }
527
+
528
+ if (choice?.index != null) {
529
+ choiceIndex = choice.index;
530
+ }
531
+
368
532
  if (choice?.finish_reason != null) {
369
533
  finishReason = {
370
534
  unified: mapMoonshotAIFinishReason(choice.finish_reason),
@@ -372,12 +536,20 @@ export class MoonshotAIChatLanguageModel implements LanguageModelV3 {
372
536
  };
373
537
  }
374
538
 
539
+ if (choice?.logprobs?.content != null) {
540
+ contentLogprobs.push(...choice.logprobs.content);
541
+ }
542
+
375
543
  if (choice?.delta == null) {
376
544
  return;
377
545
  }
378
546
 
379
547
  const delta = choice.delta;
380
548
 
549
+ if (delta.role != null) {
550
+ messageRole = delta.role;
551
+ }
552
+
381
553
  // enqueue reasoning before text deltas:
382
554
  const reasoningContent = delta.reasoning_content;
383
555
  if (reasoningContent) {
@@ -428,8 +600,15 @@ export class MoonshotAIChatLanguageModel implements LanguageModelV3 {
428
600
  isActiveReasoning = false;
429
601
  }
430
602
 
431
- for (const toolCallDelta of delta.tool_calls) {
432
- const index = toolCallDelta.index;
603
+ for (const [
604
+ fallbackIndex,
605
+ toolCallDelta,
606
+ ] of delta.tool_calls.entries()) {
607
+ const index = toolCallDelta.index ?? fallbackIndex;
608
+
609
+ if (toolCallDelta.type != null) {
610
+ toolCallTypes.set(index, toolCallDelta.type);
611
+ }
433
612
 
434
613
  if (toolCalls[index] == null) {
435
614
  if (toolCallDelta.id == null) {
@@ -531,7 +710,24 @@ export class MoonshotAIChatLanguageModel implements LanguageModelV3 {
531
710
  controller.enqueue({
532
711
  type: 'finish',
533
712
  finishReason,
534
- usage: convertMoonshotAIChatUsage(usage),
713
+ usage: convertMoonshotAIChatUsage(topLevelUsage ?? choiceUsage),
714
+ providerMetadata: {
715
+ [providerOptionsName]: {
716
+ ...(responseObject != null && { responseObject }),
717
+ ...(choiceIndex != null && { choiceIndex }),
718
+ ...(messageRole != null && { messageRole }),
719
+ ...(toolCallTypes.size > 0 && {
720
+ toolCallTypes: [...toolCallTypes.entries()]
721
+ .sort(([left], [right]) => left - right)
722
+ .map(([, type]) => type),
723
+ }),
724
+ ...(contentLogprobs.length > 0 && {
725
+ logprobs: {
726
+ content: contentLogprobs,
727
+ },
728
+ }),
729
+ },
730
+ },
535
731
  });
536
732
  },
537
733
  }),
@@ -1,31 +1,109 @@
1
+ import type { LanguageModelV3FunctionTool } from '@ai-sdk/provider';
1
2
  import { z } from 'zod/v4';
2
3
 
3
4
  export type MoonshotAIChatModelId =
5
+ | 'moonshot-v1-auto'
4
6
  | 'moonshot-v1-8k'
5
7
  | 'moonshot-v1-32k'
6
8
  | 'moonshot-v1-128k'
7
- | 'kimi-k2'
8
- | 'kimi-k2-0905'
9
- | 'kimi-k2-thinking'
10
- | 'kimi-k2-thinking-turbo'
11
- | 'kimi-k2-turbo'
9
+ | 'moonshot-v1-8k-vision-preview'
10
+ | 'moonshot-v1-32k-vision-preview'
11
+ | 'moonshot-v1-128k-vision-preview'
12
12
  | 'kimi-k2.5'
13
+ | 'kimi-k2.6'
14
+ | 'kimi-k2.7-code'
15
+ | 'kimi-k2.7-code-highspeed'
13
16
  | 'kimi-k3'
14
17
  | (string & {});
15
18
 
19
+ export function isMoonshotAIKimiModel(modelId: MoonshotAIChatModelId): boolean {
20
+ return getMoonshotAIModelFamily(modelId).startsWith('kimi-');
21
+ }
22
+
23
+ export type MoonshotAIModelFamily =
24
+ | 'kimi-k2.5'
25
+ | 'kimi-k2.6'
26
+ | 'kimi-k2.7'
27
+ | 'kimi-k3'
28
+ | 'moonshot-v1'
29
+ | 'unknown';
30
+
31
+ export function getMoonshotAIModelFamily(
32
+ modelId: MoonshotAIChatModelId,
33
+ ): MoonshotAIModelFamily {
34
+ if (modelId === 'kimi-k2.5') return 'kimi-k2.5';
35
+ if (modelId === 'kimi-k2.6') return 'kimi-k2.6';
36
+ if (modelId === 'kimi-k2.7-code' || modelId === 'kimi-k2.7-code-highspeed') {
37
+ return 'kimi-k2.7';
38
+ }
39
+ if (modelId === 'kimi-k3') return 'kimi-k3';
40
+ if (modelId.startsWith('moonshot-v1-')) return 'moonshot-v1';
41
+ return 'unknown';
42
+ }
43
+
16
44
  export const moonshotaiLanguageModelOptions = z.object({
17
45
  /**
18
- * Reasoning effort for Kimi K3.
46
+ * Whether to use strict JSON schema validation for structured outputs.
47
+ *
48
+ * @default true
49
+ */
50
+ strictJsonSchema: z.boolean().optional(),
51
+
52
+ /**
53
+ * Whether to return log probabilities for generated tokens.
54
+ */
55
+ logprobs: z.boolean().optional(),
56
+
57
+ /**
58
+ * Number of most likely tokens to return at each token position.
59
+ *
60
+ * Setting this option automatically enables `logprobs`.
61
+ */
62
+ topLogprobs: z.number().int().min(0).max(20).optional(),
63
+
64
+ /**
65
+ * Reasoning effort for Kimi K3. Supports `low`, `high`, and `max`;
66
+ * defaults to `max`.
19
67
  */
20
68
  reasoningEffort: z.enum(['low', 'high', 'max']).optional(),
21
69
 
70
+ /**
71
+ * Static predicted content that can accelerate responses when much of the
72
+ * output is known ahead of time.
73
+ */
74
+ prediction: z
75
+ .object({
76
+ type: z.literal('content'),
77
+ content: z.union([
78
+ z.string(),
79
+ z.array(z.object({ type: z.literal('text'), text: z.string() })),
80
+ ]),
81
+ })
82
+ .optional(),
83
+
84
+ /**
85
+ * Thinking configuration for Kimi K2.x models. Kimi K2.5 and K2.6 support
86
+ * enabling or disabling thinking. Kimi K2.7 Code always has thinking
87
+ * enabled.
88
+ */
22
89
  thinking: z
23
90
  .object({
24
91
  type: z.enum(['enabled', 'disabled']).optional(),
92
+ /**
93
+ * @deprecated Moonshot Chat Completions does not support thinking
94
+ * budgets. Accepted for backwards compatibility, then omitted with a
95
+ * warning.
96
+ */
25
97
  budgetTokens: z.number().int().min(1024).optional(),
26
98
  })
27
99
  .optional(),
28
100
 
101
+ /**
102
+ * Controls preserved reasoning behavior in multi-turn conversations.
103
+ * `disabled` and `interleaved` are compatibility values that leave the
104
+ * request unchanged. `preserved` maps to `thinking.keep: 'all'` for Kimi
105
+ * K2.6. Kimi K2.7 and K3 preserve reasoning by default.
106
+ */
29
107
  reasoningHistory: z.enum(['disabled', 'interleaved', 'preserved']).optional(),
30
108
 
31
109
  /**
@@ -41,21 +119,105 @@ export const moonshotaiLanguageModelOptions = z.object({
41
119
  safetyIdentifier: z.string().optional(),
42
120
  });
43
121
 
44
- export type MoonshotAILanguageModelOptions = z.infer<
45
- typeof moonshotaiLanguageModelOptions
122
+ export type MoonshotAILanguageModelOptions = {
123
+ /**
124
+ * Whether to use strict JSON schema validation for structured outputs.
125
+ *
126
+ * @default true
127
+ */
128
+ strictJsonSchema?: boolean;
129
+
130
+ /** Whether to return log probabilities for generated tokens. */
131
+ logprobs?: boolean;
132
+
133
+ /**
134
+ * Number of most likely tokens to return at each token position.
135
+ * Setting this option automatically enables `logprobs`.
136
+ */
137
+ topLogprobs?: number;
138
+
139
+ /** Reasoning effort for Kimi K3. */
140
+ reasoningEffort?: 'low' | 'high' | 'max';
141
+
142
+ /**
143
+ * Static predicted content that can accelerate responses when much of the
144
+ * output is known ahead of time.
145
+ */
146
+ prediction?: {
147
+ type: 'content';
148
+ content: string | Array<{ type: 'text'; text: string }>;
149
+ };
150
+
151
+ /** Controls thinking on Kimi K2.5 and K2.6. K2.7 is always enabled. */
152
+ thinking?: {
153
+ type?: 'enabled' | 'disabled';
154
+
155
+ /**
156
+ * @deprecated Moonshot Chat Completions does not support thinking budgets.
157
+ * This value is ignored with a warning.
158
+ */
159
+ budgetTokens?: number;
160
+ };
161
+
162
+ /**
163
+ * Controls preserved reasoning behavior in multi-turn conversations.
164
+ * `disabled` and `interleaved` are compatibility values that leave the
165
+ * request unchanged. `preserved` maps to `thinking.keep: 'all'` for Kimi
166
+ * K2.6. Kimi K2.7 and K3 preserve reasoning by default.
167
+ */
168
+ reasoningHistory?: 'disabled' | 'interleaved' | 'preserved';
169
+ promptCacheKey?: string;
170
+ safetyIdentifier?: string;
171
+ };
172
+
173
+ export const moonshotaiMessageProviderOptions = z.object({
174
+ /**
175
+ * The name of the participant represented by the message.
176
+ *
177
+ * Supported on system, user, and assistant messages.
178
+ */
179
+ name: z.string().optional(),
180
+ });
181
+
182
+ export type MoonshotAIMessageProviderOptions = z.infer<
183
+ typeof moonshotaiMessageProviderOptions
46
184
  >;
47
185
 
48
- /**
49
- * Whether the model accepts `thinking.keep` (Preserved Thinking). Verified
50
- * against the live API: kimi-k2.6, kimi-k2.7-code(+highspeed), and kimi-k3
51
- * accept `keep: 'all'`; other models reject it with a 400.
52
- */
53
- export function getModelThinkingKeepSupport(
54
- modelId: MoonshotAIChatModelId,
55
- ): boolean {
56
- return (
57
- modelId === 'kimi-k2.6' ||
58
- modelId === 'kimi-k3' ||
59
- modelId.startsWith('kimi-k2.7-code')
60
- );
61
- }
186
+ export const moonshotaiAssistantMessageProviderOptions =
187
+ moonshotaiMessageProviderOptions.extend({
188
+ /**
189
+ * Whether the assistant message content is a partial response that Moonshot
190
+ * should continue. Only supported on the final assistant message and cannot
191
+ * be combined with JSON object response format.
192
+ */
193
+ partial: z.literal(true).optional(),
194
+ });
195
+
196
+ export type MoonshotAIAssistantMessageProviderOptions = z.infer<
197
+ typeof moonshotaiAssistantMessageProviderOptions
198
+ >;
199
+
200
+ const moonshotaiDynamicToolSchema = z.object({
201
+ type: z.literal('function'),
202
+ name: z.string(),
203
+ description: z.string().optional(),
204
+ inputSchema: z.record(z.string(), z.unknown()),
205
+ strict: z.boolean().optional(),
206
+ });
207
+
208
+ export const moonshotaiAllMessageProviderOptions =
209
+ moonshotaiAssistantMessageProviderOptions.extend({
210
+ /** Function tools to load at this point in a Kimi K3 conversation. */
211
+ tools: z.array(moonshotaiDynamicToolSchema).optional(),
212
+ });
213
+
214
+ export type MoonshotAISystemMessageProviderOptions =
215
+ MoonshotAIMessageProviderOptions & {
216
+ /** Function tools to load at this point in a Kimi K3 conversation. */
217
+ tools?: Array<
218
+ Pick<
219
+ LanguageModelV3FunctionTool,
220
+ 'type' | 'name' | 'description' | 'inputSchema' | 'strict'
221
+ >
222
+ >;
223
+ };