@aituber-onair/chat 0.50.0 → 0.51.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 (67) hide show
  1. package/README.ja.md +22 -7
  2. package/README.md +22 -7
  3. package/dist/cjs/backend.d.ts +20 -0
  4. package/dist/cjs/backend.d.ts.map +1 -0
  5. package/dist/cjs/backend.js +115 -0
  6. package/dist/cjs/backend.js.map +1 -0
  7. package/dist/cjs/constants/xai.d.ts +6 -1
  8. package/dist/cjs/constants/xai.d.ts.map +1 -1
  9. package/dist/cjs/constants/xai.js +29 -7
  10. package/dist/cjs/constants/xai.js.map +1 -1
  11. package/dist/cjs/index.d.ts +1 -0
  12. package/dist/cjs/index.d.ts.map +1 -1
  13. package/dist/cjs/index.js +1 -0
  14. package/dist/cjs/index.js.map +1 -1
  15. package/dist/cjs/services/ChatServiceFactory.d.ts.map +1 -1
  16. package/dist/cjs/services/ChatServiceFactory.js +9 -18
  17. package/dist/cjs/services/ChatServiceFactory.js.map +1 -1
  18. package/dist/cjs/services/providers/gemini/GeminiChatService.d.ts.map +1 -1
  19. package/dist/cjs/services/providers/gemini/GeminiChatService.js +3 -0
  20. package/dist/cjs/services/providers/gemini/GeminiChatService.js.map +1 -1
  21. package/dist/cjs/services/providers/gemini/geminiMessageConverter.d.ts +5 -0
  22. package/dist/cjs/services/providers/gemini/geminiMessageConverter.d.ts.map +1 -1
  23. package/dist/cjs/services/providers/gemini/geminiMessageConverter.js +16 -0
  24. package/dist/cjs/services/providers/gemini/geminiMessageConverter.js.map +1 -1
  25. package/dist/cjs/services/providers/openai/openaiRequestBuilder.d.ts.map +1 -1
  26. package/dist/cjs/services/providers/openai/openaiRequestBuilder.js +27 -5
  27. package/dist/cjs/services/providers/openai/openaiRequestBuilder.js.map +1 -1
  28. package/dist/cjs/services/providers/openai/responsesParser.d.ts.map +1 -1
  29. package/dist/cjs/services/providers/openai/responsesParser.js +71 -6
  30. package/dist/cjs/services/providers/openai/responsesParser.js.map +1 -1
  31. package/dist/cjs/services/providers/xai/XAIChatServiceProvider.d.ts.map +1 -1
  32. package/dist/cjs/services/providers/xai/XAIChatServiceProvider.js +1 -0
  33. package/dist/cjs/services/providers/xai/XAIChatServiceProvider.js.map +1 -1
  34. package/dist/esm/backend.d.ts +20 -0
  35. package/dist/esm/backend.d.ts.map +1 -0
  36. package/dist/esm/backend.js +111 -0
  37. package/dist/esm/backend.js.map +1 -0
  38. package/dist/esm/constants/xai.d.ts +6 -1
  39. package/dist/esm/constants/xai.d.ts.map +1 -1
  40. package/dist/esm/constants/xai.js +27 -6
  41. package/dist/esm/constants/xai.js.map +1 -1
  42. package/dist/esm/index.d.ts +1 -0
  43. package/dist/esm/index.d.ts.map +1 -1
  44. package/dist/esm/index.js +1 -0
  45. package/dist/esm/index.js.map +1 -1
  46. package/dist/esm/services/ChatServiceFactory.d.ts.map +1 -1
  47. package/dist/esm/services/ChatServiceFactory.js +9 -18
  48. package/dist/esm/services/ChatServiceFactory.js.map +1 -1
  49. package/dist/esm/services/providers/gemini/GeminiChatService.d.ts.map +1 -1
  50. package/dist/esm/services/providers/gemini/GeminiChatService.js +4 -1
  51. package/dist/esm/services/providers/gemini/GeminiChatService.js.map +1 -1
  52. package/dist/esm/services/providers/gemini/geminiMessageConverter.d.ts +5 -0
  53. package/dist/esm/services/providers/gemini/geminiMessageConverter.d.ts.map +1 -1
  54. package/dist/esm/services/providers/gemini/geminiMessageConverter.js +15 -0
  55. package/dist/esm/services/providers/gemini/geminiMessageConverter.js.map +1 -1
  56. package/dist/esm/services/providers/openai/openaiRequestBuilder.d.ts.map +1 -1
  57. package/dist/esm/services/providers/openai/openaiRequestBuilder.js +27 -5
  58. package/dist/esm/services/providers/openai/openaiRequestBuilder.js.map +1 -1
  59. package/dist/esm/services/providers/openai/responsesParser.d.ts.map +1 -1
  60. package/dist/esm/services/providers/openai/responsesParser.js +71 -6
  61. package/dist/esm/services/providers/openai/responsesParser.js.map +1 -1
  62. package/dist/esm/services/providers/xai/XAIChatServiceProvider.d.ts.map +1 -1
  63. package/dist/esm/services/providers/xai/XAIChatServiceProvider.js +2 -1
  64. package/dist/esm/services/providers/xai/XAIChatServiceProvider.js.map +1 -1
  65. package/dist/umd/aituber-onair-chat.js +249 -32
  66. package/dist/umd/aituber-onair-chat.min.js +9 -9
  67. package/package.json +6 -1
