@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);
|
|
@@ -496,7 +778,7 @@ var buildTools = (tools, isImageModel) => {
|
|
|
496
778
|
}
|
|
497
779
|
return result.length > 0 ? result : undefined;
|
|
498
780
|
};
|
|
499
|
-
var
|
|
781
|
+
var buildResponsesRequestBody = (params, isImageModel, capabilityModel = params.model) => {
|
|
500
782
|
const body = {
|
|
501
783
|
input: buildInput(params.messages),
|
|
502
784
|
model: params.model,
|
|
@@ -906,9 +1188,20 @@ var openaiResponses = (config2) => {
|
|
|
906
1188
|
const resolveKey = async () => config2.tokenSource ? await Promise.resolve(config2.tokenSource()) : config2.apiKey;
|
|
907
1189
|
const resolveHeaders = async (params) => typeof config2.headers === "function" ? await config2.headers(params) : config2.headers ?? {};
|
|
908
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
|
+
}),
|
|
909
1202
|
stream: (params) => {
|
|
910
1203
|
const isImageModel = imageModels.has(params.model);
|
|
911
|
-
const builtBody =
|
|
1204
|
+
const builtBody = buildResponsesRequestBody(params, isImageModel, config2.modelForCapabilities?.(params.model) ?? params.model);
|
|
912
1205
|
const body = config2.transformRequestBody ? config2.transformRequestBody(builtBody, params) : builtBody;
|
|
913
1206
|
return async function* () {
|
|
914
1207
|
const [apiKey, headers] = await Promise.all([
|
|
@@ -921,8 +1214,9 @@ var openaiResponses = (config2) => {
|
|
|
921
1214
|
}, providerName);
|
|
922
1215
|
};
|
|
923
1216
|
export {
|
|
1217
|
+
buildResponsesRequestBody,
|
|
924
1218
|
openaiResponses
|
|
925
1219
|
};
|
|
926
1220
|
|
|
927
|
-
//# debugId=
|
|
1221
|
+
//# debugId=CDF72AC7A40CBC7664756E2164756E21
|
|
928
1222
|
//# sourceMappingURL=openaiResponses.js.map
|