@absolutejs/ai 0.0.55 → 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/client/index.js +5 -5
- package/dist/ai/client/index.js.map +1 -1
- package/dist/ai/index.js +1411 -889
- package/dist/ai/index.js.map +15 -12
- 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 +882 -48
- 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 +1098 -747
- package/dist/ai/providers/openrouter.js.map +10 -8
- package/dist/ai/providers/openrouterSDK.js +3 -3
- package/dist/ai/providers/openrouterSDK.js.map +1 -1
- package/dist/ai/tools/index.js +4 -4
- package/dist/ai/tools/index.js.map +2 -2
- package/dist/ai/tools/untrusted.js +3 -3
- package/dist/ai/tools/untrusted.js.map +2 -2
- package/dist/ai/ui/index.js +42 -42
- package/dist/ai/ui/index.js.map +2 -2
- package/dist/react/ai/index.js +3 -3
- package/dist/react/ai/index.js.map +1 -1
- package/dist/src/ai/generateAI.d.ts +4 -0
- 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/dist/vue/ai/index.js +3 -3
- package/dist/vue/ai/index.js.map +1 -1
- package/package.json +204 -199
|
@@ -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,14 +670,558 @@ 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";
|
|
676
|
+
var EVENT_PREFIX_LENGTH = 7;
|
|
677
|
+
var DATA_PREFIX_LENGTH = 6;
|
|
678
|
+
var isRecord = (value) => typeof value === "object" && value !== null;
|
|
679
|
+
var isRecordArray = (value) => Array.isArray(value) && value.length > 0 && isRecord(value[0]);
|
|
680
|
+
var mapBlockToResponsesFormat = (block) => {
|
|
681
|
+
if (block.type === "text") {
|
|
682
|
+
return { text: block.content, type: "input_text" };
|
|
683
|
+
}
|
|
684
|
+
if (block.type === "image") {
|
|
685
|
+
return {
|
|
686
|
+
image_url: {
|
|
687
|
+
url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
|
|
688
|
+
},
|
|
689
|
+
type: "input_image"
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
if (block.type === "document") {
|
|
693
|
+
return {
|
|
694
|
+
file: {
|
|
695
|
+
file_data: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`,
|
|
696
|
+
filename: block.name ?? "document.pdf"
|
|
697
|
+
},
|
|
698
|
+
type: "input_file"
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
if (block.type === "audio") {
|
|
702
|
+
return {
|
|
703
|
+
input_audio: { data: block.source.data, format: block.source.format },
|
|
704
|
+
type: "input_audio"
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
if (block.type === "video") {
|
|
708
|
+
return {
|
|
709
|
+
type: "input_video",
|
|
710
|
+
video_url: block.source.type === "url" ? block.source.url : `data:${block.source.media_type};base64,${block.source.data}`
|
|
711
|
+
};
|
|
712
|
+
}
|
|
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
|
+
};
|
|
743
|
+
}
|
|
744
|
+
return null;
|
|
745
|
+
};
|
|
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);
|
|
750
|
+
}
|
|
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));
|
|
764
|
+
}
|
|
765
|
+
return input;
|
|
766
|
+
};
|
|
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" });
|
|
778
|
+
}
|
|
779
|
+
return result.length > 0 ? result : undefined;
|
|
780
|
+
};
|
|
781
|
+
var buildResponsesRequestBody = (params, isImageModel, capabilityModel = params.model) => {
|
|
782
|
+
const body = {
|
|
783
|
+
input: buildInput(params.messages),
|
|
784
|
+
model: params.model,
|
|
785
|
+
stream: true
|
|
786
|
+
};
|
|
787
|
+
if (params.systemPrompt) {
|
|
788
|
+
body.instructions = params.systemPrompt;
|
|
789
|
+
}
|
|
790
|
+
const tools = buildTools(params.tools, isImageModel);
|
|
791
|
+
if (tools) {
|
|
792
|
+
body.tools = tools;
|
|
793
|
+
if (params.toolChoice === "auto" || params.toolChoice === "none" || params.toolChoice === "required") {
|
|
794
|
+
body.tool_choice = params.toolChoice;
|
|
795
|
+
} else if (params.toolChoice && typeof params.toolChoice === "object") {
|
|
796
|
+
body.tool_choice = {
|
|
797
|
+
name: params.toolChoice.name,
|
|
798
|
+
type: "function"
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
if (typeof params.parallelToolCalls === "boolean") {
|
|
802
|
+
body.parallel_tool_calls = params.parallelToolCalls;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
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;
|
|
811
|
+
if (params.stopSequences && params.stopSequences.length > 0)
|
|
812
|
+
body.stop = params.stopSequences;
|
|
813
|
+
if (typeof params.seed === "number")
|
|
814
|
+
body.seed = params.seed;
|
|
815
|
+
if (typeof params.frequencyPenalty === "number")
|
|
816
|
+
body.frequency_penalty = params.frequencyPenalty;
|
|
817
|
+
if (typeof params.presencePenalty === "number")
|
|
818
|
+
body.presence_penalty = params.presencePenalty;
|
|
819
|
+
if (params.responseFormat) {
|
|
820
|
+
if (params.responseFormat.type === "text" || params.responseFormat.type === "json_object") {
|
|
821
|
+
body.text = { format: { type: params.responseFormat.type } };
|
|
822
|
+
} else if (params.responseFormat.type === "json_schema") {
|
|
823
|
+
body.text = {
|
|
824
|
+
format: {
|
|
825
|
+
name: params.responseFormat.name,
|
|
826
|
+
schema: params.responseFormat.schema,
|
|
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
|
+
}
|
|
841
|
+
}
|
|
842
|
+
return body;
|
|
843
|
+
};
|
|
844
|
+
var parseJSON = (data) => {
|
|
845
|
+
try {
|
|
846
|
+
return JSON.parse(data);
|
|
847
|
+
} catch {
|
|
848
|
+
return null;
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
var parseToolInput = (rawArguments) => {
|
|
852
|
+
try {
|
|
853
|
+
return JSON.parse(rawArguments);
|
|
854
|
+
} catch {
|
|
855
|
+
return rawArguments;
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
var extractUsage = (response) => {
|
|
859
|
+
if (!isRecord(response.usage)) {
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
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 = {
|
|
869
|
+
cacheReadInputTokens: cached,
|
|
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
|
|
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;
|
|
881
|
+
};
|
|
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)
|
|
889
|
+
return;
|
|
890
|
+
return { generationId, model, provider, providerMetadata, serviceTier };
|
|
891
|
+
};
|
|
892
|
+
var extractMimeFormat = (mimeType) => {
|
|
893
|
+
if (typeof mimeType !== "string") {
|
|
894
|
+
return "png";
|
|
895
|
+
}
|
|
896
|
+
if (mimeType.includes("jpeg"))
|
|
897
|
+
return "jpeg";
|
|
898
|
+
if (mimeType.includes("webp"))
|
|
899
|
+
return "webp";
|
|
900
|
+
return "png";
|
|
901
|
+
};
|
|
902
|
+
var processTextDelta = function* (parsed) {
|
|
903
|
+
if (typeof parsed.delta === "string") {
|
|
904
|
+
yield { content: parsed.delta, type: "text" };
|
|
905
|
+
}
|
|
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
|
+
};
|
|
918
|
+
}
|
|
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
|
+
});
|
|
933
|
+
}
|
|
934
|
+
};
|
|
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)) {
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
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") {
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
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
|
+
});
|
|
969
|
+
};
|
|
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
|
+
};
|
|
980
|
+
};
|
|
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);
|
|
994
|
+
}
|
|
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))
|
|
1002
|
+
continue;
|
|
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
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
};
|
|
1020
|
+
var processCompleted = function* (parsed) {
|
|
1021
|
+
if (!isRecord(parsed.response)) {
|
|
1022
|
+
yield { type: "done", usage: undefined };
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
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);
|
|
1031
|
+
}
|
|
1032
|
+
yield { metadata, type: "done", usage };
|
|
1033
|
+
};
|
|
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
|
|
1044
|
+
});
|
|
1045
|
+
};
|
|
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);
|
|
1084
|
+
}
|
|
1085
|
+
};
|
|
1086
|
+
var flushSSEBuffer = function* (state) {
|
|
1087
|
+
if (!state.currentEvent || !state.buffer) {
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
const parsed = parseJSON(state.buffer);
|
|
1091
|
+
if (parsed) {
|
|
1092
|
+
yield* processSSEEvent(state.currentEvent, parsed, state.pendingCalls, state.providerName);
|
|
1093
|
+
}
|
|
1094
|
+
state.currentEvent = "";
|
|
1095
|
+
state.buffer = "";
|
|
1096
|
+
};
|
|
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);
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
var processSSELine = function* (line, state) {
|
|
1105
|
+
const trimmed = line.trim();
|
|
1106
|
+
if (trimmed) {
|
|
1107
|
+
parseSSELine(trimmed, state);
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
yield* flushSSEBuffer(state);
|
|
1111
|
+
};
|
|
1112
|
+
var processSSELines = function* (lines, state) {
|
|
1113
|
+
for (const line of lines) {
|
|
1114
|
+
yield* processSSELine(line, state);
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
var drainReader = async function* (reader, decoder, state, signal) {
|
|
1118
|
+
let textBuffer = "";
|
|
1119
|
+
for (let result = await reader.read();!result.done && !signal?.aborted; result = await reader.read()) {
|
|
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);
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1130
|
+
var parseSSEStream = async function* (body, providerName, signal) {
|
|
1131
|
+
const reader = body.getReader();
|
|
1132
|
+
const decoder = new TextDecoder;
|
|
1133
|
+
const state = {
|
|
1134
|
+
buffer: "",
|
|
1135
|
+
currentEvent: "",
|
|
1136
|
+
pendingCalls: new Map,
|
|
1137
|
+
usage: undefined,
|
|
1138
|
+
providerName
|
|
1139
|
+
};
|
|
1140
|
+
try {
|
|
1141
|
+
yield* drainReader(reader, decoder, state, signal);
|
|
1142
|
+
yield* flushSSEBuffer(state);
|
|
1143
|
+
} finally {
|
|
1144
|
+
reader.releaseLock();
|
|
1145
|
+
}
|
|
1146
|
+
};
|
|
1147
|
+
var fetchResponsesStream = async function* (baseUrl, apiKey, body, fetchImpl, headers, providerName, signal) {
|
|
1148
|
+
const target = `${baseUrl}/v1/responses`;
|
|
1149
|
+
const requestHeaders = new Headers(headers);
|
|
1150
|
+
requestHeaders.set("Authorization", `Bearer ${apiKey}`);
|
|
1151
|
+
requestHeaders.set("Content-Type", "application/json");
|
|
1152
|
+
const response = await fetchImpl(target, {
|
|
1153
|
+
...h2IfHttps(target),
|
|
1154
|
+
body: JSON.stringify(body),
|
|
1155
|
+
headers: requestHeaders,
|
|
1156
|
+
method: "POST",
|
|
1157
|
+
signal
|
|
1158
|
+
});
|
|
1159
|
+
if (!response.ok) {
|
|
1160
|
+
const errorText = await response.text();
|
|
1161
|
+
throw ProviderError.fromResponse(providerName, response.status, errorText);
|
|
1162
|
+
}
|
|
1163
|
+
if (!response.body) {
|
|
1164
|
+
throw new ProviderError({
|
|
1165
|
+
message: `${providerName} Responses API returned no response body`,
|
|
1166
|
+
provider: providerName,
|
|
1167
|
+
retryable: true
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
yield* parseSSEStream(response.body, providerName, signal);
|
|
1171
|
+
};
|
|
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");
|
|
1184
|
+
const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL;
|
|
1185
|
+
const fetchImpl = config2.fetch ?? globalThis.fetch;
|
|
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;
|
|
1189
|
+
const resolveHeaders = async (params) => typeof config2.headers === "function" ? await config2.headers(params) : config2.headers ?? {};
|
|
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
|
+
}),
|
|
1202
|
+
stream: (params) => {
|
|
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;
|
|
1206
|
+
return async function* () {
|
|
1207
|
+
const [apiKey, headers] = await Promise.all([
|
|
1208
|
+
resolveKey(),
|
|
1209
|
+
resolveHeaders(params)
|
|
1210
|
+
]);
|
|
1211
|
+
yield* fetchResponsesStream(baseUrl, apiKey, body, fetchImpl, headers, providerName, params.signal);
|
|
1212
|
+
}();
|
|
1213
|
+
}
|
|
1214
|
+
}, providerName);
|
|
1215
|
+
};
|
|
1216
|
+
|
|
1217
|
+
// src/ai/providers/openai.ts
|
|
1218
|
+
var h2IfHttps2 = (url) => url.startsWith("https://") ? { protocol: "http2" } : {};
|
|
1219
|
+
var DEFAULT_BASE_URL2 = "https://api.openai.com";
|
|
394
1220
|
var SSE_DATA_PREFIX_LENGTH = 6;
|
|
395
1221
|
var DONE_SENTINEL = "[DONE]";
|
|
396
1222
|
var NOT_FOUND = -1;
|
|
397
|
-
var
|
|
398
|
-
var
|
|
1223
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null;
|
|
1224
|
+
var isRecordArray2 = (value) => Array.isArray(value) && value.length > 0 && isRecord2(value[0]);
|
|
399
1225
|
var hasArrayContent = (msg) => typeof msg.content !== "string" && Array.isArray(msg.content);
|
|
400
1226
|
var buildToolMessages = (blocks) => {
|
|
401
1227
|
const toolUseBlocks = blocks.filter((block) => block.type === "tool_use");
|
|
@@ -428,8 +1254,8 @@ var processMessageAtIndex = (result, msg, idx) => {
|
|
|
428
1254
|
if (!hasArrayContent(msg)) {
|
|
429
1255
|
return;
|
|
430
1256
|
}
|
|
431
|
-
const
|
|
432
|
-
if (!
|
|
1257
|
+
const hasToolBlocks2 = msg.content.some((block) => block.type === "tool_use" || block.type === "tool_result");
|
|
1258
|
+
if (!hasToolBlocks2) {
|
|
433
1259
|
return;
|
|
434
1260
|
}
|
|
435
1261
|
const toolMessages = buildToolMessages(msg.content);
|
|
@@ -573,7 +1399,7 @@ var buildRequestBody = (params, capabilityModel = params.model) => {
|
|
|
573
1399
|
}
|
|
574
1400
|
return body;
|
|
575
1401
|
};
|
|
576
|
-
var
|
|
1402
|
+
var parseToolInput2 = (rawArguments) => {
|
|
577
1403
|
try {
|
|
578
1404
|
return JSON.parse(rawArguments);
|
|
579
1405
|
} catch {
|
|
@@ -582,7 +1408,7 @@ var parseToolInput = (rawArguments) => {
|
|
|
582
1408
|
};
|
|
583
1409
|
var flushPendingToolCalls = function* (pendingToolCalls) {
|
|
584
1410
|
for (const [, tool] of pendingToolCalls) {
|
|
585
|
-
const input =
|
|
1411
|
+
const input = parseToolInput2(tool.arguments);
|
|
586
1412
|
yield {
|
|
587
1413
|
id: tool.id,
|
|
588
1414
|
input,
|
|
@@ -592,7 +1418,7 @@ var flushPendingToolCalls = function* (pendingToolCalls) {
|
|
|
592
1418
|
}
|
|
593
1419
|
pendingToolCalls.clear();
|
|
594
1420
|
};
|
|
595
|
-
var
|
|
1421
|
+
var extractUsage2 = (parsedUsage) => {
|
|
596
1422
|
const prompt = parsedUsage.prompt_tokens ?? 0;
|
|
597
1423
|
const cached = parsedUsage.cached_tokens ?? 0;
|
|
598
1424
|
return {
|
|
@@ -637,7 +1463,7 @@ var processToolCallDelta = (toolCall, pendingToolCalls) => {
|
|
|
637
1463
|
if (index === undefined) {
|
|
638
1464
|
return;
|
|
639
1465
|
}
|
|
640
|
-
const func =
|
|
1466
|
+
const func = isRecord2(toolCall.function) ? toolCall.function : null;
|
|
641
1467
|
initPendingToolCall(toolCall, func, index, pendingToolCalls);
|
|
642
1468
|
const pending = pendingToolCalls.get(index);
|
|
643
1469
|
if (!pending) {
|
|
@@ -654,7 +1480,7 @@ var processDelta = function* (delta, pendingToolCalls) {
|
|
|
654
1480
|
if (typeof delta.content === "string") {
|
|
655
1481
|
yield { content: delta.content, type: "text" };
|
|
656
1482
|
}
|
|
657
|
-
if (
|
|
1483
|
+
if (isRecord2(delta.audio)) {
|
|
658
1484
|
const audio = delta.audio;
|
|
659
1485
|
if (typeof audio.data === "string" || typeof audio.transcript === "string") {
|
|
660
1486
|
yield {
|
|
@@ -666,14 +1492,14 @@ var processDelta = function* (delta, pendingToolCalls) {
|
|
|
666
1492
|
};
|
|
667
1493
|
}
|
|
668
1494
|
}
|
|
669
|
-
if (
|
|
1495
|
+
if (isRecordArray2(delta.tool_calls)) {
|
|
670
1496
|
processToolCallDeltas(delta.tool_calls, pendingToolCalls);
|
|
671
1497
|
}
|
|
672
1498
|
if (Array.isArray(delta.annotations)) {
|
|
673
1499
|
for (const annotation of delta.annotations) {
|
|
674
|
-
if (!
|
|
1500
|
+
if (!isRecord2(annotation) || annotation.type !== "url_citation")
|
|
675
1501
|
continue;
|
|
676
|
-
const citation =
|
|
1502
|
+
const citation = isRecord2(annotation.url_citation) ? annotation.url_citation : annotation;
|
|
677
1503
|
if (typeof citation.url !== "string")
|
|
678
1504
|
continue;
|
|
679
1505
|
yield {
|
|
@@ -688,19 +1514,19 @@ var processDelta = function* (delta, pendingToolCalls) {
|
|
|
688
1514
|
}
|
|
689
1515
|
};
|
|
690
1516
|
var narrowResponseMetadata = (parsed) => {
|
|
691
|
-
const providerMetadata =
|
|
1517
|
+
const providerMetadata = isRecord2(parsed.openrouter_metadata) ? parsed.openrouter_metadata : undefined;
|
|
692
1518
|
const generationId = typeof parsed.id === "string" ? parsed.id : undefined;
|
|
693
1519
|
const model = typeof parsed.model === "string" ? parsed.model : undefined;
|
|
694
1520
|
const serviceTier = typeof parsed.service_tier === "string" ? parsed.service_tier : undefined;
|
|
695
|
-
const selected = providerMetadata &&
|
|
696
|
-
const selectedEndpoint = Array.isArray(selected) ? selected.find((entry) =>
|
|
697
|
-
const provider =
|
|
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;
|
|
698
1524
|
if (!providerMetadata && !generationId && !model && !serviceTier)
|
|
699
1525
|
return;
|
|
700
1526
|
return { generationId, model, provider, providerMetadata, serviceTier };
|
|
701
1527
|
};
|
|
702
1528
|
var processChoice = function* (choice, pendingToolCalls) {
|
|
703
|
-
const delta =
|
|
1529
|
+
const delta = isRecord2(choice.delta) ? choice.delta : null;
|
|
704
1530
|
if (delta) {
|
|
705
1531
|
yield* processDelta(delta, pendingToolCalls);
|
|
706
1532
|
}
|
|
@@ -709,18 +1535,18 @@ var processChoice = function* (choice, pendingToolCalls) {
|
|
|
709
1535
|
}
|
|
710
1536
|
};
|
|
711
1537
|
var narrowUsageRecord = (parsed) => {
|
|
712
|
-
if (!
|
|
1538
|
+
if (!isRecord2(parsed.usage)) {
|
|
713
1539
|
return;
|
|
714
1540
|
}
|
|
715
1541
|
const { usage } = parsed;
|
|
716
1542
|
const promptTokens = typeof usage.prompt_tokens === "number" ? usage.prompt_tokens : 0;
|
|
717
1543
|
const completionTokens = typeof usage.completion_tokens === "number" ? usage.completion_tokens : 0;
|
|
718
|
-
const cachedTokens =
|
|
719
|
-
const cacheWriteTokens =
|
|
720
|
-
const reasoningTokens =
|
|
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;
|
|
721
1547
|
const cost = typeof usage.cost === "number" ? usage.cost : undefined;
|
|
722
|
-
const upstreamInferenceCost =
|
|
723
|
-
const normalized =
|
|
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({
|
|
724
1550
|
cache_write_tokens: cacheWriteTokens,
|
|
725
1551
|
cached_tokens: cachedTokens,
|
|
726
1552
|
completion_tokens: completionTokens,
|
|
@@ -729,12 +1555,12 @@ var narrowUsageRecord = (parsed) => {
|
|
|
729
1555
|
reasoning_tokens: reasoningTokens,
|
|
730
1556
|
upstream_inference_cost: upstreamInferenceCost
|
|
731
1557
|
});
|
|
732
|
-
if (
|
|
1558
|
+
if (isRecord2(usage.server_tool_use)) {
|
|
733
1559
|
normalized.serverToolUse = Object.fromEntries(Object.entries(usage.server_tool_use).filter((entry) => typeof entry[1] === "number"));
|
|
734
1560
|
}
|
|
735
1561
|
return normalized;
|
|
736
1562
|
};
|
|
737
|
-
var
|
|
1563
|
+
var processSSELine2 = function* (line, pendingToolCalls, providerName) {
|
|
738
1564
|
const trimmed = line.trim();
|
|
739
1565
|
if (!trimmed || !trimmed.startsWith("data: ")) {
|
|
740
1566
|
return;
|
|
@@ -750,9 +1576,9 @@ var processSSELine = function* (line, pendingToolCalls, providerName) {
|
|
|
750
1576
|
} catch {
|
|
751
1577
|
return;
|
|
752
1578
|
}
|
|
753
|
-
if (
|
|
1579
|
+
if (isRecord2(parsed.error)) {
|
|
754
1580
|
const error = parsed.error;
|
|
755
|
-
const metadata2 =
|
|
1581
|
+
const metadata2 = isRecord2(error.metadata) ? error.metadata : undefined;
|
|
756
1582
|
const status = typeof error.code === "number" ? error.code : null;
|
|
757
1583
|
const type = metadata2 && typeof metadata2.error_type === "string" ? metadata2.error_type : typeof error.error_type === "string" ? error.error_type : null;
|
|
758
1584
|
throw new ProviderError({
|
|
@@ -773,16 +1599,16 @@ var processSSELine = function* (line, pendingToolCalls, providerName) {
|
|
|
773
1599
|
yield { metadata, type: "response_metadata" };
|
|
774
1600
|
}
|
|
775
1601
|
const { choices } = parsed;
|
|
776
|
-
if (!
|
|
1602
|
+
if (!isRecordArray2(choices)) {
|
|
777
1603
|
return;
|
|
778
1604
|
}
|
|
779
1605
|
const [firstChoice] = choices;
|
|
780
1606
|
if (!firstChoice) {
|
|
781
1607
|
return;
|
|
782
1608
|
}
|
|
783
|
-
if (
|
|
1609
|
+
if (isRecord2(firstChoice.error)) {
|
|
784
1610
|
const error = firstChoice.error;
|
|
785
|
-
const metadata2 =
|
|
1611
|
+
const metadata2 = isRecord2(error.metadata) ? error.metadata : undefined;
|
|
786
1612
|
const status = typeof error.code === "number" ? error.code : null;
|
|
787
1613
|
throw new ProviderError({
|
|
788
1614
|
message: typeof error.message === "string" ? error.message : "OpenRouter stream failed",
|
|
@@ -797,7 +1623,7 @@ var processSSELine = function* (line, pendingToolCalls, providerName) {
|
|
|
797
1623
|
};
|
|
798
1624
|
var isUsageUpdate = (chunk) => chunk.type === "usage_update";
|
|
799
1625
|
var collectYieldableChunks = (line, pendingToolCalls, usageRef, metadataRef, providerName) => {
|
|
800
|
-
const allChunks = Array.from(
|
|
1626
|
+
const allChunks = Array.from(processSSELine2(line, pendingToolCalls, providerName));
|
|
801
1627
|
const usageChunks = allChunks.filter(isUsageUpdate);
|
|
802
1628
|
const lastUsage = usageChunks.at(NOT_FOUND);
|
|
803
1629
|
if (lastUsage) {
|
|
@@ -817,7 +1643,7 @@ var collectYieldableChunks = (line, pendingToolCalls, usageRef, metadataRef, pro
|
|
|
817
1643
|
}
|
|
818
1644
|
return allChunks.filter((chunk) => !isUsageUpdate(chunk) && chunk.type !== "response_metadata");
|
|
819
1645
|
};
|
|
820
|
-
var
|
|
1646
|
+
var processSSELines2 = function* (lines, pendingToolCalls, usageRef, metadataRef, providerName) {
|
|
821
1647
|
for (const line of lines) {
|
|
822
1648
|
yield* collectYieldableChunks(line, pendingToolCalls, usageRef, metadataRef, providerName);
|
|
823
1649
|
}
|
|
@@ -829,13 +1655,13 @@ var processStreamValue = (value, decoder, state) => {
|
|
|
829
1655
|
state.buffer = lines.pop() ?? "";
|
|
830
1656
|
return lines;
|
|
831
1657
|
};
|
|
832
|
-
var
|
|
1658
|
+
var drainReader2 = async function* (reader, decoder, state, signal) {
|
|
833
1659
|
for (let result = await reader.read();!result.done && !signal?.aborted; result = await reader.read()) {
|
|
834
1660
|
const lines = processStreamValue(result.value, decoder, state);
|
|
835
|
-
yield*
|
|
1661
|
+
yield* processSSELines2(lines, state.pendingToolCalls, state.usageRef, state.metadataRef, state.providerName);
|
|
836
1662
|
}
|
|
837
1663
|
};
|
|
838
|
-
var
|
|
1664
|
+
var parseSSEStream2 = async function* (body, initialMetadata, providerName = "openai", signal) {
|
|
839
1665
|
const reader = body.getReader();
|
|
840
1666
|
const decoder = new TextDecoder;
|
|
841
1667
|
const state = {
|
|
@@ -846,7 +1672,7 @@ var parseSSEStream = async function* (body, initialMetadata, providerName = "ope
|
|
|
846
1672
|
usageRef: { current: undefined }
|
|
847
1673
|
};
|
|
848
1674
|
try {
|
|
849
|
-
yield*
|
|
1675
|
+
yield* drainReader2(reader, decoder, state, signal);
|
|
850
1676
|
yield {
|
|
851
1677
|
metadata: state.metadataRef.current,
|
|
852
1678
|
type: "done",
|
|
@@ -862,7 +1688,7 @@ var fetchOpenAIStream = async function* (baseUrl, apiKey, body, fetchImpl, heade
|
|
|
862
1688
|
requestHeaders.set("Authorization", `Bearer ${apiKey}`);
|
|
863
1689
|
requestHeaders.set("Content-Type", "application/json");
|
|
864
1690
|
const response = await fetchImpl(target, {
|
|
865
|
-
...
|
|
1691
|
+
...h2IfHttps2(target),
|
|
866
1692
|
body: JSON.stringify(body),
|
|
867
1693
|
headers: requestHeaders,
|
|
868
1694
|
method: "POST",
|
|
@@ -879,7 +1705,7 @@ var fetchOpenAIStream = async function* (baseUrl, apiKey, body, fetchImpl, heade
|
|
|
879
1705
|
retryable: true
|
|
880
1706
|
});
|
|
881
1707
|
}
|
|
882
|
-
yield*
|
|
1708
|
+
yield* parseSSEStream2(response.body, {
|
|
883
1709
|
generationId: response.headers.get("X-Generation-Id") ?? undefined,
|
|
884
1710
|
providerMetadata: {
|
|
885
1711
|
cacheAge: response.headers.get("X-OpenRouter-Cache-Age") ?? undefined,
|
|
@@ -890,7 +1716,7 @@ var fetchOpenAIStream = async function* (baseUrl, apiKey, body, fetchImpl, heade
|
|
|
890
1716
|
}, providerName, signal);
|
|
891
1717
|
};
|
|
892
1718
|
var openai = (config2) => {
|
|
893
|
-
const baseUrl = config2.baseUrl ??
|
|
1719
|
+
const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL2;
|
|
894
1720
|
const fetchImpl = config2.fetch ?? globalThis.fetch;
|
|
895
1721
|
const providerName = config2.providerName ?? "openai";
|
|
896
1722
|
if (!config2.apiKey && !config2.tokenSource) {
|
|
@@ -904,6 +1730,14 @@ var openai = (config2) => {
|
|
|
904
1730
|
};
|
|
905
1731
|
const resolveHeaders = async (params) => typeof config2.headers === "function" ? await config2.headers(params) : config2.headers ?? {};
|
|
906
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
|
+
}),
|
|
907
1741
|
stream: (params) => {
|
|
908
1742
|
const openaiBody = buildRequestBody(params, config2.modelForCapabilities?.(params.model) ?? params.model);
|
|
909
1743
|
const body = config2.transformRequestBody ? config2.transformRequestBody(openaiBody, params) : openaiBody;
|
|
@@ -953,15 +1787,15 @@ var xai = (config2) => openaiCompatible({
|
|
|
953
1787
|
baseUrl: "https://api.x.ai"
|
|
954
1788
|
});
|
|
955
1789
|
export {
|
|
956
|
-
|
|
957
|
-
openaiCompatible,
|
|
958
|
-
moonshot,
|
|
959
|
-
mistralai,
|
|
960
|
-
meta,
|
|
961
|
-
google,
|
|
1790
|
+
alibaba,
|
|
962
1791
|
deepseek,
|
|
963
|
-
|
|
1792
|
+
google,
|
|
1793
|
+
meta,
|
|
1794
|
+
mistralai,
|
|
1795
|
+
moonshot,
|
|
1796
|
+
openaiCompatible,
|
|
1797
|
+
xai
|
|
964
1798
|
};
|
|
965
1799
|
|
|
966
|
-
//# debugId=
|
|
1800
|
+
//# debugId=A004F0C533D3621464756E2164756E21
|
|
967
1801
|
//# sourceMappingURL=openaiCompatible.js.map
|