@@ -159,6 +159,7 @@ var AITuberOnAirChat = (() => {
159
159
  MODEL_GROK_4_20_REASONING: () => MODEL_GROK_4_20_REASONING,
160
160
  MODEL_GROK_4_3: () => MODEL_GROK_4_3,
161
161
  MODEL_GROK_4_5: () => MODEL_GROK_4_5,
162
+ MODEL_GROK_4_6: () => MODEL_GROK_4_6,
162
163
  MODEL_KIMI_K2_5: () => MODEL_KIMI_K2_5,
163
164
  MODEL_KIMI_K2_6: () => MODEL_KIMI_K2_6,
164
165
  MODEL_KIMI_K2_7_CODE: () => MODEL_KIMI_K2_7_CODE,
@@ -244,6 +245,8 @@ var AITuberOnAirChat = (() => {
244
245
  allowsReasoningNone: () => allowsReasoningNone,
245
246
  allowsReasoningXHigh: () => allowsReasoningXHigh,
246
247
  buildOpenAICompatibleTools: () => buildOpenAICompatibleTools,
248
+ buildToolContinuationMessages: () => buildToolContinuationMessages,
249
+ getChatBackendProviderCapabilities: () => getChatBackendProviderCapabilities,
247
250
  getClaudeSupportedReasoningEfforts: () => getClaudeSupportedReasoningEfforts,
248
251
  getDeepSeekSupportedReasoningEfforts: () => getDeepSeekSupportedReasoningEfforts,
249
252
  getDefaultClaudeReasoningEffort: () => getDefaultClaudeReasoningEffort,
@@ -257,6 +260,7 @@ var AITuberOnAirChat = (() => {
257
260
  getKimiSupportedReasoningEfforts: () => getKimiSupportedReasoningEfforts,
258
261
  getMaxTokensForResponseLength: () => getMaxTokensForResponseLength,
259
262
  getOpenRouterSupportedReasoningEfforts: () => getOpenRouterSupportedReasoningEfforts,
263
+ getXaiSupportedReasoningEfforts: () => getXaiSupportedReasoningEfforts,
260
264
  installGASFetch: () => installGASFetch,
261
265
  isClaudeReasoningEffortModel: () => isClaudeReasoningEffortModel,
262
266
  isDeepSeekReasoningEffortModel: () => isDeepSeekReasoningEffortModel,
@@ -738,6 +742,7 @@ var AITuberOnAirChat = (() => {
738
742
 
739
743
  // src/constants/xai.ts
740
744
  var ENDPOINT_XAI_CHAT_COMPLETIONS_API = "https://api.x.ai/v1/chat/completions";
745
+ var MODEL_GROK_4_6 = "grok-4.6";
741
746
  var MODEL_GROK_4_5 = "grok-4.5";
742
747
  var MODEL_GROK_4_3 = "grok-4.3";
743
748
  var MODEL_GROK_4_20_REASONING = "grok-4.20-0309-reasoning";
@@ -745,6 +750,7 @@ var AITuberOnAirChat = (() => {
745
750
  var MODEL_GROK_4_1_FAST_REASONING = "grok-4-1-fast-reasoning";
746
751
  var MODEL_GROK_4_1_FAST_NON_REASONING = "grok-4-1-fast-non-reasoning";
747
752
  var XAI_VISION_SUPPORTED_MODELS = [
753
+ MODEL_GROK_4_6,
748
754
  MODEL_GROK_4_5,
749
755
  MODEL_GROK_4_3,
750
756
  MODEL_GROK_4_20_REASONING,
@@ -756,13 +762,25 @@ var AITuberOnAirChat = (() => {
756
762
  return XAI_VISION_SUPPORTED_MODELS.includes(model);
757
763
  }
758
764
  function isXaiReasoningEffortModel(model) {
759
- return model === MODEL_GROK_4_5 || model === MODEL_GROK_4_3;
765
+ return getXaiSupportedReasoningEfforts(model).length > 0;
766
+ }
767
+ function getXaiSupportedReasoningEfforts(model) {
768
+ if (model === MODEL_GROK_4_6) {
769
+ return ["low", "medium", "high", "xhigh"];
770
+ }
771
+ if (model === MODEL_GROK_4_5) {
772
+ return ["low", "medium", "high"];
773
+ }
774
+ if (model === MODEL_GROK_4_3) {
775
+ return ["none", "low", "medium", "high"];
776
+ }
777
+ return [];
760
778
  }
761
779
  function isXaiReasoningEffortNoneModel(model) {
762
- return model === MODEL_GROK_4_3;
780
+ return getXaiSupportedReasoningEfforts(model).includes("none");
763
781
  }
764
782
  function getDefaultXaiReasoningEffort(model) {
765
- if (model === MODEL_GROK_4_5) {
783
+ if (model === MODEL_GROK_4_6 || model === MODEL_GROK_4_5) {
766
784
  return "low";
767
785
  }
768
786
  return isXaiReasoningEffortNoneModel(model) ? "none" : void 0;
@@ -771,10 +789,14 @@ var AITuberOnAirChat = (() => {
771
789
  if (!isXaiReasoningEffortModel(model)) {
772
790
  return void 0;
773
791
  }
774
- if (reasoningEffort === "none" && !isXaiReasoningEffortNoneModel(model)) {
775
- return "low";
792
+ if (reasoningEffort === void 0) {
793
+ return getDefaultXaiReasoningEffort(model);
794
+ }
795
+ const supported = getXaiSupportedReasoningEfforts(model);
796
+ if (supported.includes(reasoningEffort)) {
797
+ return reasoningEffort;
776
798
  }
777
- return reasoningEffort ?? getDefaultXaiReasoningEffort(model);
799
+ return reasoningEffort === "none" ? "low" : "high";
778
800
  }
779
801
 
780
802
  // src/constants/kimi.ts
@@ -2294,6 +2316,7 @@ If it's in another language, summarize in that language.
2294
2316
  const dec = new TextDecoder();
2295
2317
  const textBlocks = [];
2296
2318
  const toolCallsMap = /* @__PURE__ */ new Map();
2319
+ const providerItems = /* @__PURE__ */ new Map();
2297
2320
  let responseStatus;
2298
2321
  let incompleteDetails;
2299
2322
  let usage;
@@ -2321,7 +2344,7 @@ If it's in another language, summarize in that language.
2321
2344
  onPartial,
2322
2345
  textBlocks,
2323
2346
  toolCallsMap,
2324
- options,
2347
+ providerItems,
2325
2348
  (metadata) => {
2326
2349
  if (metadata.responseStatus !== void 0) {
2327
2350
  responseStatus = metadata.responseStatus;
@@ -2348,21 +2371,31 @@ If it's in another language, summarize in that language.
2348
2371
  type: "tool_use",
2349
2372
  id: tool.id,
2350
2373
  name: tool.name,
2351
- input: tool.input || {}
2374
+ input: safeParseToolCallInput(tool.arguments, options.onJsonError)
2352
2375
  })
2353
2376
  );
2377
+ const providerContent = Array.from(providerItems.values());
2378
+ const text = StreamTextAccumulator.getFullText(textBlocks);
2354
2379
  return {
2355
2380
  blocks: [...textBlocks, ...toolBlocks],
2356
2381
  stop_reason: toolBlocks.length ? "tool_use" : "end",
2357
2382
  truncated: responseStatus === "incomplete",
2358
2383
  response_status: responseStatus,
2359
2384
  incomplete_details: incompleteDetails,
2360
- usage
2385
+ usage,
2386
+ ...providerContent.length > 0 ? {
2387
+ assistant_message: {
2388
+ role: "assistant",
2389
+ content: text,
2390
+ provider_content: providerContent
2391
+ }
2392
+ } : {}
2361
2393
  };
2362
2394
  }
2363
- function handleResponsesSSEEvent(eventType, data, onPartial, textBlocks, toolCallsMap, options, onMetadata) {
2395
+ function handleResponsesSSEEvent(eventType, data, onPartial, textBlocks, toolCallsMap, providerItems, onMetadata) {
2364
2396
  switch (eventType) {
2365
2397
  case "response.output_item.added":
2398
+ rememberProviderItem(providerItems, data.item);
2366
2399
  if (data.item?.type === "message" && Array.isArray(data.item.content)) {
2367
2400
  data.item.content.forEach((c) => {
2368
2401
  if (c.type === "output_text" && c.text) {
@@ -2372,12 +2405,41 @@ If it's in another language, summarize in that language.
2372
2405
  });
2373
2406
  } else if (data.item?.type === "function_call") {
2374
2407
  toolCallsMap.set(data.item.id, {
2375
- id: data.item.id,
2408
+ id: data.item.call_id ?? data.item.id,
2376
2409
  name: data.item.name,
2377
- input: safeParseToolCallInput(
2378
- data.item.arguments,
2379
- options.onJsonError
2380
- )
2410
+ arguments: data.item.arguments ?? ""
2411
+ });
2412
+ }
2413
+ break;
2414
+ case "response.function_call_arguments.delta": {
2415
+ const tool = toolCallsMap.get(data.item_id);
2416
+ if (tool && typeof data.delta === "string") {
2417
+ tool.arguments += data.delta;
2418
+ }
2419
+ const item = providerItems.get(data.item_id);
2420
+ if (item && typeof data.delta === "string") {
2421
+ item.arguments = `${item.arguments ?? ""}${data.delta}`;
2422
+ }
2423
+ break;
2424
+ }
2425
+ case "response.function_call_arguments.done": {
2426
+ const tool = toolCallsMap.get(data.item_id);
2427
+ if (tool && typeof data.arguments === "string") {
2428
+ tool.arguments = data.arguments;
2429
+ }
2430
+ const item = providerItems.get(data.item_id);
2431
+ if (item && typeof data.arguments === "string") {
2432
+ item.arguments = data.arguments;
2433
+ }
2434
+ break;
2435
+ }
2436
+ case "response.output_item.done":
2437
+ rememberProviderItem(providerItems, data.item);
2438
+ if (data.item?.type === "function_call") {
2439
+ toolCallsMap.set(data.item.id, {
2440
+ id: data.item.call_id ?? data.item.id,
2441
+ name: data.item.name,
2442
+ arguments: data.item.arguments ?? ""
2381
2443
  });
2382
2444
  }
2383
2445
  break;
@@ -2412,6 +2474,11 @@ If it's in another language, summarize in that language.
2412
2474
  break;
2413
2475
  }
2414
2476
  }
2477
+ function rememberProviderItem(items, item) {
2478
+ if (!item || typeof item !== "object") return;
2479
+ const key = typeof item.id === "string" && item.id ? item.id : `output-item-${items.size}`;
2480
+ items.set(key, { ...item });
2481
+ }
2415
2482
  function extractResponsesMetadata(data, fallbackStatus) {
2416
2483
  const response = data?.response ?? data;
2417
2484
  return {
@@ -2434,7 +2501,7 @@ If it's in another language, summarize in that language.
2434
2501
  if (outputItem.type === "function_call") {
2435
2502
  blocks.push({
2436
2503
  type: "tool_use",
2437
- id: outputItem.id,
2504
+ id: outputItem.call_id ?? outputItem.id,
2438
2505
  name: outputItem.name,
2439
2506
  input: safeParseToolCallInput(
2440
2507
  outputItem.arguments,
@@ -2450,7 +2517,16 @@ If it's in another language, summarize in that language.
2450
2517
  truncated: data?.status === "incomplete",
2451
2518
  response_status: data?.status,
2452
2519
  incomplete_details: data?.incomplete_details ?? null,
2453
- usage: data?.usage
2520
+ usage: data?.usage,
2521
+ ...Array.isArray(data?.output) && data.output.length > 0 ? {
2522
+ assistant_message: {
2523
+ role: "assistant",
2524
+ content: blocks.filter(
2525
+ (block) => block.type === "text"
2526
+ ).map((block) => block.text).join(""),
2527
+ provider_content: data.output
2528
+ }
2529
+ } : {}
2454
2530
  };
2455
2531
  }
2456
2532
 
@@ -2669,10 +2745,22 @@ If it's in another language, summarize in that language.
2669
2745
  }
2670
2746
  }
2671
2747
  function cleanMessagesForResponsesAPI(messages) {
2672
- return messages.map((msg) => {
2673
- const role = msg.role === "tool" ? "user" : msg.role;
2748
+ return messages.flatMap((msg) => {
2749
+ if (msg.role === "assistant" && msg.provider_content?.length) {
2750
+ return msg.provider_content;
2751
+ }
2752
+ if (msg.role === "tool" && msg.tool_call_id) {
2753
+ return [
2754
+ {
2755
+ type: "function_call_output",
2756
+ call_id: msg.tool_call_id,
2757
+ output: msg.content
2758
+ }
2759
+ ];
2760
+ }
2761
+ const items = [];
2674
2762
  const cleanMsg = {
2675
- role
2763
+ role: msg.role === "tool" ? "user" : msg.role
2676
2764
  };
2677
2765
  if (typeof msg.content === "string") {
2678
2766
  cleanMsg.content = msg.content;
@@ -2694,7 +2782,19 @@ If it's in another language, summarize in that language.
2694
2782
  } else {
2695
2783
  cleanMsg.content = msg.content;
2696
2784
  }
2697
- return cleanMsg;
2785
+ const hasContent = typeof cleanMsg.content !== "string" || cleanMsg.content.length > 0;
2786
+ if (hasContent) items.push(cleanMsg);
2787
+ if (msg.role === "assistant" && msg.tool_calls) {
2788
+ items.push(
2789
+ ...msg.tool_calls.map((call) => ({
2790
+ type: "function_call",
2791
+ call_id: call.id,
2792
+ name: call.function.name,
2793
+ arguments: call.function.arguments
2794
+ }))
2795
+ );
2796
+ }
2797
+ return items;
2698
2798
  });
2699
2799
  }
2700
2800
  function cleanMessagesForMistralChatCompletions(messages) {
@@ -3130,6 +3230,7 @@ If it's in another language, summarize in that language.
3130
3230
  currentRole = null;
3131
3231
  };
3132
3232
  for (const msg of messages) {
3233
+ if (msg.role === "system") continue;
3133
3234
  const role = mapRoleToGemini(msg.role);
3134
3235
  if (msg.tool_calls) {
3135
3236
  pushCurrent();
@@ -3173,6 +3274,7 @@ If it's in another language, summarize in that language.
3173
3274
  currentRole = null;
3174
3275
  };
3175
3276
  for (const msg of messages) {
3277
+ if (msg.role === "system") continue;
3176
3278
  const role = mapRoleToGemini(msg.role);
3177
3279
  if (msg.tool_calls) {
3178
3280
  pushCurrent();
@@ -3227,6 +3329,18 @@ If it's in another language, summarize in that language.
3227
3329
  pushCurrent();
3228
3330
  return geminiMessages;
3229
3331
  }
3332
+ function extractGeminiSystemInstruction(messages) {
3333
+ const parts = messages.flatMap((message) => {
3334
+ if (message.role !== "system") return [];
3335
+ if (typeof message.content === "string") {
3336
+ return message.content ? [{ text: message.content }] : [];
3337
+ }
3338
+ return message.content.flatMap(
3339
+ (block) => block.type === "text" && block.text ? [{ text: block.text }] : []
3340
+ );
3341
+ });
3342
+ return parts.length > 0 ? { parts } : void 0;
3343
+ }
3230
3344
  function createFunctionCallPart(call, options) {
3231
3345
  options.callIdMap?.set(call.id, call.function.name);
3232
3346
  const context = options.functionCallContextMap?.get(call.id);
@@ -3569,6 +3683,8 @@ If it's in another language, summarize in that language.
3569
3683
  maxOutputTokens: maxTokens !== void 0 ? maxTokens : getMaxTokensForResponseLength(this.responseLength)
3570
3684
  }
3571
3685
  };
3686
+ const systemInstruction = extractGeminiSystemInstruction(messages);
3687
+ if (systemInstruction) body.systemInstruction = systemInstruction;
3572
3688
  const thinkingConfig = this.resolveThinkingConfig(model);
3573
3689
  if (thinkingConfig) {
3574
3690
  body.generationConfig.thinkingConfig = thinkingConfig;
@@ -5507,6 +5623,7 @@ If it's in another language, summarize in that language.
5507
5623
  */
5508
5624
  getSupportedModels() {
5509
5625
  return [
5626
+ MODEL_GROK_4_6,
5510
5627
  MODEL_GROK_4_5,
5511
5628
  MODEL_GROK_4_3,
5512
5629
  MODEL_GROK_4_20_REASONING,
@@ -5805,21 +5922,120 @@ If it's in another language, summarize in that language.
5805
5922
  new PlamoChatServiceProvider()
5806
5923
  ];
5807
5924
 
5808
- // src/services/ChatServiceFactory.ts
5809
- var TOOL_SUPPORTED_PROVIDERS = /* @__PURE__ */ new Set([
5925
+ // src/backend.ts
5926
+ var KNOWN_CHAT_PROVIDERS = /* @__PURE__ */ new Set([
5927
+ "claude",
5928
+ "claude-agent-sdk",
5929
+ "codex-sdk",
5930
+ "copilot-sdk",
5931
+ "deepseek",
5932
+ "gemini",
5933
+ "gemini-nano",
5934
+ "kimi",
5935
+ "mistral",
5810
5936
  "openai",
5811
5937
  "openai-compatible",
5812
5938
  "openrouter",
5813
- "gemini",
5814
- "claude",
5815
- "zai",
5939
+ "plamo",
5940
+ "sakana",
5816
5941
  "xai",
5817
- "kimi",
5942
+ "zai"
5943
+ ]);
5944
+ var TOOL_SUPPORTED_PROVIDERS = /* @__PURE__ */ new Set([
5945
+ "claude",
5818
5946
  "deepseek",
5947
+ "gemini",
5948
+ "kimi",
5819
5949
  "mistral",
5950
+ "openai",
5951
+ "openai-compatible",
5952
+ "openrouter",
5953
+ "plamo",
5820
5954
  "sakana",
5821
- "plamo"
5955
+ "xai",
5956
+ "zai"
5822
5957
  ]);
5958
+ var NON_STREAMING_PROVIDERS = /* @__PURE__ */ new Set(["codex-sdk"]);
5959
+ function getChatBackendProviderCapabilities(provider) {
5960
+ if (!KNOWN_CHAT_PROVIDERS.has(provider)) return void 0;
5961
+ return {
5962
+ text: true,
5963
+ streaming: !NON_STREAMING_PROVIDERS.has(provider),
5964
+ tools: TOOL_SUPPORTED_PROVIDERS.has(provider)
5965
+ };
5966
+ }
5967
+ function buildToolContinuationMessages(input) {
5968
+ const isClaude = input.provider === "claude";
5969
+ const messages = input.messages.filter(
5970
+ (message) => !isEmptyClaudeAssistantMessage(isClaude, message)
5971
+ );
5972
+ const toolUses = input.completion.blocks.filter(
5973
+ (block) => block.type === "tool_use"
5974
+ );
5975
+ const assistantMessage = input.completion.assistant_message ?? buildAssistantToolCall(isClaude, toolUses);
5976
+ if (!isEmptyClaudeAssistantMessage(isClaude, assistantMessage)) {
5977
+ messages.push({ ...assistantMessage });
5978
+ }
5979
+ messages.push(...buildToolResultMessages(isClaude, input.toolResults));
5980
+ return messages;
5981
+ }
5982
+ function isEmptyClaudeAssistantMessage(isClaude, message) {
5983
+ if (!isClaude || message.role !== "assistant") {
5984
+ return false;
5985
+ }
5986
+ const content = message.content;
5987
+ return Array.isArray(content) && content.length === 0;
5988
+ }
5989
+ function buildAssistantToolCall(isClaude, toolUses) {
5990
+ if (isClaude) {
5991
+ return {
5992
+ role: "assistant",
5993
+ content: toolUses.map((toolUse) => ({
5994
+ type: "tool_use",
5995
+ id: toolUse.id,
5996
+ name: toolUse.name,
5997
+ input: toolUse.input ?? {}
5998
+ }))
5999
+ };
6000
+ }
6001
+ return {
6002
+ role: "assistant",
6003
+ content: [],
6004
+ tool_calls: toolUses.map((toolUse) => ({
6005
+ id: toolUse.id,
6006
+ type: "function",
6007
+ function: {
6008
+ name: toolUse.name,
6009
+ arguments: JSON.stringify(toolUse.input ?? {})
6010
+ }
6011
+ }))
6012
+ };
6013
+ }
6014
+ function buildToolResultMessages(isClaude, toolResults) {
6015
+ if (isClaude) {
6016
+ return toolResults.map(
6017
+ (result) => ({
6018
+ role: "user",
6019
+ content: [
6020
+ {
6021
+ type: "tool_result",
6022
+ tool_use_id: result.tool_use_id,
6023
+ content: result.content
6024
+ }
6025
+ ]
6026
+ })
6027
+ );
6028
+ }
6029
+ return toolResults.map(
6030
+ (result) => ({
6031
+ role: "tool",
6032
+ tool_call_id: result.tool_use_id,
6033
+ content: result.content
6034
+ })
6035
+ );
6036
+ }
6037
+
6038
+ // src/services/ChatServiceFactory.ts
5823
6039
  var MCP_SUPPORTED_PROVIDERS = /* @__PURE__ */ new Set(["openai", "gemini", "claude"]);
5824
6040
  var JSON_MODE_SUPPORTED_PROVIDERS = /* @__PURE__ */ new Set([
5825
6041
  "openai",
@@ -5835,7 +6051,7 @@ If it's in another language, summarize in that language.
5835
6051
  kimi: ["low", "high", "max"],
5836
6052
  mistral: ["low", "medium", "high"],
5837
6053
  plamo: ["none", "medium"],
5838
- xai: ["none", "low", "medium", "high"],
6054
+ xai: ["none", "low", "medium", "high", "xhigh"],
5839
6055
  deepseek: ["none", "low", "high", "max"]
5840
6056
  };
5841
6057
  var ChatServiceFactory = class {
@@ -5885,18 +6101,19 @@ If it's in another language, summarize in that language.
5885
6101
  return void 0;
5886
6102
  }
5887
6103
  const vision = model ? this.getVisionSupportLevelForModel(providerName, model) : provider.getVisionSupportLevel();
6104
+ const backendCapabilities = getChatBackendProviderCapabilities(providerName);
5888
6105
  return {
5889
6106
  provider: providerName,
5890
6107
  models: provider.getSupportedModels(),
5891
6108
  defaultModel: typeof provider.getDefaultModel === "function" ? provider.getDefaultModel() : void 0,
5892
6109
  text: true,
5893
- streaming: true,
6110
+ streaming: backendCapabilities?.streaming ?? true,
5894
6111
  vision,
5895
- tools: TOOL_SUPPORTED_PROVIDERS.has(providerName),
6112
+ tools: backendCapabilities?.tools ?? false,
5896
6113
  mcp: MCP_SUPPORTED_PROVIDERS.has(providerName),
5897
6114
  jsonMode: JSON_MODE_SUPPORTED_PROVIDERS.has(providerName),
5898
6115
  responseLength: true,
5899
- reasoningEffort: providerName === "claude" && model ? [...getClaudeSupportedReasoningEfforts(model)] : providerName === "kimi" && model ? [...getKimiSupportedReasoningEfforts(model)] : providerName === "deepseek" && model ? [...getDeepSeekSupportedReasoningEfforts(model)] : providerName === "openrouter" && model ? [...getOpenRouterSupportedReasoningEfforts(model)] : REASONING_EFFORT_BY_PROVIDER[providerName] ?? []
6116
+ reasoningEffort: providerName === "claude" && model ? [...getClaudeSupportedReasoningEfforts(model)] : providerName === "kimi" && model ? [...getKimiSupportedReasoningEfforts(model)] : providerName === "deepseek" && model ? [...getDeepSeekSupportedReasoningEfforts(model)] : providerName === "openrouter" && model ? [...getOpenRouterSupportedReasoningEfforts(model)] : providerName === "xai" && model ? [...getXaiSupportedReasoningEfforts(model)] : REASONING_EFFORT_BY_PROVIDER[providerName] ?? []
5900
6117
  };
5901
6118
  }
5902
6119
  /**