@aituber-onair/chat 0.21.1 → 0.22.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 +63 -2
  2. package/README.md +62 -1
  3. package/dist/cjs/index.d.ts +1 -1
  4. package/dist/cjs/index.d.ts.map +1 -1
  5. package/dist/cjs/index.js.map +1 -1
  6. package/dist/cjs/services/ChatServiceFactory.d.ts +9 -1
  7. package/dist/cjs/services/ChatServiceFactory.d.ts.map +1 -1
  8. package/dist/cjs/services/ChatServiceFactory.js +25 -0
  9. package/dist/cjs/services/ChatServiceFactory.js.map +1 -1
  10. package/dist/cjs/services/providers/ChatServiceProvider.d.ts +18 -1
  11. package/dist/cjs/services/providers/ChatServiceProvider.d.ts.map +1 -1
  12. package/dist/cjs/services/providers/claude/ClaudeChatServiceProvider.d.ts +3 -1
  13. package/dist/cjs/services/providers/claude/ClaudeChatServiceProvider.d.ts.map +1 -1
  14. package/dist/cjs/services/providers/claude/ClaudeChatServiceProvider.js +7 -1
  15. package/dist/cjs/services/providers/claude/ClaudeChatServiceProvider.js.map +1 -1
  16. package/dist/cjs/services/providers/gemini/GeminiChatServiceProvider.d.ts +3 -1
  17. package/dist/cjs/services/providers/gemini/GeminiChatServiceProvider.d.ts.map +1 -1
  18. package/dist/cjs/services/providers/gemini/GeminiChatServiceProvider.js +7 -1
  19. package/dist/cjs/services/providers/gemini/GeminiChatServiceProvider.js.map +1 -1
  20. package/dist/cjs/services/providers/kimi/KimiChatServiceProvider.d.ts +3 -1
  21. package/dist/cjs/services/providers/kimi/KimiChatServiceProvider.d.ts.map +1 -1
  22. package/dist/cjs/services/providers/kimi/KimiChatServiceProvider.js +7 -1
  23. package/dist/cjs/services/providers/kimi/KimiChatServiceProvider.js.map +1 -1
  24. package/dist/cjs/services/providers/openai/OpenAIChatService.d.ts +2 -0
  25. package/dist/cjs/services/providers/openai/OpenAIChatService.d.ts.map +1 -1
  26. package/dist/cjs/services/providers/openai/OpenAIChatService.js +69 -9
  27. package/dist/cjs/services/providers/openai/OpenAIChatService.js.map +1 -1
  28. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.d.ts +3 -1
  29. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.d.ts.map +1 -1
  30. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.js +7 -1
  31. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.js.map +1 -1
  32. package/dist/cjs/services/providers/openaiCompatible/OpenAICompatibleChatServiceProvider.d.ts +4 -1
  33. package/dist/cjs/services/providers/openaiCompatible/OpenAICompatibleChatServiceProvider.d.ts.map +1 -1
  34. package/dist/cjs/services/providers/openaiCompatible/OpenAICompatibleChatServiceProvider.js +10 -1
  35. package/dist/cjs/services/providers/openaiCompatible/OpenAICompatibleChatServiceProvider.js.map +1 -1
  36. package/dist/cjs/services/providers/openrouter/OpenRouterChatServiceProvider.d.ts +3 -1
  37. package/dist/cjs/services/providers/openrouter/OpenRouterChatServiceProvider.d.ts.map +1 -1
  38. package/dist/cjs/services/providers/openrouter/OpenRouterChatServiceProvider.js +9 -1
  39. package/dist/cjs/services/providers/openrouter/OpenRouterChatServiceProvider.js.map +1 -1
  40. package/dist/cjs/services/providers/zai/ZAIChatServiceProvider.d.ts +3 -1
  41. package/dist/cjs/services/providers/zai/ZAIChatServiceProvider.d.ts.map +1 -1
  42. package/dist/cjs/services/providers/zai/ZAIChatServiceProvider.js +7 -1
  43. package/dist/cjs/services/providers/zai/ZAIChatServiceProvider.js.map +1 -1
  44. package/dist/cjs/types/toolChat.d.ts +8 -0
  45. package/dist/cjs/types/toolChat.d.ts.map +1 -1
  46. package/dist/cjs/utils/openaiCompatibleSse.d.ts.map +1 -1
  47. package/dist/cjs/utils/openaiCompatibleSse.js +16 -1
  48. package/dist/cjs/utils/openaiCompatibleSse.js.map +1 -1
  49. package/dist/esm/index.d.ts +1 -1
  50. package/dist/esm/index.d.ts.map +1 -1
  51. package/dist/esm/index.js.map +1 -1
  52. package/dist/esm/services/ChatServiceFactory.d.ts +9 -1
  53. package/dist/esm/services/ChatServiceFactory.d.ts.map +1 -1
  54. package/dist/esm/services/ChatServiceFactory.js +25 -0
  55. package/dist/esm/services/ChatServiceFactory.js.map +1 -1
  56. package/dist/esm/services/providers/ChatServiceProvider.d.ts +18 -1
  57. package/dist/esm/services/providers/ChatServiceProvider.d.ts.map +1 -1
  58. package/dist/esm/services/providers/claude/ClaudeChatServiceProvider.d.ts +3 -1
  59. package/dist/esm/services/providers/claude/ClaudeChatServiceProvider.d.ts.map +1 -1
  60. package/dist/esm/services/providers/claude/ClaudeChatServiceProvider.js +7 -1
  61. package/dist/esm/services/providers/claude/ClaudeChatServiceProvider.js.map +1 -1
  62. package/dist/esm/services/providers/gemini/GeminiChatServiceProvider.d.ts +3 -1
  63. package/dist/esm/services/providers/gemini/GeminiChatServiceProvider.d.ts.map +1 -1
  64. package/dist/esm/services/providers/gemini/GeminiChatServiceProvider.js +7 -1
  65. package/dist/esm/services/providers/gemini/GeminiChatServiceProvider.js.map +1 -1
  66. package/dist/esm/services/providers/kimi/KimiChatServiceProvider.d.ts +3 -1
  67. package/dist/esm/services/providers/kimi/KimiChatServiceProvider.d.ts.map +1 -1
  68. package/dist/esm/services/providers/kimi/KimiChatServiceProvider.js +7 -1
  69. package/dist/esm/services/providers/kimi/KimiChatServiceProvider.js.map +1 -1
  70. package/dist/esm/services/providers/openai/OpenAIChatService.d.ts +2 -0
  71. package/dist/esm/services/providers/openai/OpenAIChatService.d.ts.map +1 -1
  72. package/dist/esm/services/providers/openai/OpenAIChatService.js +71 -11
  73. package/dist/esm/services/providers/openai/OpenAIChatService.js.map +1 -1
  74. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.d.ts +3 -1
  75. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.d.ts.map +1 -1
  76. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.js +7 -1
  77. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.js.map +1 -1
  78. package/dist/esm/services/providers/openaiCompatible/OpenAICompatibleChatServiceProvider.d.ts +4 -1
  79. package/dist/esm/services/providers/openaiCompatible/OpenAICompatibleChatServiceProvider.d.ts.map +1 -1
  80. package/dist/esm/services/providers/openaiCompatible/OpenAICompatibleChatServiceProvider.js +10 -1
  81. package/dist/esm/services/providers/openaiCompatible/OpenAICompatibleChatServiceProvider.js.map +1 -1
  82. package/dist/esm/services/providers/openrouter/OpenRouterChatServiceProvider.d.ts +3 -1
  83. package/dist/esm/services/providers/openrouter/OpenRouterChatServiceProvider.d.ts.map +1 -1
  84. package/dist/esm/services/providers/openrouter/OpenRouterChatServiceProvider.js +9 -1
  85. package/dist/esm/services/providers/openrouter/OpenRouterChatServiceProvider.js.map +1 -1
  86. package/dist/esm/services/providers/zai/ZAIChatServiceProvider.d.ts +3 -1
  87. package/dist/esm/services/providers/zai/ZAIChatServiceProvider.d.ts.map +1 -1
  88. package/dist/esm/services/providers/zai/ZAIChatServiceProvider.js +7 -1
  89. package/dist/esm/services/providers/zai/ZAIChatServiceProvider.js.map +1 -1
  90. package/dist/esm/types/toolChat.d.ts +8 -0
  91. package/dist/esm/types/toolChat.d.ts.map +1 -1
  92. package/dist/esm/utils/openaiCompatibleSse.d.ts.map +1 -1
  93. package/dist/esm/utils/openaiCompatibleSse.js +16 -1
  94. package/dist/esm/utils/openaiCompatibleSse.js.map +1 -1
  95. package/dist/umd/aituber-onair-chat.js +163 -15
  96. package/dist/umd/aituber-onair-chat.min.js +6 -6
  97. package/package.json +1 -1
