@aituber-onair/chat 0.47.0 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.ja.md +25 -12
  2. package/README.md +27 -12
  3. package/dist/cjs/constants/gemini.d.ts +17 -0
  4. package/dist/cjs/constants/gemini.d.ts.map +1 -1
  5. package/dist/cjs/constants/gemini.js +67 -1
  6. package/dist/cjs/constants/gemini.js.map +1 -1
  7. package/dist/cjs/constants/kimi.d.ts +10 -0
  8. package/dist/cjs/constants/kimi.d.ts.map +1 -1
  9. package/dist/cjs/constants/kimi.js +20 -1
  10. package/dist/cjs/constants/kimi.js.map +1 -1
  11. package/dist/cjs/services/ChatService.d.ts +2 -2
  12. package/dist/cjs/services/ChatService.d.ts.map +1 -1
  13. package/dist/cjs/services/ChatServiceFactory.d.ts.map +1 -1
  14. package/dist/cjs/services/ChatServiceFactory.js +1 -0
  15. package/dist/cjs/services/ChatServiceFactory.js.map +1 -1
  16. package/dist/cjs/services/providers/ChatServiceProvider.d.ts +9 -2
  17. package/dist/cjs/services/providers/ChatServiceProvider.d.ts.map +1 -1
  18. package/dist/cjs/services/providers/gemini/GeminiChatService.d.ts +8 -2
  19. package/dist/cjs/services/providers/gemini/GeminiChatService.d.ts.map +1 -1
  20. package/dist/cjs/services/providers/gemini/GeminiChatService.js +65 -38
  21. package/dist/cjs/services/providers/gemini/GeminiChatService.js.map +1 -1
  22. package/dist/cjs/services/providers/gemini/GeminiChatServiceProvider.d.ts.map +1 -1
  23. package/dist/cjs/services/providers/gemini/GeminiChatServiceProvider.js +9 -2
  24. package/dist/cjs/services/providers/gemini/GeminiChatServiceProvider.js.map +1 -1
  25. package/dist/cjs/services/providers/gemini/geminiMessageConverter.d.ts +6 -0
  26. package/dist/cjs/services/providers/gemini/geminiMessageConverter.d.ts.map +1 -1
  27. package/dist/cjs/services/providers/gemini/geminiMessageConverter.js +61 -58
  28. package/dist/cjs/services/providers/gemini/geminiMessageConverter.js.map +1 -1
  29. package/dist/cjs/services/providers/kimi/KimiChatService.d.ts +5 -4
  30. package/dist/cjs/services/providers/kimi/KimiChatService.d.ts.map +1 -1
  31. package/dist/cjs/services/providers/kimi/KimiChatService.js +34 -18
  32. package/dist/cjs/services/providers/kimi/KimiChatService.js.map +1 -1
  33. package/dist/cjs/services/providers/kimi/KimiChatServiceProvider.d.ts +1 -0
  34. package/dist/cjs/services/providers/kimi/KimiChatServiceProvider.d.ts.map +1 -1
  35. package/dist/cjs/services/providers/kimi/KimiChatServiceProvider.js +23 -1
  36. package/dist/cjs/services/providers/kimi/KimiChatServiceProvider.js.map +1 -1
  37. package/dist/cjs/types/chat.d.ts +10 -2
  38. package/dist/cjs/types/chat.d.ts.map +1 -1
  39. package/dist/cjs/types/toolChat.d.ts +20 -0
  40. package/dist/cjs/types/toolChat.d.ts.map +1 -1
  41. package/dist/cjs/utils/openaiCompatibleSse.d.ts +1 -0
  42. package/dist/cjs/utils/openaiCompatibleSse.d.ts.map +1 -1
  43. package/dist/cjs/utils/openaiCompatibleSse.js +48 -5
  44. package/dist/cjs/utils/openaiCompatibleSse.js.map +1 -1
  45. package/dist/cjs/utils/processChatFlow.d.ts +2 -2
  46. package/dist/cjs/utils/processChatFlow.d.ts.map +1 -1
  47. package/dist/cjs/utils/processChatFlow.js +8 -3
  48. package/dist/cjs/utils/processChatFlow.js.map +1 -1
  49. package/dist/esm/constants/gemini.d.ts +17 -0
  50. package/dist/esm/constants/gemini.d.ts.map +1 -1
  51. package/dist/esm/constants/gemini.js +62 -0
  52. package/dist/esm/constants/gemini.js.map +1 -1
  53. package/dist/esm/constants/kimi.d.ts +10 -0
  54. package/dist/esm/constants/kimi.d.ts.map +1 -1
  55. package/dist/esm/constants/kimi.js +17 -0
  56. package/dist/esm/constants/kimi.js.map +1 -1
  57. package/dist/esm/services/ChatService.d.ts +2 -2
  58. package/dist/esm/services/ChatService.d.ts.map +1 -1
  59. package/dist/esm/services/ChatServiceFactory.d.ts.map +1 -1
  60. package/dist/esm/services/ChatServiceFactory.js +1 -0
  61. package/dist/esm/services/ChatServiceFactory.js.map +1 -1
  62. package/dist/esm/services/providers/ChatServiceProvider.d.ts +9 -2
  63. package/dist/esm/services/providers/ChatServiceProvider.d.ts.map +1 -1
  64. package/dist/esm/services/providers/gemini/GeminiChatService.d.ts +8 -2
  65. package/dist/esm/services/providers/gemini/GeminiChatService.d.ts.map +1 -1
  66. package/dist/esm/services/providers/gemini/GeminiChatService.js +66 -39
  67. package/dist/esm/services/providers/gemini/GeminiChatService.js.map +1 -1
  68. package/dist/esm/services/providers/gemini/GeminiChatServiceProvider.d.ts.map +1 -1
  69. package/dist/esm/services/providers/gemini/GeminiChatServiceProvider.js +10 -3
  70. package/dist/esm/services/providers/gemini/GeminiChatServiceProvider.js.map +1 -1
  71. package/dist/esm/services/providers/gemini/geminiMessageConverter.d.ts +6 -0
  72. package/dist/esm/services/providers/gemini/geminiMessageConverter.d.ts.map +1 -1
  73. package/dist/esm/services/providers/gemini/geminiMessageConverter.js +61 -58
  74. package/dist/esm/services/providers/gemini/geminiMessageConverter.js.map +1 -1
  75. package/dist/esm/services/providers/kimi/KimiChatService.d.ts +5 -4
  76. package/dist/esm/services/providers/kimi/KimiChatService.d.ts.map +1 -1
  77. package/dist/esm/services/providers/kimi/KimiChatService.js +36 -20
  78. package/dist/esm/services/providers/kimi/KimiChatService.js.map +1 -1
  79. package/dist/esm/services/providers/kimi/KimiChatServiceProvider.d.ts +1 -0
  80. package/dist/esm/services/providers/kimi/KimiChatServiceProvider.d.ts.map +1 -1
  81. package/dist/esm/services/providers/kimi/KimiChatServiceProvider.js +24 -2
  82. package/dist/esm/services/providers/kimi/KimiChatServiceProvider.js.map +1 -1
  83. package/dist/esm/types/chat.d.ts +10 -2
  84. package/dist/esm/types/chat.d.ts.map +1 -1
  85. package/dist/esm/types/toolChat.d.ts +20 -0
  86. package/dist/esm/types/toolChat.d.ts.map +1 -1
  87. package/dist/esm/utils/openaiCompatibleSse.d.ts +1 -0
  88. package/dist/esm/utils/openaiCompatibleSse.d.ts.map +1 -1
  89. package/dist/esm/utils/openaiCompatibleSse.js +48 -5
  90. package/dist/esm/utils/openaiCompatibleSse.js.map +1 -1
  91. package/dist/esm/utils/processChatFlow.d.ts +2 -2
  92. package/dist/esm/utils/processChatFlow.d.ts.map +1 -1
  93. package/dist/esm/utils/processChatFlow.js +8 -3
  94. package/dist/esm/utils/processChatFlow.js.map +1 -1
  95. package/dist/umd/aituber-onair-chat.js +325 -131
  96. package/dist/umd/aituber-onair-chat.min.js +8 -8
  97. package/package.json +1 -1
