@aituber-onair/chat 0.37.0 → 0.38.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 (75) hide show
  1. package/README.ja.md +45 -1
  2. package/README.md +44 -1
  3. package/dist/cjs/constants/openai.d.ts +2 -1
  4. package/dist/cjs/constants/openai.d.ts.map +1 -1
  5. package/dist/cjs/constants/openai.js +3 -4
  6. package/dist/cjs/constants/openai.js.map +1 -1
  7. package/dist/cjs/services/providers/gemini/GeminiChatService.d.ts +5 -0
  8. package/dist/cjs/services/providers/gemini/GeminiChatService.d.ts.map +1 -1
  9. package/dist/cjs/services/providers/gemini/GeminiChatService.js +22 -6
  10. package/dist/cjs/services/providers/gemini/GeminiChatService.js.map +1 -1
  11. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.d.ts +6 -0
  12. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.d.ts.map +1 -1
  13. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.js +17 -7
  14. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.js.map +1 -1
  15. package/dist/cjs/services/providers/openai/responsesParser.d.ts +7 -2
  16. package/dist/cjs/services/providers/openai/responsesParser.d.ts.map +1 -1
  17. package/dist/cjs/services/providers/openai/responsesParser.js +9 -7
  18. package/dist/cjs/services/providers/openai/responsesParser.js.map +1 -1
  19. package/dist/cjs/services/providers/openrouter/OpenRouterChatService.d.ts.map +1 -1
  20. package/dist/cjs/services/providers/openrouter/OpenRouterChatService.js +7 -5
  21. package/dist/cjs/services/providers/openrouter/OpenRouterChatService.js.map +1 -1
  22. package/dist/cjs/utils/index.d.ts +1 -0
  23. package/dist/cjs/utils/index.d.ts.map +1 -1
  24. package/dist/cjs/utils/index.js +1 -0
  25. package/dist/cjs/utils/index.js.map +1 -1
  26. package/dist/cjs/utils/mcpSchemaFetcher.d.ts +20 -0
  27. package/dist/cjs/utils/mcpSchemaFetcher.d.ts.map +1 -1
  28. package/dist/cjs/utils/mcpSchemaFetcher.js +60 -44
  29. package/dist/cjs/utils/mcpSchemaFetcher.js.map +1 -1
  30. package/dist/cjs/utils/openaiCompatibleSse.d.ts +3 -2
  31. package/dist/cjs/utils/openaiCompatibleSse.d.ts.map +1 -1
  32. package/dist/cjs/utils/openaiCompatibleSse.js +4 -3
  33. package/dist/cjs/utils/openaiCompatibleSse.js.map +1 -1
  34. package/dist/cjs/utils/safeJsonParse.d.ts +4 -0
  35. package/dist/cjs/utils/safeJsonParse.d.ts.map +1 -0
  36. package/dist/cjs/utils/safeJsonParse.js +21 -0
  37. package/dist/cjs/utils/safeJsonParse.js.map +1 -0
  38. package/dist/esm/constants/openai.d.ts +2 -1
  39. package/dist/esm/constants/openai.d.ts.map +1 -1
  40. package/dist/esm/constants/openai.js +3 -4
  41. package/dist/esm/constants/openai.js.map +1 -1
  42. package/dist/esm/services/providers/gemini/GeminiChatService.d.ts +5 -0
  43. package/dist/esm/services/providers/gemini/GeminiChatService.d.ts.map +1 -1
  44. package/dist/esm/services/providers/gemini/GeminiChatService.js +22 -6
  45. package/dist/esm/services/providers/gemini/GeminiChatService.js.map +1 -1
  46. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.d.ts +6 -0
  47. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.d.ts.map +1 -1
  48. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.js +17 -7
  49. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.js.map +1 -1
  50. package/dist/esm/services/providers/openai/responsesParser.d.ts +7 -2
  51. package/dist/esm/services/providers/openai/responsesParser.d.ts.map +1 -1
  52. package/dist/esm/services/providers/openai/responsesParser.js +9 -7
  53. package/dist/esm/services/providers/openai/responsesParser.js.map +1 -1
  54. package/dist/esm/services/providers/openrouter/OpenRouterChatService.d.ts.map +1 -1
  55. package/dist/esm/services/providers/openrouter/OpenRouterChatService.js +7 -5
  56. package/dist/esm/services/providers/openrouter/OpenRouterChatService.js.map +1 -1
  57. package/dist/esm/utils/index.d.ts +1 -0
  58. package/dist/esm/utils/index.d.ts.map +1 -1
  59. package/dist/esm/utils/index.js +1 -0
  60. package/dist/esm/utils/index.js.map +1 -1
  61. package/dist/esm/utils/mcpSchemaFetcher.d.ts +20 -0
  62. package/dist/esm/utils/mcpSchemaFetcher.d.ts.map +1 -1
  63. package/dist/esm/utils/mcpSchemaFetcher.js +60 -44
  64. package/dist/esm/utils/mcpSchemaFetcher.js.map +1 -1
  65. package/dist/esm/utils/openaiCompatibleSse.d.ts +3 -2
  66. package/dist/esm/utils/openaiCompatibleSse.d.ts.map +1 -1
  67. package/dist/esm/utils/openaiCompatibleSse.js +4 -3
  68. package/dist/esm/utils/openaiCompatibleSse.js.map +1 -1
  69. package/dist/esm/utils/safeJsonParse.d.ts +4 -0
  70. package/dist/esm/utils/safeJsonParse.d.ts.map +1 -0
  71. package/dist/esm/utils/safeJsonParse.js +16 -0
  72. package/dist/esm/utils/safeJsonParse.js.map +1 -0
  73. package/dist/umd/aituber-onair-chat.js +142 -72
  74. package/dist/umd/aituber-onair-chat.min.js +10 -10
  75. package/package.json +1 -1
