@aituber-onair/chat 0.2.1 → 0.3.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.
- package/README.ja.md +21 -2
- package/README.md +22 -3
- package/dist/cjs/constants/index.d.ts +1 -0
- package/dist/cjs/constants/index.d.ts.map +1 -1
- package/dist/cjs/constants/index.js +1 -0
- package/dist/cjs/constants/index.js.map +1 -1
- package/dist/cjs/constants/openrouter.d.ts +21 -0
- package/dist/cjs/constants/openrouter.d.ts.map +1 -0
- package/dist/cjs/constants/openrouter.js +34 -0
- package/dist/cjs/constants/openrouter.js.map +1 -0
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +6 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/services/ChatServiceFactory.d.ts.map +1 -1
- package/dist/cjs/services/ChatServiceFactory.js +3 -0
- package/dist/cjs/services/ChatServiceFactory.js.map +1 -1
- package/dist/cjs/services/providers/ChatServiceProvider.d.ts +5 -1
- package/dist/cjs/services/providers/ChatServiceProvider.d.ts.map +1 -1
- package/dist/cjs/services/providers/openrouter/OpenRouterChatService.d.ts +108 -0
- package/dist/cjs/services/providers/openrouter/OpenRouterChatService.d.ts.map +1 -0
- package/dist/cjs/services/providers/openrouter/OpenRouterChatService.js +397 -0
- package/dist/cjs/services/providers/openrouter/OpenRouterChatService.js.map +1 -0
- package/dist/cjs/services/providers/openrouter/OpenRouterChatServiceProvider.d.ts +53 -0
- package/dist/cjs/services/providers/openrouter/OpenRouterChatServiceProvider.d.ts.map +1 -0
- package/dist/cjs/services/providers/openrouter/OpenRouterChatServiceProvider.js +89 -0
- package/dist/cjs/services/providers/openrouter/OpenRouterChatServiceProvider.js.map +1 -0
- package/dist/esm/constants/index.d.ts +1 -0
- package/dist/esm/constants/index.d.ts.map +1 -1
- package/dist/esm/constants/index.js +1 -0
- package/dist/esm/constants/index.js.map +1 -1
- package/dist/esm/constants/openrouter.d.ts +21 -0
- package/dist/esm/constants/openrouter.d.ts.map +1 -0
- package/dist/esm/constants/openrouter.js +29 -0
- package/dist/esm/constants/openrouter.js.map +1 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/services/ChatServiceFactory.d.ts.map +1 -1
- package/dist/esm/services/ChatServiceFactory.js +3 -0
- package/dist/esm/services/ChatServiceFactory.js.map +1 -1
- package/dist/esm/services/providers/ChatServiceProvider.d.ts +5 -1
- package/dist/esm/services/providers/ChatServiceProvider.d.ts.map +1 -1
- package/dist/esm/services/providers/openrouter/OpenRouterChatService.d.ts +108 -0
- package/dist/esm/services/providers/openrouter/OpenRouterChatService.d.ts.map +1 -0
- package/dist/esm/services/providers/openrouter/OpenRouterChatService.js +393 -0
- package/dist/esm/services/providers/openrouter/OpenRouterChatService.js.map +1 -0
- package/dist/esm/services/providers/openrouter/OpenRouterChatServiceProvider.d.ts +53 -0
- package/dist/esm/services/providers/openrouter/OpenRouterChatServiceProvider.d.ts.map +1 -0
- package/dist/esm/services/providers/openrouter/OpenRouterChatServiceProvider.js +85 -0
- package/dist/esm/services/providers/openrouter/OpenRouterChatServiceProvider.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenRouterChatService = void 0;
|
|
4
|
+
const openrouter_1 = require("../../../constants/openrouter");
|
|
5
|
+
const chat_1 = require("../../../constants/chat");
|
|
6
|
+
const streamTextAccumulator_1 = require("../../../utils/streamTextAccumulator");
|
|
7
|
+
const chatServiceHttpClient_1 = require("../../../utils/chatServiceHttpClient");
|
|
8
|
+
/**
|
|
9
|
+
* OpenRouter implementation of ChatService
|
|
10
|
+
* OpenRouter provides access to multiple AI models through a unified API
|
|
11
|
+
*/
|
|
12
|
+
class OpenRouterChatService {
|
|
13
|
+
/**
|
|
14
|
+
* Constructor
|
|
15
|
+
* @param apiKey OpenRouter API key
|
|
16
|
+
* @param model Name of the model to use
|
|
17
|
+
* @param visionModel Name of the vision model
|
|
18
|
+
* @param tools Tool definitions (optional)
|
|
19
|
+
* @param endpoint API endpoint (optional)
|
|
20
|
+
* @param responseLength Response length configuration (optional)
|
|
21
|
+
* @param appName Application name for OpenRouter analytics (optional)
|
|
22
|
+
* @param appUrl Application URL for OpenRouter analytics (optional)
|
|
23
|
+
* @param reasoning_effort Reasoning effort level (optional)
|
|
24
|
+
* @param includeReasoning Whether to include reasoning in response (optional)
|
|
25
|
+
* @param reasoningMaxTokens Maximum tokens for reasoning (optional)
|
|
26
|
+
*/
|
|
27
|
+
constructor(apiKey, model = openrouter_1.MODEL_GPT_OSS_20B_FREE, visionModel = openrouter_1.MODEL_GPT_OSS_20B_FREE, tools, endpoint = openrouter_1.ENDPOINT_OPENROUTER_API, responseLength, appName, appUrl, reasoning_effort, includeReasoning, reasoningMaxTokens) {
|
|
28
|
+
/** Provider name */
|
|
29
|
+
this.provider = 'openrouter';
|
|
30
|
+
this.lastRequestTime = 0;
|
|
31
|
+
this.requestCount = 0;
|
|
32
|
+
this.apiKey = apiKey;
|
|
33
|
+
this.model = model;
|
|
34
|
+
this.tools = tools || [];
|
|
35
|
+
this.endpoint = endpoint;
|
|
36
|
+
this.responseLength = responseLength;
|
|
37
|
+
this.appName = appName;
|
|
38
|
+
this.appUrl = appUrl;
|
|
39
|
+
this.reasoning_effort = reasoning_effort;
|
|
40
|
+
this.includeReasoning = includeReasoning;
|
|
41
|
+
this.reasoningMaxTokens = reasoningMaxTokens;
|
|
42
|
+
// Store vision model without validation at construction time
|
|
43
|
+
// Validation will be performed when vision methods are actually called
|
|
44
|
+
this.visionModel = visionModel;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get the current model name
|
|
48
|
+
* @returns Model name
|
|
49
|
+
*/
|
|
50
|
+
getModel() {
|
|
51
|
+
return this.model;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get the current vision model name
|
|
55
|
+
* @returns Vision model name
|
|
56
|
+
*/
|
|
57
|
+
getVisionModel() {
|
|
58
|
+
return this.visionModel;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Apply rate limiting for free tier models
|
|
62
|
+
*/
|
|
63
|
+
async applyRateLimiting() {
|
|
64
|
+
if (!(0, openrouter_1.isOpenRouterFreeModel)(this.model)) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const now = Date.now();
|
|
68
|
+
const timeSinceLastRequest = now - this.lastRequestTime;
|
|
69
|
+
// Reset counter if more than a minute has passed
|
|
70
|
+
if (timeSinceLastRequest > 60000) {
|
|
71
|
+
this.requestCount = 0;
|
|
72
|
+
}
|
|
73
|
+
// If we've hit the rate limit, wait
|
|
74
|
+
if (this.requestCount >= openrouter_1.OPENROUTER_FREE_RATE_LIMIT_PER_MINUTE) {
|
|
75
|
+
const waitTime = 60000 - timeSinceLastRequest;
|
|
76
|
+
if (waitTime > 0) {
|
|
77
|
+
console.log(`Rate limit reached for free tier. Waiting ${waitTime}ms...`);
|
|
78
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
79
|
+
this.requestCount = 0;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
this.lastRequestTime = now;
|
|
83
|
+
this.requestCount++;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Process chat messages
|
|
87
|
+
* @param messages Array of messages to send
|
|
88
|
+
* @param onPartialResponse Callback to receive each part of streaming response
|
|
89
|
+
* @param onCompleteResponse Callback to execute when response is complete
|
|
90
|
+
*/
|
|
91
|
+
async processChat(messages, onPartialResponse, onCompleteResponse) {
|
|
92
|
+
// Apply rate limiting for free tier
|
|
93
|
+
await this.applyRateLimiting();
|
|
94
|
+
// Not using tools
|
|
95
|
+
if (this.tools.length === 0) {
|
|
96
|
+
const res = await this.callOpenRouter(messages, this.model, true);
|
|
97
|
+
const full = await this.handleStream(res, onPartialResponse);
|
|
98
|
+
await onCompleteResponse(full);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// Using tools
|
|
102
|
+
const { blocks, stop_reason } = await this.chatOnce(messages);
|
|
103
|
+
if (stop_reason === 'end') {
|
|
104
|
+
const full = blocks
|
|
105
|
+
.filter((b) => b.type === 'text')
|
|
106
|
+
.map((b) => b.text)
|
|
107
|
+
.join('');
|
|
108
|
+
await onCompleteResponse(full);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
throw new Error('processChat received tool_calls. ' +
|
|
112
|
+
'ChatProcessor must use chatOnce() loop when tools are enabled.');
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Process chat messages with images
|
|
116
|
+
* @param messages Array of messages to send (including images)
|
|
117
|
+
* @param onPartialResponse Callback to receive each part of streaming response
|
|
118
|
+
* @param onCompleteResponse Callback to execute when response is complete
|
|
119
|
+
*/
|
|
120
|
+
async processVisionChat(messages, onPartialResponse, onCompleteResponse) {
|
|
121
|
+
// Always validate vision capabilities when vision methods are called
|
|
122
|
+
if (!(0, openrouter_1.isOpenRouterVisionModel)(this.visionModel)) {
|
|
123
|
+
throw new Error(`Model ${this.visionModel} does not support vision capabilities.`);
|
|
124
|
+
}
|
|
125
|
+
// Apply rate limiting for free tier
|
|
126
|
+
await this.applyRateLimiting();
|
|
127
|
+
try {
|
|
128
|
+
// Not using tools
|
|
129
|
+
if (this.tools.length === 0) {
|
|
130
|
+
const res = await this.callOpenRouter(messages, this.visionModel, true);
|
|
131
|
+
const full = await this.handleStream(res, onPartialResponse);
|
|
132
|
+
await onCompleteResponse(full);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
// Using tools
|
|
136
|
+
const { blocks, stop_reason } = await this.visionChatOnce(messages, true, onPartialResponse);
|
|
137
|
+
if (stop_reason === 'end') {
|
|
138
|
+
const full = blocks
|
|
139
|
+
.filter((b) => b.type === 'text')
|
|
140
|
+
.map((b) => b.text)
|
|
141
|
+
.join('');
|
|
142
|
+
await onCompleteResponse(full);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
throw new Error('processVisionChat received tool_calls. ' +
|
|
146
|
+
'ChatProcessor must use visionChatOnce() loop when tools are enabled.');
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
console.error('Error in processVisionChat:', error);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Process chat messages with tools (text only)
|
|
155
|
+
* @param messages Array of messages to send
|
|
156
|
+
* @param stream Whether to use streaming
|
|
157
|
+
* @param onPartialResponse Callback for partial responses
|
|
158
|
+
* @param maxTokens Maximum tokens for response (optional)
|
|
159
|
+
* @returns Tool chat completion
|
|
160
|
+
*/
|
|
161
|
+
async chatOnce(messages, stream = true, onPartialResponse = () => { }, maxTokens) {
|
|
162
|
+
await this.applyRateLimiting();
|
|
163
|
+
const res = await this.callOpenRouter(messages, this.model, stream, maxTokens);
|
|
164
|
+
return stream
|
|
165
|
+
? this.parseStream(res, onPartialResponse)
|
|
166
|
+
: this.parseOneShot(await res.json());
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Process vision chat messages with tools
|
|
170
|
+
* @param messages Array of messages to send (including images)
|
|
171
|
+
* @param stream Whether to use streaming
|
|
172
|
+
* @param onPartialResponse Callback for partial responses
|
|
173
|
+
* @param maxTokens Maximum tokens for response (optional)
|
|
174
|
+
* @returns Tool chat completion
|
|
175
|
+
*/
|
|
176
|
+
async visionChatOnce(messages, stream = false, onPartialResponse = () => { }, maxTokens) {
|
|
177
|
+
// Always validate vision capabilities when vision methods are called
|
|
178
|
+
if (!(0, openrouter_1.isOpenRouterVisionModel)(this.visionModel)) {
|
|
179
|
+
throw new Error(`Model ${this.visionModel} does not support vision capabilities.`);
|
|
180
|
+
}
|
|
181
|
+
await this.applyRateLimiting();
|
|
182
|
+
const res = await this.callOpenRouter(messages, this.visionModel, stream, maxTokens);
|
|
183
|
+
return stream
|
|
184
|
+
? this.parseStream(res, onPartialResponse)
|
|
185
|
+
: this.parseOneShot(await res.json());
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Call OpenRouter API
|
|
189
|
+
*/
|
|
190
|
+
async callOpenRouter(messages, model, stream = false, maxTokens) {
|
|
191
|
+
const body = this.buildRequestBody(messages, model, stream, maxTokens);
|
|
192
|
+
// Build headers
|
|
193
|
+
const headers = {
|
|
194
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
195
|
+
};
|
|
196
|
+
// Add optional analytics headers
|
|
197
|
+
if (this.appUrl) {
|
|
198
|
+
headers['HTTP-Referer'] = this.appUrl;
|
|
199
|
+
}
|
|
200
|
+
if (this.appName) {
|
|
201
|
+
headers['X-Title'] = this.appName;
|
|
202
|
+
}
|
|
203
|
+
const res = await chatServiceHttpClient_1.ChatServiceHttpClient.post(this.endpoint, body, headers);
|
|
204
|
+
return res;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Build request body for OpenRouter API (OpenAI-compatible format)
|
|
208
|
+
*/
|
|
209
|
+
buildRequestBody(messages, model, stream, maxTokens) {
|
|
210
|
+
const body = {
|
|
211
|
+
model,
|
|
212
|
+
messages,
|
|
213
|
+
stream,
|
|
214
|
+
};
|
|
215
|
+
// Add max_tokens if specified
|
|
216
|
+
const tokenLimit = maxTokens !== undefined
|
|
217
|
+
? maxTokens
|
|
218
|
+
: (0, chat_1.getMaxTokensForResponseLength)(this.responseLength);
|
|
219
|
+
// OpenRouter gpt-oss-20b model has known issues with token limits causing empty responses
|
|
220
|
+
// Remove all token limits to ensure proper functionality
|
|
221
|
+
if (tokenLimit) {
|
|
222
|
+
console.warn(`OpenRouter: Token limits are not supported for gpt-oss-20b model due to known issues. Using unlimited tokens instead.`);
|
|
223
|
+
// Do not set max_tokens - use unlimited tokens
|
|
224
|
+
}
|
|
225
|
+
// Add OpenRouter reasoning control
|
|
226
|
+
if (this.reasoning_effort ||
|
|
227
|
+
this.includeReasoning !== undefined ||
|
|
228
|
+
this.reasoningMaxTokens) {
|
|
229
|
+
body.reasoning = {};
|
|
230
|
+
if (this.reasoning_effort) {
|
|
231
|
+
// OpenRouter uses 'low' as the minimum effort level, map 'minimal' to 'low'
|
|
232
|
+
const effort = this.reasoning_effort === 'minimal' ? 'low' : this.reasoning_effort;
|
|
233
|
+
body.reasoning.effort = effort;
|
|
234
|
+
}
|
|
235
|
+
// Default to exclude reasoning if includeReasoning is not explicitly set to true
|
|
236
|
+
if (this.includeReasoning !== true) {
|
|
237
|
+
body.reasoning.exclude = true;
|
|
238
|
+
}
|
|
239
|
+
if (this.reasoningMaxTokens) {
|
|
240
|
+
body.reasoning.max_tokens = this.reasoningMaxTokens;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
// Default behavior: exclude reasoning to avoid empty responses
|
|
245
|
+
body.reasoning = { exclude: true };
|
|
246
|
+
}
|
|
247
|
+
// Add tools if available
|
|
248
|
+
if (this.tools.length > 0) {
|
|
249
|
+
body.tools = this.tools.map((t) => ({
|
|
250
|
+
type: 'function',
|
|
251
|
+
function: {
|
|
252
|
+
name: t.name,
|
|
253
|
+
description: t.description,
|
|
254
|
+
parameters: t.parameters,
|
|
255
|
+
},
|
|
256
|
+
}));
|
|
257
|
+
body.tool_choice = 'auto';
|
|
258
|
+
}
|
|
259
|
+
return body;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Handle streaming response from OpenRouter
|
|
263
|
+
* OpenRouter uses SSE format with potential comment lines
|
|
264
|
+
*/
|
|
265
|
+
async handleStream(res, onPartial) {
|
|
266
|
+
const reader = res.body.getReader();
|
|
267
|
+
const dec = new TextDecoder();
|
|
268
|
+
let buffer = '';
|
|
269
|
+
let full = '';
|
|
270
|
+
while (true) {
|
|
271
|
+
const { done, value } = await reader.read();
|
|
272
|
+
if (done)
|
|
273
|
+
break;
|
|
274
|
+
buffer += dec.decode(value, { stream: true });
|
|
275
|
+
// Process line by line
|
|
276
|
+
const lines = buffer.split('\n');
|
|
277
|
+
buffer = lines.pop() || ''; // Keep incomplete line
|
|
278
|
+
for (const line of lines) {
|
|
279
|
+
const trimmedLine = line.trim();
|
|
280
|
+
// Skip empty lines and comment lines (OpenRouter specific)
|
|
281
|
+
if (!trimmedLine || trimmedLine.startsWith(':'))
|
|
282
|
+
continue;
|
|
283
|
+
if (!trimmedLine.startsWith('data:'))
|
|
284
|
+
continue;
|
|
285
|
+
const jsonStr = trimmedLine.slice(5).trim();
|
|
286
|
+
if (jsonStr === '[DONE]') {
|
|
287
|
+
return full;
|
|
288
|
+
}
|
|
289
|
+
try {
|
|
290
|
+
const json = JSON.parse(jsonStr);
|
|
291
|
+
const content = json.choices?.[0]?.delta?.content || '';
|
|
292
|
+
if (content) {
|
|
293
|
+
onPartial(content);
|
|
294
|
+
full += content;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
catch (e) {
|
|
298
|
+
// Skip invalid JSON (could be partial or malformed)
|
|
299
|
+
console.debug('Failed to parse SSE data:', jsonStr);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return full;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Parse streaming response with tool support
|
|
307
|
+
*/
|
|
308
|
+
async parseStream(res, onPartial) {
|
|
309
|
+
const reader = res.body.getReader();
|
|
310
|
+
const dec = new TextDecoder();
|
|
311
|
+
const textBlocks = [];
|
|
312
|
+
const toolCallsMap = new Map();
|
|
313
|
+
let buf = '';
|
|
314
|
+
while (true) {
|
|
315
|
+
const { done, value } = await reader.read();
|
|
316
|
+
if (done)
|
|
317
|
+
break;
|
|
318
|
+
buf += dec.decode(value, { stream: true });
|
|
319
|
+
// Process line by line
|
|
320
|
+
const lines = buf.split('\n');
|
|
321
|
+
buf = lines.pop() || ''; // Keep incomplete line
|
|
322
|
+
for (const line of lines) {
|
|
323
|
+
const trimmedLine = line.trim();
|
|
324
|
+
// Skip empty lines and OpenRouter comment lines
|
|
325
|
+
if (!trimmedLine || trimmedLine.startsWith(':'))
|
|
326
|
+
continue;
|
|
327
|
+
if (!trimmedLine.startsWith('data:'))
|
|
328
|
+
continue;
|
|
329
|
+
const payload = trimmedLine.slice(5).trim();
|
|
330
|
+
if (payload === '[DONE]') {
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
try {
|
|
334
|
+
const json = JSON.parse(payload);
|
|
335
|
+
const delta = json.choices?.[0]?.delta;
|
|
336
|
+
if (delta?.content) {
|
|
337
|
+
onPartial(delta.content);
|
|
338
|
+
streamTextAccumulator_1.StreamTextAccumulator.append(textBlocks, delta.content);
|
|
339
|
+
}
|
|
340
|
+
// Handle tool calls
|
|
341
|
+
if (delta?.tool_calls) {
|
|
342
|
+
delta.tool_calls.forEach((c) => {
|
|
343
|
+
const entry = toolCallsMap.get(c.index) ?? {
|
|
344
|
+
id: c.id,
|
|
345
|
+
name: c.function?.name,
|
|
346
|
+
args: '',
|
|
347
|
+
};
|
|
348
|
+
entry.args += c.function?.arguments || '';
|
|
349
|
+
toolCallsMap.set(c.index, entry);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
catch (e) {
|
|
354
|
+
console.debug('Failed to parse SSE data:', payload);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// Convert tool_calls to blocks
|
|
359
|
+
const toolBlocks = Array.from(toolCallsMap.entries())
|
|
360
|
+
.sort((a, b) => a[0] - b[0])
|
|
361
|
+
.map(([_, e]) => ({
|
|
362
|
+
type: 'tool_use',
|
|
363
|
+
id: e.id,
|
|
364
|
+
name: e.name,
|
|
365
|
+
input: JSON.parse(e.args || '{}'),
|
|
366
|
+
}));
|
|
367
|
+
const blocks = [...textBlocks, ...toolBlocks];
|
|
368
|
+
return {
|
|
369
|
+
blocks,
|
|
370
|
+
stop_reason: toolBlocks.length ? 'tool_use' : 'end',
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Parse non-streaming response
|
|
375
|
+
*/
|
|
376
|
+
parseOneShot(data) {
|
|
377
|
+
const choice = data.choices?.[0];
|
|
378
|
+
const blocks = [];
|
|
379
|
+
if (choice?.finish_reason === 'tool_calls' && choice?.message?.tool_calls) {
|
|
380
|
+
choice.message.tool_calls.forEach((c) => blocks.push({
|
|
381
|
+
type: 'tool_use',
|
|
382
|
+
id: c.id,
|
|
383
|
+
name: c.function?.name,
|
|
384
|
+
input: JSON.parse(c.function?.arguments || '{}'),
|
|
385
|
+
}));
|
|
386
|
+
}
|
|
387
|
+
else if (choice?.message?.content) {
|
|
388
|
+
blocks.push({ type: 'text', text: choice.message.content });
|
|
389
|
+
}
|
|
390
|
+
return {
|
|
391
|
+
blocks,
|
|
392
|
+
stop_reason: choice?.finish_reason === 'tool_calls' ? 'tool_use' : 'end',
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
exports.OpenRouterChatService = OpenRouterChatService;
|
|
397
|
+
//# sourceMappingURL=OpenRouterChatService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenRouterChatService.js","sourceRoot":"","sources":["../../../../../src/services/providers/openrouter/OpenRouterChatService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ChatService } from '../../ChatService';
|
|
2
|
+
import { ChatServiceOptions, ChatServiceProvider } from '../ChatServiceProvider';
|
|
3
|
+
/**
|
|
4
|
+
* OpenRouter API provider implementation
|
|
5
|
+
* Provides access to multiple AI models through OpenRouter's unified API
|
|
6
|
+
*/
|
|
7
|
+
export declare class OpenRouterChatServiceProvider implements ChatServiceProvider {
|
|
8
|
+
/**
|
|
9
|
+
* Create a chat service instance
|
|
10
|
+
* @param options Service options
|
|
11
|
+
* @returns OpenRouterChatService instance
|
|
12
|
+
*/
|
|
13
|
+
createChatService(options: ChatServiceOptions): ChatService;
|
|
14
|
+
/**
|
|
15
|
+
* Get the provider name
|
|
16
|
+
* @returns Provider name ('openrouter')
|
|
17
|
+
*/
|
|
18
|
+
getProviderName(): string;
|
|
19
|
+
/**
|
|
20
|
+
* Get the list of supported models
|
|
21
|
+
* Currently only supports gpt-oss-20b:free
|
|
22
|
+
* @returns Array of supported model names
|
|
23
|
+
*/
|
|
24
|
+
getSupportedModels(): string[];
|
|
25
|
+
/**
|
|
26
|
+
* Get the default model
|
|
27
|
+
* @returns Default model name (gpt-oss-20b:free)
|
|
28
|
+
*/
|
|
29
|
+
getDefaultModel(): string;
|
|
30
|
+
/**
|
|
31
|
+
* Check if this provider supports vision (image processing)
|
|
32
|
+
* @returns Vision support status (false - gpt-oss-20b does not support vision)
|
|
33
|
+
*/
|
|
34
|
+
supportsVision(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Check if a specific model supports vision capabilities
|
|
37
|
+
* @param model The model name to check
|
|
38
|
+
* @returns True if the model supports vision, false otherwise
|
|
39
|
+
*/
|
|
40
|
+
supportsVisionForModel(model: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Get list of free tier models
|
|
43
|
+
* @returns Array of free model names
|
|
44
|
+
*/
|
|
45
|
+
getFreeModels(): string[];
|
|
46
|
+
/**
|
|
47
|
+
* Check if a model is free tier
|
|
48
|
+
* @param model Model name to check
|
|
49
|
+
* @returns True if the model is free
|
|
50
|
+
*/
|
|
51
|
+
isModelFree(model: string): boolean;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=OpenRouterChatServiceProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenRouterChatServiceProvider.d.ts","sourceRoot":"","sources":["../../../../../src/services/providers/openrouter/OpenRouterChatServiceProvider.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAGhC;;;GAGG;AACH,qBAAa,6BAA8B,YAAW,mBAAmB;IACvE;;;;OAIG;IACH,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW;IAsC3D;;;OAGG;IACH,eAAe,IAAI,MAAM;IAIzB;;;;OAIG;IACH,kBAAkB,IAAI,MAAM,EAAE;IAO9B;;;OAGG;IACH,eAAe,IAAI,MAAM;IAIzB;;;OAGG;IACH,cAAc,IAAI,OAAO;IAIzB;;;;OAIG;IACH,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAI9C;;;OAGG;IACH,aAAa,IAAI,MAAM,EAAE;IAIzB;;;;OAIG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;CAGpC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenRouterChatServiceProvider = void 0;
|
|
4
|
+
const openrouter_1 = require("../../../constants/openrouter");
|
|
5
|
+
const OpenRouterChatService_1 = require("./OpenRouterChatService");
|
|
6
|
+
/**
|
|
7
|
+
* OpenRouter API provider implementation
|
|
8
|
+
* Provides access to multiple AI models through OpenRouter's unified API
|
|
9
|
+
*/
|
|
10
|
+
class OpenRouterChatServiceProvider {
|
|
11
|
+
/**
|
|
12
|
+
* Create a chat service instance
|
|
13
|
+
* @param options Service options
|
|
14
|
+
* @returns OpenRouterChatService instance
|
|
15
|
+
*/
|
|
16
|
+
createChatService(options) {
|
|
17
|
+
// For OpenRouter, use the main model as vision model placeholder
|
|
18
|
+
// Only validate if visionModel is explicitly provided
|
|
19
|
+
const visionModel = options.visionModel || options.model || this.getDefaultModel();
|
|
20
|
+
// If visionModel is explicitly provided and different from main model, validate it
|
|
21
|
+
if (options.visionModel &&
|
|
22
|
+
!this.supportsVisionForModel(options.visionModel)) {
|
|
23
|
+
throw new Error(`Model ${options.visionModel} does not support vision capabilities.`);
|
|
24
|
+
}
|
|
25
|
+
// Tools definition
|
|
26
|
+
const tools = options.tools;
|
|
27
|
+
// Extract OpenRouter-specific options
|
|
28
|
+
const appName = options.appName;
|
|
29
|
+
const appUrl = options.appUrl;
|
|
30
|
+
return new OpenRouterChatService_1.OpenRouterChatService(options.apiKey, options.model || this.getDefaultModel(), visionModel, tools, options.endpoint, options.responseLength, appName, appUrl, options.reasoning_effort, options.includeReasoning, options.reasoningMaxTokens);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get the provider name
|
|
34
|
+
* @returns Provider name ('openrouter')
|
|
35
|
+
*/
|
|
36
|
+
getProviderName() {
|
|
37
|
+
return 'openrouter';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the list of supported models
|
|
41
|
+
* Currently only supports gpt-oss-20b:free
|
|
42
|
+
* @returns Array of supported model names
|
|
43
|
+
*/
|
|
44
|
+
getSupportedModels() {
|
|
45
|
+
return [
|
|
46
|
+
// Free models
|
|
47
|
+
openrouter_1.MODEL_GPT_OSS_20B_FREE,
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get the default model
|
|
52
|
+
* @returns Default model name (gpt-oss-20b:free)
|
|
53
|
+
*/
|
|
54
|
+
getDefaultModel() {
|
|
55
|
+
return openrouter_1.MODEL_GPT_OSS_20B_FREE;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if this provider supports vision (image processing)
|
|
59
|
+
* @returns Vision support status (false - gpt-oss-20b does not support vision)
|
|
60
|
+
*/
|
|
61
|
+
supportsVision() {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if a specific model supports vision capabilities
|
|
66
|
+
* @param model The model name to check
|
|
67
|
+
* @returns True if the model supports vision, false otherwise
|
|
68
|
+
*/
|
|
69
|
+
supportsVisionForModel(model) {
|
|
70
|
+
return (0, openrouter_1.isOpenRouterVisionModel)(model);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get list of free tier models
|
|
74
|
+
* @returns Array of free model names
|
|
75
|
+
*/
|
|
76
|
+
getFreeModels() {
|
|
77
|
+
return openrouter_1.OPENROUTER_FREE_MODELS;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if a model is free tier
|
|
81
|
+
* @param model Model name to check
|
|
82
|
+
* @returns True if the model is free
|
|
83
|
+
*/
|
|
84
|
+
isModelFree(model) {
|
|
85
|
+
return openrouter_1.OPENROUTER_FREE_MODELS.includes(model) || model.endsWith(':free');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.OpenRouterChatServiceProvider = OpenRouterChatServiceProvider;
|
|
89
|
+
//# sourceMappingURL=OpenRouterChatServiceProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenRouterChatServiceProvider.js","sourceRoot":"","sources":["../../../../../src/services/providers/openrouter/OpenRouterChatServiceProvider.ts"],"names":[],"mappings":";;;AAAA,8DAIuC;AAEvC,mEAAgE;AAOhE;;;GAGG;AACH,MAAa,6BAA6B;IACxC;;;;OAIG;IACH,iBAAiB,CAAC,OAA2B;QAC3C,iEAAiE;QACjE,sDAAsD;QACtD,MAAM,WAAW,GACf,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;QAEjE,mFAAmF;QACnF,IACE,OAAO,CAAC,WAAW;YACnB,CAAC,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,WAAW,CAAC,EACjD,CAAC;YACD,MAAM,IAAI,KAAK,CACb,SAAS,OAAO,CAAC,WAAW,wCAAwC,CACrE,CAAC;QACJ,CAAC;QAED,mBAAmB;QACnB,MAAM,KAAK,GAAiC,OAAO,CAAC,KAAK,CAAC;QAE1D,sCAAsC;QACtC,MAAM,OAAO,GAAI,OAAe,CAAC,OAAO,CAAC;QACzC,MAAM,MAAM,GAAI,OAAe,CAAC,MAAM,CAAC;QAEvC,OAAO,IAAI,6CAAqB,CAC9B,OAAO,CAAC,MAAM,EACd,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE,EACvC,WAAW,EACX,KAAK,EACL,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,cAAc,EACtB,OAAO,EACP,MAAM,EACN,OAAO,CAAC,gBAAgB,EACxB,OAAO,CAAC,gBAAgB,EACvB,OAAe,CAAC,kBAAkB,CACpC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,eAAe;QACb,OAAO,YAAY,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACH,kBAAkB;QAChB,OAAO;YACL,cAAc;YACd,mCAAsB;SACvB,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,eAAe;QACb,OAAO,mCAAsB,CAAC;IAChC,CAAC;IAED;;;OAGG;IACH,cAAc;QACZ,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;OAIG;IACH,sBAAsB,CAAC,KAAa;QAClC,OAAO,IAAA,oCAAuB,EAAC,KAAK,CAAC,CAAC;IACxC,CAAC;IAED;;;OAGG;IACH,aAAa;QACX,OAAO,mCAAsB,CAAC;IAChC,CAAC;IAED;;;;OAIG;IACH,WAAW,CAAC,KAAa;QACvB,OAAO,mCAAsB,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3E,CAAC;CACF;AAzGD,sEAyGC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/constants/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/constants/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/constants/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/constants/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const ENDPOINT_OPENROUTER_API = "https://openrouter.ai/api/v1/chat/completions";
|
|
2
|
+
export declare const MODEL_GPT_OSS_20B_FREE = "openai/gpt-oss-20b:free";
|
|
3
|
+
export declare const OPENROUTER_FREE_MODELS: string[];
|
|
4
|
+
export declare const OPENROUTER_VISION_SUPPORTED_MODELS: never[];
|
|
5
|
+
export declare const OPENROUTER_FREE_RATE_LIMIT_PER_MINUTE = 20;
|
|
6
|
+
export declare const OPENROUTER_FREE_DAILY_LIMIT_LOW_CREDITS = 50;
|
|
7
|
+
export declare const OPENROUTER_FREE_DAILY_LIMIT_HIGH_CREDITS = 1000;
|
|
8
|
+
export declare const OPENROUTER_CREDITS_THRESHOLD = 10;
|
|
9
|
+
/**
|
|
10
|
+
* Check if a model is a free tier model
|
|
11
|
+
* @param model Model name to check
|
|
12
|
+
* @returns True if the model is free tier
|
|
13
|
+
*/
|
|
14
|
+
export declare function isOpenRouterFreeModel(model: string): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a model supports vision on OpenRouter
|
|
17
|
+
* @param model Model name to check
|
|
18
|
+
* @returns True if the model supports vision
|
|
19
|
+
*/
|
|
20
|
+
export declare function isOpenRouterVisionModel(model: string): boolean;
|
|
21
|
+
//# sourceMappingURL=openrouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../../src/constants/openrouter.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB,kDACa,CAAC;AAGlD,eAAO,MAAM,sBAAsB,4BAA4B,CAAC;AAGhE,eAAO,MAAM,sBAAsB,UAA2B,CAAC;AAG/D,eAAO,MAAM,kCAAkC,SAAK,CAAC;AAGrD,eAAO,MAAM,qCAAqC,KAAK,CAAC;AACxD,eAAO,MAAM,uCAAuC,KAAK,CAAC;AAC1D,eAAO,MAAM,wCAAwC,OAAO,CAAC;AAC7D,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAI9D"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const ENDPOINT_OPENROUTER_API = 'https://openrouter.ai/api/v1/chat/completions';
|
|
2
|
+
// OpenRouter models
|
|
3
|
+
export const MODEL_GPT_OSS_20B_FREE = 'openai/gpt-oss-20b:free';
|
|
4
|
+
// Free tier models
|
|
5
|
+
export const OPENROUTER_FREE_MODELS = [MODEL_GPT_OSS_20B_FREE];
|
|
6
|
+
// Vision supported models on OpenRouter
|
|
7
|
+
export const OPENROUTER_VISION_SUPPORTED_MODELS = [];
|
|
8
|
+
// Rate limits for free tier
|
|
9
|
+
export const OPENROUTER_FREE_RATE_LIMIT_PER_MINUTE = 20;
|
|
10
|
+
export const OPENROUTER_FREE_DAILY_LIMIT_LOW_CREDITS = 50;
|
|
11
|
+
export const OPENROUTER_FREE_DAILY_LIMIT_HIGH_CREDITS = 1000;
|
|
12
|
+
export const OPENROUTER_CREDITS_THRESHOLD = 10;
|
|
13
|
+
/**
|
|
14
|
+
* Check if a model is a free tier model
|
|
15
|
+
* @param model Model name to check
|
|
16
|
+
* @returns True if the model is free tier
|
|
17
|
+
*/
|
|
18
|
+
export function isOpenRouterFreeModel(model) {
|
|
19
|
+
return OPENROUTER_FREE_MODELS.some((freeModel) => model.includes(freeModel));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Check if a model supports vision on OpenRouter
|
|
23
|
+
* @param model Model name to check
|
|
24
|
+
* @returns True if the model supports vision
|
|
25
|
+
*/
|
|
26
|
+
export function isOpenRouterVisionModel(model) {
|
|
27
|
+
return OPENROUTER_VISION_SUPPORTED_MODELS.some((visionModel) => model.includes(visionModel));
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=openrouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../../src/constants/openrouter.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAClC,+CAA+C,CAAC;AAElD,oBAAoB;AACpB,MAAM,CAAC,MAAM,sBAAsB,GAAG,yBAAyB,CAAC;AAEhE,mBAAmB;AACnB,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,sBAAsB,CAAC,CAAC;AAE/D,wCAAwC;AACxC,MAAM,CAAC,MAAM,kCAAkC,GAAG,EAAE,CAAC;AAErD,4BAA4B;AAC5B,MAAM,CAAC,MAAM,qCAAqC,GAAG,EAAE,CAAC;AACxD,MAAM,CAAC,MAAM,uCAAuC,GAAG,EAAE,CAAC;AAC1D,MAAM,CAAC,MAAM,wCAAwC,GAAG,IAAI,CAAC;AAC7D,MAAM,CAAC,MAAM,4BAA4B,GAAG,EAAE,CAAC;AAE/C;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAa;IACnD,OAAO,kCAAkC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAC7D,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,CAC5B,CAAC;AACJ,CAAC"}
|