@@ -722,11 +722,20 @@ If it's in another language, summarize in that language.
722
722
  async function parseOpenAICompatibleToolStream(res, onPartial, options = {}) {
723
723
  const textBlocks = [];
724
724
  const toolCallsMap = /* @__PURE__ */ new Map();
725
+ let finishReason;
726
+ let usage;
725
727
  const appendTextBlock = options.appendTextBlock ?? StreamTextAccumulator.append;
726
728
  await forEachSsePayload(res, (payload) => {
727
729
  const json = parseJsonPayload(payload, options.onJsonError);
728
730
  if (!json) return;
729
- const delta = json.choices?.[0]?.delta;
731
+ const choice = json.choices?.[0];
732
+ if (typeof choice?.finish_reason === "string") {
733
+ finishReason = choice.finish_reason;
734
+ }
735
+ if (json.usage) {
736
+ usage = json.usage;
737
+ }
738
+ const delta = choice?.delta;
730
739
  if (delta?.content) {
731
740
  onPartial(delta.content);
732
741
  appendTextBlock(textBlocks, delta.content);
@@ -752,7 +761,10 @@ If it's in another language, summarize in that language.
752
761
  const blocks = [...textBlocks, ...toolBlocks];
753
762
  return {
754
763
  blocks,
755
- stop_reason: toolBlocks.length ? "tool_use" : "end"
764
+ stop_reason: toolBlocks.length ? "tool_use" : "end",
765
+ truncated: finishReason === "length",
766
+ finish_reason: finishReason,
767
+ usage
756
768
  };
757
769
  }
758
770
  function parseOpenAICompatibleOneShot(data) {
@@ -772,7 +784,10 @@ If it's in another language, summarize in that language.
772
784
  }
773
785
  return {
774
786
  blocks,
775
- stop_reason: choice?.finish_reason === "tool_calls" || blocks.some((b) => b.type === "tool_use") ? "tool_use" : "end"
787
+ stop_reason: choice?.finish_reason === "tool_calls" || blocks.some((b) => b.type === "tool_use") ? "tool_use" : "end",
788
+ truncated: choice?.finish_reason === "length",
789
+ finish_reason: choice?.finish_reason,
790
+ usage: data?.usage
776
791
  };
777
792
  }
778
793
 
@@ -1552,7 +1567,10 @@ If it's in another language, summarize in that language.
1552
1567
  * @returns Vision support status (true)
1553
1568
  */
1554
1569
  supportsVision() {
1555
- return true;
1570
+ return this.getVisionSupportLevel() !== "unsupported";
1571
+ }
1572
+ getVisionSupportLevel() {
1573
+ return "supported";
1556
1574
  }
1557
1575
  /**
1558
1576
  * Check if a specific model supports vision capabilities
@@ -1562,6 +1580,9 @@ If it's in another language, summarize in that language.
1562
1580
  supportsVisionForModel(model) {
1563
1581
  return CLAUDE_VISION_SUPPORTED_MODELS.includes(model);
1564
1582
  }
1583
+ getVisionSupportLevelForModel(model) {
1584
+ return this.supportsVisionForModel(model) ? "supported" : "unsupported";
1585
+ }
1565
1586
  };
1566
1587
 
1567
1588
  // src/utils/mcpSchemaFetcher.ts
@@ -2308,7 +2329,10 @@ If it's in another language, summarize in that language.
2308
2329
  * @returns Vision support status (true)
2309
2330
  */
2310
2331
  supportsVision() {
2311
- return true;
2332
+ return this.getVisionSupportLevel() !== "unsupported";
2333
+ }
2334
+ getVisionSupportLevel() {
2335
+ return "supported";
2312
2336
  }
2313
2337
  /**
2314
2338
  * Check if a specific model supports vision capabilities
@@ -2318,6 +2342,9 @@ If it's in another language, summarize in that language.
2318
2342
  supportsVisionForModel(model) {
2319
2343
  return GEMINI_VISION_SUPPORTED_MODELS.includes(model);
2320
2344
  }
2345
+ getVisionSupportLevelForModel(model) {
2346
+ return this.supportsVisionForModel(model) ? "supported" : "unsupported";
2347
+ }
2321
2348
  };
2322
2349
 
2323
2350
  // src/services/providers/kimi/KimiChatService.ts
@@ -2544,7 +2571,10 @@ If it's in another language, summarize in that language.
2544
2571
  * Check if this provider supports vision
2545
2572
  */
2546
2573
  supportsVision() {
2547
- return true;
2574
+ return this.getVisionSupportLevel() !== "unsupported";
2575
+ }
2576
+ getVisionSupportLevel() {
2577
+ return "supported";
2548
2578
  }
2549
2579
  /**
2550
2580
  * Check if a specific model supports vision capabilities
@@ -2552,6 +2582,9 @@ If it's in another language, summarize in that language.
2552
2582
  supportsVisionForModel(model) {
2553
2583
  return isKimiVisionModel(model);
2554
2584
  }
2585
+ getVisionSupportLevelForModel(model) {
2586
+ return this.supportsVisionForModel(model) ? "supported" : "unsupported";
2587
+ }
2555
2588
  resolveEndpoint(options) {
2556
2589
  if (options.endpoint) {
2557
2590
  return this.normalizeEndpoint(options.endpoint);
@@ -2571,6 +2604,22 @@ If it's in another language, summarize in that language.
2571
2604
  };
2572
2605
 
2573
2606
  // src/services/providers/openai/OpenAIChatService.ts
2607
+ var GPT5_RESPONSE_LENGTH_MIN_TOKENS = {
2608
+ [CHAT_RESPONSE_LENGTH.VERY_SHORT]: 800,
2609
+ [CHAT_RESPONSE_LENGTH.SHORT]: 1200,
2610
+ [CHAT_RESPONSE_LENGTH.MEDIUM]: 2e3,
2611
+ [CHAT_RESPONSE_LENGTH.LONG]: 3e3,
2612
+ [CHAT_RESPONSE_LENGTH.VERY_LONG]: 8e3,
2613
+ [CHAT_RESPONSE_LENGTH.DEEP]: 25e3
2614
+ };
2615
+ var GPT5_REASONING_MIN_TOKENS = {
2616
+ none: 1200,
2617
+ minimal: 1600,
2618
+ low: 2500,
2619
+ medium: 4e3,
2620
+ high: 8e3,
2621
+ xhigh: 12e3
2622
+ };
2574
2623
  var OpenAIChatService = class {
2575
2624
  /**
2576
2625
  * Constructor
@@ -2742,7 +2791,7 @@ If it's in another language, summarize in that language.
2742
2791
  model,
2743
2792
  stream
2744
2793
  };
2745
- const tokenLimit = maxTokens !== void 0 ? maxTokens : this.provider === "openai-compatible" ? this.responseLength !== void 0 ? getMaxTokensForResponseLength(this.responseLength) : void 0 : getMaxTokensForResponseLength(this.responseLength);
2794
+ const tokenLimit = this.resolveTokenLimit(model, maxTokens);
2746
2795
  if (isResponsesAPI) {
2747
2796
  if (tokenLimit !== void 0) {
2748
2797
  body.max_output_tokens = tokenLimit;
@@ -2797,6 +2846,21 @@ If it's in another language, summarize in that language.
2797
2846
  }
2798
2847
  return body;
2799
2848
  }
2849
+ resolveTokenLimit(model, maxTokens) {
2850
+ if (maxTokens !== void 0) {
2851
+ return maxTokens;
2852
+ }
2853
+ const baseTokenLimit = this.provider === "openai-compatible" ? this.responseLength !== void 0 ? getMaxTokensForResponseLength(this.responseLength) : void 0 : getMaxTokensForResponseLength(this.responseLength);
2854
+ if (this.provider !== "openai" || !isGPT5Model(model) || this.responseLength === void 0) {
2855
+ return baseTokenLimit;
2856
+ }
2857
+ const effectiveReasoningEffort = this.reasoning_effort ?? getDefaultReasoningEffortForGPT5Model(model);
2858
+ return Math.max(
2859
+ baseTokenLimit ?? 0,
2860
+ GPT5_RESPONSE_LENGTH_MIN_TOKENS[this.responseLength],
2861
+ GPT5_REASONING_MIN_TOKENS[effectiveReasoningEffort]
2862
+ );
2863
+ }
2800
2864
  /**
2801
2865
  * Validate MCP servers compatibility with the current endpoint
2802
2866
  */
@@ -2905,6 +2969,9 @@ If it's in another language, summarize in that language.
2905
2969
  const dec = new TextDecoder();
2906
2970
  const textBlocks = [];
2907
2971
  const toolCallsMap = /* @__PURE__ */ new Map();
2972
+ let responseStatus;
2973
+ let incompleteDetails;
2974
+ let usage;
2908
2975
  let buf = "";
2909
2976
  while (true) {
2910
2977
  const { done, value } = await reader.read();
@@ -2928,7 +2995,18 @@ If it's in another language, summarize in that language.
2928
2995
  json,
2929
2996
  onPartial,
2930
2997
  textBlocks,
2931
- toolCallsMap
2998
+ toolCallsMap,
2999
+ (metadata) => {
3000
+ if (metadata.responseStatus !== void 0) {
3001
+ responseStatus = metadata.responseStatus;
3002
+ }
3003
+ if (metadata.incompleteDetails !== void 0) {
3004
+ incompleteDetails = metadata.incompleteDetails;
3005
+ }
3006
+ if (metadata.usage !== void 0) {
3007
+ usage = metadata.usage;
3008
+ }
3009
+ }
2932
3010
  );
2933
3011
  if (completionResult === "completed") {
2934
3012
  }
@@ -2951,14 +3029,18 @@ If it's in another language, summarize in that language.
2951
3029
  const blocks = [...textBlocks, ...toolBlocks];
2952
3030
  return {
2953
3031
  blocks,
2954
- stop_reason: toolBlocks.length ? "tool_use" : "end"
3032
+ stop_reason: toolBlocks.length ? "tool_use" : "end",
3033
+ truncated: responseStatus === "incomplete",
3034
+ response_status: responseStatus,
3035
+ incomplete_details: incompleteDetails,
3036
+ usage
2955
3037
  };
2956
3038
  }
2957
3039
  /**
2958
3040
  * Handle specific SSE events from Responses API
2959
3041
  * @returns 'completed' if the response is completed, undefined otherwise
2960
3042
  */
2961
- handleResponsesSSEEvent(eventType, data, onPartial, textBlocks, toolCallsMap) {
3043
+ handleResponsesSSEEvent(eventType, data, onPartial, textBlocks, toolCallsMap, onMetadata) {
2962
3044
  switch (eventType) {
2963
3045
  // Item addition events
2964
3046
  case "response.output_item.added":
@@ -3001,6 +3083,10 @@ If it's in another language, summarize in that language.
3001
3083
  break;
3002
3084
  // Response completion events
3003
3085
  case "response.completed":
3086
+ onMetadata(this.extractResponsesMetadata(data, "completed"));
3087
+ return "completed";
3088
+ case "response.incomplete":
3089
+ onMetadata(this.extractResponsesMetadata(data, "incomplete"));
3004
3090
  return "completed";
3005
3091
  // GPT-5 reasoning token events (not visible but counted for billing)
3006
3092
  case "response.reasoning.started":
@@ -3012,6 +3098,14 @@ If it's in another language, summarize in that language.
3012
3098
  }
3013
3099
  return void 0;
3014
3100
  }
3101
+ extractResponsesMetadata(data, fallbackStatus) {
3102
+ const response = data?.response ?? data;
3103
+ return {
3104
+ responseStatus: response?.status ?? fallbackStatus,
3105
+ incompleteDetails: response?.incomplete_details ?? null,
3106
+ usage: response?.usage
3107
+ };
3108
+ }
3015
3109
  /**
3016
3110
  * Parse non-streaming response from Responses API
3017
3111
  */
@@ -3038,7 +3132,11 @@ If it's in another language, summarize in that language.
3038
3132
  }
3039
3133
  return {
3040
3134
  blocks,
3041
- stop_reason: blocks.some((b) => b.type === "tool_use") ? "tool_use" : "end"
3135
+ stop_reason: blocks.some((b) => b.type === "tool_use") ? "tool_use" : "end",
3136
+ truncated: data?.status === "incomplete",
3137
+ response_status: data?.status,
3138
+ incomplete_details: data?.incomplete_details ?? null,
3139
+ usage: data?.usage
3042
3140
  };
3043
3141
  }
