@aituber-onair/chat 0.15.0 → 0.17.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 (45) hide show
  1. package/README.ja.md +29 -0
  2. package/README.md +28 -0
  3. package/dist/cjs/constants/openai.d.ts +0 -1
  4. package/dist/cjs/constants/openai.d.ts.map +1 -1
  5. package/dist/cjs/constants/openai.js +1 -4
  6. package/dist/cjs/constants/openai.js.map +1 -1
  7. package/dist/cjs/constants/openrouter.js +1 -1
  8. package/dist/cjs/constants/openrouter.js.map +1 -1
  9. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.d.ts.map +1 -1
  10. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.js +0 -1
  11. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.js.map +1 -1
  12. package/dist/cjs/services/providers/openrouter/OpenRouterChatServiceProvider.d.ts.map +1 -1
  13. package/dist/cjs/services/providers/openrouter/OpenRouterChatServiceProvider.js +1 -1
  14. package/dist/cjs/services/providers/openrouter/OpenRouterChatServiceProvider.js.map +1 -1
  15. package/dist/cjs/utils/index.d.ts +1 -0
  16. package/dist/cjs/utils/index.d.ts.map +1 -1
  17. package/dist/cjs/utils/index.js +1 -0
  18. package/dist/cjs/utils/index.js.map +1 -1
  19. package/dist/cjs/utils/refreshOpenRouterFreeModels.d.ts +25 -0
  20. package/dist/cjs/utils/refreshOpenRouterFreeModels.d.ts.map +1 -0
  21. package/dist/cjs/utils/refreshOpenRouterFreeModels.js +207 -0
  22. package/dist/cjs/utils/refreshOpenRouterFreeModels.js.map +1 -0
  23. package/dist/esm/constants/openai.d.ts +0 -1
  24. package/dist/esm/constants/openai.d.ts.map +1 -1
  25. package/dist/esm/constants/openai.js +0 -3
  26. package/dist/esm/constants/openai.js.map +1 -1
  27. package/dist/esm/constants/openrouter.js +1 -1
  28. package/dist/esm/constants/openrouter.js.map +1 -1
  29. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.d.ts.map +1 -1
  30. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.js +1 -2
  31. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.js.map +1 -1
  32. package/dist/esm/services/providers/openrouter/OpenRouterChatServiceProvider.d.ts.map +1 -1
  33. package/dist/esm/services/providers/openrouter/OpenRouterChatServiceProvider.js +2 -2
  34. package/dist/esm/services/providers/openrouter/OpenRouterChatServiceProvider.js.map +1 -1
  35. package/dist/esm/utils/index.d.ts +1 -0
  36. package/dist/esm/utils/index.d.ts.map +1 -1
  37. package/dist/esm/utils/index.js +1 -0
  38. package/dist/esm/utils/index.js.map +1 -1
  39. package/dist/esm/utils/refreshOpenRouterFreeModels.d.ts +25 -0
  40. package/dist/esm/utils/refreshOpenRouterFreeModels.d.ts.map +1 -0
  41. package/dist/esm/utils/refreshOpenRouterFreeModels.js +204 -0
  42. package/dist/esm/utils/refreshOpenRouterFreeModels.js.map +1 -0
  43. package/dist/umd/aituber-onair-chat.js +210 -7
  44. package/dist/umd/aituber-onair-chat.min.js +6 -6
  45. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { MODEL_GPT_OSS_20B_FREE, MODEL_MOONSHOTAI_KIMI_K2_5, MODEL_OPENAI_GPT_5_1_CHAT, MODEL_OPENAI_GPT_5_1_CODEX, MODEL_OPENAI_GPT_5_MINI, MODEL_OPENAI_GPT_5_NANO, MODEL_OPENAI_GPT_4O, MODEL_OPENAI_GPT_4_1_MINI, MODEL_OPENAI_GPT_4_1_NANO, MODEL_ANTHROPIC_CLAUDE_OPUS_4, MODEL_ANTHROPIC_CLAUDE_SONNET_4, MODEL_ANTHROPIC_CLAUDE_3_7_SONNET, MODEL_ANTHROPIC_CLAUDE_3_5_SONNET, MODEL_ANTHROPIC_CLAUDE_4_5_HAIKU, MODEL_GOOGLE_GEMINI_2_5_PRO, MODEL_GOOGLE_GEMINI_2_5_FLASH, MODEL_GOOGLE_GEMINI_2_5_FLASH_LITE_PREVIEW_09_2025, MODEL_ZAI_GLM_4_7_FLASH, MODEL_ZAI_GLM_4_5_AIR, MODEL_ZAI_GLM_4_5_AIR_FREE, OPENROUTER_FREE_MODELS, isOpenRouterVisionModel, } from '../../../constants/openrouter';