@@ -0,0 +1,16 @@
1
+ export const safeJsonParse = (payload, fallback, onJsonError) => {
2
+ try {
3
+ return JSON.parse(payload);
4
+ }
5
+ catch (error) {
6
+ onJsonError?.(payload, error);
7
+ return fallback;
8
+ }
9
+ };
10
+ export const safeParseToolCallInput = (payload, onJsonError) => {
11
+ if (!payload) {
12
+ return {};
13
+ }
14
+ return safeJsonParse(payload, {}, onJsonError);
15
+ };
16
+ //# sourceMappingURL=safeJsonParse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safeJsonParse.js","sourceRoot":"","sources":["../../../src/utils/safeJsonParse.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,OAAe,EACf,QAAW,EACX,WAAmC,EAChC,EAAE;IACL,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAM,CAAC;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,WAAW,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC9B,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,OAA2B,EAC3B,WAAmC,EAC9B,EAAE;IACP,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,aAAa,CAAC,OAAO,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC;AACjD,CAAC,CAAC"}
@@ -213,6 +213,8 @@ var AITuberOnAirChat = (() => {
213
213
  refreshOpenRouterFreeModels: () => refreshOpenRouterFreeModels,
214
214
  resolveVisionModel: () => resolveVisionModel,
215
215
  runOnceText: () => runOnceText,
216
+ safeJsonParse: () => safeJsonParse,
217
+ safeParseToolCallInput: () => safeParseToolCallInput,
216
218
  screenplayToText: () => screenplayToText,
217
219
  textToScreenplay: () => textToScreenplay,
218
220
  textsToScreenplay: () => textsToScreenplay
@@ -286,7 +288,7 @@ var AITuberOnAirChat = (() => {
286
288
  return model !== MODEL_GPT_5_4_PRO;
287
289
  }
288
290
  function getDefaultReasoningEffortForGPT5Model(model) {
289
- if (model === MODEL_GPT_5_1 || model === MODEL_GPT_5_4 || model === MODEL_GPT_5_5) {
291
+ if (allowsReasoningNone(model)) {
290
292
  return "none";
291
293
  }
292
294
  return "medium";
@@ -836,6 +838,22 @@ If it's in another language, summarize in that language.
836
838
  return StreamTextAccumulator.getFullText(blocks);
837
839
  }
838
840
 
841
+ // src/utils/safeJsonParse.ts
842
+ var safeJsonParse = (payload, fallback, onJsonError) => {
843
+ try {
844
+ return JSON.parse(payload);
845
+ } catch (error) {
846
+ onJsonError?.(payload, error);
847
+ return fallback;
848
+ }
849
+ };
850
+ var safeParseToolCallInput = (payload, onJsonError) => {
851
+ if (!payload) {
852
+ return {};
853
+ }
854
+ return safeJsonParse(payload, {}, onJsonError);
855
+ };
856
+
839
857
  // src/utils/openaiCompatibleSse.ts
840
858
  var parseJsonPayload = (payload, onJsonError) => {
841
859
  try {
@@ -943,7 +961,7 @@ If it's in another language, summarize in that language.
943
961
  type: "tool_use",
944
962
  id: e.id,
945
963
  name: e.name,
946
- input: JSON.parse(e.args || "{}")
964
+ input: safeParseToolCallInput(e.args, options.onJsonError)
947
965
  }));
948
966
  const blocks = [...textBlocks, ...toolBlocks];
949
967
  return {
@@ -954,7 +972,7 @@ If it's in another language, summarize in that language.
954
972
  usage
955
973
  };
956
974
  }
957
- function parseOpenAICompatibleOneShot(data) {
975
+ function parseOpenAICompatibleOneShot(data, options = {}) {
958
976
  const choice = data?.choices?.[0];
959
977
  const blocks = [];
960
978
  if (choice?.message?.tool_calls?.length) {
@@ -963,7 +981,10 @@ If it's in another language, summarize in that language.
963
981
  type: "tool_use",
964
982
  id: c.id,
965
983
  name: c.function?.name,
966
- input: JSON.parse(c.function?.arguments || "{}")
984
+ input: safeParseToolCallInput(
985
+ c.function?.arguments,
986
+ options.onJsonError
987
+ )
967
988
  })
968
989
  );
969
990
  } else {
@@ -1755,7 +1776,7 @@ If it's in another language, summarize in that language.
1755
1776
  };
1756
1777
 
1757
1778
  // src/services/providers/openai/responsesParser.ts
1758
- async function parseOpenAIResponsesStream(res, onPartial) {
1779
+ async function parseOpenAIResponsesStream(res, onPartial, options = {}) {
1759
1780
  const reader = res.body.getReader();
1760
1781
  const dec = new TextDecoder();
1761
1782
  const textBlocks = [];
@@ -1787,6 +1808,7 @@ If it's in another language, summarize in that language.
1787
1808
  onPartial,
1788
1809
  textBlocks,
1789
1810
  toolCallsMap,
1811
+ options,
1790
1812
  (metadata) => {
1791
1813
  if (metadata.responseStatus !== void 0) {
1792
1814
  responseStatus = metadata.responseStatus;
@@ -1799,7 +1821,8 @@ If it's in another language, summarize in that language.
1799
1821
  }
1800
1822
  }
1801
1823
  );
1802
- } catch {
1824
+ } catch (error) {
1825
+ options.onJsonError?.(eventData, error);
1803
1826
  console.warn("Failed to parse SSE data:", eventData);
1804
1827
  }
1805
1828
  eventType = "";
@@ -1824,7 +1847,7 @@ If it's in another language, summarize in that language.
1824
1847
  usage
1825
1848
  };