3044
3142
  };
@@ -3072,7 +3170,16 @@ If it's in another language, summarize in that language.
3072
3170
  return [];
3073
3171
  }
3074
3172
  supportsVision() {
3075
- return false;
3173
+ return this.getVisionSupportLevel() !== "unsupported";
3174
+ }
3175
+ getVisionSupportLevel() {
3176
+ return "unknown";
3177
+ }
3178
+ supportsVisionForModel(_model) {
3179
+ return true;
3180
+ }
3181
+ getVisionSupportLevelForModel(_model) {
3182
+ return "unknown";
3076
3183
  }
3077
3184
  getDefaultModel() {
3078
3185
  return "local-model";
@@ -3195,7 +3302,10 @@ If it's in another language, summarize in that language.
3195
3302
  * @returns Vision support status (true)
3196
3303
  */
3197
3304
  supportsVision() {
3198
- return true;
3305
+ return this.getVisionSupportLevel() !== "unsupported";
3306
+ }
3307
+ getVisionSupportLevel() {
3308
+ return "supported";
3199
3309
  }
3200
3310
  /**
3201
3311
  * Check if a specific model supports vision capabilities
@@ -3205,6 +3315,9 @@ If it's in another language, summarize in that language.
3205
3315
  supportsVisionForModel(model) {
3206
3316
  return VISION_SUPPORTED_MODELS.includes(model);
3207
3317
  }
3318
+ getVisionSupportLevelForModel(model) {
3319
+ return this.supportsVisionForModel(model) ? "supported" : "unsupported";
3320
+ }
3208
3321
  /**
3209
3322
  * Apply GPT-5 specific optimizations to options
3210
3323
  * @param options Original chat service options
@@ -3586,9 +3699,12 @@ If it's in another language, summarize in that language.
3586
3699
  * @returns Vision support status (false - gpt-oss-20b does not support vision)
3587
3700
  */
3588
3701
  supportsVision() {
3702
+ return this.getVisionSupportLevel() !== "unsupported";
3703
+ }
3704
+ getVisionSupportLevel() {
3589
3705
  return this.getSupportedModels().some(
3590
3706
  (model) => this.supportsVisionForModel(model)
3591
- );
3707
+ ) ? "supported" : "unsupported";
3592
3708
  }