1
+ import { MODEL_GPT_OSS_20B_FREE, MODEL_MOONSHOTAI_KIMI_K2_5, MODEL_OPENAI_GPT_5_1_CHAT, MODEL_OPENAI_GPT_5_1_CODEX, MODEL_OPENAI_GPT_5_MINI, MODEL_OPENAI_GPT_5_NANO, MODEL_OPENAI_GPT_4O, MODEL_OPENAI_GPT_4_1_MINI, MODEL_OPENAI_GPT_4_1_NANO, MODEL_ANTHROPIC_CLAUDE_OPUS_4, MODEL_ANTHROPIC_CLAUDE_SONNET_4, MODEL_ANTHROPIC_CLAUDE_3_7_SONNET, MODEL_ANTHROPIC_CLAUDE_3_5_SONNET, MODEL_ANTHROPIC_CLAUDE_4_5_HAIKU, MODEL_GOOGLE_GEMINI_2_5_PRO, MODEL_GOOGLE_GEMINI_2_5_FLASH, MODEL_GOOGLE_GEMINI_2_5_FLASH_LITE_PREVIEW_09_2025, MODEL_ZAI_GLM_4_7_FLASH, MODEL_ZAI_GLM_4_5_AIR, MODEL_ZAI_GLM_4_5_AIR_FREE, OPENROUTER_FREE_MODELS, isOpenRouterFreeModel, isOpenRouterVisionModel, } from '../../../constants/openrouter';
2
2
  import { OpenRouterChatService } from './OpenRouterChatService';
3
3
  import { resolveVisionModel } from '../../../utils';
4
4
  /**
@@ -106,7 +106,7 @@ export class OpenRouterChatServiceProvider {
106
106
  * @returns True if the model is free
107
107
  */
108
108
  isModelFree(model) {
109
- return OPENROUTER_FREE_MODELS.includes(model) || model.endsWith(':free');
109
+ return isOpenRouterFreeModel(model);
110
110
  }
111
111
  }
112
112
  //# sourceMappingURL=OpenRouterChatServiceProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OpenRouterChatServiceProvider.js","sourceRoot":"","sources":["../../../../../src/services/providers/openrouter/OpenRouterChatServiceProvider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OpenRouterChatServiceProvider.js","sourceRoot":"","sources":["../../../../../src/services/providers/openrouter/OpenRouterChatServiceProvider.ts"],"names":[],"mappings":"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"}
@@ -10,4 +10,5 @@ export * from './openaiCompatibleSse';
10
10
  export * from './openaiCompatibleTools';
11
11
  export * from './processChatFlow';
12
12
  export * from './visionModelResolver';
13
+ export * from './refreshOpenRouterFreeModels';
13
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC"}
@@ -10,4 +10,5 @@ export * from './openaiCompatibleSse';
10
10
  export * from './openaiCompatibleTools';
11
11
  export * from './processChatFlow';
12
12
  export * from './visionModelResolver';
