@absolutejs/ai 0.0.56 → 0.0.57
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/CHANGELOG.md +17 -0
- package/README.md +42 -0
- package/changelog.json +30 -0
- package/dist/ai/index.js +1261 -778
- package/dist/ai/index.js.map +13 -10
- package/dist/ai/providers/anthropic.js +117 -1
- package/dist/ai/providers/anthropic.js.map +7 -6
- package/dist/ai/providers/gemini.js +97 -4
- package/dist/ai/providers/gemini.js.map +7 -6
- package/dist/ai/providers/ollama.js +3 -1
- package/dist/ai/providers/ollama.js.map +4 -4
- package/dist/ai/providers/openai.js +875 -41
- package/dist/ai/providers/openai.js.map +9 -6
- package/dist/ai/providers/openaiCompatible.js +875 -41
- package/dist/ai/providers/openaiCompatible.js.map +9 -6
- package/dist/ai/providers/openaiResponses.js +297 -3
- package/dist/ai/providers/openaiResponses.js.map +8 -6
- package/dist/ai/providers/openrouter.js +1088 -737
- package/dist/ai/providers/openrouter.js.map +10 -8
- package/dist/src/ai/index.d.ts +4 -0
- package/dist/src/ai/inputCapacity.d.ts +25 -0
- package/dist/src/ai/prepareTextInput.d.ts +21 -0
- package/dist/src/ai/providers/gemini.d.ts +1 -0
- package/dist/src/ai/providers/openai.d.ts +1 -0
- package/dist/src/ai/providers/openaiCapacity.d.ts +11 -0
- package/dist/src/ai/providers/openaiResponses.d.ts +2 -0
- package/dist/src/ai/providers/openrouterClient.d.ts +1 -1
- package/dist/types/ai.d.ts +5 -0
- package/package.json +11 -6
|
@@ -1,6 +1,286 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
var __require = import.meta.require;
|
|
3
3
|
|
|
4
|
+
// src/ai/inputCapacity.ts
|
|
5
|
+
class AIInputError extends Error {
|
|
6
|
+
code;
|
|
7
|
+
constructor(code, message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.code = code;
|
|
10
|
+
this.name = "AIInputError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
var positiveTokenLimit = (value) => {
|
|
14
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0)
|
|
15
|
+
throw new AIInputError("capacity_unavailable", "The provider did not supply a valid model limit.");
|
|
16
|
+
return value;
|
|
17
|
+
};
|
|
18
|
+
var inputTokenCount = (value) => {
|
|
19
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
|
|
20
|
+
throw new AIInputError("capacity_unavailable", "The provider did not supply a valid token count.");
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var inspectAIInput = async (provider, params) => {
|
|
24
|
+
params.signal?.throwIfAborted();
|
|
25
|
+
if (!provider.inputCapacity)
|
|
26
|
+
throw new AIInputError("capacity_unavailable", "This provider does not expose model capacity and token counting.");
|
|
27
|
+
const [limits, tokens] = await Promise.all([
|
|
28
|
+
provider.inputCapacity.getLimits(params),
|
|
29
|
+
provider.inputCapacity.countTokens(params)
|
|
30
|
+
]);
|
|
31
|
+
const inputTokens = inputTokenCount(tokens);
|
|
32
|
+
const outputTokens = positiveTokenLimit(provider.inputCapacity.outputTokens?.(params) ?? params.maxTokens ?? limits.maxOutputTokens);
|
|
33
|
+
const maxInputTokens = positiveTokenLimit(limits.maxInputTokens);
|
|
34
|
+
const maxOutputTokens = positiveTokenLimit(limits.maxOutputTokens);
|
|
35
|
+
const availableInputTokens = Math.max(0, Math.min(maxInputTokens, limits.contextWindowTokens === undefined ? maxInputTokens : positiveTokenLimit(limits.contextWindowTokens) - outputTokens));
|
|
36
|
+
return {
|
|
37
|
+
limits,
|
|
38
|
+
inputTokens,
|
|
39
|
+
outputTokens,
|
|
40
|
+
availableInputTokens,
|
|
41
|
+
fits: outputTokens <= maxOutputTokens && inputTokens <= availableInputTokens
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
var cacheModelLimits = (load, ttlMs = 300000) => {
|
|
45
|
+
const cache = new Map;
|
|
46
|
+
return async (params) => {
|
|
47
|
+
const entry = cache.get(params.model);
|
|
48
|
+
if (entry && Date.now() - entry.at < ttlMs)
|
|
49
|
+
return entry.limits;
|
|
50
|
+
const limits = await load(params);
|
|
51
|
+
positiveTokenLimit(limits.maxInputTokens);
|
|
52
|
+
positiveTokenLimit(limits.maxOutputTokens);
|
|
53
|
+
if (cache.size >= 100)
|
|
54
|
+
cache.clear();
|
|
55
|
+
cache.set(params.model, { at: Date.now(), limits });
|
|
56
|
+
return limits;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
var capacityJson = async (response) => {
|
|
60
|
+
if (!response.ok)
|
|
61
|
+
throw new AIInputError("capacity_unavailable", `Model capacity request failed (${response.status}).`);
|
|
62
|
+
const value = await response.json();
|
|
63
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
64
|
+
throw new AIInputError("capacity_unavailable", "Model capacity response was invalid.");
|
|
65
|
+
return value;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// src/ai/providers/openaiCapacity.ts
|
|
69
|
+
var LIMITS = {
|
|
70
|
+
"gpt-4.1": {
|
|
71
|
+
maxInputTokens: 1047576,
|
|
72
|
+
contextWindowTokens: 1047576,
|
|
73
|
+
maxOutputTokens: 32768
|
|
74
|
+
},
|
|
75
|
+
"gpt-4.1-2025-04-14": {
|
|
76
|
+
maxInputTokens: 1047576,
|
|
77
|
+
contextWindowTokens: 1047576,
|
|
78
|
+
maxOutputTokens: 32768
|
|
79
|
+
},
|
|
80
|
+
"gpt-4.1-mini": {
|
|
81
|
+
maxInputTokens: 1047576,
|
|
82
|
+
contextWindowTokens: 1047576,
|
|
83
|
+
maxOutputTokens: 32768
|
|
84
|
+
},
|
|
85
|
+
"gpt-4.1-mini-2025-04-14": {
|
|
86
|
+
maxInputTokens: 1047576,
|
|
87
|
+
contextWindowTokens: 1047576,
|
|
88
|
+
maxOutputTokens: 32768
|
|
89
|
+
},
|
|
90
|
+
"gpt-4.1-nano": {
|
|
91
|
+
maxInputTokens: 1047576,
|
|
92
|
+
contextWindowTokens: 1047576,
|
|
93
|
+
maxOutputTokens: 32768
|
|
94
|
+
},
|
|
95
|
+
"gpt-4.1-nano-2025-04-14": {
|
|
96
|
+
maxInputTokens: 1047576,
|
|
97
|
+
contextWindowTokens: 1047576,
|
|
98
|
+
maxOutputTokens: 32768
|
|
99
|
+
},
|
|
100
|
+
"gpt-4o": {
|
|
101
|
+
maxInputTokens: 128000,
|
|
102
|
+
contextWindowTokens: 128000,
|
|
103
|
+
maxOutputTokens: 16384
|
|
104
|
+
},
|
|
105
|
+
"gpt-4o-mini": {
|
|
106
|
+
maxInputTokens: 128000,
|
|
107
|
+
contextWindowTokens: 128000,
|
|
108
|
+
maxOutputTokens: 16384
|
|
109
|
+
},
|
|
110
|
+
"gpt-4o-mini-2024-07-18": {
|
|
111
|
+
maxInputTokens: 128000,
|
|
112
|
+
contextWindowTokens: 128000,
|
|
113
|
+
maxOutputTokens: 16384
|
|
114
|
+
},
|
|
115
|
+
"gpt-5": {
|
|
116
|
+
maxInputTokens: 272000,
|
|
117
|
+
contextWindowTokens: 400000,
|
|
118
|
+
maxOutputTokens: 128000
|
|
119
|
+
},
|
|
120
|
+
"gpt-5-mini": {
|
|
121
|
+
maxInputTokens: 272000,
|
|
122
|
+
contextWindowTokens: 400000,
|
|
123
|
+
maxOutputTokens: 128000
|
|
124
|
+
},
|
|
125
|
+
"gpt-5-mini-2025-08-07": {
|
|
126
|
+
maxInputTokens: 272000,
|
|
127
|
+
contextWindowTokens: 400000,
|
|
128
|
+
maxOutputTokens: 128000
|
|
129
|
+
},
|
|
130
|
+
"gpt-5-nano": {
|
|
131
|
+
maxInputTokens: 272000,
|
|
132
|
+
contextWindowTokens: 400000,
|
|
133
|
+
maxOutputTokens: 128000
|
|
134
|
+
},
|
|
135
|
+
"gpt-5-nano-2025-08-07": {
|
|
136
|
+
maxInputTokens: 272000,
|
|
137
|
+
contextWindowTokens: 400000,
|
|
138
|
+
maxOutputTokens: 128000
|
|
139
|
+
},
|
|
140
|
+
"gpt-5.4-mini": {
|
|
141
|
+
maxInputTokens: 272000,
|
|
142
|
+
contextWindowTokens: 400000,
|
|
143
|
+
maxOutputTokens: 128000
|
|
144
|
+
},
|
|
145
|
+
"gpt-5.4-nano": {
|
|
146
|
+
maxInputTokens: 272000,
|
|
147
|
+
contextWindowTokens: 400000,
|
|
148
|
+
maxOutputTokens: 128000
|
|
149
|
+
},
|
|
150
|
+
"gpt-5.1": {
|
|
151
|
+
maxInputTokens: 400000,
|
|
152
|
+
contextWindowTokens: 400000,
|
|
153
|
+
maxOutputTokens: 128000
|
|
154
|
+
},
|
|
155
|
+
"gpt-5.1-2025-11-13": {
|
|
156
|
+
maxInputTokens: 400000,
|
|
157
|
+
contextWindowTokens: 400000,
|
|
158
|
+
maxOutputTokens: 128000
|
|
159
|
+
},
|
|
160
|
+
"gpt-5.2": {
|
|
161
|
+
maxInputTokens: 400000,
|
|
162
|
+
contextWindowTokens: 400000,
|
|
163
|
+
maxOutputTokens: 128000
|
|
164
|
+
},
|
|
165
|
+
"gpt-5.2-2025-12-11": {
|
|
166
|
+
maxInputTokens: 400000,
|
|
167
|
+
contextWindowTokens: 400000,
|
|
168
|
+
maxOutputTokens: 128000
|
|
169
|
+
},
|
|
170
|
+
"gpt-5.4": {
|
|
171
|
+
maxInputTokens: 1050000,
|
|
172
|
+
contextWindowTokens: 1050000,
|
|
173
|
+
maxOutputTokens: 128000
|
|
174
|
+
},
|
|
175
|
+
"gpt-5.4-2026-03-05": {
|
|
176
|
+
maxInputTokens: 1050000,
|
|
177
|
+
contextWindowTokens: 1050000,
|
|
178
|
+
maxOutputTokens: 128000
|
|
179
|
+
},
|
|
180
|
+
"gpt-5.5": {
|
|
181
|
+
maxInputTokens: 1050000,
|
|
182
|
+
contextWindowTokens: 1050000,
|
|
183
|
+
maxOutputTokens: 128000
|
|
184
|
+
},
|
|
185
|
+
"gpt-6-astra": {
|
|
186
|
+
maxInputTokens: 922000,
|
|
187
|
+
contextWindowTokens: 1050000,
|
|
188
|
+
maxOutputTokens: 128000
|
|
189
|
+
},
|
|
190
|
+
"gpt-5.6-sol": {
|
|
191
|
+
maxInputTokens: 922000,
|
|
192
|
+
contextWindowTokens: 1050000,
|
|
193
|
+
maxOutputTokens: 128000
|
|
194
|
+
},
|
|
195
|
+
"gpt-5.6-terra": {
|
|
196
|
+
maxInputTokens: 922000,
|
|
197
|
+
contextWindowTokens: 1050000,
|
|
198
|
+
maxOutputTokens: 128000
|
|
199
|
+
},
|
|
200
|
+
"gpt-5.6-luna": {
|
|
201
|
+
maxInputTokens: 922000,
|
|
202
|
+
contextWindowTokens: 1050000,
|
|
203
|
+
maxOutputTokens: 128000
|
|
204
|
+
},
|
|
205
|
+
o3: {
|
|
206
|
+
maxInputTokens: 200000,
|
|
207
|
+
contextWindowTokens: 200000,
|
|
208
|
+
maxOutputTokens: 1e5
|
|
209
|
+
},
|
|
210
|
+
"o3-2025-04-16": {
|
|
211
|
+
maxInputTokens: 200000,
|
|
212
|
+
contextWindowTokens: 200000,
|
|
213
|
+
maxOutputTokens: 1e5
|
|
214
|
+
},
|
|
215
|
+
"o4-mini": {
|
|
216
|
+
maxInputTokens: 200000,
|
|
217
|
+
contextWindowTokens: 200000,
|
|
218
|
+
maxOutputTokens: 1e5
|
|
219
|
+
},
|
|
220
|
+
"o4-mini-2025-04-16": {
|
|
221
|
+
maxInputTokens: 200000,
|
|
222
|
+
contextWindowTokens: 200000,
|
|
223
|
+
maxOutputTokens: 1e5
|
|
224
|
+
},
|
|
225
|
+
"gpt-5-chat-latest": {
|
|
226
|
+
maxInputTokens: 128000,
|
|
227
|
+
contextWindowTokens: 128000,
|
|
228
|
+
maxOutputTokens: 16384
|
|
229
|
+
},
|
|
230
|
+
"gpt-5.1-chat-latest": {
|
|
231
|
+
maxInputTokens: 128000,
|
|
232
|
+
contextWindowTokens: 128000,
|
|
233
|
+
maxOutputTokens: 16384
|
|
234
|
+
},
|
|
235
|
+
"gpt-5.2-chat-latest": {
|
|
236
|
+
maxInputTokens: 128000,
|
|
237
|
+
contextWindowTokens: 128000,
|
|
238
|
+
maxOutputTokens: 16384
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
var openaiInputCapacity = (config) => ({
|
|
242
|
+
outputTokens: (params) => {
|
|
243
|
+
const value = config.body(params).max_output_tokens;
|
|
244
|
+
return value === undefined ? undefined : positiveTokenLimit(value);
|
|
245
|
+
},
|
|
246
|
+
getLimits: async (params) => {
|
|
247
|
+
if (config.modelLimits)
|
|
248
|
+
return config.modelLimits(params);
|
|
249
|
+
if (new URL(config.baseUrl).origin !== "https://api.openai.com")
|
|
250
|
+
throw new AIInputError("capacity_unavailable", "This compatible endpoint must expose its own model capacity.");
|
|
251
|
+
const limits = LIMITS[params.model];
|
|
252
|
+
if (!limits)
|
|
253
|
+
throw new AIInputError("capacity_unavailable", `Model limits are unavailable for ${params.model}; no character limit has been substituted.`);
|
|
254
|
+
return { ...limits };
|
|
255
|
+
},
|
|
256
|
+
countTokens: async (params) => {
|
|
257
|
+
const headers = new Headers(await config.headers(params));
|
|
258
|
+
headers.set("Authorization", `Bearer ${await config.key()}`);
|
|
259
|
+
headers.set("Content-Type", "application/json");
|
|
260
|
+
const body = config.body(params);
|
|
261
|
+
const counted = {};
|
|
262
|
+
for (const key of [
|
|
263
|
+
"model",
|
|
264
|
+
"input",
|
|
265
|
+
"instructions",
|
|
266
|
+
"tools",
|
|
267
|
+
"tool_choice",
|
|
268
|
+
"reasoning",
|
|
269
|
+
"text",
|
|
270
|
+
"parallel_tool_calls"
|
|
271
|
+
])
|
|
272
|
+
if (body[key] !== undefined)
|
|
273
|
+
counted[key] = body[key];
|
|
274
|
+
const response = await config.fetch(`${config.baseUrl}/v1/responses/input_tokens`, {
|
|
275
|
+
method: "POST",
|
|
276
|
+
headers,
|
|
277
|
+
body: JSON.stringify(counted),
|
|
278
|
+
signal: params.signal ? AbortSignal.any([params.signal, AbortSignal.timeout(15000)]) : AbortSignal.timeout(15000)
|
|
279
|
+
});
|
|
280
|
+
return inputTokenCount((await capacityJson(response)).input_tokens);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
|
|
4
284
|
// src/ai/errors/providerError.ts
|
|
5
285
|
var PROVIDER_STATUS_PAGES = {
|
|
6
286
|
anthropic: "https://status.claude.com",
|
|
@@ -231,6 +511,7 @@ var withResilience = (provider, providerName = "unknown") => {
|
|
|
231
511
|
}
|
|
232
512
|
};
|
|
233
513
|
return {
|
|
514
|
+
...provider,
|
|
234
515
|
stream: (params) => {
|
|
235
516
|
const tripped = circuitOpen(providerName);
|
|
236
517
|
if (tripped) {
|
|
@@ -247,6 +528,7 @@ var withResilience = (provider, providerName = "unknown") => {
|
|
|
247
528
|
var instrumentAIProvider = (provider, providerName) => {
|
|
248
529
|
const resilient = withResilience(provider, providerName);
|
|
249
530
|
return {
|
|
531
|
+
...provider,
|
|
250
532
|
stream: (params) => {
|
|
251
533
|
if (!params.onUsage && !params.onSpan) {
|
|
252
534
|
return resilient.stream(params);
|
|
@@ -388,81 +670,23 @@ var openaiEffortValue = (model, reasoning) => {
|
|
|
388
670
|
return clampEffort(requested, allowed);
|
|
389
671
|
};
|
|
390
672
|
|
|
391
|
-
// src/ai/providers/
|
|
673
|
+
// src/ai/providers/openaiResponses.ts
|
|
392
674
|
var h2IfHttps = (url) => url.startsWith("https://") ? { protocol: "http2" } : {};
|
|
393
675
|
var DEFAULT_BASE_URL = "https://api.openai.com";
|
|
394
|
-
var
|
|
395
|
-
var
|
|
396
|
-
var NOT_FOUND = -1;
|
|
676
|
+
var EVENT_PREFIX_LENGTH = 7;
|
|
677
|
+
var DATA_PREFIX_LENGTH = 6;
|
|
397
678
|
var isRecord = (value) => typeof value === "object" && value !== null;
|
|
398
679
|
var isRecordArray = (value) => Array.isArray(value) && value.length > 0 && isRecord(value[0]);
|
|
399
|
-
var
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
const toolResultBlocks = blocks.filter((block) => block.type === "tool_result");
|
|
403
|
-
const messages = [];
|
|
404
|
-
if (toolUseBlocks.length > 0) {
|
|
405
|
-
messages.push({
|
|
406
|
-
content: null,
|
|
407
|
-
role: "assistant",
|
|
408
|
-
tool_calls: toolUseBlocks.map((block) => ({
|
|
409
|
-
function: {
|
|
410
|
-
arguments: typeof block.input === "string" ? block.input : JSON.stringify(block.input),
|
|
411
|
-
name: block.name
|
|
412
|
-
},
|
|
413
|
-
id: block.id,
|
|
414
|
-
type: "function"
|
|
415
|
-
}))
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
for (const result of toolResultBlocks) {
|
|
419
|
-
messages.push({
|
|
420
|
-
content: typeof result.content === "string" ? result.content : "",
|
|
421
|
-
role: "tool",
|
|
422
|
-
tool_call_id: result.tool_use_id
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
return messages;
|
|
426
|
-
};
|
|
427
|
-
var processMessageAtIndex = (result, msg, idx) => {
|
|
428
|
-
if (!hasArrayContent(msg)) {
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
|
-
const hasToolBlocks = msg.content.some((block) => block.type === "tool_use" || block.type === "tool_result");
|
|
432
|
-
if (!hasToolBlocks) {
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
const toolMessages = buildToolMessages(msg.content);
|
|
436
|
-
result.splice(idx, 1, ...toolMessages);
|
|
437
|
-
};
|
|
438
|
-
var convertSingleMessage = (result, msg, idx) => {
|
|
439
|
-
if (!msg) {
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
processMessageAtIndex(result, msg, idx);
|
|
443
|
-
};
|
|
444
|
-
var convertToolResultMessages = (messages, params) => {
|
|
445
|
-
const result = [...messages];
|
|
446
|
-
for (let idx = 0;idx < params.messages.length; idx++) {
|
|
447
|
-
convertSingleMessage(result, params.messages[idx], idx);
|
|
680
|
+
var mapBlockToResponsesFormat = (block) => {
|
|
681
|
+
if (block.type === "text") {
|
|
682
|
+
return { text: block.content, type: "input_text" };
|
|
448
683
|
}
|
|
449
|
-
return result;
|
|
450
|
-
};
|
|
451
|
-
var mapToolDefinitions = (tools) => tools.map((tool) => ({
|
|
452
|
-
function: {
|
|
453
|
-
description: tool.description,
|
|
454
|
-
name: tool.name,
|
|
455
|
-
parameters: tool.input_schema
|
|
456
|
-
},
|
|
457
|
-
type: "function"
|
|
458
|
-
}));
|
|
459
|
-
var mapContentBlockToOpenAI = (block) => {
|
|
460
684
|
if (block.type === "image") {
|
|
461
685
|
return {
|
|
462
686
|
image_url: {
|
|
463
687
|
url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
|
|
464
688
|
},
|
|
465
|
-
type: "
|
|
689
|
+
type: "input_image"
|
|
466
690
|
};
|
|
467
691
|
}
|
|
468
692
|
if (block.type === "document") {
|
|
@@ -471,7 +695,7 @@ var mapContentBlockToOpenAI = (block) => {
|
|
|
471
695
|
file_data: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`,
|
|
472
696
|
filename: block.name ?? "document.pdf"
|
|
473
697
|
},
|
|
474
|
-
type: "
|
|
698
|
+
type: "input_file"
|
|
475
699
|
};
|
|
476
700
|
}
|
|
477
701
|
if (block.type === "audio") {
|
|
@@ -482,48 +706,95 @@ var mapContentBlockToOpenAI = (block) => {
|
|
|
482
706
|
}
|
|
483
707
|
if (block.type === "video") {
|
|
484
708
|
return {
|
|
485
|
-
type: "
|
|
486
|
-
video_url: {
|
|
487
|
-
url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
|
|
488
|
-
}
|
|
709
|
+
type: "input_video",
|
|
710
|
+
video_url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
|
|
489
711
|
};
|
|
490
712
|
}
|
|
491
|
-
|
|
492
|
-
|
|
713
|
+
return null;
|
|
714
|
+
};
|
|
715
|
+
var mapContentToResponsesFormat = (content) => {
|
|
716
|
+
if (typeof content === "string") {
|
|
717
|
+
return content;
|
|
718
|
+
}
|
|
719
|
+
const parts = content.map(mapBlockToResponsesFormat).filter((mapped) => mapped !== null);
|
|
720
|
+
return parts.length > 0 ? parts : "";
|
|
721
|
+
};
|
|
722
|
+
var hasToolBlocks = (content) => content.some((block) => block.type === "tool_use" || block.type === "tool_result");
|
|
723
|
+
var convertToolBlock = (block) => {
|
|
724
|
+
if (block.type === "provider_data" && block.provider === "openrouter") {
|
|
725
|
+
return { ...block.data };
|
|
726
|
+
}
|
|
727
|
+
if (block.type === "tool_use") {
|
|
728
|
+
if (block.providerData)
|
|
729
|
+
return { ...block.providerData };
|
|
730
|
+
return {
|
|
731
|
+
arguments: typeof block.input === "string" ? block.input : JSON.stringify(block.input),
|
|
732
|
+
call_id: block.id,
|
|
733
|
+
name: block.name,
|
|
734
|
+
type: "function_call"
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
if (block.type === "tool_result") {
|
|
738
|
+
return {
|
|
739
|
+
call_id: block.tool_use_id,
|
|
740
|
+
output: typeof block.content === "string" ? block.content : "",
|
|
741
|
+
type: "function_call_output"
|
|
742
|
+
};
|
|
493
743
|
}
|
|
494
744
|
return null;
|
|
495
745
|
};
|
|
496
|
-
var
|
|
497
|
-
|
|
498
|
-
|
|
746
|
+
var convertToolBlocks = (content) => content.map(convertToolBlock).filter((converted) => converted !== null);
|
|
747
|
+
var convertMessage = (msg) => {
|
|
748
|
+
if (typeof msg.content !== "string" && Array.isArray(msg.content) && hasToolBlocks(msg.content)) {
|
|
749
|
+
return convertToolBlocks(msg.content);
|
|
499
750
|
}
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
751
|
+
const content = mapContentToResponsesFormat(msg.content);
|
|
752
|
+
return [
|
|
753
|
+
{
|
|
754
|
+
content,
|
|
755
|
+
role: msg.role === "system" ? "developer" : msg.role,
|
|
756
|
+
type: "message"
|
|
757
|
+
}
|
|
758
|
+
];
|
|
759
|
+
};
|
|
760
|
+
var buildInput = (messages) => {
|
|
761
|
+
const input = [];
|
|
762
|
+
for (const msg of messages) {
|
|
763
|
+
input.push(...convertMessage(msg));
|
|
503
764
|
}
|
|
504
|
-
return
|
|
765
|
+
return input;
|
|
505
766
|
};
|
|
506
|
-
var
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
767
|
+
var mapToolDefinition = (tool) => ({
|
|
768
|
+
description: tool.description,
|
|
769
|
+
name: tool.name,
|
|
770
|
+
parameters: tool.input_schema,
|
|
771
|
+
type: "function"
|
|
772
|
+
});
|
|
773
|
+
var buildTools = (tools, isImageModel) => {
|
|
774
|
+
const mapped = tools ? tools.map(mapToolDefinition) : [];
|
|
775
|
+
const result = [...mapped];
|
|
776
|
+
if (isImageModel) {
|
|
777
|
+
result.push({ type: "image_generation" });
|
|
513
778
|
}
|
|
779
|
+
return result.length > 0 ? result : undefined;
|
|
780
|
+
};
|
|
781
|
+
var buildResponsesRequestBody = (params, isImageModel, capabilityModel = params.model) => {
|
|
514
782
|
const body = {
|
|
515
|
-
messages,
|
|
783
|
+
input: buildInput(params.messages),
|
|
516
784
|
model: params.model,
|
|
517
|
-
stream: true
|
|
518
|
-
stream_options: { include_usage: true }
|
|
785
|
+
stream: true
|
|
519
786
|
};
|
|
520
|
-
if (params.
|
|
521
|
-
body.
|
|
787
|
+
if (params.systemPrompt) {
|
|
788
|
+
body.instructions = params.systemPrompt;
|
|
789
|
+
}
|
|
790
|
+
const tools = buildTools(params.tools, isImageModel);
|
|
791
|
+
if (tools) {
|
|
792
|
+
body.tools = tools;
|
|
522
793
|
if (params.toolChoice === "auto" || params.toolChoice === "none" || params.toolChoice === "required") {
|
|
523
794
|
body.tool_choice = params.toolChoice;
|
|
524
795
|
} else if (params.toolChoice && typeof params.toolChoice === "object") {
|
|
525
796
|
body.tool_choice = {
|
|
526
|
-
|
|
797
|
+
name: params.toolChoice.name,
|
|
527
798
|
type: "function"
|
|
528
799
|
};
|
|
529
800
|
}
|
|
@@ -531,24 +802,12 @@ var buildRequestBody = (params, capabilityModel = params.model) => {
|
|
|
531
802
|
body.parallel_tool_calls = params.parallelToolCalls;
|
|
532
803
|
}
|
|
533
804
|
}
|
|
534
|
-
if (
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
if (effort)
|
|
541
|
-
body.reasoning_effort = effort;
|
|
542
|
-
}
|
|
543
|
-
} else {
|
|
544
|
-
if (typeof params.temperature === "number") {
|
|
545
|
-
body.temperature = params.temperature;
|
|
546
|
-
}
|
|
547
|
-
if (typeof params.topP === "number")
|
|
548
|
-
body.top_p = params.topP;
|
|
549
|
-
if (typeof params.maxTokens === "number")
|
|
550
|
-
body.max_tokens = params.maxTokens;
|
|
551
|
-
}
|
|
805
|
+
if (typeof params.temperature === "number")
|
|
806
|
+
body.temperature = params.temperature;
|
|
807
|
+
if (typeof params.topP === "number")
|
|
808
|
+
body.top_p = params.topP;
|
|
809
|
+
if (typeof params.maxTokens === "number")
|
|
810
|
+
body.max_output_tokens = params.maxTokens;
|
|
552
811
|
if (params.stopSequences && params.stopSequences.length > 0)
|
|
553
812
|
body.stop = params.stopSequences;
|
|
554
813
|
if (typeof params.seed === "number")
|
|
@@ -559,20 +818,36 @@ var buildRequestBody = (params, capabilityModel = params.model) => {
|
|
|
559
818
|
body.presence_penalty = params.presencePenalty;
|
|
560
819
|
if (params.responseFormat) {
|
|
561
820
|
if (params.responseFormat.type === "text" || params.responseFormat.type === "json_object") {
|
|
562
|
-
body.
|
|
821
|
+
body.text = { format: { type: params.responseFormat.type } };
|
|
563
822
|
} else if (params.responseFormat.type === "json_schema") {
|
|
564
|
-
body.
|
|
565
|
-
|
|
823
|
+
body.text = {
|
|
824
|
+
format: {
|
|
566
825
|
name: params.responseFormat.name,
|
|
567
826
|
schema: params.responseFormat.schema,
|
|
568
|
-
strict: params.responseFormat.strict ?? true
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
};
|
|
572
|
-
}
|
|
827
|
+
strict: params.responseFormat.strict ?? true,
|
|
828
|
+
type: "json_schema"
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
if (params.reasoning && isOpenAIReasoningModel(capabilityModel)) {
|
|
834
|
+
const effort = openaiEffortValue(capabilityModel, params.reasoning);
|
|
835
|
+
if (effort) {
|
|
836
|
+
body.reasoning = {
|
|
837
|
+
effort,
|
|
838
|
+
summary: "auto"
|
|
839
|
+
};
|
|
840
|
+
}
|
|
573
841
|
}
|
|
574
842
|
return body;
|
|
575
843
|
};
|
|
844
|
+
var parseJSON = (data) => {
|
|
845
|
+
try {
|
|
846
|
+
return JSON.parse(data);
|
|
847
|
+
} catch {
|
|
848
|
+
return null;
|
|
849
|
+
}
|
|
850
|
+
};
|
|
576
851
|
var parseToolInput = (rawArguments) => {
|
|
577
852
|
try {
|
|
578
853
|
return JSON.parse(rawArguments);
|
|
@@ -580,284 +855,297 @@ var parseToolInput = (rawArguments) => {
|
|
|
580
855
|
return rawArguments;
|
|
581
856
|
}
|
|
582
857
|
};
|
|
583
|
-
var
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
yield {
|
|
587
|
-
id: tool.id,
|
|
588
|
-
input,
|
|
589
|
-
name: tool.name,
|
|
590
|
-
type: "tool_use"
|
|
591
|
-
};
|
|
858
|
+
var extractUsage = (response) => {
|
|
859
|
+
if (!isRecord(response.usage)) {
|
|
860
|
+
return;
|
|
592
861
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
const
|
|
597
|
-
const
|
|
598
|
-
|
|
862
|
+
const { usage } = response;
|
|
863
|
+
const input = typeof usage.input_tokens === "number" ? usage.input_tokens : 0;
|
|
864
|
+
const cached = isRecord(usage.input_tokens_details) && typeof usage.input_tokens_details.cached_tokens === "number" ? usage.input_tokens_details.cached_tokens : 0;
|
|
865
|
+
const outputDetails = isRecord(usage.output_tokens_details) ? usage.output_tokens_details : undefined;
|
|
866
|
+
const inputDetails = isRecord(usage.input_tokens_details) ? usage.input_tokens_details : undefined;
|
|
867
|
+
const costDetails = isRecord(usage.cost_details) ? usage.cost_details : undefined;
|
|
868
|
+
const normalized = {
|
|
599
869
|
cacheReadInputTokens: cached,
|
|
600
|
-
cacheWriteInputTokens:
|
|
601
|
-
costCredits:
|
|
602
|
-
inputTokens: Math.max(0,
|
|
603
|
-
outputTokens:
|
|
604
|
-
reasoningTokens:
|
|
605
|
-
upstreamInferenceCostCredits:
|
|
870
|
+
cacheWriteInputTokens: inputDetails && typeof inputDetails.cache_write_tokens === "number" ? inputDetails.cache_write_tokens : undefined,
|
|
871
|
+
costCredits: typeof usage.cost === "number" ? usage.cost : undefined,
|
|
872
|
+
inputTokens: Math.max(0, input - cached),
|
|
873
|
+
outputTokens: typeof usage.output_tokens === "number" ? usage.output_tokens : 0,
|
|
874
|
+
reasoningTokens: outputDetails && typeof outputDetails.reasoning_tokens === "number" ? outputDetails.reasoning_tokens : undefined,
|
|
875
|
+
upstreamInferenceCostCredits: costDetails && typeof costDetails.upstream_inference_cost === "number" ? costDetails.upstream_inference_cost : undefined
|
|
606
876
|
};
|
|
877
|
+
if (isRecord(usage.server_tool_use)) {
|
|
878
|
+
normalized.serverToolUse = Object.fromEntries(Object.entries(usage.server_tool_use).filter((entry) => typeof entry[1] === "number"));
|
|
879
|
+
}
|
|
880
|
+
return normalized;
|
|
607
881
|
};
|
|
608
|
-
var
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
882
|
+
var extractResponseMetadata = (response) => {
|
|
883
|
+
const providerMetadata = isRecord(response.openrouter_metadata) ? response.openrouter_metadata : undefined;
|
|
884
|
+
const generationId = typeof response.id === "string" ? response.id : undefined;
|
|
885
|
+
const model = typeof response.model === "string" ? response.model : undefined;
|
|
886
|
+
const provider = typeof response.provider === "string" ? response.provider : undefined;
|
|
887
|
+
const serviceTier = typeof response.service_tier === "string" ? response.service_tier : undefined;
|
|
888
|
+
if (!providerMetadata && !generationId && !model && !provider && !serviceTier)
|
|
614
889
|
return;
|
|
890
|
+
return { generationId, model, provider, providerMetadata, serviceTier };
|
|
891
|
+
};
|
|
892
|
+
var extractMimeFormat = (mimeType) => {
|
|
893
|
+
if (typeof mimeType !== "string") {
|
|
894
|
+
return "png";
|
|
615
895
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
name: toolName
|
|
622
|
-
});
|
|
896
|
+
if (mimeType.includes("jpeg"))
|
|
897
|
+
return "jpeg";
|
|
898
|
+
if (mimeType.includes("webp"))
|
|
899
|
+
return "webp";
|
|
900
|
+
return "png";
|
|
623
901
|
};
|
|
624
|
-
var
|
|
625
|
-
if (typeof
|
|
626
|
-
|
|
902
|
+
var processTextDelta = function* (parsed) {
|
|
903
|
+
if (typeof parsed.delta === "string") {
|
|
904
|
+
yield { content: parsed.delta, type: "text" };
|
|
627
905
|
}
|
|
628
|
-
|
|
629
|
-
|
|
906
|
+
};
|
|
907
|
+
var processPartialImage = function* (parsed) {
|
|
908
|
+
const itemId = typeof parsed.item_id === "string" ? parsed.item_id : undefined;
|
|
909
|
+
const b64 = typeof parsed.partial_image_b64 === "string" ? parsed.partial_image_b64 : undefined;
|
|
910
|
+
if (b64) {
|
|
911
|
+
yield {
|
|
912
|
+
data: b64,
|
|
913
|
+
format: "png",
|
|
914
|
+
imageId: itemId,
|
|
915
|
+
isPartial: true,
|
|
916
|
+
type: "image"
|
|
917
|
+
};
|
|
630
918
|
}
|
|
631
|
-
|
|
632
|
-
|
|
919
|
+
};
|
|
920
|
+
var processFunctionCallArgumentsDelta = (parsed, pendingCalls) => {
|
|
921
|
+
const itemId = typeof parsed.item_id === "string" ? parsed.item_id : "";
|
|
922
|
+
const callId = typeof parsed.call_id === "string" ? parsed.call_id : "";
|
|
923
|
+
const delta = typeof parsed.arguments_delta === "string" ? parsed.arguments_delta : "";
|
|
924
|
+
const existing = pendingCalls.get(itemId);
|
|
925
|
+
if (existing) {
|
|
926
|
+
existing.arguments += delta;
|
|
927
|
+
} else {
|
|
928
|
+
pendingCalls.set(itemId, {
|
|
929
|
+
arguments: delta,
|
|
930
|
+
callId,
|
|
931
|
+
name: ""
|
|
932
|
+
});
|
|
633
933
|
}
|
|
634
934
|
};
|
|
635
|
-
var
|
|
636
|
-
const
|
|
637
|
-
|
|
935
|
+
var processFunctionCallArgumentsDone = function* (parsed, pendingCalls) {
|
|
936
|
+
const itemId = typeof parsed.item_id === "string" ? parsed.item_id : "";
|
|
937
|
+
const callId = typeof parsed.call_id === "string" ? parsed.call_id : "";
|
|
938
|
+
const fullArgs = typeof parsed.arguments === "string" ? parsed.arguments : "";
|
|
939
|
+
const pending = pendingCalls.get(itemId);
|
|
940
|
+
const name = pending?.name ?? "";
|
|
941
|
+
const args = fullArgs || pending?.arguments || "";
|
|
942
|
+
pendingCalls.delete(itemId);
|
|
943
|
+
yield {
|
|
944
|
+
id: callId || pending?.callId || itemId,
|
|
945
|
+
input: parseToolInput(args),
|
|
946
|
+
name,
|
|
947
|
+
providerData: pending?.providerData ? { ...pending.providerData, arguments: args } : undefined,
|
|
948
|
+
type: "tool_use"
|
|
949
|
+
};
|
|
950
|
+
};
|
|
951
|
+
var processOutputItemAdded = (parsed, pendingCalls) => {
|
|
952
|
+
if (!isRecord(parsed.item)) {
|
|
638
953
|
return;
|
|
639
954
|
}
|
|
640
|
-
const
|
|
641
|
-
|
|
642
|
-
const
|
|
643
|
-
if (
|
|
955
|
+
const { item } = parsed;
|
|
956
|
+
const itemId = typeof item.id === "string" ? item.id : "";
|
|
957
|
+
const itemType = typeof item.type === "string" ? item.type : "";
|
|
958
|
+
if (itemType !== "function_call") {
|
|
644
959
|
return;
|
|
645
960
|
}
|
|
646
|
-
|
|
961
|
+
const callId = typeof item.call_id === "string" ? item.call_id : "";
|
|
962
|
+
const name = typeof item.name === "string" ? item.name : "";
|
|
963
|
+
pendingCalls.set(itemId, {
|
|
964
|
+
arguments: "",
|
|
965
|
+
callId,
|
|
966
|
+
name,
|
|
967
|
+
providerData: { ...item }
|
|
968
|
+
});
|
|
647
969
|
};
|
|
648
|
-
var
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
970
|
+
var processOutputItemDone = function* (parsed) {
|
|
971
|
+
if (!isRecord(parsed.item) || typeof parsed.item.type !== "string")
|
|
972
|
+
return;
|
|
973
|
+
if (!parsed.item.type.startsWith("openrouter:"))
|
|
974
|
+
return;
|
|
975
|
+
yield {
|
|
976
|
+
data: { ...parsed.item },
|
|
977
|
+
provider: "openrouter",
|
|
978
|
+
type: "provider_event"
|
|
979
|
+
};
|
|
652
980
|
};
|
|
653
|
-
var
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
};
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
if (isRecordArray(delta.tool_calls)) {
|
|
670
|
-
processToolCallDeltas(delta.tool_calls, pendingToolCalls);
|
|
981
|
+
var isCompletedImageGeneration = (item) => item.type === "image_generation_call" && item.status === "completed" && typeof item.result === "string" && item.result !== "";
|
|
982
|
+
var buildImageChunk = (item) => ({
|
|
983
|
+
data: typeof item.result === "string" ? item.result : "",
|
|
984
|
+
format: extractMimeFormat(item.output_format),
|
|
985
|
+
imageId: typeof item.id === "string" ? item.id : undefined,
|
|
986
|
+
isPartial: false,
|
|
987
|
+
revisedPrompt: typeof item.revised_prompt === "string" ? item.revised_prompt : undefined,
|
|
988
|
+
type: "image"
|
|
989
|
+
});
|
|
990
|
+
var extractImageFromOutput = function* (output) {
|
|
991
|
+
const completedImages = output.filter(isCompletedImageGeneration);
|
|
992
|
+
for (const item of completedImages) {
|
|
993
|
+
yield buildImageChunk(item);
|
|
671
994
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
995
|
+
};
|
|
996
|
+
var extractCitationsFromOutput = function* (output) {
|
|
997
|
+
for (const item of output) {
|
|
998
|
+
if (!isRecordArray(item.content))
|
|
999
|
+
continue;
|
|
1000
|
+
for (const content of item.content) {
|
|
1001
|
+
if (!Array.isArray(content.annotations))
|
|
678
1002
|
continue;
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
1003
|
+
for (const annotation of content.annotations) {
|
|
1004
|
+
if (!isRecord(annotation) || annotation.type !== "url_citation")
|
|
1005
|
+
continue;
|
|
1006
|
+
if (typeof annotation.url !== "string")
|
|
1007
|
+
continue;
|
|
1008
|
+
yield {
|
|
1009
|
+
content: typeof annotation.content === "string" ? annotation.content : undefined,
|
|
1010
|
+
endIndex: typeof annotation.end_index === "number" ? annotation.end_index : undefined,
|
|
1011
|
+
startIndex: typeof annotation.start_index === "number" ? annotation.start_index : undefined,
|
|
1012
|
+
title: typeof annotation.title === "string" ? annotation.title : undefined,
|
|
1013
|
+
type: "citation",
|
|
1014
|
+
url: annotation.url
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
687
1017
|
}
|
|
688
1018
|
}
|
|
689
1019
|
};
|
|
690
|
-
var
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
const model = typeof parsed.model === "string" ? parsed.model : undefined;
|
|
694
|
-
const serviceTier = typeof parsed.service_tier === "string" ? parsed.service_tier : undefined;
|
|
695
|
-
const selected = providerMetadata && isRecord(providerMetadata.endpoints) ? providerMetadata.endpoints.available : undefined;
|
|
696
|
-
const selectedEndpoint = Array.isArray(selected) ? selected.find((entry) => isRecord(entry) && entry.selected === true) : undefined;
|
|
697
|
-
const provider = isRecord(selectedEndpoint) && typeof selectedEndpoint.provider === "string" ? selectedEndpoint.provider : undefined;
|
|
698
|
-
if (!providerMetadata && !generationId && !model && !serviceTier)
|
|
1020
|
+
var processCompleted = function* (parsed) {
|
|
1021
|
+
if (!isRecord(parsed.response)) {
|
|
1022
|
+
yield { type: "done", usage: undefined };
|
|
699
1023
|
return;
|
|
700
|
-
return { generationId, model, provider, providerMetadata, serviceTier };
|
|
701
|
-
};
|
|
702
|
-
var processChoice = function* (choice, pendingToolCalls) {
|
|
703
|
-
const delta = isRecord(choice.delta) ? choice.delta : null;
|
|
704
|
-
if (delta) {
|
|
705
|
-
yield* processDelta(delta, pendingToolCalls);
|
|
706
1024
|
}
|
|
707
|
-
|
|
708
|
-
|
|
1025
|
+
const { response } = parsed;
|
|
1026
|
+
const usage = extractUsage(response);
|
|
1027
|
+
const metadata = extractResponseMetadata(response);
|
|
1028
|
+
if (isRecordArray(response.output)) {
|
|
1029
|
+
yield* extractCitationsFromOutput(response.output);
|
|
1030
|
+
yield* extractImageFromOutput(response.output);
|
|
709
1031
|
}
|
|
1032
|
+
yield { metadata, type: "done", usage };
|
|
710
1033
|
};
|
|
711
|
-
var
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
const cost = typeof usage.cost === "number" ? usage.cost : undefined;
|
|
722
|
-
const upstreamInferenceCost = isRecord(usage.cost_details) && typeof usage.cost_details.upstream_inference_cost === "number" ? usage.cost_details.upstream_inference_cost : undefined;
|
|
723
|
-
const normalized = extractUsage({
|
|
724
|
-
cache_write_tokens: cacheWriteTokens,
|
|
725
|
-
cached_tokens: cachedTokens,
|
|
726
|
-
completion_tokens: completionTokens,
|
|
727
|
-
cost,
|
|
728
|
-
prompt_tokens: promptTokens,
|
|
729
|
-
reasoning_tokens: reasoningTokens,
|
|
730
|
-
upstream_inference_cost: upstreamInferenceCost
|
|
1034
|
+
var responseFailure = (eventType, parsed, providerName) => {
|
|
1035
|
+
const response = isRecord(parsed.response) ? parsed.response : parsed;
|
|
1036
|
+
const error = isRecord(response.error) ? response.error : undefined;
|
|
1037
|
+
const type = typeof response.error_type === "string" ? response.error_type : error && typeof error.code === "string" ? error.code : eventType;
|
|
1038
|
+
return new ProviderError({
|
|
1039
|
+
message: error && typeof error.message === "string" ? error.message : `OpenRouter Responses API: ${eventType}`,
|
|
1040
|
+
metadata: response,
|
|
1041
|
+
provider: providerName,
|
|
1042
|
+
retryable: type === "rate_limit_exceeded" || type === "provider_overloaded" || type === "provider_unavailable" || type === "server",
|
|
1043
|
+
type
|
|
731
1044
|
});
|
|
732
|
-
if (isRecord(usage.server_tool_use)) {
|
|
733
|
-
normalized.serverToolUse = Object.fromEntries(Object.entries(usage.server_tool_use).filter((entry) => typeof entry[1] === "number"));
|
|
734
|
-
}
|
|
735
|
-
return normalized;
|
|
736
1045
|
};
|
|
737
|
-
var
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
const { choices } = parsed;
|
|
776
|
-
if (!isRecordArray(choices)) {
|
|
777
|
-
return;
|
|
1046
|
+
var processSSEEvent = function* (eventType, parsed, pendingCalls, providerName) {
|
|
1047
|
+
switch (eventType) {
|
|
1048
|
+
case "response.reasoning_summary_text.delta": {
|
|
1049
|
+
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
1050
|
+
if (!delta)
|
|
1051
|
+
break;
|
|
1052
|
+
yield {
|
|
1053
|
+
content: delta,
|
|
1054
|
+
type: "thinking"
|
|
1055
|
+
};
|
|
1056
|
+
break;
|
|
1057
|
+
}
|
|
1058
|
+
case "response.output_text.delta":
|
|
1059
|
+
yield* processTextDelta(parsed);
|
|
1060
|
+
break;
|
|
1061
|
+
case "response.image_generation_call.partial_image":
|
|
1062
|
+
yield* processPartialImage(parsed);
|
|
1063
|
+
break;
|
|
1064
|
+
case "response.output_item.added":
|
|
1065
|
+
processOutputItemAdded(parsed, pendingCalls);
|
|
1066
|
+
break;
|
|
1067
|
+
case "response.output_item.done":
|
|
1068
|
+
yield* processOutputItemDone(parsed);
|
|
1069
|
+
break;
|
|
1070
|
+
case "response.function_call_arguments.delta":
|
|
1071
|
+
processFunctionCallArgumentsDelta(parsed, pendingCalls);
|
|
1072
|
+
break;
|
|
1073
|
+
case "response.function_call_arguments.done":
|
|
1074
|
+
yield* processFunctionCallArgumentsDone(parsed, pendingCalls);
|
|
1075
|
+
break;
|
|
1076
|
+
case "response.completed":
|
|
1077
|
+
yield* processCompleted(parsed);
|
|
1078
|
+
break;
|
|
1079
|
+
case "response.failed":
|
|
1080
|
+
case "response.incomplete":
|
|
1081
|
+
case "response.error":
|
|
1082
|
+
case "error":
|
|
1083
|
+
throw responseFailure(eventType, parsed, providerName);
|
|
778
1084
|
}
|
|
779
|
-
|
|
780
|
-
|
|
1085
|
+
};
|
|
1086
|
+
var flushSSEBuffer = function* (state) {
|
|
1087
|
+
if (!state.currentEvent || !state.buffer) {
|
|
781
1088
|
return;
|
|
782
1089
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
const status = typeof error.code === "number" ? error.code : null;
|
|
787
|
-
throw new ProviderError({
|
|
788
|
-
message: typeof error.message === "string" ? error.message : "OpenRouter stream failed",
|
|
789
|
-
metadata: metadata2,
|
|
790
|
-
provider: providerName,
|
|
791
|
-
retryable: status === 429 || status !== null && status >= 500,
|
|
792
|
-
status,
|
|
793
|
-
type: metadata2 && typeof metadata2.error_type === "string" ? metadata2.error_type : null
|
|
794
|
-
});
|
|
1090
|
+
const parsed = parseJSON(state.buffer);
|
|
1091
|
+
if (parsed) {
|
|
1092
|
+
yield* processSSEEvent(state.currentEvent, parsed, state.pendingCalls, state.providerName);
|
|
795
1093
|
}
|
|
796
|
-
|
|
1094
|
+
state.currentEvent = "";
|
|
1095
|
+
state.buffer = "";
|
|
797
1096
|
};
|
|
798
|
-
var
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
if (lastUsage) {
|
|
804
|
-
usageRef.current = lastUsage.usage;
|
|
805
|
-
}
|
|
806
|
-
const metadataChunks = allChunks.filter((chunk) => chunk.type === "response_metadata");
|
|
807
|
-
const lastMetadata = metadataChunks.at(NOT_FOUND);
|
|
808
|
-
if (lastMetadata && "metadata" in lastMetadata) {
|
|
809
|
-
metadataRef.current = {
|
|
810
|
-
...metadataRef.current,
|
|
811
|
-
...lastMetadata.metadata,
|
|
812
|
-
providerMetadata: {
|
|
813
|
-
...metadataRef.current?.providerMetadata,
|
|
814
|
-
...lastMetadata.metadata.providerMetadata
|
|
815
|
-
}
|
|
816
|
-
};
|
|
1097
|
+
var parseSSELine = (trimmed, state) => {
|
|
1098
|
+
if (trimmed.startsWith("event: ")) {
|
|
1099
|
+
state.currentEvent = trimmed.slice(EVENT_PREFIX_LENGTH);
|
|
1100
|
+
} else if (trimmed.startsWith("data: ")) {
|
|
1101
|
+
state.buffer = trimmed.slice(DATA_PREFIX_LENGTH);
|
|
817
1102
|
}
|
|
818
|
-
return allChunks.filter((chunk) => !isUsageUpdate(chunk) && chunk.type !== "response_metadata");
|
|
819
1103
|
};
|
|
820
|
-
var
|
|
821
|
-
|
|
822
|
-
|
|
1104
|
+
var processSSELine = function* (line, state) {
|
|
1105
|
+
const trimmed = line.trim();
|
|
1106
|
+
if (trimmed) {
|
|
1107
|
+
parseSSELine(trimmed, state);
|
|
1108
|
+
return;
|
|
823
1109
|
}
|
|
1110
|
+
yield* flushSSEBuffer(state);
|
|
824
1111
|
};
|
|
825
|
-
var
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
state.buffer = lines.pop() ?? "";
|
|
830
|
-
return lines;
|
|
1112
|
+
var processSSELines = function* (lines, state) {
|
|
1113
|
+
for (const line of lines) {
|
|
1114
|
+
yield* processSSELine(line, state);
|
|
1115
|
+
}
|
|
831
1116
|
};
|
|
832
1117
|
var drainReader = async function* (reader, decoder, state, signal) {
|
|
1118
|
+
let textBuffer = "";
|
|
833
1119
|
for (let result = await reader.read();!result.done && !signal?.aborted; result = await reader.read()) {
|
|
834
|
-
|
|
835
|
-
|
|
1120
|
+
textBuffer += decoder.decode(result.value, { stream: true });
|
|
1121
|
+
const lines = textBuffer.split(`
|
|
1122
|
+
`);
|
|
1123
|
+
textBuffer = lines.pop() ?? "";
|
|
1124
|
+
yield* processSSELines(lines, state);
|
|
1125
|
+
}
|
|
1126
|
+
if (textBuffer.trim()) {
|
|
1127
|
+
yield* processSSELines([textBuffer, ""], state);
|
|
836
1128
|
}
|
|
837
1129
|
};
|
|
838
|
-
var parseSSEStream = async function* (body,
|
|
1130
|
+
var parseSSEStream = async function* (body, providerName, signal) {
|
|
839
1131
|
const reader = body.getReader();
|
|
840
1132
|
const decoder = new TextDecoder;
|
|
841
1133
|
const state = {
|
|
842
1134
|
buffer: "",
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1135
|
+
currentEvent: "",
|
|
1136
|
+
pendingCalls: new Map,
|
|
1137
|
+
usage: undefined,
|
|
1138
|
+
providerName
|
|
847
1139
|
};
|
|
848
1140
|
try {
|
|
849
1141
|
yield* drainReader(reader, decoder, state, signal);
|
|
850
|
-
yield
|
|
851
|
-
metadata: state.metadataRef.current,
|
|
852
|
-
type: "done",
|
|
853
|
-
usage: state.usageRef.current
|
|
854
|
-
};
|
|
1142
|
+
yield* flushSSEBuffer(state);
|
|
855
1143
|
} finally {
|
|
856
1144
|
reader.releaseLock();
|
|
857
1145
|
}
|
|
858
1146
|
};
|
|
859
|
-
var
|
|
860
|
-
const target = `${baseUrl}/v1/
|
|
1147
|
+
var fetchResponsesStream = async function* (baseUrl, apiKey, body, fetchImpl, headers, providerName, signal) {
|
|
1148
|
+
const target = `${baseUrl}/v1/responses`;
|
|
861
1149
|
const requestHeaders = new Headers(headers);
|
|
862
1150
|
requestHeaders.set("Authorization", `Bearer ${apiKey}`);
|
|
863
1151
|
requestHeaders.set("Content-Type", "application/json");
|
|
@@ -874,67 +1162,133 @@ var fetchOpenAIStream = async function* (baseUrl, apiKey, body, fetchImpl, heade
|
|
|
874
1162
|
}
|
|
875
1163
|
if (!response.body) {
|
|
876
1164
|
throw new ProviderError({
|
|
877
|
-
message: `${providerName} API returned no response body`,
|
|
1165
|
+
message: `${providerName} Responses API returned no response body`,
|
|
878
1166
|
provider: providerName,
|
|
879
1167
|
retryable: true
|
|
880
1168
|
});
|
|
881
1169
|
}
|
|
882
|
-
yield* parseSSEStream(response.body,
|
|
883
|
-
generationId: response.headers.get("X-Generation-Id") ?? undefined,
|
|
884
|
-
providerMetadata: {
|
|
885
|
-
cacheAge: response.headers.get("X-OpenRouter-Cache-Age") ?? undefined,
|
|
886
|
-
cacheSourceId: response.headers.get("X-OpenRouter-Cache-Source-Id") ?? undefined,
|
|
887
|
-
cacheStatus: response.headers.get("X-OpenRouter-Cache-Status") ?? undefined,
|
|
888
|
-
cacheTtl: response.headers.get("X-OpenRouter-Cache-TTL") ?? undefined
|
|
889
|
-
}
|
|
890
|
-
}, providerName, signal);
|
|
1170
|
+
yield* parseSSEStream(response.body, providerName, signal);
|
|
891
1171
|
};
|
|
892
|
-
var
|
|
1172
|
+
var resolveImageModels = (imageModels) => {
|
|
1173
|
+
if (!imageModels) {
|
|
1174
|
+
return new Set;
|
|
1175
|
+
}
|
|
1176
|
+
if (imageModels instanceof Set) {
|
|
1177
|
+
return imageModels;
|
|
1178
|
+
}
|
|
1179
|
+
return new Set(imageModels);
|
|
1180
|
+
};
|
|
1181
|
+
var openaiResponses = (config2) => {
|
|
1182
|
+
if (!config2.apiKey && !config2.tokenSource)
|
|
1183
|
+
throw new Error("openaiResponses() requires either apiKey or tokenSource");
|
|
893
1184
|
const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL;
|
|
894
1185
|
const fetchImpl = config2.fetch ?? globalThis.fetch;
|
|
895
|
-
const
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
}
|
|
899
|
-
const resolveKey = async () => {
|
|
900
|
-
if (config2.tokenSource) {
|
|
901
|
-
return await Promise.resolve(config2.tokenSource());
|
|
902
|
-
}
|
|
903
|
-
return config2.apiKey;
|
|
904
|
-
};
|
|
1186
|
+
const imageModels = resolveImageModels(config2.imageModels);
|
|
1187
|
+
const providerName = config2.providerName ?? "openai-responses";
|
|
1188
|
+
const resolveKey = async () => config2.tokenSource ? await Promise.resolve(config2.tokenSource()) : config2.apiKey;
|
|
905
1189
|
const resolveHeaders = async (params) => typeof config2.headers === "function" ? await config2.headers(params) : config2.headers ?? {};
|
|
906
1190
|
return instrumentAIProvider({
|
|
1191
|
+
inputCapacity: openaiInputCapacity({
|
|
1192
|
+
baseUrl,
|
|
1193
|
+
fetch: fetchImpl,
|
|
1194
|
+
key: resolveKey,
|
|
1195
|
+
headers: resolveHeaders,
|
|
1196
|
+
modelLimits: config2.modelLimits,
|
|
1197
|
+
body: (params) => {
|
|
1198
|
+
const built = buildResponsesRequestBody(params, imageModels.has(params.model), config2.modelForCapabilities?.(params.model) ?? params.model);
|
|
1199
|
+
return config2.transformRequestBody ? config2.transformRequestBody(built, params) : built;
|
|
1200
|
+
}
|
|
1201
|
+
}),
|
|
907
1202
|
stream: (params) => {
|
|
908
|
-
const
|
|
909
|
-
const
|
|
1203
|
+
const isImageModel = imageModels.has(params.model);
|
|
1204
|
+
const builtBody = buildResponsesRequestBody(params, isImageModel, config2.modelForCapabilities?.(params.model) ?? params.model);
|
|
1205
|
+
const body = config2.transformRequestBody ? config2.transformRequestBody(builtBody, params) : builtBody;
|
|
910
1206
|
return async function* () {
|
|
911
1207
|
const [apiKey, headers] = await Promise.all([
|
|
912
1208
|
resolveKey(),
|
|
913
1209
|
resolveHeaders(params)
|
|
914
1210
|
]);
|
|
915
|
-
yield*
|
|
1211
|
+
yield* fetchResponsesStream(baseUrl, apiKey, body, fetchImpl, headers, providerName, params.signal);
|
|
916
1212
|
}();
|
|
917
1213
|
}
|
|
918
1214
|
}, providerName);
|
|
919
1215
|
};
|
|
920
1216
|
|
|
921
|
-
// src/ai/providers/
|
|
1217
|
+
// src/ai/providers/openai.ts
|
|
922
1218
|
var h2IfHttps2 = (url) => url.startsWith("https://") ? { protocol: "http2" } : {};
|
|
923
1219
|
var DEFAULT_BASE_URL2 = "https://api.openai.com";
|
|
924
|
-
var
|
|
925
|
-
var
|
|
1220
|
+
var SSE_DATA_PREFIX_LENGTH = 6;
|
|
1221
|
+
var DONE_SENTINEL = "[DONE]";
|
|
1222
|
+
var NOT_FOUND = -1;
|
|
926
1223
|
var isRecord2 = (value) => typeof value === "object" && value !== null;
|
|
927
1224
|
var isRecordArray2 = (value) => Array.isArray(value) && value.length > 0 && isRecord2(value[0]);
|
|
928
|
-
var
|
|
929
|
-
|
|
930
|
-
|
|
1225
|
+
var hasArrayContent = (msg) => typeof msg.content !== "string" && Array.isArray(msg.content);
|
|
1226
|
+
var buildToolMessages = (blocks) => {
|
|
1227
|
+
const toolUseBlocks = blocks.filter((block) => block.type === "tool_use");
|
|
1228
|
+
const toolResultBlocks = blocks.filter((block) => block.type === "tool_result");
|
|
1229
|
+
const messages = [];
|
|
1230
|
+
if (toolUseBlocks.length > 0) {
|
|
1231
|
+
messages.push({
|
|
1232
|
+
content: null,
|
|
1233
|
+
role: "assistant",
|
|
1234
|
+
tool_calls: toolUseBlocks.map((block) => ({
|
|
1235
|
+
function: {
|
|
1236
|
+
arguments: typeof block.input === "string" ? block.input : JSON.stringify(block.input),
|
|
1237
|
+
name: block.name
|
|
1238
|
+
},
|
|
1239
|
+
id: block.id,
|
|
1240
|
+
type: "function"
|
|
1241
|
+
}))
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
for (const result of toolResultBlocks) {
|
|
1245
|
+
messages.push({
|
|
1246
|
+
content: typeof result.content === "string" ? result.content : "",
|
|
1247
|
+
role: "tool",
|
|
1248
|
+
tool_call_id: result.tool_use_id
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
return messages;
|
|
1252
|
+
};
|
|
1253
|
+
var processMessageAtIndex = (result, msg, idx) => {
|
|
1254
|
+
if (!hasArrayContent(msg)) {
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
const hasToolBlocks2 = msg.content.some((block) => block.type === "tool_use" || block.type === "tool_result");
|
|
1258
|
+
if (!hasToolBlocks2) {
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1261
|
+
const toolMessages = buildToolMessages(msg.content);
|
|
1262
|
+
result.splice(idx, 1, ...toolMessages);
|
|
1263
|
+
};
|
|
1264
|
+
var convertSingleMessage = (result, msg, idx) => {
|
|
1265
|
+
if (!msg) {
|
|
1266
|
+
return;
|
|
931
1267
|
}
|
|
1268
|
+
processMessageAtIndex(result, msg, idx);
|
|
1269
|
+
};
|
|
1270
|
+
var convertToolResultMessages = (messages, params) => {
|
|
1271
|
+
const result = [...messages];
|
|
1272
|
+
for (let idx = 0;idx < params.messages.length; idx++) {
|
|
1273
|
+
convertSingleMessage(result, params.messages[idx], idx);
|
|
1274
|
+
}
|
|
1275
|
+
return result;
|
|
1276
|
+
};
|
|
1277
|
+
var mapToolDefinitions = (tools) => tools.map((tool) => ({
|
|
1278
|
+
function: {
|
|
1279
|
+
description: tool.description,
|
|
1280
|
+
name: tool.name,
|
|
1281
|
+
parameters: tool.input_schema
|
|
1282
|
+
},
|
|
1283
|
+
type: "function"
|
|
1284
|
+
}));
|
|
1285
|
+
var mapContentBlockToOpenAI = (block) => {
|
|
932
1286
|
if (block.type === "image") {
|
|
933
1287
|
return {
|
|
934
1288
|
image_url: {
|
|
935
1289
|
url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
|
|
936
1290
|
},
|
|
937
|
-
type: "
|
|
1291
|
+
type: "image_url"
|
|
938
1292
|
};
|
|
939
1293
|
}
|
|
940
1294
|
if (block.type === "document") {
|
|
@@ -943,7 +1297,7 @@ var mapBlockToResponsesFormat = (block) => {
|
|
|
943
1297
|
file_data: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`,
|
|
944
1298
|
filename: block.name ?? "document.pdf"
|
|
945
1299
|
},
|
|
946
|
-
type: "
|
|
1300
|
+
type: "file"
|
|
947
1301
|
};
|
|
948
1302
|
}
|
|
949
1303
|
if (block.type === "audio") {
|
|
@@ -954,95 +1308,48 @@ var mapBlockToResponsesFormat = (block) => {
|
|
|
954
1308
|
}
|
|
955
1309
|
if (block.type === "video") {
|
|
956
1310
|
return {
|
|
957
|
-
type: "
|
|
958
|
-
video_url:
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
return null;
|
|
962
|
-
};
|
|
963
|
-
var mapContentToResponsesFormat = (content) => {
|
|
964
|
-
if (typeof content === "string") {
|
|
965
|
-
return content;
|
|
966
|
-
}
|
|
967
|
-
const parts = content.map(mapBlockToResponsesFormat).filter((mapped) => mapped !== null);
|
|
968
|
-
return parts.length > 0 ? parts : "";
|
|
969
|
-
};
|
|
970
|
-
var hasToolBlocks = (content) => content.some((block) => block.type === "tool_use" || block.type === "tool_result");
|
|
971
|
-
var convertToolBlock = (block) => {
|
|
972
|
-
if (block.type === "provider_data" && block.provider === "openrouter") {
|
|
973
|
-
return { ...block.data };
|
|
974
|
-
}
|
|
975
|
-
if (block.type === "tool_use") {
|
|
976
|
-
if (block.providerData)
|
|
977
|
-
return { ...block.providerData };
|
|
978
|
-
return {
|
|
979
|
-
arguments: typeof block.input === "string" ? block.input : JSON.stringify(block.input),
|
|
980
|
-
call_id: block.id,
|
|
981
|
-
name: block.name,
|
|
982
|
-
type: "function_call"
|
|
1311
|
+
type: "video_url",
|
|
1312
|
+
video_url: {
|
|
1313
|
+
url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
|
|
1314
|
+
}
|
|
983
1315
|
};
|
|
984
1316
|
}
|
|
985
|
-
if (block.type === "
|
|
986
|
-
return {
|
|
987
|
-
call_id: block.tool_use_id,
|
|
988
|
-
output: typeof block.content === "string" ? block.content : "",
|
|
989
|
-
type: "function_call_output"
|
|
990
|
-
};
|
|
1317
|
+
if (block.type === "text") {
|
|
1318
|
+
return { text: block.content, type: "text" };
|
|
991
1319
|
}
|
|
992
1320
|
return null;
|
|
993
1321
|
};
|
|
994
|
-
var
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
return convertToolBlocks(msg.content);
|
|
1322
|
+
var mapOpenAIContent = (msg) => {
|
|
1323
|
+
if (typeof msg.content === "string") {
|
|
1324
|
+
return msg.content;
|
|
998
1325
|
}
|
|
999
|
-
const
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
content,
|
|
1003
|
-
role: msg.role === "system" ? "developer" : msg.role,
|
|
1004
|
-
type: "message"
|
|
1005
|
-
}
|
|
1006
|
-
];
|
|
1007
|
-
};
|
|
1008
|
-
var buildInput = (messages) => {
|
|
1009
|
-
const input = [];
|
|
1010
|
-
for (const msg of messages) {
|
|
1011
|
-
input.push(...convertMessage(msg));
|
|
1326
|
+
const hasMedia = msg.content.some((block) => block.type === "image" || block.type === "document" || block.type === "audio" || block.type === "video");
|
|
1327
|
+
if (!hasMedia) {
|
|
1328
|
+
return null;
|
|
1012
1329
|
}
|
|
1013
|
-
return
|
|
1330
|
+
return msg.content.map(mapContentBlockToOpenAI).filter((mapped) => mapped !== null);
|
|
1014
1331
|
};
|
|
1015
|
-
var
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
const mapped = tools ? tools.map(mapToolDefinition) : [];
|
|
1023
|
-
const result = [...mapped];
|
|
1024
|
-
if (isImageModel) {
|
|
1025
|
-
result.push({ type: "image_generation" });
|
|
1332
|
+
var buildRequestBody = (params, capabilityModel = params.model) => {
|
|
1333
|
+
const messages = convertToolResultMessages(params.messages.map((msg) => ({
|
|
1334
|
+
content: mapOpenAIContent(msg),
|
|
1335
|
+
role: msg.role
|
|
1336
|
+
})), params);
|
|
1337
|
+
if (params.systemPrompt) {
|
|
1338
|
+
messages.unshift({ content: params.systemPrompt, role: "system" });
|
|
1026
1339
|
}
|
|
1027
|
-
return result.length > 0 ? result : undefined;
|
|
1028
|
-
};
|
|
1029
|
-
var buildRequestBody2 = (params, isImageModel, capabilityModel = params.model) => {
|
|
1030
1340
|
const body = {
|
|
1031
|
-
|
|
1341
|
+
messages,
|
|
1032
1342
|
model: params.model,
|
|
1033
|
-
stream: true
|
|
1343
|
+
stream: true,
|
|
1344
|
+
stream_options: { include_usage: true }
|
|
1034
1345
|
};
|
|
1035
|
-
if (params.
|
|
1036
|
-
body.
|
|
1037
|
-
}
|
|
1038
|
-
const tools = buildTools(params.tools, isImageModel);
|
|
1039
|
-
if (tools) {
|
|
1040
|
-
body.tools = tools;
|
|
1346
|
+
if (params.tools && params.tools.length > 0) {
|
|
1347
|
+
body.tools = mapToolDefinitions(params.tools);
|
|
1041
1348
|
if (params.toolChoice === "auto" || params.toolChoice === "none" || params.toolChoice === "required") {
|
|
1042
1349
|
body.tool_choice = params.toolChoice;
|
|
1043
1350
|
} else if (params.toolChoice && typeof params.toolChoice === "object") {
|
|
1044
1351
|
body.tool_choice = {
|
|
1045
|
-
name: params.toolChoice.name,
|
|
1352
|
+
function: { name: params.toolChoice.name },
|
|
1046
1353
|
type: "function"
|
|
1047
1354
|
};
|
|
1048
1355
|
}
|
|
@@ -1050,12 +1357,24 @@ var buildRequestBody2 = (params, isImageModel, capabilityModel = params.model) =
|
|
|
1050
1357
|
body.parallel_tool_calls = params.parallelToolCalls;
|
|
1051
1358
|
}
|
|
1052
1359
|
}
|
|
1053
|
-
if (
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1360
|
+
if (isOpenAIReasoningModel(capabilityModel)) {
|
|
1361
|
+
if (typeof params.maxTokens === "number") {
|
|
1362
|
+
body.max_completion_tokens = params.maxTokens;
|
|
1363
|
+
}
|
|
1364
|
+
if (params.reasoning) {
|
|
1365
|
+
const effort = openaiEffortValue(capabilityModel, params.reasoning);
|
|
1366
|
+
if (effort)
|
|
1367
|
+
body.reasoning_effort = effort;
|
|
1368
|
+
}
|
|
1369
|
+
} else {
|
|
1370
|
+
if (typeof params.temperature === "number") {
|
|
1371
|
+
body.temperature = params.temperature;
|
|
1372
|
+
}
|
|
1373
|
+
if (typeof params.topP === "number")
|
|
1374
|
+
body.top_p = params.topP;
|
|
1375
|
+
if (typeof params.maxTokens === "number")
|
|
1376
|
+
body.max_tokens = params.maxTokens;
|
|
1377
|
+
}
|
|
1059
1378
|
if (params.stopSequences && params.stopSequences.length > 0)
|
|
1060
1379
|
body.stop = params.stopSequences;
|
|
1061
1380
|
if (typeof params.seed === "number")
|
|
@@ -1066,36 +1385,20 @@ var buildRequestBody2 = (params, isImageModel, capabilityModel = params.model) =
|
|
|
1066
1385
|
body.presence_penalty = params.presencePenalty;
|
|
1067
1386
|
if (params.responseFormat) {
|
|
1068
1387
|
if (params.responseFormat.type === "text" || params.responseFormat.type === "json_object") {
|
|
1069
|
-
body.
|
|
1388
|
+
body.response_format = { type: params.responseFormat.type };
|
|
1070
1389
|
} else if (params.responseFormat.type === "json_schema") {
|
|
1071
|
-
body.
|
|
1072
|
-
|
|
1390
|
+
body.response_format = {
|
|
1391
|
+
json_schema: {
|
|
1073
1392
|
name: params.responseFormat.name,
|
|
1074
1393
|
schema: params.responseFormat.schema,
|
|
1075
|
-
strict: params.responseFormat.strict ?? true
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
};
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
if (params.reasoning && isOpenAIReasoningModel(capabilityModel)) {
|
|
1082
|
-
const effort = openaiEffortValue(capabilityModel, params.reasoning);
|
|
1083
|
-
if (effort) {
|
|
1084
|
-
body.reasoning = {
|
|
1085
|
-
effort,
|
|
1086
|
-
summary: "auto"
|
|
1394
|
+
strict: params.responseFormat.strict ?? true
|
|
1395
|
+
},
|
|
1396
|
+
type: "json_schema"
|
|
1087
1397
|
};
|
|
1088
1398
|
}
|
|
1089
1399
|
}
|
|
1090
1400
|
return body;
|
|
1091
1401
|
};
|
|
1092
|
-
var parseJSON = (data) => {
|
|
1093
|
-
try {
|
|
1094
|
-
return JSON.parse(data);
|
|
1095
|
-
} catch {
|
|
1096
|
-
return null;
|
|
1097
|
-
}
|
|
1098
|
-
};
|
|
1099
1402
|
var parseToolInput2 = (rawArguments) => {
|
|
1100
1403
|
try {
|
|
1101
1404
|
return JSON.parse(rawArguments);
|
|
@@ -1103,297 +1406,284 @@ var parseToolInput2 = (rawArguments) => {
|
|
|
1103
1406
|
return rawArguments;
|
|
1104
1407
|
}
|
|
1105
1408
|
};
|
|
1106
|
-
var
|
|
1107
|
-
|
|
1108
|
-
|
|
1409
|
+
var flushPendingToolCalls = function* (pendingToolCalls) {
|
|
1410
|
+
for (const [, tool] of pendingToolCalls) {
|
|
1411
|
+
const input = parseToolInput2(tool.arguments);
|
|
1412
|
+
yield {
|
|
1413
|
+
id: tool.id,
|
|
1414
|
+
input,
|
|
1415
|
+
name: tool.name,
|
|
1416
|
+
type: "tool_use"
|
|
1417
|
+
};
|
|
1109
1418
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
const
|
|
1114
|
-
const
|
|
1115
|
-
|
|
1116
|
-
const normalized = {
|
|
1419
|
+
pendingToolCalls.clear();
|
|
1420
|
+
};
|
|
1421
|
+
var extractUsage2 = (parsedUsage) => {
|
|
1422
|
+
const prompt = parsedUsage.prompt_tokens ?? 0;
|
|
1423
|
+
const cached = parsedUsage.cached_tokens ?? 0;
|
|
1424
|
+
return {
|
|
1117
1425
|
cacheReadInputTokens: cached,
|
|
1118
|
-
cacheWriteInputTokens:
|
|
1119
|
-
costCredits:
|
|
1120
|
-
inputTokens: Math.max(0,
|
|
1121
|
-
outputTokens:
|
|
1122
|
-
reasoningTokens:
|
|
1123
|
-
upstreamInferenceCostCredits:
|
|
1426
|
+
cacheWriteInputTokens: parsedUsage.cache_write_tokens || undefined,
|
|
1427
|
+
costCredits: parsedUsage.cost,
|
|
1428
|
+
inputTokens: Math.max(0, prompt - cached),
|
|
1429
|
+
outputTokens: parsedUsage.completion_tokens ?? 0,
|
|
1430
|
+
reasoningTokens: parsedUsage.reasoning_tokens || undefined,
|
|
1431
|
+
upstreamInferenceCostCredits: parsedUsage.upstream_inference_cost || undefined
|
|
1124
1432
|
};
|
|
1125
|
-
if (isRecord2(usage.server_tool_use)) {
|
|
1126
|
-
normalized.serverToolUse = Object.fromEntries(Object.entries(usage.server_tool_use).filter((entry) => typeof entry[1] === "number"));
|
|
1127
|
-
}
|
|
1128
|
-
return normalized;
|
|
1129
1433
|
};
|
|
1130
|
-
var
|
|
1131
|
-
const
|
|
1132
|
-
|
|
1133
|
-
const model = typeof response.model === "string" ? response.model : undefined;
|
|
1134
|
-
const provider = typeof response.provider === "string" ? response.provider : undefined;
|
|
1135
|
-
const serviceTier = typeof response.service_tier === "string" ? response.service_tier : undefined;
|
|
1136
|
-
if (!providerMetadata && !generationId && !model && !provider && !serviceTier)
|
|
1137
|
-
return;
|
|
1138
|
-
return { generationId, model, provider, providerMetadata, serviceTier };
|
|
1434
|
+
var resolveToolCallIndex = (toolCall) => {
|
|
1435
|
+
const raw = typeof toolCall.index === "number" ? toolCall.index : NOT_FOUND;
|
|
1436
|
+
return raw < 0 ? undefined : raw;
|
|
1139
1437
|
};
|
|
1140
|
-
var
|
|
1141
|
-
if (
|
|
1142
|
-
return
|
|
1438
|
+
var initPendingToolCall = (toolCall, func, index, pendingToolCalls) => {
|
|
1439
|
+
if (pendingToolCalls.has(index)) {
|
|
1440
|
+
return;
|
|
1143
1441
|
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1442
|
+
const toolId = typeof toolCall.id === "string" ? toolCall.id : "";
|
|
1443
|
+
const toolName = func && typeof func.name === "string" ? func.name : "";
|
|
1444
|
+
pendingToolCalls.set(index, {
|
|
1445
|
+
arguments: "",
|
|
1446
|
+
id: toolId,
|
|
1447
|
+
name: toolName
|
|
1448
|
+
});
|
|
1149
1449
|
};
|
|
1150
|
-
var
|
|
1151
|
-
if (typeof
|
|
1152
|
-
|
|
1450
|
+
var updatePendingToolCall = (toolCall, func, pending) => {
|
|
1451
|
+
if (typeof toolCall.id === "string") {
|
|
1452
|
+
pending.id = toolCall.id;
|
|
1153
1453
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
const itemId = typeof parsed.item_id === "string" ? parsed.item_id : undefined;
|
|
1157
|
-
const b64 = typeof parsed.partial_image_b64 === "string" ? parsed.partial_image_b64 : undefined;
|
|
1158
|
-
if (b64) {
|
|
1159
|
-
yield {
|
|
1160
|
-
data: b64,
|
|
1161
|
-
format: "png",
|
|
1162
|
-
imageId: itemId,
|
|
1163
|
-
isPartial: true,
|
|
1164
|
-
type: "image"
|
|
1165
|
-
};
|
|
1454
|
+
if (func && typeof func.name === "string") {
|
|
1455
|
+
pending.name = func.name;
|
|
1166
1456
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
const itemId = typeof parsed.item_id === "string" ? parsed.item_id : "";
|
|
1170
|
-
const callId = typeof parsed.call_id === "string" ? parsed.call_id : "";
|
|
1171
|
-
const delta = typeof parsed.arguments_delta === "string" ? parsed.arguments_delta : "";
|
|
1172
|
-
const existing = pendingCalls.get(itemId);
|
|
1173
|
-
if (existing) {
|
|
1174
|
-
existing.arguments += delta;
|
|
1175
|
-
} else {
|
|
1176
|
-
pendingCalls.set(itemId, {
|
|
1177
|
-
arguments: delta,
|
|
1178
|
-
callId,
|
|
1179
|
-
name: ""
|
|
1180
|
-
});
|
|
1457
|
+
if (func && typeof func.arguments === "string") {
|
|
1458
|
+
pending.arguments += func.arguments;
|
|
1181
1459
|
}
|
|
1182
1460
|
};
|
|
1183
|
-
var
|
|
1184
|
-
const
|
|
1185
|
-
|
|
1186
|
-
const fullArgs = typeof parsed.arguments === "string" ? parsed.arguments : "";
|
|
1187
|
-
const pending = pendingCalls.get(itemId);
|
|
1188
|
-
const name = pending?.name ?? "";
|
|
1189
|
-
const args = fullArgs || pending?.arguments || "";
|
|
1190
|
-
pendingCalls.delete(itemId);
|
|
1191
|
-
yield {
|
|
1192
|
-
id: callId || pending?.callId || itemId,
|
|
1193
|
-
input: parseToolInput2(args),
|
|
1194
|
-
name,
|
|
1195
|
-
providerData: pending?.providerData ? { ...pending.providerData, arguments: args } : undefined,
|
|
1196
|
-
type: "tool_use"
|
|
1197
|
-
};
|
|
1198
|
-
};
|
|
1199
|
-
var processOutputItemAdded = (parsed, pendingCalls) => {
|
|
1200
|
-
if (!isRecord2(parsed.item)) {
|
|
1461
|
+
var processToolCallDelta = (toolCall, pendingToolCalls) => {
|
|
1462
|
+
const index = resolveToolCallIndex(toolCall);
|
|
1463
|
+
if (index === undefined) {
|
|
1201
1464
|
return;
|
|
1202
1465
|
}
|
|
1203
|
-
const
|
|
1204
|
-
|
|
1205
|
-
const
|
|
1206
|
-
if (
|
|
1466
|
+
const func = isRecord2(toolCall.function) ? toolCall.function : null;
|
|
1467
|
+
initPendingToolCall(toolCall, func, index, pendingToolCalls);
|
|
1468
|
+
const pending = pendingToolCalls.get(index);
|
|
1469
|
+
if (!pending) {
|
|
1207
1470
|
return;
|
|
1208
1471
|
}
|
|
1209
|
-
|
|
1210
|
-
const name = typeof item.name === "string" ? item.name : "";
|
|
1211
|
-
pendingCalls.set(itemId, {
|
|
1212
|
-
arguments: "",
|
|
1213
|
-
callId,
|
|
1214
|
-
name,
|
|
1215
|
-
providerData: { ...item }
|
|
1216
|
-
});
|
|
1217
|
-
};
|
|
1218
|
-
var processOutputItemDone = function* (parsed) {
|
|
1219
|
-
if (!isRecord2(parsed.item) || typeof parsed.item.type !== "string")
|
|
1220
|
-
return;
|
|
1221
|
-
if (!parsed.item.type.startsWith("openrouter:"))
|
|
1222
|
-
return;
|
|
1223
|
-
yield {
|
|
1224
|
-
data: { ...parsed.item },
|
|
1225
|
-
provider: "openrouter",
|
|
1226
|
-
type: "provider_event"
|
|
1227
|
-
};
|
|
1472
|
+
updatePendingToolCall(toolCall, func, pending);
|
|
1228
1473
|
};
|
|
1229
|
-
var
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
format: extractMimeFormat(item.output_format),
|
|
1233
|
-
imageId: typeof item.id === "string" ? item.id : undefined,
|
|
1234
|
-
isPartial: false,
|
|
1235
|
-
revisedPrompt: typeof item.revised_prompt === "string" ? item.revised_prompt : undefined,
|
|
1236
|
-
type: "image"
|
|
1237
|
-
});
|
|
1238
|
-
var extractImageFromOutput = function* (output) {
|
|
1239
|
-
const completedImages = output.filter(isCompletedImageGeneration);
|
|
1240
|
-
for (const item of completedImages) {
|
|
1241
|
-
yield buildImageChunk(item);
|
|
1474
|
+
var processToolCallDeltas = (toolCalls, pendingToolCalls) => {
|
|
1475
|
+
for (const toolCall of toolCalls) {
|
|
1476
|
+
processToolCallDelta(toolCall, pendingToolCalls);
|
|
1242
1477
|
}
|
|
1243
1478
|
};
|
|
1244
|
-
var
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1479
|
+
var processDelta = function* (delta, pendingToolCalls) {
|
|
1480
|
+
if (typeof delta.content === "string") {
|
|
1481
|
+
yield { content: delta.content, type: "text" };
|
|
1482
|
+
}
|
|
1483
|
+
if (isRecord2(delta.audio)) {
|
|
1484
|
+
const audio = delta.audio;
|
|
1485
|
+
if (typeof audio.data === "string" || typeof audio.transcript === "string") {
|
|
1486
|
+
yield {
|
|
1487
|
+
audioId: typeof audio.id === "string" ? audio.id : undefined,
|
|
1488
|
+
data: typeof audio.data === "string" ? audio.data : "",
|
|
1489
|
+
format: typeof audio.format === "string" ? audio.format : "pcm16",
|
|
1490
|
+
transcript: typeof audio.transcript === "string" ? audio.transcript : undefined,
|
|
1491
|
+
type: "audio"
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
if (isRecordArray2(delta.tool_calls)) {
|
|
1496
|
+
processToolCallDeltas(delta.tool_calls, pendingToolCalls);
|
|
1497
|
+
}
|
|
1498
|
+
if (Array.isArray(delta.annotations)) {
|
|
1499
|
+
for (const annotation of delta.annotations) {
|
|
1500
|
+
if (!isRecord2(annotation) || annotation.type !== "url_citation")
|
|
1250
1501
|
continue;
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
url: annotation.url
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1502
|
+
const citation = isRecord2(annotation.url_citation) ? annotation.url_citation : annotation;
|
|
1503
|
+
if (typeof citation.url !== "string")
|
|
1504
|
+
continue;
|
|
1505
|
+
yield {
|
|
1506
|
+
content: typeof citation.content === "string" ? citation.content : undefined,
|
|
1507
|
+
endIndex: typeof citation.end_index === "number" ? citation.end_index : undefined,
|
|
1508
|
+
startIndex: typeof citation.start_index === "number" ? citation.start_index : undefined,
|
|
1509
|
+
title: typeof citation.title === "string" ? citation.title : undefined,
|
|
1510
|
+
type: "citation",
|
|
1511
|
+
url: citation.url
|
|
1512
|
+
};
|
|
1265
1513
|
}
|
|
1266
1514
|
}
|
|
1267
1515
|
};
|
|
1268
|
-
var
|
|
1269
|
-
|
|
1270
|
-
|
|
1516
|
+
var narrowResponseMetadata = (parsed) => {
|
|
1517
|
+
const providerMetadata = isRecord2(parsed.openrouter_metadata) ? parsed.openrouter_metadata : undefined;
|
|
1518
|
+
const generationId = typeof parsed.id === "string" ? parsed.id : undefined;
|
|
1519
|
+
const model = typeof parsed.model === "string" ? parsed.model : undefined;
|
|
1520
|
+
const serviceTier = typeof parsed.service_tier === "string" ? parsed.service_tier : undefined;
|
|
1521
|
+
const selected = providerMetadata && isRecord2(providerMetadata.endpoints) ? providerMetadata.endpoints.available : undefined;
|
|
1522
|
+
const selectedEndpoint = Array.isArray(selected) ? selected.find((entry) => isRecord2(entry) && entry.selected === true) : undefined;
|
|
1523
|
+
const provider = isRecord2(selectedEndpoint) && typeof selectedEndpoint.provider === "string" ? selectedEndpoint.provider : undefined;
|
|
1524
|
+
if (!providerMetadata && !generationId && !model && !serviceTier)
|
|
1271
1525
|
return;
|
|
1526
|
+
return { generationId, model, provider, providerMetadata, serviceTier };
|
|
1527
|
+
};
|
|
1528
|
+
var processChoice = function* (choice, pendingToolCalls) {
|
|
1529
|
+
const delta = isRecord2(choice.delta) ? choice.delta : null;
|
|
1530
|
+
if (delta) {
|
|
1531
|
+
yield* processDelta(delta, pendingToolCalls);
|
|
1272
1532
|
}
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
const metadata = extractResponseMetadata(response);
|
|
1276
|
-
if (isRecordArray2(response.output)) {
|
|
1277
|
-
yield* extractCitationsFromOutput(response.output);
|
|
1278
|
-
yield* extractImageFromOutput(response.output);
|
|
1533
|
+
if (choice.finish_reason === "tool_calls") {
|
|
1534
|
+
yield* flushPendingToolCalls(pendingToolCalls);
|
|
1279
1535
|
}
|
|
1280
|
-
yield { metadata, type: "done", usage };
|
|
1281
1536
|
};
|
|
1282
|
-
var
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1537
|
+
var narrowUsageRecord = (parsed) => {
|
|
1538
|
+
if (!isRecord2(parsed.usage)) {
|
|
1539
|
+
return;
|
|
1540
|
+
}
|
|
1541
|
+
const { usage } = parsed;
|
|
1542
|
+
const promptTokens = typeof usage.prompt_tokens === "number" ? usage.prompt_tokens : 0;
|
|
1543
|
+
const completionTokens = typeof usage.completion_tokens === "number" ? usage.completion_tokens : 0;
|
|
1544
|
+
const cachedTokens = isRecord2(usage.prompt_tokens_details) && typeof usage.prompt_tokens_details.cached_tokens === "number" ? usage.prompt_tokens_details.cached_tokens : 0;
|
|
1545
|
+
const cacheWriteTokens = isRecord2(usage.prompt_tokens_details) && typeof usage.prompt_tokens_details.cache_write_tokens === "number" ? usage.prompt_tokens_details.cache_write_tokens : 0;
|
|
1546
|
+
const reasoningTokens = isRecord2(usage.completion_tokens_details) && typeof usage.completion_tokens_details.reasoning_tokens === "number" ? usage.completion_tokens_details.reasoning_tokens : 0;
|
|
1547
|
+
const cost = typeof usage.cost === "number" ? usage.cost : undefined;
|
|
1548
|
+
const upstreamInferenceCost = isRecord2(usage.cost_details) && typeof usage.cost_details.upstream_inference_cost === "number" ? usage.cost_details.upstream_inference_cost : undefined;
|
|
1549
|
+
const normalized = extractUsage2({
|
|
1550
|
+
cache_write_tokens: cacheWriteTokens,
|
|
1551
|
+
cached_tokens: cachedTokens,
|
|
1552
|
+
completion_tokens: completionTokens,
|
|
1553
|
+
cost,
|
|
1554
|
+
prompt_tokens: promptTokens,
|
|
1555
|
+
reasoning_tokens: reasoningTokens,
|
|
1556
|
+
upstream_inference_cost: upstreamInferenceCost
|
|
1292
1557
|
});
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
switch (eventType) {
|
|
1296
|
-
case "response.reasoning_summary_text.delta": {
|
|
1297
|
-
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
1298
|
-
if (!delta)
|
|
1299
|
-
break;
|
|
1300
|
-
yield {
|
|
1301
|
-
content: delta,
|
|
1302
|
-
type: "thinking"
|
|
1303
|
-
};
|
|
1304
|
-
break;
|
|
1305
|
-
}
|
|
1306
|
-
case "response.output_text.delta":
|
|
1307
|
-
yield* processTextDelta(parsed);
|
|
1308
|
-
break;
|
|
1309
|
-
case "response.image_generation_call.partial_image":
|
|
1310
|
-
yield* processPartialImage(parsed);
|
|
1311
|
-
break;
|
|
1312
|
-
case "response.output_item.added":
|
|
1313
|
-
processOutputItemAdded(parsed, pendingCalls);
|
|
1314
|
-
break;
|
|
1315
|
-
case "response.output_item.done":
|
|
1316
|
-
yield* processOutputItemDone(parsed);
|
|
1317
|
-
break;
|
|
1318
|
-
case "response.function_call_arguments.delta":
|
|
1319
|
-
processFunctionCallArgumentsDelta(parsed, pendingCalls);
|
|
1320
|
-
break;
|
|
1321
|
-
case "response.function_call_arguments.done":
|
|
1322
|
-
yield* processFunctionCallArgumentsDone(parsed, pendingCalls);
|
|
1323
|
-
break;
|
|
1324
|
-
case "response.completed":
|
|
1325
|
-
yield* processCompleted(parsed);
|
|
1326
|
-
break;
|
|
1327
|
-
case "response.failed":
|
|
1328
|
-
case "response.incomplete":
|
|
1329
|
-
case "response.error":
|
|
1330
|
-
case "error":
|
|
1331
|
-
throw responseFailure(eventType, parsed, providerName);
|
|
1558
|
+
if (isRecord2(usage.server_tool_use)) {
|
|
1559
|
+
normalized.serverToolUse = Object.fromEntries(Object.entries(usage.server_tool_use).filter((entry) => typeof entry[1] === "number"));
|
|
1332
1560
|
}
|
|
1561
|
+
return normalized;
|
|
1333
1562
|
};
|
|
1334
|
-
var
|
|
1335
|
-
|
|
1563
|
+
var processSSELine2 = function* (line, pendingToolCalls, providerName) {
|
|
1564
|
+
const trimmed = line.trim();
|
|
1565
|
+
if (!trimmed || !trimmed.startsWith("data: ")) {
|
|
1336
1566
|
return;
|
|
1337
1567
|
}
|
|
1338
|
-
const
|
|
1339
|
-
if (
|
|
1340
|
-
yield*
|
|
1568
|
+
const data = trimmed.slice(SSE_DATA_PREFIX_LENGTH);
|
|
1569
|
+
if (data === DONE_SENTINEL) {
|
|
1570
|
+
yield* flushPendingToolCalls(pendingToolCalls);
|
|
1571
|
+
return;
|
|
1341
1572
|
}
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
state.currentEvent = trimmed.slice(EVENT_PREFIX_LENGTH);
|
|
1348
|
-
} else if (trimmed.startsWith("data: ")) {
|
|
1349
|
-
state.buffer = trimmed.slice(DATA_PREFIX_LENGTH);
|
|
1573
|
+
let parsed;
|
|
1574
|
+
try {
|
|
1575
|
+
parsed = JSON.parse(data);
|
|
1576
|
+
} catch {
|
|
1577
|
+
return;
|
|
1350
1578
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1579
|
+
if (isRecord2(parsed.error)) {
|
|
1580
|
+
const error = parsed.error;
|
|
1581
|
+
const metadata2 = isRecord2(error.metadata) ? error.metadata : undefined;
|
|
1582
|
+
const status = typeof error.code === "number" ? error.code : null;
|
|
1583
|
+
const type = metadata2 && typeof metadata2.error_type === "string" ? metadata2.error_type : typeof error.error_type === "string" ? error.error_type : null;
|
|
1584
|
+
throw new ProviderError({
|
|
1585
|
+
message: typeof error.message === "string" ? error.message : "OpenRouter stream failed",
|
|
1586
|
+
metadata: metadata2,
|
|
1587
|
+
provider: providerName,
|
|
1588
|
+
retryable: status === 408 || status === 409 || status === 425 || status === 429 || status !== null && status >= 500,
|
|
1589
|
+
status,
|
|
1590
|
+
type
|
|
1591
|
+
});
|
|
1592
|
+
}
|
|
1593
|
+
const usageUpdate = narrowUsageRecord(parsed);
|
|
1594
|
+
if (usageUpdate) {
|
|
1595
|
+
yield { type: "usage_update", usage: usageUpdate };
|
|
1596
|
+
}
|
|
1597
|
+
const metadata = narrowResponseMetadata(parsed);
|
|
1598
|
+
if (metadata) {
|
|
1599
|
+
yield { metadata, type: "response_metadata" };
|
|
1600
|
+
}
|
|
1601
|
+
const { choices } = parsed;
|
|
1602
|
+
if (!isRecordArray2(choices)) {
|
|
1356
1603
|
return;
|
|
1357
1604
|
}
|
|
1358
|
-
|
|
1605
|
+
const [firstChoice] = choices;
|
|
1606
|
+
if (!firstChoice) {
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
if (isRecord2(firstChoice.error)) {
|
|
1610
|
+
const error = firstChoice.error;
|
|
1611
|
+
const metadata2 = isRecord2(error.metadata) ? error.metadata : undefined;
|
|
1612
|
+
const status = typeof error.code === "number" ? error.code : null;
|
|
1613
|
+
throw new ProviderError({
|
|
1614
|
+
message: typeof error.message === "string" ? error.message : "OpenRouter stream failed",
|
|
1615
|
+
metadata: metadata2,
|
|
1616
|
+
provider: providerName,
|
|
1617
|
+
retryable: status === 429 || status !== null && status >= 500,
|
|
1618
|
+
status,
|
|
1619
|
+
type: metadata2 && typeof metadata2.error_type === "string" ? metadata2.error_type : null
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
yield* processChoice(firstChoice, pendingToolCalls);
|
|
1623
|
+
};
|
|
1624
|
+
var isUsageUpdate = (chunk) => chunk.type === "usage_update";
|
|
1625
|
+
var collectYieldableChunks = (line, pendingToolCalls, usageRef, metadataRef, providerName) => {
|
|
1626
|
+
const allChunks = Array.from(processSSELine2(line, pendingToolCalls, providerName));
|
|
1627
|
+
const usageChunks = allChunks.filter(isUsageUpdate);
|
|
1628
|
+
const lastUsage = usageChunks.at(NOT_FOUND);
|
|
1629
|
+
if (lastUsage) {
|
|
1630
|
+
usageRef.current = lastUsage.usage;
|
|
1631
|
+
}
|
|
1632
|
+
const metadataChunks = allChunks.filter((chunk) => chunk.type === "response_metadata");
|
|
1633
|
+
const lastMetadata = metadataChunks.at(NOT_FOUND);
|
|
1634
|
+
if (lastMetadata && "metadata" in lastMetadata) {
|
|
1635
|
+
metadataRef.current = {
|
|
1636
|
+
...metadataRef.current,
|
|
1637
|
+
...lastMetadata.metadata,
|
|
1638
|
+
providerMetadata: {
|
|
1639
|
+
...metadataRef.current?.providerMetadata,
|
|
1640
|
+
...lastMetadata.metadata.providerMetadata
|
|
1641
|
+
}
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1644
|
+
return allChunks.filter((chunk) => !isUsageUpdate(chunk) && chunk.type !== "response_metadata");
|
|
1359
1645
|
};
|
|
1360
|
-
var processSSELines2 = function* (lines,
|
|
1646
|
+
var processSSELines2 = function* (lines, pendingToolCalls, usageRef, metadataRef, providerName) {
|
|
1361
1647
|
for (const line of lines) {
|
|
1362
|
-
yield*
|
|
1648
|
+
yield* collectYieldableChunks(line, pendingToolCalls, usageRef, metadataRef, providerName);
|
|
1363
1649
|
}
|
|
1364
1650
|
};
|
|
1651
|
+
var processStreamValue = (value, decoder, state) => {
|
|
1652
|
+
state.buffer += decoder.decode(value, { stream: true });
|
|
1653
|
+
const lines = state.buffer.split(`
|
|
1654
|
+
`);
|
|
1655
|
+
state.buffer = lines.pop() ?? "";
|
|
1656
|
+
return lines;
|
|
1657
|
+
};
|
|
1365
1658
|
var drainReader2 = async function* (reader, decoder, state, signal) {
|
|
1366
|
-
let textBuffer = "";
|
|
1367
1659
|
for (let result = await reader.read();!result.done && !signal?.aborted; result = await reader.read()) {
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
`);
|
|
1371
|
-
textBuffer = lines.pop() ?? "";
|
|
1372
|
-
yield* processSSELines2(lines, state);
|
|
1373
|
-
}
|
|
1374
|
-
if (textBuffer.trim()) {
|
|
1375
|
-
yield* processSSELines2([textBuffer, ""], state);
|
|
1660
|
+
const lines = processStreamValue(result.value, decoder, state);
|
|
1661
|
+
yield* processSSELines2(lines, state.pendingToolCalls, state.usageRef, state.metadataRef, state.providerName);
|
|
1376
1662
|
}
|
|
1377
1663
|
};
|
|
1378
|
-
var parseSSEStream2 = async function* (body, providerName, signal) {
|
|
1664
|
+
var parseSSEStream2 = async function* (body, initialMetadata, providerName = "openai", signal) {
|
|
1379
1665
|
const reader = body.getReader();
|
|
1380
1666
|
const decoder = new TextDecoder;
|
|
1381
1667
|
const state = {
|
|
1382
1668
|
buffer: "",
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1669
|
+
metadataRef: { current: initialMetadata },
|
|
1670
|
+
pendingToolCalls: new Map,
|
|
1671
|
+
providerName,
|
|
1672
|
+
usageRef: { current: undefined }
|
|
1387
1673
|
};
|
|
1388
1674
|
try {
|
|
1389
1675
|
yield* drainReader2(reader, decoder, state, signal);
|
|
1390
|
-
yield
|
|
1676
|
+
yield {
|
|
1677
|
+
metadata: state.metadataRef.current,
|
|
1678
|
+
type: "done",
|
|
1679
|
+
usage: state.usageRef.current
|
|
1680
|
+
};
|
|
1391
1681
|
} finally {
|
|
1392
1682
|
reader.releaseLock();
|
|
1393
1683
|
}
|
|
1394
1684
|
};
|
|
1395
|
-
var
|
|
1396
|
-
const target = `${baseUrl}/v1/
|
|
1685
|
+
var fetchOpenAIStream = async function* (baseUrl, apiKey, body, fetchImpl, headers, providerName, signal) {
|
|
1686
|
+
const target = `${baseUrl}/v1/chat/completions`;
|
|
1397
1687
|
const requestHeaders = new Headers(headers);
|
|
1398
1688
|
requestHeaders.set("Authorization", `Bearer ${apiKey}`);
|
|
1399
1689
|
requestHeaders.set("Content-Type", "application/json");
|
|
@@ -1410,42 +1700,53 @@ var fetchResponsesStream = async function* (baseUrl, apiKey, body, fetchImpl, he
|
|
|
1410
1700
|
}
|
|
1411
1701
|
if (!response.body) {
|
|
1412
1702
|
throw new ProviderError({
|
|
1413
|
-
message: `${providerName}
|
|
1703
|
+
message: `${providerName} API returned no response body`,
|
|
1414
1704
|
provider: providerName,
|
|
1415
1705
|
retryable: true
|
|
1416
1706
|
});
|
|
1417
1707
|
}
|
|
1418
|
-
yield* parseSSEStream2(response.body,
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
}
|
|
1427
|
-
return new Set(imageModels);
|
|
1708
|
+
yield* parseSSEStream2(response.body, {
|
|
1709
|
+
generationId: response.headers.get("X-Generation-Id") ?? undefined,
|
|
1710
|
+
providerMetadata: {
|
|
1711
|
+
cacheAge: response.headers.get("X-OpenRouter-Cache-Age") ?? undefined,
|
|
1712
|
+
cacheSourceId: response.headers.get("X-OpenRouter-Cache-Source-Id") ?? undefined,
|
|
1713
|
+
cacheStatus: response.headers.get("X-OpenRouter-Cache-Status") ?? undefined,
|
|
1714
|
+
cacheTtl: response.headers.get("X-OpenRouter-Cache-TTL") ?? undefined
|
|
1715
|
+
}
|
|
1716
|
+
}, providerName, signal);
|
|
1428
1717
|
};
|
|
1429
|
-
var
|
|
1430
|
-
if (!config2.apiKey && !config2.tokenSource)
|
|
1431
|
-
throw new Error("openaiResponses() requires either apiKey or tokenSource");
|
|
1718
|
+
var openai = (config2) => {
|
|
1432
1719
|
const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL2;
|
|
1433
1720
|
const fetchImpl = config2.fetch ?? globalThis.fetch;
|
|
1434
|
-
const
|
|
1435
|
-
|
|
1436
|
-
|
|
1721
|
+
const providerName = config2.providerName ?? "openai";
|
|
1722
|
+
if (!config2.apiKey && !config2.tokenSource) {
|
|
1723
|
+
throw new Error("openai() requires either apiKey or tokenSource");
|
|
1724
|
+
}
|
|
1725
|
+
const resolveKey = async () => {
|
|
1726
|
+
if (config2.tokenSource) {
|
|
1727
|
+
return await Promise.resolve(config2.tokenSource());
|
|
1728
|
+
}
|
|
1729
|
+
return config2.apiKey;
|
|
1730
|
+
};
|
|
1437
1731
|
const resolveHeaders = async (params) => typeof config2.headers === "function" ? await config2.headers(params) : config2.headers ?? {};
|
|
1438
1732
|
return instrumentAIProvider({
|
|
1733
|
+
inputCapacity: config2.transformRequestBody ? undefined : openaiInputCapacity({
|
|
1734
|
+
baseUrl,
|
|
1735
|
+
fetch: fetchImpl,
|
|
1736
|
+
key: resolveKey,
|
|
1737
|
+
headers: resolveHeaders,
|
|
1738
|
+
modelLimits: config2.modelLimits,
|
|
1739
|
+
body: (params) => buildResponsesRequestBody(params, false, config2.modelForCapabilities?.(params.model) ?? params.model)
|
|
1740
|
+
}),
|
|
1439
1741
|
stream: (params) => {
|
|
1440
|
-
const
|
|
1441
|
-
const
|
|
1442
|
-
const body = config2.transformRequestBody ? config2.transformRequestBody(builtBody, params) : builtBody;
|
|
1742
|
+
const openaiBody = buildRequestBody(params, config2.modelForCapabilities?.(params.model) ?? params.model);
|
|
1743
|
+
const body = config2.transformRequestBody ? config2.transformRequestBody(openaiBody, params) : openaiBody;
|
|
1443
1744
|
return async function* () {
|
|
1444
1745
|
const [apiKey, headers] = await Promise.all([
|
|
1445
1746
|
resolveKey(),
|
|
1446
1747
|
resolveHeaders(params)
|
|
1447
1748
|
]);
|
|
1448
|
-
yield*
|
|
1749
|
+
yield* fetchOpenAIStream(baseUrl, apiKey, body, fetchImpl, headers, providerName, params.signal);
|
|
1449
1750
|
}();
|
|
1450
1751
|
}
|
|
1451
1752
|
}, providerName);
|
|
@@ -1588,7 +1889,7 @@ var cacheLastContentBlock = (msg) => {
|
|
|
1588
1889
|
};
|
|
1589
1890
|
return { content: blocks, role: msg.role };
|
|
1590
1891
|
};
|
|
1591
|
-
var
|
|
1892
|
+
var buildRequestBody2 = (params, configuredMax, configCaching) => {
|
|
1592
1893
|
const caching = params.promptCaching ?? configCaching;
|
|
1593
1894
|
const cacheSystem = params.cacheSystemPrompt ?? caching;
|
|
1594
1895
|
const options = requestOptionsFor(params);
|
|
@@ -2014,7 +2315,7 @@ async function* parseSSEStream3(body, providerName, signal) {
|
|
|
2014
2315
|
}
|
|
2015
2316
|
}
|
|
2016
2317
|
var fetchAndStream = async function* (baseUrl, config2, params, configuredMax, promptCaching, providerName) {
|
|
2017
|
-
const builtBody =
|
|
2318
|
+
const builtBody = buildRequestBody2(params, configuredMax, promptCaching);
|
|
2018
2319
|
const body = config2.transformRequestBody ? config2.transformRequestBody(builtBody, params) : builtBody;
|
|
2019
2320
|
const target = `${baseUrl}/v1/messages`;
|
|
2020
2321
|
const fetchImpl = config2.fetch ?? fetch;
|
|
@@ -2055,7 +2356,57 @@ var anthropic = (config2) => {
|
|
|
2055
2356
|
const configuredMax = config2.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
2056
2357
|
const promptCaching = config2.promptCaching ?? true;
|
|
2057
2358
|
const providerName = config2.providerName ?? "anthropic";
|
|
2359
|
+
const capacityRequest = async (params, path, body) => {
|
|
2360
|
+
const token = config2.tokenSource ? await config2.tokenSource() : config2.apiKey;
|
|
2361
|
+
const headers = new Headers(typeof config2.headers === "function" ? await config2.headers(params) : config2.headers);
|
|
2362
|
+
headers.set("Content-Type", "application/json");
|
|
2363
|
+
if (config2.authStyle === "bearer")
|
|
2364
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
2365
|
+
else {
|
|
2366
|
+
headers.set("anthropic-version", API_VERSION);
|
|
2367
|
+
headers.set("x-api-key", token);
|
|
2368
|
+
}
|
|
2369
|
+
return capacityJson(await (config2.fetch ?? fetch)(`${baseUrl}${path}`, {
|
|
2370
|
+
method: body ? "POST" : "GET",
|
|
2371
|
+
headers,
|
|
2372
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
2373
|
+
signal: params.signal ? AbortSignal.any([params.signal, AbortSignal.timeout(15000)]) : AbortSignal.timeout(15000)
|
|
2374
|
+
}));
|
|
2375
|
+
};
|
|
2376
|
+
const inputCapacity = {
|
|
2377
|
+
outputTokens: (params) => {
|
|
2378
|
+
const built = buildRequestBody2(params, configuredMax, promptCaching);
|
|
2379
|
+
const body = config2.transformRequestBody ? config2.transformRequestBody(built, params) : built;
|
|
2380
|
+
return positiveTokenLimit(body.max_tokens);
|
|
2381
|
+
},
|
|
2382
|
+
getLimits: cacheModelLimits(async (params) => {
|
|
2383
|
+
const data = await capacityRequest(params, `/v1/models/${encodeURIComponent(params.model)}`);
|
|
2384
|
+
const context = positiveTokenLimit(data.max_input_tokens);
|
|
2385
|
+
return {
|
|
2386
|
+
maxInputTokens: context,
|
|
2387
|
+
contextWindowTokens: context,
|
|
2388
|
+
maxOutputTokens: positiveTokenLimit(data.max_tokens)
|
|
2389
|
+
};
|
|
2390
|
+
}, config2.tokenSource || typeof config2.headers === "function" ? 0 : 300000),
|
|
2391
|
+
countTokens: async (params) => {
|
|
2392
|
+
const built = buildRequestBody2(params, configuredMax, promptCaching);
|
|
2393
|
+
const body = config2.transformRequestBody ? config2.transformRequestBody(built, params) : built;
|
|
2394
|
+
const counted = {};
|
|
2395
|
+
for (const key of [
|
|
2396
|
+
"model",
|
|
2397
|
+
"messages",
|
|
2398
|
+
"system",
|
|
2399
|
+
"tools",
|
|
2400
|
+
"tool_choice",
|
|
2401
|
+
"thinking"
|
|
2402
|
+
])
|
|
2403
|
+
if (body[key] !== undefined)
|
|
2404
|
+
counted[key] = body[key];
|
|
2405
|
+
return inputTokenCount((await capacityRequest(params, "/v1/messages/count_tokens", counted)).input_tokens);
|
|
2406
|
+
}
|
|
2407
|
+
};
|
|
2058
2408
|
return instrumentAIProvider({
|
|
2409
|
+
inputCapacity,
|
|
2059
2410
|
stream: (params) => fetchAndStream(baseUrl, config2, params, configuredMax, promptCaching, providerName)
|
|
2060
2411
|
}, providerName);
|
|
2061
2412
|
};
|
|
@@ -2978,5 +3329,5 @@ export {
|
|
|
2978
3329
|
verifyOpenRouterWebhookSignature
|
|
2979
3330
|
};
|
|
2980
3331
|
|
|
2981
|
-
//# debugId=
|
|
3332
|
+
//# debugId=97E7A9DE2EC4EDCB64756E2164756E21
|
|
2982
3333
|
//# sourceMappingURL=openrouter.js.map
|