1826
1849
  }
1827
- function handleResponsesSSEEvent(eventType, data, onPartial, textBlocks, toolCallsMap, onMetadata) {
1850
+ function handleResponsesSSEEvent(eventType, data, onPartial, textBlocks, toolCallsMap, options, onMetadata) {
1828
1851
  switch (eventType) {
1829
1852
  case "response.output_item.added":
1830
1853
  if (data.item?.type === "message" && Array.isArray(data.item.content)) {
@@ -1838,7 +1861,10 @@ If it's in another language, summarize in that language.
1838
1861
  toolCallsMap.set(data.item.id, {
1839
1862
  id: data.item.id,
1840
1863
  name: data.item.name,
1841
- input: data.item.arguments ? JSON.parse(data.item.arguments) : {}
1864
+ input: safeParseToolCallInput(
1865
+ data.item.arguments,
1866
+ options.onJsonError
1867
+ )
1842
1868
  });
1843
1869
  }
1844
1870
  break;
@@ -1881,7 +1907,7 @@ If it's in another language, summarize in that language.
1881
1907
  usage: response?.usage
1882
1908
  };
1883
1909
  }
1884
- function parseOpenAIResponsesOneShot(data) {
1910
+ function parseOpenAIResponsesOneShot(data, options = {}) {
1885
1911
  const blocks = [];
1886
1912
  if (data.output && Array.isArray(data.output)) {
1887
1913
  data.output.forEach((outputItem) => {
@@ -1897,7 +1923,10 @@ If it's in another language, summarize in that language.
1897
1923
  type: "tool_use",
1898
1924
  id: outputItem.id,
1899
1925
  name: outputItem.name,
1900
- input: outputItem.arguments ? JSON.parse(outputItem.arguments) : {}
1926
+ input: safeParseToolCallInput(
1927
+ outputItem.arguments,
1928
+ options.onJsonError
1929
+ )
1901
1930
  });
1902
1931
  }
1903
1932
  });
@@ -2414,6 +2443,20 @@ If it's in another language, summarize in that language.
2414
2443
  };