13
+ export * from './refreshOpenRouterFreeModels';
13
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC"}
@@ -0,0 +1,25 @@
1
+ export interface RefreshOpenRouterFreeModelsOptions {
2
+ apiKey: string;
3
+ endpoint?: string;
4
+ modelsEndpoint?: string;
5
+ timeoutMs?: number;
6
+ concurrency?: number;
7
+ maxCandidates?: number;
8
+ maxWorking?: number;
9
+ appName?: string;
10
+ appUrl?: string;
11
+ }
12
+ export interface RefreshOpenRouterFreeModelsFailure {
13
+ id: string;
14
+ reason: string;
15
+ }
16
+ export interface RefreshOpenRouterFreeModelsResult {
17
+ working: string[];
18
+ failed: RefreshOpenRouterFreeModelsFailure[];
19
+ fetchedAt: number;
20
+ }
21
+ /**
22
+ * Fetch currently available OpenRouter free models and probe each model.
23
+ */
24
+ export declare function refreshOpenRouterFreeModels(options: RefreshOpenRouterFreeModelsOptions): Promise<RefreshOpenRouterFreeModelsResult>;
25
+ //# sourceMappingURL=refreshOpenRouterFreeModels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshOpenRouterFreeModels.d.ts","sourceRoot":"","sources":["../../../src/utils/refreshOpenRouterFreeModels.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,kCAAkC;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kCAAkC;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iCAAiC;IAChD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,kCAAkC,EAAE,CAAC;IAC7C,SAAS,EAAE,MAAM,CAAC;CACnB;AA6MD;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,kCAAkC,GAC1C,OAAO,CAAC,iCAAiC,CAAC,CAoE5C"}
@@ -0,0 +1,204 @@
1
+ import { ENDPOINT_OPENROUTER_API, isOpenRouterFreeModel, } from '../constants/openrouter';
2
+ const OPENROUTER_MODELS_ENDPOINT = 'https://openrouter.ai/api/v1/models';
3
+ const DEFAULT_CONCURRENCY = 2;
4
+ const DEFAULT_TIMEOUT_MS = 12000;
5
+ const DEFAULT_MAX_CANDIDATES = 1;
6
+ const DEFAULT_MAX_WORKING = 10;
7
+ function toErrorMessage(error) {
8
+ if (error instanceof Error) {
9
+ return error.message;
10
+ }
11
+ return String(error);
12
+ }
13
+ function normalizeLimit(value, fallback) {
14
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
15
+ return fallback;
16
+ }
17
+ return Math.max(1, Math.floor(value));
18
+ }
19
+ function normalizeModelIds(modelIds) {
20
+ const seen = new Set();
21
+ const normalized = [];
22
+ for (const modelId of modelIds) {
23
+ const trimmed = modelId.trim();
24
+ if (!trimmed || seen.has(trimmed)) {
25
+ continue;
26
+ }
27
+ seen.add(trimmed);
28
+ normalized.push(trimmed);
29
+ }
30
+ return normalized;
31
+ }
32
+ async function fetchWithTimeout(url, init, timeoutMs) {
33
+ const hasAbortController = typeof AbortController !== 'undefined';
34
+ if (!hasAbortController) {
35
+ return fetch(url, init);
36
+ }
37
+ const controller = new AbortController();
38
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
39
+ try {
40
+ return await fetch(url, {
41
+ ...init,
42
+ signal: controller.signal,
43
+ });
44
+ }
45
+ catch (error) {
46
+ if (error instanceof Error && error.name === 'AbortError') {
47
+ throw new Error(`Timeout after ${timeoutMs}ms`);
48
+ }
49
+ throw error;
50
+ }
51
+ finally {
52
+ clearTimeout(timeoutId);
53
+ }
54
+ }
55
+ async function toHttpFailureReason(response) {
56
+ const status = `HTTP ${response.status} ${response.statusText}`.trim();
57
+ let body = '';
58
+ try {
59
+ body = await response.text();
60
+ }
61
+ catch {
62
+ return status;
63
+ }
64
+ const compactBody = body.replace(/\s+/g, ' ').trim().slice(0, 200);
65
+ if (!compactBody) {
66
+ return status;
67
+ }
68
+ return `${status}: ${compactBody}`;
69
+ }
70
+ function extractModelIds(payload) {
71
+ if (!payload || typeof payload !== 'object') {
72
+ throw new Error('Invalid models response shape');
73
+ }
74
+ const response = payload;
75
+ const modelEntries = Array.isArray(response.data)
76
+ ? response.data
77
+ : Array.isArray(response.models)
78
+ ? response.models
79
+ : [];
80
+ if (modelEntries.length === 0) {
81
+ return [];
82
+ }
83
+ const modelIds = modelEntries
84
+ .map((entry) => entry.id)
85
+ .filter((id) => typeof id === 'string');
86
+ return normalizeModelIds(modelIds);
87
+ }
88
+ async function probeModel({ modelId, apiKey, endpoint, timeoutMs, appName, appUrl, }) {
89
+ const headers = {
90
+ Authorization: `Bearer ${apiKey}`,
91
+ 'Content-Type': 'application/json',
92
+ };
93
+ if (appName) {
94
+ headers['X-Title'] = appName;
95
+ }
96
+ if (appUrl) {
97
+ headers['HTTP-Referer'] = appUrl;
98
+ }
99
+ try {
100
+ const response = await fetchWithTimeout(endpoint, {
101
+ method: 'POST',
102
+ headers,
103
+ body: JSON.stringify({
104
+ model: modelId,
105
+ messages: [{ role: 'user', content: 'Reply only with OK.' }],
106
+ stream: false,
107
+ }),
108
+ }, timeoutMs);
109
+ if (!response.ok) {
110
+ return {
111
+ id: modelId,
112
+ ok: false,
113
+ reason: await toHttpFailureReason(response),
114
+ };
115
+ }
116
+ try {
117
+ await response.json();
118
+ }
119
+ catch (error) {
120
+ return {
121
+ id: modelId,
122
+ ok: false,
123
+ reason: `JSON parse failed: ${toErrorMessage(error)}`,
124
+ };
125
+ }
126
+ return { id: modelId, ok: true };
127
+ }
128
+ catch (error) {
129
+ return {
130
+ id: modelId,
131
+ ok: false,
132
+ reason: toErrorMessage(error),
133
+ };
134
+ }
135
+ }
136
+ async function runWithConcurrency(items, concurrency, worker) {
137
+ if (items.length === 0) {
138
+ return [];
139
+ }
140
+ const results = new Array(items.length);
141
+ let nextIndex = 0;
142
+ const workerCount = Math.min(concurrency, items.length);
143
+ await Promise.all(Array.from({ length: workerCount }, async () => {
144
+ while (nextIndex < items.length) {
145
+ const current = nextIndex;
146
+ nextIndex += 1;
147
+ results[current] = await worker(items[current]);
148
+ }
149
+ }));
150
+ return results;
151
+ }
152
+ /**
153
+ * Fetch currently available OpenRouter free models and probe each model.
154
+ */
155
+ export async function refreshOpenRouterFreeModels(options) {
156
+ const apiKey = options.apiKey.trim();
157
+ if (!apiKey) {
158
+ throw new Error('OpenRouter API key is required.');
159
+ }
160
+ const modelsEndpoint = options.modelsEndpoint || OPENROUTER_MODELS_ENDPOINT;
161
+ const endpoint = options.endpoint || ENDPOINT_OPENROUTER_API;
162
+ const timeoutMs = normalizeLimit(options.timeoutMs, DEFAULT_TIMEOUT_MS);
163
+ const concurrency = normalizeLimit(options.concurrency, DEFAULT_CONCURRENCY);
164
+ const maxCandidates = normalizeLimit(options.maxCandidates, DEFAULT_MAX_CANDIDATES);
165
+ const maxWorking = normalizeLimit(options.maxWorking, DEFAULT_MAX_WORKING);
166
+ const modelsResponse = await fetchWithTimeout(modelsEndpoint, { method: 'GET' }, timeoutMs);
167
+ if (!modelsResponse.ok) {
168
+ throw new Error(await toHttpFailureReason(modelsResponse));
169
+ }
170
+ let payload;
171
+ try {
172
+ payload = await modelsResponse.json();
173
+ }
174
+ catch (error) {
175
+ throw new Error(`JSON parse failed: ${toErrorMessage(error)}`);
176
+ }
177
+ const candidateModelIds = extractModelIds(payload)
178
+ .filter((modelId) => isOpenRouterFreeModel(modelId))
179
+ .slice(0, maxCandidates);
180
+ const probeResults = await runWithConcurrency(candidateModelIds, concurrency, (modelId) => probeModel({
181
+ modelId,
182
+ apiKey,
183
+ endpoint,
184
+ timeoutMs,
185
+ appName: options.appName,
186
+ appUrl: options.appUrl,
187
+ }));
188
+ const working = probeResults
189
+ .filter((result) => result.ok)
190
+ .map((result) => result.id)
191
+ .slice(0, maxWorking);
192
+ const failed = probeResults
193
+ .filter((result) => !result.ok)
194
+ .map((result) => ({
195
+ id: result.id,
196
+ reason: result.reason || 'Unknown error',
197
+ }));
198
+ return {
199
+ working,
200
+ failed,
201
+ fetchedAt: Date.now(),
202
+ };
203
+ }
204
+ //# sourceMappingURL=refreshOpenRouterFreeModels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshOpenRouterFreeModels.js","sourceRoot":"","sources":["../../../src/utils/refreshOpenRouterFreeModels.ts"],"names":[],"mappings":"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"}
@@ -91,7 +91,6 @@ var AITuberOnAirChat = (() => {
91
91
  MODEL_GPT_4_1: () => MODEL_GPT_4_1,
92
92
  MODEL_GPT_4_1_MINI: () => MODEL_GPT_4_1_MINI,
93
93
  MODEL_GPT_4_1_NANO: () => MODEL_GPT_4_1_NANO,
94
- MODEL_GPT_4_5_PREVIEW: () => MODEL_GPT_4_5_PREVIEW,
95
94
  MODEL_GPT_5: () => MODEL_GPT_5,
96
95
  MODEL_GPT_5_1: () => MODEL_GPT_5_1,
97
96
  MODEL_GPT_5_MINI: () => MODEL_GPT_5_MINI,
@@ -143,6 +142,7 @@ var AITuberOnAirChat = (() => {
143
142
  parseOpenAICompatibleTextStream: () => parseOpenAICompatibleTextStream,
144
143
  parseOpenAICompatibleToolStream: () => parseOpenAICompatibleToolStream,
145
144
  processChatWithOptionalTools: () => processChatWithOptionalTools,
145
+ refreshOpenRouterFreeModels: () => refreshOpenRouterFreeModels,
146
146
  resolveVisionModel: () => resolveVisionModel,
147
147
  runOnceText: () => runOnceText,
148
148
  screenplayToText: () => screenplayToText,
@@ -165,7 +165,6 @@ var AITuberOnAirChat = (() => {
165
165
  var MODEL_O3_MINI = "o3-mini";
166
166
  var MODEL_O1_MINI = "o1-mini";
167
167
  var MODEL_O1 = "o1";
168
- var MODEL_GPT_4_5_PREVIEW = "gpt-4.5-preview";
169
168
  var VISION_SUPPORTED_MODELS = [
170
169
  MODEL_GPT_5_NANO,
171
170
  MODEL_GPT_5_MINI,
@@ -176,7 +175,6 @@ var AITuberOnAirChat = (() => {
176
175
  MODEL_GPT_4_1_NANO,
177
176
  MODEL_GPT_4O_MINI,
178
177
  MODEL_GPT_4O,
179
- MODEL_GPT_4_5_PREVIEW,
180
178
  MODEL_O1
181
179
  // MODEL_O3_MINI and MODEL_O1_MINI are not included as they don't support vision
182
180
  ];
@@ -294,7 +292,7 @@ var AITuberOnAirChat = (() => {
294
292
  var OPENROUTER_FREE_DAILY_LIMIT_HIGH_CREDITS = 1e3;
295
293
  var OPENROUTER_CREDITS_THRESHOLD = 10;
296
294
  function isOpenRouterFreeModel(model) {
297
- return OPENROUTER_FREE_MODELS.some((freeModel) => model.includes(freeModel));
295
+ return model.trim().endsWith(":free");
298
296
  }
299
297
  function isOpenRouterVisionModel(model) {
300
298
  return OPENROUTER_VISION_SUPPORTED_MODELS.some(
@@ -795,6 +793,212 @@ If it's in another language, summarize in that language.
795
793
  return resolved;
796
794
  };
797
795
 
796
+ // src/utils/refreshOpenRouterFreeModels.ts
797
+ var OPENROUTER_MODELS_ENDPOINT = "https://openrouter.ai/api/v1/models";
798
+ var DEFAULT_CONCURRENCY = 2;
799
+ var DEFAULT_TIMEOUT_MS = 12e3;
800
+ var DEFAULT_MAX_CANDIDATES = 1;
801
+ var DEFAULT_MAX_WORKING = 10;
802
+ function toErrorMessage(error) {
803
+ if (error instanceof Error) {
804
+ return error.message;
805
+ }
806
+ return String(error);
807
+ }
808
+ function normalizeLimit(value, fallback) {
809
+ if (typeof value !== "number" || !Number.isFinite(value)) {
810
+ return fallback;
811
+ }
812
+ return Math.max(1, Math.floor(value));
813
+ }
814
+ function normalizeModelIds(modelIds) {
815
+ const seen = /* @__PURE__ */ new Set();
816
+ const normalized = [];
817
+ for (const modelId of modelIds) {
818
+ const trimmed = modelId.trim();
819
+ if (!trimmed || seen.has(trimmed)) {
820
+ continue;
821
+ }
822
+ seen.add(trimmed);
823
+ normalized.push(trimmed);
824
+ }
825
+ return normalized;
826
+ }
827
+ async function fetchWithTimeout(url, init, timeoutMs) {
828
+ const hasAbortController = typeof AbortController !== "undefined";
829
+ if (!hasAbortController) {
830
+ return fetch(url, init);
831
+ }
832
+ const controller = new AbortController();
833
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
834
+ try {
835
+ return await fetch(url, {
836
+ ...init,
837
+ signal: controller.signal
838
+ });
839
+ } catch (error) {
840
+ if (error instanceof Error && error.name === "AbortError") {
841
+ throw new Error(`Timeout after ${timeoutMs}ms`);
842
+ }
843
+ throw error;
844
+ } finally {
845
+ clearTimeout(timeoutId);
846
+ }
847
+ }
848
+ async function toHttpFailureReason(response) {
849
+ const status = `HTTP ${response.status} ${response.statusText}`.trim();
850
+ let body = "";
851
+ try {
852
+ body = await response.text();
853
+ } catch {
854
+ return status;
855
+ }
856
+ const compactBody = body.replace(/\s+/g, " ").trim().slice(0, 200);
857
+ if (!compactBody) {
858
+ return status;
859
+ }
860
+ return `${status}: ${compactBody}`;
861
+ }
862
+ function extractModelIds(payload) {
863
+ if (!payload || typeof payload !== "object") {
864
+ throw new Error("Invalid models response shape");
865
+ }
866
+ const response = payload;
867
+ const modelEntries = Array.isArray(response.data) ? response.data : Array.isArray(response.models) ? response.models : [];
868
+ if (modelEntries.length === 0) {
869
+ return [];
870
+ }
871
+ const modelIds = modelEntries.map((entry) => entry.id).filter((id) => typeof id === "string");
872
+ return normalizeModelIds(modelIds);
873
+ }
874
+ async function probeModel({
875
+ modelId,
876
+ apiKey,
877
+ endpoint,
878
+ timeoutMs,
879
+ appName,
880
+ appUrl
881
+ }) {
882
+ const headers = {
883
+ Authorization: `Bearer ${apiKey}`,
884
+ "Content-Type": "application/json"
885
+ };
886
+ if (appName) {
887
+ headers["X-Title"] = appName;
888
+ }
889
+ if (appUrl) {
890
+ headers["HTTP-Referer"] = appUrl;
891
+ }
892
+ try {
893
+ const response = await fetchWithTimeout(
894
+ endpoint,
895
+ {
896
+ method: "POST",
897
+ headers,
898
+ body: JSON.stringify({
899
+ model: modelId,
900
+ messages: [{ role: "user", content: "Reply only with OK." }],
901
+ stream: false
902
+ })
903
+ },
904
+ timeoutMs
905
+ );
906
+ if (!response.ok) {
907
+ return {
908
+ id: modelId,
909
+ ok: false,
910
+ reason: await toHttpFailureReason(response)
911
+ };
912
+ }
913
+ try {
914
+ await response.json();
915
+ } catch (error) {
916
+ return {
917
+ id: modelId,
918
+ ok: false,
919
+ reason: `JSON parse failed: ${toErrorMessage(error)}`
920
+ };
921
+ }
922
+ return { id: modelId, ok: true };
923
+ } catch (error) {
924
+ return {
925
+ id: modelId,
926
+ ok: false,
927
+ reason: toErrorMessage(error)
928
+ };
929
+ }
930
+ }
931
+ async function runWithConcurrency(items, concurrency, worker) {
932
+ if (items.length === 0) {
933
+ return [];
934
+ }
935
+ const results = new Array(items.length);
936
+ let nextIndex = 0;
937
+ const workerCount = Math.min(concurrency, items.length);
938
+ await Promise.all(
939
+ Array.from({ length: workerCount }, async () => {
940
+ while (nextIndex < items.length) {
941
+ const current = nextIndex;
942
+ nextIndex += 1;
943
+ results[current] = await worker(items[current]);
944
+ }
945
+ })
946
+ );
947
+ return results;
948
+ }
949
+ async function refreshOpenRouterFreeModels(options) {
950
+ const apiKey = options.apiKey.trim();
951
+ if (!apiKey) {
952
+ throw new Error("OpenRouter API key is required.");
953
+ }
954
+ const modelsEndpoint = options.modelsEndpoint || OPENROUTER_MODELS_ENDPOINT;
955
+ const endpoint = options.endpoint || ENDPOINT_OPENROUTER_API;
956
+ const timeoutMs = normalizeLimit(options.timeoutMs, DEFAULT_TIMEOUT_MS);
957
+ const concurrency = normalizeLimit(options.concurrency, DEFAULT_CONCURRENCY);
958
+ const maxCandidates = normalizeLimit(
959
+ options.maxCandidates,
960
+ DEFAULT_MAX_CANDIDATES
961
+ );
962
+ const maxWorking = normalizeLimit(options.maxWorking, DEFAULT_MAX_WORKING);
963
+ const modelsResponse = await fetchWithTimeout(
964
+ modelsEndpoint,
965
+ { method: "GET" },
966
+ timeoutMs
967
+ );
968
+ if (!modelsResponse.ok) {
969
+ throw new Error(await toHttpFailureReason(modelsResponse));
970
+ }
971
+ let payload;
972
+ try {
973
+ payload = await modelsResponse.json();
974
+ } catch (error) {
975
+ throw new Error(`JSON parse failed: ${toErrorMessage(error)}`);
976
+ }
977
+ const candidateModelIds = extractModelIds(payload).filter((modelId) => isOpenRouterFreeModel(modelId)).slice(0, maxCandidates);
978
+ const probeResults = await runWithConcurrency(
979
+ candidateModelIds,
980
+ concurrency,
981
+ (modelId) => probeModel({
982
+ modelId,
983
+ apiKey,
984
+ endpoint,
985
+ timeoutMs,
986
+ appName: options.appName,
987
+ appUrl: options.appUrl
988
+ })
989
+ );
990
+ const working = probeResults.filter((result) => result.ok).map((result) => result.id).slice(0, maxWorking);
991
+ const failed = probeResults.filter((result) => !result.ok).map((result) => ({
992
+ id: result.id,
993
+ reason: result.reason || "Unknown error"
994
+ }));
995
+ return {
996
+ working,
997
+ failed,
998
+ fetchedAt: Date.now()
999
+ };
1000
+ }
1001
+
798
1002
  // src/services/providers/claude/ClaudeChatService.ts
799
1003
  var ClaudeChatService = class {
800
1004
  /**
@@ -2929,8 +3133,7 @@ If it's in another language, summarize in that language.
2929
3133
  MODEL_GPT_4O,
2930
3134
  MODEL_O3_MINI,
2931
3135
  MODEL_O1_MINI,
2932
- MODEL_O1,
2933
- MODEL_GPT_4_5_PREVIEW
3136
+ MODEL_O1
2934
3137
  ];
2935
3138
  }
2936
3139
  /**
@@ -3362,7 +3565,7 @@ If it's in another language, summarize in that language.
3362
3565
  * @returns True if the model is free
3363
3566
  */
3364
3567
  isModelFree(model) {
3365
- return OPENROUTER_FREE_MODELS.includes(model) || model.endsWith(":free");
3568
+ return isOpenRouterFreeModel(model);
3366
3569
  }
3367
3570
  };
3368
3571