@@ -106,6 +106,8 @@ var AITuberOnAirChat = (() => {
106
106
  MODEL_GEMINI_3_1_FLASH_LITE_PREVIEW: () => MODEL_GEMINI_3_1_FLASH_LITE_PREVIEW,
107
107
  MODEL_GEMINI_3_1_PRO_PREVIEW: () => MODEL_GEMINI_3_1_PRO_PREVIEW,
108
108
  MODEL_GEMINI_3_5_FLASH: () => MODEL_GEMINI_3_5_FLASH,
109
+ MODEL_GEMINI_3_5_FLASH_LITE: () => MODEL_GEMINI_3_5_FLASH_LITE,
110
+ MODEL_GEMINI_3_6_FLASH: () => MODEL_GEMINI_3_6_FLASH,
109
111
  MODEL_GEMINI_3_FLASH_PREVIEW: () => MODEL_GEMINI_3_FLASH_PREVIEW,
110
112
  MODEL_GEMINI_3_PRO_PREVIEW: () => MODEL_GEMINI_3_PRO_PREVIEW,
111
113
  MODEL_GEMINI_NANO: () => MODEL_GEMINI_NANO,
@@ -157,6 +159,7 @@ var AITuberOnAirChat = (() => {
157
159
  MODEL_KIMI_K2_6: () => MODEL_KIMI_K2_6,
158
160
  MODEL_KIMI_K2_7_CODE: () => MODEL_KIMI_K2_7_CODE,
159
161
  MODEL_KIMI_K2_7_CODE_HIGHSPEED: () => MODEL_KIMI_K2_7_CODE_HIGHSPEED,
162
+ MODEL_KIMI_K3: () => MODEL_KIMI_K3,
160
163
  MODEL_MINISTRAL_14B_2512: () => MODEL_MINISTRAL_14B_2512,
161
164
  MODEL_MINISTRAL_3B_2512: () => MODEL_MINISTRAL_3B_2512,
162
165
  MODEL_MINISTRAL_8B_2512: () => MODEL_MINISTRAL_8B_2512,
@@ -226,11 +229,16 @@ var AITuberOnAirChat = (() => {
226
229
  allowsReasoningNone: () => allowsReasoningNone,
227
230
  allowsReasoningXHigh: () => allowsReasoningXHigh,
228
231
  buildOpenAICompatibleTools: () => buildOpenAICompatibleTools,
232
+ getDefaultGeminiReasoningEffort: () => getDefaultGeminiReasoningEffort,
229
233
  getDefaultReasoningEffortForGPT5Model: () => getDefaultReasoningEffortForGPT5Model,
230
234
  getDefaultXaiReasoningEffort: () => getDefaultXaiReasoningEffort,
235
+ getGeminiSupportedReasoningEfforts: () => getGeminiSupportedReasoningEfforts,
236
+ getKimiSupportedReasoningEfforts: () => getKimiSupportedReasoningEfforts,
231
237
  getMaxTokensForResponseLength: () => getMaxTokensForResponseLength,
232
238
  installGASFetch: () => installGASFetch,
233
239
  isGPT5Model: () => isGPT5Model,
240
+ isGeminiReasoningEffortModel: () => isGeminiReasoningEffortModel,
241
+ isKimiReasoningEffortModel: () => isKimiReasoningEffortModel,
234
242
  isKimiThinkingRequiredModel: () => isKimiThinkingRequiredModel,
235
243
  isKimiVisionModel: () => isKimiVisionModel,
236
244
  isMistralReasoningEffort: () => isMistralReasoningEffort,
@@ -244,6 +252,7 @@ var AITuberOnAirChat = (() => {
244
252
  isXaiVisionModel: () => isXaiVisionModel,
245
253
  isZaiToolStreamModel: () => isZaiToolStreamModel,
246
254
  isZaiVisionModel: () => isZaiVisionModel,
255
+ normalizeGeminiReasoningEffort: () => normalizeGeminiReasoningEffort,
247
256
  normalizeXaiReasoningEffort: () => normalizeXaiReasoningEffort,
248
257
  parseOpenAICompatibleOneShot: () => parseOpenAICompatibleOneShot,
249
258
  parseOpenAICompatibleTextStream: () => parseOpenAICompatibleTextStream,
@@ -355,7 +364,9 @@ var AITuberOnAirChat = (() => {
355
364
  var ENDPOINT_GEMINI_API = "https://generativelanguage.googleapis.com";
356
365
  var MODEL_GEMMA_4_31B_IT = "gemma-4-31b-it";
357
366
  var MODEL_GEMMA_4_26B_A4B_IT = "gemma-4-26b-a4b-it";
367
+ var MODEL_GEMINI_3_6_FLASH = "gemini-3.6-flash";
358
368
  var MODEL_GEMINI_3_5_FLASH = "gemini-3.5-flash";
369
+ var MODEL_GEMINI_3_5_FLASH_LITE = "gemini-3.5-flash-lite";
359
370
  var MODEL_GEMINI_3_1_PRO_PREVIEW = "gemini-3.1-pro-preview";
360
371
  var MODEL_GEMINI_3_1_FLASH_LITE = "gemini-3.1-flash-lite";
361
372
  var MODEL_GEMINI_3_1_FLASH_LITE_PREVIEW = "gemini-3.1-flash-lite-preview";
@@ -366,7 +377,9 @@ var AITuberOnAirChat = (() => {
366
377
  var MODEL_GEMINI_2_5_FLASH_LITE = "gemini-2.5-flash-lite";
367
378
  var MODEL_GEMINI_2_5_FLASH_LITE_PREVIEW_06_17 = "gemini-2.5-flash-lite-preview-06-17";
368
379
  var GEMINI_RECOMMENDED_MODELS = [
380
+ MODEL_GEMINI_3_6_FLASH,
369
381
  MODEL_GEMINI_3_5_FLASH,
382
+ MODEL_GEMINI_3_5_FLASH_LITE,
370
383
  MODEL_GEMINI_3_1_FLASH_LITE,
371
384
  MODEL_GEMINI_3_1_PRO_PREVIEW,
372
385
  MODEL_GEMINI_3_FLASH_PREVIEW,
@@ -385,6 +398,54 @@ var AITuberOnAirChat = (() => {
385
398
  ...GEMINI_RECOMMENDED_MODELS,
386
399
  ...GEMINI_DEPRECATED_MODELS
387
400
  ];
401
+ var GEMINI_FLASH_REASONING_EFFORTS = [
402
+ "minimal",
403
+ "low",
404
+ "medium",
405
+ "high"
406
+ ];
407
+ var GEMINI_PRO_REASONING_EFFORTS = [
408
+ "low",
409
+ "medium",
410
+ "high"
411
+ ];
412
+ var GEMINI_FLASH_REASONING_EFFORT_MODELS = [
413
+ MODEL_GEMINI_3_6_FLASH,
414
+ MODEL_GEMINI_3_5_FLASH,
415
+ MODEL_GEMINI_3_5_FLASH_LITE,
416
+ MODEL_GEMINI_3_1_FLASH_LITE,
417
+ MODEL_GEMINI_3_1_FLASH_LITE_PREVIEW,
418
+ MODEL_GEMINI_3_FLASH_PREVIEW
419
+ ];
420
+ var GEMINI_PRO_REASONING_EFFORT_MODELS = [
421
+ MODEL_GEMINI_3_1_PRO_PREVIEW,
422
+ MODEL_GEMINI_3_PRO_PREVIEW
423
+ ];
424
+ function getGeminiSupportedReasoningEfforts(model) {
425
+ if (GEMINI_FLASH_REASONING_EFFORT_MODELS.includes(model)) {
426
+ return GEMINI_FLASH_REASONING_EFFORTS;
427
+ }
428
+ if (GEMINI_PRO_REASONING_EFFORT_MODELS.includes(model)) {
429
+ return GEMINI_PRO_REASONING_EFFORTS;
430
+ }
431
+ return [];
432
+ }
433
+ function isGeminiReasoningEffortModel(model) {
434
+ return getGeminiSupportedReasoningEfforts(model).length > 0;
435
+ }
436
+ function getDefaultGeminiReasoningEffort(model) {
437
+ return getGeminiSupportedReasoningEfforts(model)[0];
438
+ }
439
+ function normalizeGeminiReasoningEffort(model, effort) {
440
+ const supported = getGeminiSupportedReasoningEfforts(model);
441
+ if (supported.length === 0) {
442
+ return void 0;
443
+ }
444
+ if (effort && supported.includes(effort)) {
445
+ return effort;
446
+ }
447
+ return supported[0];
448
+ }
388
449
 
389
450
  // src/constants/claude.ts
390
451
  var ENDPOINT_CLAUDE_API = "https://api.anthropic.com/v1/messages";
@@ -565,11 +626,16 @@ var AITuberOnAirChat = (() => {
565
626
 
566
627
  // src/constants/kimi.ts
567
628
  var ENDPOINT_KIMI_CHAT_COMPLETIONS_API = "https://api.moonshot.ai/v1/chat/completions";
629
+ var MODEL_KIMI_K3 = "kimi-k3";
568
630
  var MODEL_KIMI_K2_7_CODE = "kimi-k2.7-code";
569
631
  var MODEL_KIMI_K2_7_CODE_HIGHSPEED = "kimi-k2.7-code-highspeed";
570
632
  var MODEL_KIMI_K2_6 = "kimi-k2.6";
571
633
  var MODEL_KIMI_K2_5 = "kimi-k2.5";
634
+ var KIMI_REASONING_EFFORTS_BY_MODEL = {
635
+ [MODEL_KIMI_K3]: ["max"]
636
+ };
572
637
  var KIMI_VISION_SUPPORTED_MODELS = [
638
+ MODEL_KIMI_K3,
573
639
  MODEL_KIMI_K2_7_CODE,
574
640
  MODEL_KIMI_K2_7_CODE_HIGHSPEED,
575
641
  MODEL_KIMI_K2_6,
@@ -585,6 +651,12 @@ var AITuberOnAirChat = (() => {
585
651
  function isKimiThinkingRequiredModel(model) {
586
652
  return KIMI_THINKING_REQUIRED_MODELS.includes(model);
587
653
  }
654
+ function getKimiSupportedReasoningEfforts(model) {
655
+ return KIMI_REASONING_EFFORTS_BY_MODEL[model] ?? [];
656
+ }
657
+ function isKimiReasoningEffortModel(model) {
658
+ return getKimiSupportedReasoningEfforts(model).length > 0;
659
+ }
588
660
 
589
661
  // src/constants/deepseek.ts
590
662
  var DEEPSEEK_API_BASE_URL = "https://api.deepseek.com";
@@ -1061,6 +1133,8 @@ If it's in another language, summarize in that language.
1061
1133
  async function parseOpenAICompatibleToolStream(res, onPartial, options = {}) {
1062
1134
  const textBlocks = [];
1063
1135
  const toolCallsMap = /* @__PURE__ */ new Map();
1136
+ let fullContent = "";
1137
+ let reasoningContent = "";
1064
1138
  let finishReason;
1065
1139
  let usage;
1066
1140
  const appendTextBlock = options.appendTextBlock ?? StreamTextAccumulator.append;
@@ -1079,14 +1153,23 @@ If it's in another language, summarize in that language.
1079
1153
  if (content) {
1080
1154
  onPartial(content);
1081
1155
  appendTextBlock(textBlocks, content);
1156
+ fullContent += content;
1157
+ }
1158
+ const reasoning = extractTextContent(delta?.reasoning_content);
1159
+ if (reasoning) {
1160
+ reasoningContent += reasoning;
1082
1161
  }
1083
1162
  if (delta?.tool_calls) {
1084
1163
  delta.tool_calls.forEach((c) => {
1085
1164
  const entry = toolCallsMap.get(c.index) ?? {
1086
1165
  id: c.id,
1166
+ type: c.type,
1087
1167
  name: c.function?.name,
1088
1168
  args: ""
1089
1169
  };
1170
+ if (c.id) entry.id = c.id;
1171
+ if (c.type) entry.type = c.type;
1172
+ if (c.function?.name) entry.name = c.function.name;
1090
1173
  entry.args += c.function?.arguments || "";
1091
1174
  toolCallsMap.set(c.index, entry);
1092
1175
  });
@@ -1099,17 +1182,35 @@ If it's in another language, summarize in that language.
1099
1182
  input: safeParseToolCallInput(e.args, options.onJsonError)
1100
1183
  }));
1101
1184
  const blocks = [...textBlocks, ...toolBlocks];
1185
+ const assistantToolCalls = Array.from(
1186
+ toolCallsMap.entries()
1187
+ ).sort((a, b) => a[0] - b[0]).map(([_, entry]) => ({
1188
+ id: entry.id,
1189
+ type: "function",
1190
+ function: {
1191
+ name: entry.name,
1192
+ arguments: entry.args
1193
+ }
1194
+ }));
1195
+ const assistantMessage = {
1196
+ role: "assistant",
1197
+ content: fullContent,
1198
+ ...reasoningContent ? { reasoning_content: reasoningContent } : {},
1199
+ ...assistantToolCalls.length > 0 ? { tool_calls: assistantToolCalls } : {}
1200
+ };
1102
1201
  return {
1103
1202
  blocks,
1104
1203
  stop_reason: toolBlocks.length ? "tool_use" : "end",
1105
1204
  truncated: finishReason === "length",
1106
1205
  finish_reason: finishReason,
1107
- usage
1206
+ usage,
1207
+ ...options.preserveAssistantMessage ? { assistant_message: assistantMessage } : {}
1108
1208
  };
1109
1209
  }
1110
1210
  function parseOpenAICompatibleOneShot(data, options = {}) {
1111
1211
  const choice = data?.choices?.[0];
1112
1212
  const blocks = [];
1213
+ const content = extractTextContent(choice?.message?.content);
1113
1214
  if (choice?.message?.tool_calls?.length) {
1114
1215
  choice.message.tool_calls.forEach(
1115
1216
  (c) => blocks.push({
@@ -1122,18 +1223,21 @@ If it's in another language, summarize in that language.
1122
1223
  )
1123
1224
  })
1124
1225
  );
1125
- } else {
1126
- const content = extractTextContent(choice?.message?.content);
1127
- if (content) {
1128
- blocks.push({ type: "text", text: content });
1129
- }
1130
- }
1226
+ } else if (content) {
1227
+ blocks.push({ type: "text", text: content });
1228
+ }
1229
+ const assistantMessage = choice?.message ? {
1230
+ ...choice.message,
1231
+ role: "assistant",
1232
+ content
1233
+ } : void 0;
1131
1234
  return {
1132
1235
  blocks,
1133
1236
  stop_reason: choice?.finish_reason === "tool_calls" || blocks.some((b) => b.type === "tool_use") ? "tool_use" : "end",
1134
1237
  truncated: choice?.finish_reason === "length",
1135
1238
  finish_reason: choice?.finish_reason,
1136
- usage: data?.usage
1239
+ usage: data?.usage,
1240
+ ...options.preserveAssistantMessage ? { assistant_message: assistantMessage } : {}
1137
1241
  };
1138
1242
  }
1139
1243
 
@@ -1161,8 +1265,15 @@ If it's in another language, summarize in that language.
1161
1265
  // src/utils/processChatFlow.ts
1162
1266
  async function processChatWithOptionalTools(options) {
1163
1267
  if (!options.hasTools) {
1164
- const full = await options.runWithoutTools();
1165
- await options.onCompleteResponse(full);
1268
+ const result2 = await options.runWithoutTools();
1269
+ if (typeof result2 === "string") {
1270
+ await options.onCompleteResponse(result2);
1271
+ return;
1272
+ }
1273
+ const full = StreamTextAccumulator.getFullText(
1274
+ result2.blocks
1275
+ );
1276
+ await options.onCompleteResponse(full, result2);
1166
1277
  return;
1167
1278
  }
1168
1279
  const result = await options.runWithTools();
@@ -1173,7 +1284,7 @@ If it's in another language, summarize in that language.
1173
1284
  const full = StreamTextAccumulator.getFullText(
1174
1285
  result.blocks
1175
1286
  );
1176
- await options.onCompleteResponse(full);
1287
+ await options.onCompleteResponse(full, result);
1177
1288
  return;
1178
1289
  }
1179
1290
  throw new Error(options.toolErrorMessage);
@@ -2732,41 +2843,26 @@ If it's in another language, summarize in that language.
2732
2843
  gemini.push({ role: currentRole, parts: [...currentParts] });
2733
2844
  currentParts = [];
2734
2845
  }
2846
+ currentRole = null;
2735
2847
  };
2736
2848
  for (const msg of messages) {
2737
2849
  const role = mapRoleToGemini(msg.role);
2738
2850
  if (msg.tool_calls) {
2739
2851
  pushCurrent();
2740
- for (const call of msg.tool_calls) {
2741
- options.callIdMap?.set(call.id, call.function.name);
2852
+ const parts = msg.tool_calls.map(
2853
+ (call) => createFunctionCallPart(call, options)
2854
+ );
2855
+ if (parts.length > 0) {
2742
2856
  gemini.push({
2743
2857
  role: "model",
2744
- parts: [
2745
- {
2746
- functionCall: {
2747
- name: call.function.name,
2748
- args: JSON.parse(call.function.arguments || "{}")
2749
- }
2750
- }
2751
- ]
2858
+ parts
2752
2859
  });
2753
2860
  }
2754
2861
  continue;
2755
2862
  }
2756
2863
  if (msg.role === "tool") {
2757
2864
  pushCurrent();
2758
- const funcName = msg.name ?? options.callIdMap?.get(msg.tool_call_id) ?? "result";
2759
- gemini.push({
2760
- role: "user",
2761
- parts: [
2762
- {
2763
- functionResponse: {
2764
- name: funcName,
2765
- response: normalizeToolResult(safeJsonParse2(msg.content))
2766
- }
2767
- }
2768
- ]
2769
- });
2865
+ appendFunctionResponse(gemini, createFunctionResponsePart(msg, options));
2770
2866
  continue;
2771
2867
  }
2772
2868
  if (role !== currentRole) pushCurrent();
@@ -2782,47 +2878,41 @@ If it's in another language, summarize in that language.
2782
2878
  const geminiMessages = [];
2783
2879
  let currentRole = null;
2784
2880
  let currentParts = [];
2881
+ const pushCurrent = () => {
2882
+ if (currentRole && currentParts.length > 0) {
2883
+ geminiMessages.push({
2884
+ role: currentRole,
2885
+ parts: [...currentParts]
2886
+ });
2887
+ currentParts = [];
2888
+ }
2889
+ currentRole = null;
2890
+ };
2785
2891
  for (const msg of messages) {
2786
2892
  const role = mapRoleToGemini(msg.role);
2787
2893
  if (msg.tool_calls) {
2788
- for (const call of msg.tool_calls) {
2894
+ pushCurrent();
2895
+ const parts = msg.tool_calls.map(
2896
+ (call) => createFunctionCallPart(call, options)
2897
+ );
2898
+ if (parts.length > 0) {
2789
2899
  geminiMessages.push({
2790
2900
  role: "model",
2791
- parts: [
2792
- {
2793
- functionCall: {
2794
- name: call.function.name,
2795
- args: JSON.parse(call.function.arguments || "{}")
2796
- }
2797
- }
2798
- ]
2901
+ parts
2799
2902
  });
2800
2903
  }
2801
2904
  continue;
2802
2905
  }
2803
2906
  if (msg.role === "tool") {
2804
- const funcName = msg.name ?? options.callIdMap?.get(msg.tool_call_id) ?? "result";
2805
- geminiMessages.push({
2806
- role: "user",
2807
- parts: [
2808
- {
2809
- functionResponse: {
2810
- name: funcName,
2811
- response: normalizeToolResult(
2812
- safeJsonParse2(msg.content)
2813
- )
2814
- }
2815
- }
2816
- ]
2817
- });
2907
+ pushCurrent();
2908
+ appendFunctionResponse(
2909
+ geminiMessages,
2910
+ createFunctionResponsePart(msg, options)
2911
+ );
2818
2912
  continue;
2819
2913
  }
2820
2914
  if (role !== currentRole && currentParts.length > 0) {
2821
- geminiMessages.push({
2822
- role: currentRole,
2823
- parts: [...currentParts]
2824
- });
2825
- currentParts = [];
2915
+ pushCurrent();
2826
2916
  }
2827
2917
  currentRole = role;
2828
2918
  if (typeof msg.content === "string") {
@@ -2850,14 +2940,43 @@ If it's in another language, summarize in that language.
2850
2940
  }
2851
2941
  }
2852
2942
  }
2853
- if (currentRole && currentParts.length > 0) {
2854
- geminiMessages.push({
2855
- role: currentRole,
2856
- parts: [...currentParts]
2857
- });
2858
- }
2943
+ pushCurrent();
2859
2944
  return geminiMessages;
2860
2945
  }
2946
+ function createFunctionCallPart(call, options) {
2947
+ options.callIdMap?.set(call.id, call.function.name);
2948
+ const context = options.functionCallContextMap?.get(call.id);
2949
+ const part = {
2950
+ functionCall: {
2951
+ ...context?.providerCallId ? { id: context.providerCallId } : {},
2952
+ name: call.function.name,
2953
+ args: JSON.parse(call.function.arguments || "{}")
2954
+ }
2955
+ };
2956
+ if (context?.thoughtSignature) {
2957
+ part.thoughtSignature = context.thoughtSignature;
2958
+ }
2959
+ return part;
2960
+ }
2961
+ function createFunctionResponsePart(msg, options) {
2962
+ const toolCallId = msg.tool_call_id;
2963
+ const context = options.functionCallContextMap?.get(toolCallId);
2964
+ const functionResponse = {
2965
+ ...context?.providerCallId ? { id: context.providerCallId } : {},
2966
+ name: msg.name ?? context?.name ?? options.callIdMap?.get(toolCallId) ?? "result",
2967
+ response: normalizeToolResult(safeJsonParse2(msg.content))
2968
+ };
2969
+ return { functionResponse };
2970
+ }
2971
+ function appendFunctionResponse(messages, part) {
2972
+ const previous = messages[messages.length - 1];
2973
+ const isFunctionResponseGroup = previous?.role === "user" && previous.parts.every((item) => item.functionResponse);
2974
+ if (isFunctionResponseGroup) {
2975
+ previous.parts.push(part);
2976
+ return;
2977
+ }
2978
+ messages.push({ role: "user", parts: [part] });
2979
+ }
2861
2980
  function safeJsonParse2(str) {
2862
2981
  try {
2863
2982
  return JSON.parse(str);
@@ -2935,16 +3054,19 @@ If it's in another language, summarize in that language.
2935
3054
  * @param tools Array of tool definitions
2936
3055
  * @param mcpServers Array of MCP server configurations
2937
3056
  */
2938
- constructor(apiKey, model = MODEL_GEMINI_3_1_FLASH_LITE, visionModel = MODEL_GEMINI_3_1_FLASH_LITE, tools = [], mcpServers = [], responseLength) {
3057
+ constructor(apiKey, model = MODEL_GEMINI_3_1_FLASH_LITE, visionModel = MODEL_GEMINI_3_1_FLASH_LITE, tools = [], mcpServers = [], responseLength, reasoningEffort) {
2939
3058
  /** Provider name */
2940
3059
  this.provider = "gemini";
2941
3060
  this.mcpToolSchemas = [];
2942
3061
  this.mcpSchemasInitialized = false;
2943
3062
  /** id(OpenAI) → name(Gemini) mapping */
2944
3063
  this.callIdMap = /* @__PURE__ */ new Map();
3064
+ /** Common tool id → Gemini function-call metadata required for replay. */
3065
+ this.functionCallContextMap = /* @__PURE__ */ new Map();
2945
3066
  this.apiKey = apiKey;
2946
3067
  this.model = model;
2947
3068
  this.responseLength = responseLength;
3069
+ this.reasoningEffort = reasoningEffort;
2948
3070
  if (!GEMINI_VISION_SUPPORTED_MODELS.includes(visionModel)) {
2949
3071
  throw new Error(
2950
3072
  `Model ${visionModel} does not support vision capabilities.`
@@ -2957,8 +3079,21 @@ If it's in another language, summarize in that language.
2957
3079
  isGemma4Model(model) {
2958
3080
  return /^gemma-4-/.test(model);
2959
3081
  }
2960
- shouldMinimizeThinking(model) {
2961
- return model === MODEL_GEMINI_3_5_FLASH || this.isGemma4Model(model);
3082
+ resolveThinkingConfig(model) {
3083
+ const effort = normalizeGeminiReasoningEffort(model, this.reasoningEffort);
3084
+ if (effort) {
3085
+ return {
3086
+ includeThoughts: false,
3087
+ thinkingLevel: effort.toUpperCase()
3088
+ };
3089
+ }
3090
+ if (this.isGemma4Model(model)) {
3091
+ return {
3092
+ includeThoughts: false,
3093
+ thinkingLevel: "MINIMAL"
3094
+ };
3095
+ }
3096
+ return void 0;
2962
3097
  }
2963
3098
  shouldExposeTextPart(part, model) {
2964
3099
  if (!part.text) return false;
@@ -2976,7 +3111,8 @@ If it's in another language, summarize in that language.
2976
3111
  functionCallingConfig: "function_calling_config",
2977
3112
  functionDeclarations: "function_declarations",
2978
3113
  functionCall: "function_call",
2979
- functionResponse: "function_response"
3114
+ functionResponse: "function_response",
3115
+ thoughtSignature: "thought_signature"
2980
3116
  };
2981
3117
  if (Array.isArray(obj)) return obj.map((v) => this.adaptKeysForApi(v));
2982
3118
  if (obj && typeof obj === "object") {
@@ -3136,10 +3272,12 @@ If it's in another language, summarize in that language.
3136
3272
  const contents = hasVision ? await convertVisionMessagesToGeminiFormat(
3137
3273
  messages,
3138
3274
  {
3139
- callIdMap: this.callIdMap
3275
+ callIdMap: this.callIdMap,
3276
+ functionCallContextMap: this.functionCallContextMap
3140
3277
  }
3141
3278
  ) : convertMessagesToGeminiFormat(messages, {
3142
- callIdMap: this.callIdMap
3279
+ callIdMap: this.callIdMap,
3280
+ functionCallContextMap: this.functionCallContextMap
3143
3281
  });
3144
3282
  const body = {
3145
3283
  contents,
@@ -3147,11 +3285,9 @@ If it's in another language, summarize in that language.
3147
3285
  maxOutputTokens: maxTokens !== void 0 ? maxTokens : getMaxTokensForResponseLength(this.responseLength)
3148
3286
  }
3149
3287
  };
3150
- if (this.shouldMinimizeThinking(model)) {
3151
- body.generationConfig.thinkingConfig = {
3152
- includeThoughts: false,
3153
- thinkingLevel: "MINIMAL"
3154
- };
3288
+ const thinkingConfig = this.resolveThinkingConfig(model);
3289
+ if (thinkingConfig) {
3290
+ body.generationConfig.thinkingConfig = thinkingConfig;
3155
3291
  }
3156
3292
  let activeMCPToolSchemas = [];
3157
3293
  if (this.mcpServers.length > 0) {
@@ -3208,6 +3344,32 @@ If it's in another language, summarize in that language.
3208
3344
  throw error;
3209
3345
  }
3210
3346
  }
3347
+ createFunctionCallBlock(part) {
3348
+ const functionCall = part.functionCall ?? part.function_call;
3349
+ if (!functionCall) return void 0;
3350
+ const toolUseId = functionCall.id ?? this.genUUID();
3351
+ this.callIdMap.set(toolUseId, functionCall.name);
3352
+ this.functionCallContextMap.set(toolUseId, {
3353
+ name: functionCall.name,
3354
+ providerCallId: functionCall.id,
3355
+ thoughtSignature: part.thoughtSignature ?? part.thought_signature
3356
+ });
3357
+ return {
3358
+ type: "tool_use",
3359
+ id: toolUseId,
3360
+ name: functionCall.name,
3361
+ input: functionCall.args ?? {}
3362
+ };
3363
+ }
3364
+ createFunctionResponseBlock(part) {
3365
+ const functionResponse = part.functionResponse ?? part.function_response;
3366
+ if (!functionResponse) return void 0;
3367
+ return {
3368
+ type: "tool_result",
3369
+ tool_use_id: functionResponse.id ?? functionResponse.name,
3370
+ content: JSON.stringify(functionResponse.response)
3371
+ };
3372
+ }
3211
3373
  /* ────────────────────────────────────────────────────────── */
3212
3374
  /* Convert NDJSON stream to common format */
3213
3375
  /* ────────────────────────────────────────────────────────── */
@@ -3231,21 +3393,10 @@ If it's in another language, summarize in that language.
3231
3393
  onPartial(part.text);
3232
3394
  StreamTextAccumulator.addTextBlock(textBlocks, part.text);
3233
3395
  }
3234
- if (part.functionCall) {
3235
- toolBlocks.push({
3236
- type: "tool_use",
3237
- id: this.genUUID(),
3238
- name: part.functionCall.name,
3239
- input: part.functionCall.args ?? {}
3240
- });
3241
- }
3242
- if (part.functionResponse) {
3243
- toolBlocks.push({
3244
- type: "tool_result",
3245
- tool_use_id: part.functionResponse.name,
3246
- content: JSON.stringify(part.functionResponse.response)
3247
- });
3248
- }
3396
+ const functionCallBlock = this.createFunctionCallBlock(part);
3397
+ if (functionCallBlock) toolBlocks.push(functionCallBlock);
3398
+ const functionResponseBlock = this.createFunctionResponseBlock(part);
3399
+ if (functionResponseBlock) toolBlocks.push(functionResponseBlock);
3249
3400
  }
3250
3401
  }
3251
3402
  };
@@ -3285,21 +3436,10 @@ If it's in another language, summarize in that language.
3285
3436
  if (this.shouldExposeTextPart(part, model)) {
3286
3437
  textBlocks.push({ type: "text", text: part.text });
3287
3438
  }
3288
- if (part.functionCall) {
3289
- toolBlocks.push({
3290
- type: "tool_use",
3291
- id: this.genUUID(),
3292
- name: part.functionCall.name,
3293
- input: part.functionCall.args ?? {}
3294
- });
3295
- }
3296
- if (part.functionResponse) {
3297
- toolBlocks.push({
3298
- type: "tool_result",
3299
- tool_use_id: part.functionResponse.name,
3300
- content: JSON.stringify(part.functionResponse.response)
3301
- });
3302
- }
3439
+ const functionCallBlock = this.createFunctionCallBlock(part);
3440
+ if (functionCallBlock) toolBlocks.push(functionCallBlock);
3441
+ const functionResponseBlock = this.createFunctionResponseBlock(part);
3442
+ if (functionResponseBlock) toolBlocks.push(functionResponseBlock);
3303
3443
  }
3304
3444
  }
3305
3445
  const blocks = [...textBlocks, ...toolBlocks];
@@ -3349,21 +3489,28 @@ If it's in another language, summarize in that language.
3349
3489
  * @returns GeminiChatService instance
3350
3490
  */
3351
3491
  createChatService(options) {
3492
+ const model = options.model || this.getDefaultModel();
3493
+ if (options.reasoning_effort !== void 0 && !isGeminiReasoningEffortModel(model)) {
3494
+ throw new Error(
3495
+ `Model ${model} does not support Gemini reasoning_effort. Use it with Gemini 3 thinkingLevel models; Gemini 2.5 models use thinkingBudget instead.`
3496
+ );
3497
+ }
3352
3498
  const visionModel = resolveVisionModel({
3353
- model: options.model,
3499
+ model,
3354
3500
  visionModel: options.visionModel,
3355
3501
  defaultModel: this.getDefaultModel(),
3356
3502
  defaultVisionModel: this.getDefaultModel(),
3357
- supportsVisionForModel: (model) => this.supportsVisionForModel(model),
3503
+ supportsVisionForModel: (model2) => this.supportsVisionForModel(model2),
3358
3504
  validate: "resolved"
3359
3505
  });
3360
3506
  return new GeminiChatService(
3361
3507
  options.apiKey,
3362
- options.model || this.getDefaultModel(),
3508
+ model,
3363
3509
  visionModel,
3364
3510
  options.tools || [],
3365
3511
  options.mcpServers || [],
3366
- options.responseLength
3512
+ options.responseLength,
3513
+ normalizeGeminiReasoningEffort(model, options.reasoning_effort)
3367
3514
  );
3368
3515
  }
3369
3516
  /**
@@ -3571,7 +3718,7 @@ If it's in another language, summarize in that language.
3571
3718
  * @param model Name of the model to use
3572
3719
  * @param visionModel Name of the vision model
3573
3720
  */
3574
- constructor(apiKey, model = MODEL_KIMI_K2_6, visionModel = MODEL_KIMI_K2_6, tools, endpoint = ENDPOINT_KIMI_CHAT_COMPLETIONS_API, responseLength, responseFormat, thinking) {
3721
+ constructor(apiKey, model = MODEL_KIMI_K2_6, visionModel = MODEL_KIMI_K2_6, tools, endpoint = ENDPOINT_KIMI_CHAT_COMPLETIONS_API, responseLength, responseFormat, thinking, reasoningEffort) {
3575
3722
  /** Provider name */
3576
3723
  this.provider = "kimi";
3577
3724
  this.apiKey = apiKey;
@@ -3580,7 +3727,14 @@ If it's in another language, summarize in that language.
3580
3727
  this.endpoint = endpoint;
3581
3728
  this.responseLength = responseLength;
3582
3729
  this.responseFormat = responseFormat;
3583
- this.thinking = thinking ?? { type: "enabled" };
3730
+ this.thinking = thinking;
3731
+ const supportedReasoningEfforts = getKimiSupportedReasoningEfforts(model);
3732
+ if (reasoningEffort !== void 0 && !supportedReasoningEfforts.includes(reasoningEffort)) {
3733
+ throw new Error(
3734
+ `Model ${model} does not support reasoning_effort: ${reasoningEffort}.`
3735
+ );
3736
+ }
3737
+ this.reasoningEffort = reasoningEffort ?? (isKimiReasoningEffortModel(model) ? supportedReasoningEfforts[0] : void 0);
3584
3738
  this.visionModel = visionModel;
3585
3739
  }
3586
3740
  /**
@@ -3601,10 +3755,7 @@ If it's in another language, summarize in that language.
3601
3755
  async processChat(messages, onPartialResponse, onCompleteResponse) {
3602
3756
  await processChatWithOptionalTools({
3603
3757
  hasTools: this.tools.length > 0,
3604
- runWithoutTools: async () => {
3605
- const res = await this.callKimi(messages, this.model, true);
3606
- return this.handleStream(res, onPartialResponse);
3607
- },
3758
+ runWithoutTools: () => this.chatOnce(messages, true, onPartialResponse),
3608
3759
  runWithTools: () => this.chatOnce(messages, true, onPartialResponse),
3609
3760
  onCompleteResponse,
3610
3761
  toolErrorMessage: "processChat received tool_calls. ChatProcessor must use chatOnce() loop when tools are enabled."
@@ -3621,10 +3772,7 @@ If it's in another language, summarize in that language.
3621
3772
  }
3622
3773
  await processChatWithOptionalTools({
3623
3774
  hasTools: this.tools.length > 0,
3624
- runWithoutTools: async () => {
3625
- const res = await this.callKimi(messages, this.visionModel, true);
3626
- return this.handleStream(res, onPartialResponse);
3627
- },
3775
+ runWithoutTools: () => this.visionChatOnce(messages, true, onPartialResponse),
3628
3776
  runWithTools: () => this.visionChatOnce(messages, true, onPartialResponse),
3629
3777
  onCompleteResponse,
3630
3778
  toolErrorMessage: "processVisionChat received tool_calls. ChatProcessor must use visionChatOnce() loop when tools are enabled."
@@ -3677,11 +3825,18 @@ If it's in another language, summarize in that language.
3677
3825
  };
3678
3826
  const tokenLimit = maxTokens !== void 0 ? maxTokens : getMaxTokensForResponseLength(this.responseLength);
3679
3827
  if (tokenLimit !== void 0) {
3680
- body.max_tokens = tokenLimit;
3828
+ if (isKimiReasoningEffortModel(model)) {
3829
+ body.max_completion_tokens = tokenLimit;
3830
+ } else {
3831
+ body.max_tokens = tokenLimit;
3832
+ }
3681
3833
  }
3682
3834
  if (this.responseFormat) {
3683
3835
  body.response_format = this.responseFormat;
3684
3836
  }
3837
+ if (isKimiReasoningEffortModel(model)) {
3838
+ body.reasoning_effort = this.reasoningEffort ?? "max";
3839
+ }
3685
3840
  const effectiveThinking = this.resolveEffectiveThinking(model);
3686
3841
  if (effectiveThinking) {
3687
3842
  if (this.isSelfHostedEndpoint()) {
@@ -3706,6 +3861,14 @@ If it's in another language, summarize in that language.
3706
3861
  return value.replace(/\/+$/, "");
3707
3862
  }
3708
3863
  resolveEffectiveThinking(model) {
3864
+ if (isKimiReasoningEffortModel(model)) {
3865
+ if (this.thinking) {
3866
+ throw new Error(
3867
+ `Model ${model} uses reasoning_effort and does not support the K2.x thinking option.`
3868
+ );
3869
+ }
3870
+ return void 0;
3871
+ }
3709
3872
  if (isKimiThinkingRequiredModel(model)) {
3710
3873
  if (this.thinking?.type === "disabled") {
3711
3874
  throw new Error(
@@ -3717,21 +3880,17 @@ If it's in another language, summarize in that language.
3717
3880
  if (this.tools.length > 0) {
3718
3881
  return { type: "disabled" };
3719
3882
  }
3720
- return this.thinking;
3883
+ return this.thinking ?? { type: "enabled" };
3721
3884
  }
3722
3885
  buildToolsDefinition() {
3723
3886
  return buildOpenAICompatibleTools(this.tools, "chat-completions");
3724
3887
  }
3725
- async handleStream(res, onPartial) {
3726
- return parseOpenAICompatibleTextStream(res, onPartial, {
3727
- onJsonError: (payload) => console.debug("Failed to parse SSE data:", payload)
3728
- });
3729
- }
3730
3888
  /**
3731
3889
  * Parse streaming response with tool support
3732
3890
  */
3733
3891
  async parseStream(res, onPartial) {
3734
3892
  return parseOpenAICompatibleToolStream(res, onPartial, {
3893
+ preserveAssistantMessage: true,
3735
3894
  onJsonError: (payload) => console.debug("Failed to parse SSE data:", payload)
3736
3895
  });
3737
3896
  }
@@ -3739,7 +3898,9 @@ If it's in another language, summarize in that language.
3739
3898
  * Parse non-streaming response
3740
3899
  */
3741
3900
  parseOneShot(data) {
3742
- return parseOpenAICompatibleOneShot(data);
3901
+ return parseOpenAICompatibleOneShot(data, {
3902
+ preserveAssistantMessage: true
3903
+ });
3743
3904
  }
3744
3905
  };
3745
3906
 
@@ -3764,6 +3925,10 @@ If it's in another language, summarize in that language.
3764
3925
  });
3765
3926
  const tools = options.tools;
3766
3927
  const thinking = this.resolveThinking(model, tools, options.thinking);
3928
+ const reasoningEffort = this.resolveReasoningEffort(
3929
+ model,
3930
+ options.reasoning_effort
3931
+ );
3767
3932
  return new KimiChatService(
3768
3933
  options.apiKey,
3769
3934
  model,
@@ -3772,7 +3937,8 @@ If it's in another language, summarize in that language.
3772
3937
  endpoint,
3773
3938
  options.responseLength,
3774
3939
  options.responseFormat,
3775
- thinking
3940
+ thinking,
3941
+ reasoningEffort
3776
3942
  );
3777
3943
  }
3778
3944
  /**
@@ -3786,6 +3952,7 @@ If it's in another language, summarize in that language.
3786
3952
  */
3787
3953
  getSupportedModels() {
3788
3954
  return [
3955
+ MODEL_KIMI_K3,
3789
3956
  MODEL_KIMI_K2_7_CODE,
3790
3957
  MODEL_KIMI_K2_7_CODE_HIGHSPEED,
3791
3958
  MODEL_KIMI_K2_6,
@@ -3839,6 +4006,14 @@ If it's in another language, summarize in that language.
3839
4006
  return value.replace(/\/+$/, "");
3840
4007
  }
3841
4008
  resolveThinking(model, tools, thinking) {
4009
+ if (isKimiReasoningEffortModel(model)) {
4010
+ if (thinking) {
4011
+ throw new Error(
4012
+ `Model ${model} uses reasoning_effort and does not support the K2.x thinking option.`
4013
+ );
4014
+ }
4015
+ return void 0;
4016
+ }
3842
4017
  if (isKimiThinkingRequiredModel(model)) {
3843
4018
  if (thinking?.type === "disabled") {
3844
4019
  throw new Error(
@@ -3852,6 +4027,24 @@ If it's in another language, summarize in that language.
3852
4027
  }
3853
4028
  return thinking ?? this.defaultThinking;
3854
4029
  }
4030
+ resolveReasoningEffort(model, reasoningEffort) {
4031
+ const supported = getKimiSupportedReasoningEfforts(model);
4032
+ if (supported.length === 0) {
4033
+ if (reasoningEffort !== void 0) {
4034
+ throw new Error(
4035
+ `Model ${model} does not support the reasoning_effort option.`
4036
+ );
4037
+ }
4038
+ return void 0;
4039
+ }
4040
+ const resolved = reasoningEffort ?? supported[0];
4041
+ if (!supported.includes(resolved)) {
4042
+ throw new Error(
4043
+ `Model ${model} supports reasoning_effort values: ${supported.join(", ")}.`
4044
+ );
4045
+ }
4046
+ return resolved;
4047
+ }
3855
4048
  };
3856
4049
 
3857
4050
  // src/services/providers/mistral/MistralChatService.ts
@@ -5258,6 +5451,7 @@ If it's in another language, summarize in that language.
5258
5451
  ]);
5259
5452
  var REASONING_EFFORT_BY_PROVIDER = {
5260
5453
  openai: ["none", "minimal", "low", "medium", "high", "xhigh", "max"],
5454
+ gemini: ["minimal", "low", "medium", "high"],
5261
5455
  openrouter: ["none", "minimal", "low", "medium", "high"],
5262
5456
  mistral: ["low", "medium", "high"],
5263
5457
  plamo: ["none", "medium"],