2415
2444
 
2416
2445
  // src/utils/mcpSchemaFetcher.ts
2446
+ var createGenericSearchTool = (serverConfig, reason) => ({
2447
+ name: `mcp_${serverConfig.name}_search`,
2448
+ description: reason === "schema-fetch-failed" ? `Search using ${serverConfig.name} MCP server (schema fetch failed)` : `Search using ${serverConfig.name} MCP server`,
2449
+ parameters: {
2450
+ type: "object",
2451
+ properties: {
2452
+ query: {
2453
+ type: "string",
2454
+ description: "Search query"
2455
+ }
2456
+ },
2457
+ required: ["query"]
2458
+ }
2459
+ });
2417
2460
  var MCPSchemaFetcher = class {
2418
2461
  /**
2419
2462
  * Fetch tool schemas from MCP server
@@ -2421,6 +2464,15 @@ If it's in another language, summarize in that language.
2421
2464
  * @returns Array of tool definitions
2422
2465
  */
2423
2466
  static async fetchToolSchemas(serverConfig) {
2467
+ const result = await this.fetchToolSchemasWithStatus(serverConfig);
2468
+ return result.schemas;
2469
+ }
2470
+ /**
2471
+ * Fetch tool schemas from MCP server with failure metadata.
2472
+ * @param serverConfig MCP server configuration
2473
+ * @returns Tool schemas and failure metadata if fallback was used
2474
+ */
2475
+ static async fetchToolSchemasWithStatus(serverConfig) {
2424
2476
  try {
2425
2477
  const headers = {
2426
2478
  "Content-Type": "application/json"
@@ -2435,53 +2487,32 @@ If it's in another language, summarize in that language.
2435
2487
  );
2436
2488
  const toolsData = await response.json();
2437
2489
  if (Array.isArray(toolsData.tools)) {
2438
- return toolsData.tools.map((tool) => ({
2439
- name: `mcp_${serverConfig.name}_${tool.name}`,
2440
- description: tool.description || `Tool from ${serverConfig.name} MCP server`,
2441
- parameters: tool.inputSchema || {
2442
- type: "object",
2443
- properties: {},
2444
- required: []
2445
- }
2446
- }));
2490
+ return {
2491
+ schemas: toolsData.tools.map((tool) => ({
2492
+ name: `mcp_${serverConfig.name}_${tool.name}`,
2493
+ description: tool.description || `Tool from ${serverConfig.name} MCP server`,
2494
+ parameters: tool.inputSchema || {
2495
+ type: "object",
2496
+ properties: {},
2497
+ required: []
2498
+ }
2499
+ })),
2500
+ failures: []
2501
+ };
2447
2502
  }
2448
- return [
2449
- {
2450
- name: `mcp_${serverConfig.name}_search`,
2451
- description: `Search using ${serverConfig.name} MCP server`,
2452
- parameters: {
2453
- type: "object",
2454
- properties: {
2455
- query: {
2456
- type: "string",
2457
- description: "Search query"
2458
- }
2459
- },
2460
- required: ["query"]
2461
- }
2462
- }
2463
- ];
2503
+ return {
2504
+ schemas: [createGenericSearchTool(serverConfig)],
2505
+ failures: []
2506
+ };
2464
2507
  } catch (error) {
2465
2508
  console.warn(
2466
2509
  `Failed to fetch MCP schemas from ${serverConfig.name}:`,
2467
2510
  error
2468
2511
  );
2469
- return [
2470
- {
2471
- name: `mcp_${serverConfig.name}_search`,
2472
- description: `Search using ${serverConfig.name} MCP server (schema fetch failed)`,
2473
- parameters: {
2474
- type: "object",
2475
- properties: {
2476
- query: {
2477
- type: "string",
2478
- description: "Search query"
2479
- }
2480
- },
2481
- required: ["query"]
2482
- }
2483
- }
2484
- ];
2512
+ return {
2513
+ schemas: [createGenericSearchTool(serverConfig, "schema-fetch-failed")],
2514
+ failures: [{ server: serverConfig, error }]
2515
+ };
2485
2516
  }
2486
2517
  }
2487
2518
  /**
@@ -2490,16 +2521,28 @@ If it's in another language, summarize in that language.
2490
2521
  * @returns Array of all tool definitions
2491
2522
  */
2492
2523
  static async fetchAllToolSchemas(mcpServers) {
2524
+ const result = await this.fetchAllToolSchemasWithStatus(mcpServers);
2525
+ return result.schemas;
2526
+ }
2527
+ /**
2528
+ * Fetch all tool schemas from multiple MCP servers with failure metadata.
2529
+ * @param mcpServers Array of MCP server configurations
2530
+ * @returns Array of all tool definitions and failures
2531
+ */
2532
+ static async fetchAllToolSchemasWithStatus(mcpServers) {
2493
2533
  const allSchemas = [];
2534
+ const failures = [];
2494
2535
  for (const server of mcpServers) {
2495
2536
  try {
2496
- const schemas = await this.fetchToolSchemas(server);
2497
- allSchemas.push(...schemas);
2537
+ const result = await this.fetchToolSchemasWithStatus(server);
2538
+ allSchemas.push(...result.schemas);
2539
+ failures.push(...result.failures);
2498
2540
  } catch (error) {
2499
2541
  console.error(`Failed to fetch schemas from ${server.name}:`, error);
2542
+ failures.push({ server, error });
2500
2543
  }
2501
2544
  }
2502
- return allSchemas;
2545
+ return { schemas: allSchemas, failures };
2503
2546
  }
2504
2547
  };