3593
3709
  /**
3594
3710
  * Check if a specific model supports vision capabilities
@@ -3598,6 +3714,9 @@ If it's in another language, summarize in that language.
3598
3714
  supportsVisionForModel(model) {
3599
3715
  return isOpenRouterVisionModel(model);
3600
3716
  }
3717
+ getVisionSupportLevelForModel(model) {
3718
+ return this.supportsVisionForModel(model) ? "supported" : "unsupported";
3719
+ }
3601
3720
  /**
3602
3721
  * Get list of free tier models
3603
3722
  * @returns Array of free model names
@@ -3837,7 +3956,10 @@ If it's in another language, summarize in that language.
3837
3956
  * Check if this provider supports vision
3838
3957
  */
3839
3958
  supportsVision() {
3840
- return true;
3959
+ return this.getVisionSupportLevel() !== "unsupported";
3960
+ }
3961
+ getVisionSupportLevel() {
3962
+ return "supported";
3841
3963
  }
3842
3964
  /**
3843
3965
  * Check if a specific model supports vision capabilities
@@ -3845,6 +3967,9 @@ If it's in another language, summarize in that language.
3845
3967
  supportsVisionForModel(model) {
3846
3968
  return isZaiVisionModel(model);
3847
3969
  }
3970
+ getVisionSupportLevelForModel(model) {
3971
+ return this.supportsVisionForModel(model) ? "supported" : "unsupported";
3972
+ }
3848
3973
  };
3849
3974
 
3850
3975
  // src/services/providers/index.ts
@@ -3897,6 +4022,29 @@ If it's in another language, summarize in that language.
3897
4022
  const provider = this.providers.get(providerName);
3898
4023
  return provider ? provider.getSupportedModels() : [];
3899
4024
  }
4025
+ /**
4026
+ * Get provider-level vision support status.
4027
+ */
4028
+ static getVisionSupportLevel(providerName) {
4029
+ const provider = this.providers.get(providerName);
4030
+ return provider ? provider.getVisionSupportLevel() : "unsupported";
4031
+ }
4032
+ /**
4033
+ * Get model-level vision support status.
4034
+ */
4035
+ static getVisionSupportLevelForModel(providerName, model) {
4036
+ const provider = this.providers.get(providerName);
4037
+ if (!provider) {
4038
+ return "unsupported";
4039
+ }
4040
+ if (provider.getVisionSupportLevelForModel) {
4041
+ return provider.getVisionSupportLevelForModel(model);
4042
+ }
4043
+ if (provider.supportsVisionForModel) {
4044
+ return provider.supportsVisionForModel(model) ? "supported" : "unsupported";
4045
+ }
4046
+ return provider.getVisionSupportLevel();
4047
+ }
3900
4048
  };
3901
4049
  /** Map of registered providers */
3902
4050
  ChatServiceFactory.providers = /* @__PURE__ */ new Map();