2505
2548
 
@@ -2555,7 +2598,7 @@ If it's in another language, summarize in that language.
2555
2598
  {
2556
2599
  functionResponse: {
2557
2600
  name: funcName,
2558
- response: normalizeToolResult(safeJsonParse(msg.content))
2601
+ response: normalizeToolResult(safeJsonParse2(msg.content))
2559
2602
  }
2560
2603
  }
2561
2604
  ]
@@ -2602,7 +2645,7 @@ If it's in another language, summarize in that language.
2602
2645
  functionResponse: {
2603
2646
  name: funcName,
2604
2647
  response: normalizeToolResult(
2605
- safeJsonParse(msg.content)
2648
+ safeJsonParse2(msg.content)
2606
2649
  )
2607
2650
  }
2608
2651
  }
@@ -2651,7 +2694,7 @@ If it's in another language, summarize in that language.
2651
2694
  }
2652
2695
  return geminiMessages;
2653
2696
  }
2654
- function safeJsonParse(str) {
2697
+ function safeJsonParse2(str) {
2655
2698
  try {
2656
2699
  return JSON.parse(str);
2657
2700
  } catch {
@@ -2810,6 +2853,7 @@ If it's in another language, summarize in that language.
2810
2853
  addMCPServer(serverConfig) {
2811
2854
  this.mcpServers.push(serverConfig);
2812
2855
  this.mcpSchemasInitialized = false;
2856
+ this.mcpSchemaInitializationError = void 0;
2813
2857
  }
2814
2858
  /**
2815
2859
  * Remove MCP server by name
@@ -2820,6 +2864,7 @@ If it's in another language, summarize in that language.
2820
2864
  (server) => server.name !== serverName
2821
2865
  );
2822
2866
  this.mcpSchemasInitialized = false;
2867
+ this.mcpSchemaInitializationError = void 0;
2823
2868
  }
2824
2869
  /**
2825
2870
  * Check if MCP servers are configured
@@ -2828,6 +2873,12 @@ If it's in another language, summarize in that language.
2828
2873
  hasMCPServers() {
2829
2874
  return this.mcpServers.length > 0;
2830
2875
  }
2876
+ /**
2877
+ * Get the last MCP schema initialization error, if schema fallback was used.
2878
+ */
2879
+ getMCPSchemaInitializationError() {
2880
+ return this.mcpSchemaInitializationError;
2881
+ }
2831
2882
  /**
2832
2883
  * Initialize MCP tool schemas by fetching from servers
2833
2884
  * @private
@@ -2840,16 +2891,16 @@ If it's in another language, summarize in that language.
2840
2891
  const timeoutPromise = new Promise(
2841
2892
  (_, reject) => setTimeout(() => reject(new Error("MCP schema fetch timeout")), 5e3)
2842
2893
  );
2843
- const schemasPromise = MCPSchemaFetcher.fetchAllToolSchemas(
2894
+ const schemasPromise = MCPSchemaFetcher.fetchAllToolSchemasWithStatus(
2844
2895
  this.mcpServers
2845
2896
  );
2846
- this.mcpToolSchemas = await Promise.race([
2847
- schemasPromise,
2848
- timeoutPromise
2849
- ]);
2897
+ const result = await Promise.race([schemasPromise, timeoutPromise]);
2898
+ this.mcpToolSchemas = result.schemas;
2850
2899
  this.mcpSchemasInitialized = true;
2900
+ this.mcpSchemaInitializationError = result.failures[0]?.error;
2851
2901
  } catch (error) {
2852
2902
  console.warn("Failed to initialize MCP schemas, using fallback:", error);
2903
+ this.mcpSchemaInitializationError = error;
2853
2904
  this.mcpToolSchemas = createFallbackMCPToolSchemas(this.mcpServers);
2854
2905
  this.mcpSchemasInitialized = true;
2855
2906
  }
@@ -2970,7 +3021,14 @@ If it's in another language, summarize in that language.
2970
3021
  } catch (e) {
2971
3022
  const looksLikeVersionMismatch = /Unknown name|Cannot find field|404/.test(e?.message || "") || e?.status === 404;
2972
3023
  if (!requiresV1beta && looksLikeVersionMismatch) {
2973
- return await fetchOnce("v1beta", this.adaptKeysForApi(body));
3024
+ try {
3025
+ return await fetchOnce("v1beta", this.adaptKeysForApi(body));
3026
+ } catch (fallbackError) {
3027
+ if (fallbackError instanceof Error) {
3028
+ fallbackError.cause = e;
3029
+ }
3030
+ throw fallbackError;
3031
+ }
2974
3032
  }
2975
3033
  throw e;
2976
3034
  }
@@ -3895,28 +3953,38 @@ If it's in another language, summarize in that language.
3895
3953
  }
3896
3954
  /**
3897
3955
  * Normalize reasoning effort to a model-supported value
3956
+ *
3957
+ * Unsupported values are rounded to the nearest supported level instead of
3958
+ * resetting to the model default, so a low-latency request stays low
3959
+ * (e.g. 'minimal' on GPT-5.4 resolves to 'none', not 'medium') and a
3960
+ * high-effort request stays high (e.g. 'xhigh' on GPT-5.1 resolves to
3961
+ * 'high', not 'none').
3898
3962
  */
3899
3963
  normalizeReasoningEffort(modelName, effort) {
3900
3964
  if (!effort) {
3901
3965
  return void 0;
3902
3966
  }
3903
- if (effort === "none" && !allowsReasoningNone(modelName)) {
3904
- return getDefaultReasoningEffortForGPT5Model(modelName);
3905
- }
3906
- if (effort === "minimal" && !allowsReasoningMinimal(modelName)) {
3907
- return getDefaultReasoningEffortForGPT5Model(modelName);
3967
+ if (effort === "none" && !allowsReasoningNone(modelName) || effort === "minimal" && !allowsReasoningMinimal(modelName)) {
3968
+ if (effort === "minimal" && allowsReasoningNone(modelName)) {
3969
+ return "none";
3970
+ }
3971
+ if (effort === "none" && allowsReasoningMinimal(modelName)) {
3972
+ return "minimal";
3973
+ }
3974
+ return allowsReasoningLow(modelName) ? "low" : "medium";
3908
3975
  }
3909
3976
  if (effort === "low" && !allowsReasoningLow(modelName)) {
3910
- return getDefaultReasoningEffortForGPT5Model(modelName);
3977
+ return "medium";
3911
3978
  }
3912
3979
  if (effort === "xhigh" && !allowsReasoningXHigh(modelName)) {
3913
- return getDefaultReasoningEffortForGPT5Model(modelName);
3980
+ return "high";
3914
3981
  }
3915
3982
  return effort;
3916
3983
  }
3917
3984
  };
3918
3985
 
3919
3986
  // src/services/providers/openrouter/OpenRouterChatService.ts
3987
+ var isTokenLimitUnsupportedModel = (model) => model.trim() === MODEL_GPT_OSS_20B_FREE;
3920
3988
  var OpenRouterChatService = class {
3921
3989
  /**
3922
3990
  * Constructor
@@ -4110,10 +4178,12 @@ If it's in another language, summarize in that language.
4110
4178
  stream
4111
4179
  };
4112
4180
  const tokenLimit = maxTokens !== void 0 ? maxTokens : getMaxTokensForResponseLength(this.responseLength);
4113
- if (tokenLimit) {
4181
+ if (tokenLimit && isTokenLimitUnsupportedModel(model)) {
4114
4182
  console.warn(
4115
- `OpenRouter: Token limits are not supported for gpt-oss-20b model due to known issues. Using unlimited tokens instead.`
4183
+ `OpenRouter: Token limits are not supported for ${model} due to known issues. Using unlimited tokens instead.`
4116
4184
  );
4185
+ } else if (tokenLimit) {
4186
+ body.max_tokens = tokenLimit;
4117
4187
  }
4118
4188
  if (this.reasoning_effort !== void 0 || this.includeReasoning !== void 0 || this.reasoningMaxTokens) {
4119
4189
  body.reasoning = {};