@agentskit/adapters 0.12.2 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/catalog/index.cjs +153746 -0
- package/dist/catalog/index.cjs.map +1 -0
- package/dist/catalog/index.d.cts +205 -0
- package/dist/catalog/index.d.ts +205 -0
- package/dist/catalog/index.js +153479 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/chunk-6FPLWOVE.js +26 -0
- package/dist/chunk-6FPLWOVE.js.map +1 -0
- package/dist/chunk-77QS3QRT.js +487 -0
- package/dist/chunk-77QS3QRT.js.map +1 -0
- package/dist/createAdapter-Dfnf3Iio.d.cts +14 -0
- package/dist/createAdapter-Dfnf3Iio.d.ts +14 -0
- package/dist/createAdapter.cjs +28 -0
- package/dist/createAdapter.cjs.map +1 -0
- package/dist/createAdapter.d.cts +2 -0
- package/dist/createAdapter.d.ts +2 -0
- package/dist/createAdapter.js +3 -0
- package/dist/createAdapter.js.map +1 -0
- package/dist/index.cjs +235 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +202 -77
- package/dist/index.d.ts +202 -77
- package/dist/index.js +214 -538
- package/dist/index.js.map +1 -1
- package/dist/utils-ddwu4MN4.d.cts +66 -0
- package/dist/utils-ddwu4MN4.d.ts +66 -0
- package/package.json +20 -7
package/dist/index.js
CHANGED
|
@@ -1,28 +1,8 @@
|
|
|
1
|
+
export { createAdapter } from './chunk-6FPLWOVE.js';
|
|
2
|
+
import { createStreamSource, parseAnthropicStream, parseGeminiStream, parseOllamaStream, toProviderMessages, parseOpenAIStream, openai } from './chunk-77QS3QRT.js';
|
|
3
|
+
export { chunkText, fetchWithRetry, openai, simulateStream } from './chunk-77QS3QRT.js';
|
|
1
4
|
import { ConfigError, ErrorCodes, AdapterError } from '@agentskit/core';
|
|
2
5
|
|
|
3
|
-
// src/createAdapter.ts
|
|
4
|
-
function createAdapter(config) {
|
|
5
|
-
return {
|
|
6
|
-
createSource: (request) => ({
|
|
7
|
-
stream: async function* () {
|
|
8
|
-
try {
|
|
9
|
-
const result = await config.send(request);
|
|
10
|
-
const stream = result instanceof Response ? result.body : result;
|
|
11
|
-
yield* config.parse(stream);
|
|
12
|
-
} catch (err) {
|
|
13
|
-
yield {
|
|
14
|
-
type: "error",
|
|
15
|
-
content: err instanceof Error ? err.message : String(err)
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
abort: () => {
|
|
20
|
-
config.abort?.();
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
6
|
// src/generic.ts
|
|
27
7
|
function generic(config) {
|
|
28
8
|
return {
|
|
@@ -58,429 +38,6 @@ function generic(config) {
|
|
|
58
38
|
};
|
|
59
39
|
}
|
|
60
40
|
|
|
61
|
-
// src/utils.ts
|
|
62
|
-
function toProviderMessages(messages) {
|
|
63
|
-
const knownToolCallIds = /* @__PURE__ */ new Set();
|
|
64
|
-
const output = [];
|
|
65
|
-
for (const message of messages) {
|
|
66
|
-
if (message.role === "tool") {
|
|
67
|
-
const id = message.toolCallId;
|
|
68
|
-
if (!id || !knownToolCallIds.has(id)) continue;
|
|
69
|
-
output.push({
|
|
70
|
-
role: "tool",
|
|
71
|
-
content: message.content,
|
|
72
|
-
tool_call_id: id
|
|
73
|
-
});
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
if (message.role === "assistant" && message.toolCalls && message.toolCalls.length > 0) {
|
|
77
|
-
for (const tc of message.toolCalls) knownToolCallIds.add(tc.id);
|
|
78
|
-
output.push({
|
|
79
|
-
role: "assistant",
|
|
80
|
-
content: message.content || null,
|
|
81
|
-
tool_calls: message.toolCalls.map((tc) => ({
|
|
82
|
-
id: tc.id,
|
|
83
|
-
type: "function",
|
|
84
|
-
function: {
|
|
85
|
-
name: tc.name,
|
|
86
|
-
arguments: typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args ?? {})
|
|
87
|
-
}
|
|
88
|
-
}))
|
|
89
|
-
});
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
if (message.role === "assistant" && !message.content) continue;
|
|
93
|
-
output.push({ role: message.role, content: message.content });
|
|
94
|
-
}
|
|
95
|
-
return output;
|
|
96
|
-
}
|
|
97
|
-
async function* readSSELines(stream) {
|
|
98
|
-
const reader = stream.getReader();
|
|
99
|
-
const decoder = new TextDecoder();
|
|
100
|
-
let buffer = "";
|
|
101
|
-
try {
|
|
102
|
-
while (true) {
|
|
103
|
-
const { done, value } = await reader.read();
|
|
104
|
-
if (done) break;
|
|
105
|
-
buffer += decoder.decode(value, { stream: true });
|
|
106
|
-
const lines = buffer.split("\n");
|
|
107
|
-
buffer = lines.pop() ?? "";
|
|
108
|
-
for (const line of lines) {
|
|
109
|
-
if (!line.startsWith("data: ")) continue;
|
|
110
|
-
const data = line.slice(6).trim();
|
|
111
|
-
if (data) yield data;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
} finally {
|
|
115
|
-
reader.releaseLock();
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
async function* readNDJSONLines(stream) {
|
|
119
|
-
const reader = stream.getReader();
|
|
120
|
-
const decoder = new TextDecoder();
|
|
121
|
-
let buffer = "";
|
|
122
|
-
try {
|
|
123
|
-
while (true) {
|
|
124
|
-
const { done, value } = await reader.read();
|
|
125
|
-
if (done) break;
|
|
126
|
-
buffer += decoder.decode(value, { stream: true });
|
|
127
|
-
const lines = buffer.split("\n");
|
|
128
|
-
buffer = lines.pop() ?? "";
|
|
129
|
-
for (const line of lines) {
|
|
130
|
-
const trimmed = line.trim();
|
|
131
|
-
if (trimmed) yield trimmed;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
} finally {
|
|
135
|
-
reader.releaseLock();
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
async function* parseOpenAIStream(stream) {
|
|
139
|
-
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
140
|
-
for await (const data of readSSELines(stream)) {
|
|
141
|
-
if (data === "[DONE]") {
|
|
142
|
-
for (const [, tc] of pendingToolCalls) {
|
|
143
|
-
yield { type: "tool_call", toolCall: { id: tc.id, name: tc.name, args: tc.args || "{}" } };
|
|
144
|
-
}
|
|
145
|
-
pendingToolCalls.clear();
|
|
146
|
-
yield { type: "done" };
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
try {
|
|
150
|
-
const event = JSON.parse(data);
|
|
151
|
-
const delta = event.choices?.[0]?.delta;
|
|
152
|
-
if (typeof delta?.content === "string") {
|
|
153
|
-
yield { type: "text", content: delta.content };
|
|
154
|
-
}
|
|
155
|
-
if (Array.isArray(delta?.tool_calls)) {
|
|
156
|
-
for (const toolCall of delta.tool_calls) {
|
|
157
|
-
const index = toolCall.index ?? 0;
|
|
158
|
-
const existing = pendingToolCalls.get(index);
|
|
159
|
-
if (toolCall?.function?.name) {
|
|
160
|
-
pendingToolCalls.set(index, {
|
|
161
|
-
id: toolCall.id ?? existing?.id ?? `tool-${index}-${Date.now()}`,
|
|
162
|
-
name: toolCall.function.name,
|
|
163
|
-
args: (existing?.args ?? "") + (toolCall.function.arguments ?? "")
|
|
164
|
-
});
|
|
165
|
-
} else if (existing && toolCall?.function?.arguments) {
|
|
166
|
-
existing.args += toolCall.function.arguments;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
if (event.usage) {
|
|
171
|
-
yield {
|
|
172
|
-
type: "usage",
|
|
173
|
-
usage: {
|
|
174
|
-
promptTokens: event.usage.prompt_tokens ?? 0,
|
|
175
|
-
completionTokens: event.usage.completion_tokens ?? 0,
|
|
176
|
-
totalTokens: event.usage.total_tokens ?? 0
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
} catch {
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
for (const [, tc] of pendingToolCalls) {
|
|
184
|
-
yield { type: "tool_call", toolCall: { id: tc.id, name: tc.name, args: tc.args || "{}" } };
|
|
185
|
-
}
|
|
186
|
-
pendingToolCalls.clear();
|
|
187
|
-
yield { type: "done" };
|
|
188
|
-
}
|
|
189
|
-
async function* parseAnthropicStream(stream) {
|
|
190
|
-
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
191
|
-
for await (const data of readSSELines(stream)) {
|
|
192
|
-
if (data === "[DONE]") continue;
|
|
193
|
-
try {
|
|
194
|
-
const event = JSON.parse(data);
|
|
195
|
-
if (event.type === "content_block_delta" && event.delta?.type === "text_delta" && event.delta?.text) {
|
|
196
|
-
yield { type: "text", content: event.delta.text };
|
|
197
|
-
} else if (event.type === "content_block_delta" && event.delta?.type === "input_json_delta") {
|
|
198
|
-
const index = event.index ?? 0;
|
|
199
|
-
const existing = pendingToolCalls.get(index);
|
|
200
|
-
if (existing) {
|
|
201
|
-
existing.args += event.delta.partial_json ?? "";
|
|
202
|
-
}
|
|
203
|
-
} else if (event.type === "content_block_start" && event.content_block?.type === "tool_use") {
|
|
204
|
-
const index = event.index ?? 0;
|
|
205
|
-
pendingToolCalls.set(index, {
|
|
206
|
-
id: event.content_block.id,
|
|
207
|
-
name: event.content_block.name,
|
|
208
|
-
args: ""
|
|
209
|
-
});
|
|
210
|
-
} else if (event.type === "content_block_stop") {
|
|
211
|
-
const index = event.index ?? 0;
|
|
212
|
-
const tc = pendingToolCalls.get(index);
|
|
213
|
-
if (tc) {
|
|
214
|
-
yield {
|
|
215
|
-
type: "tool_call",
|
|
216
|
-
toolCall: {
|
|
217
|
-
id: tc.id,
|
|
218
|
-
name: tc.name,
|
|
219
|
-
args: tc.args || "{}"
|
|
220
|
-
}
|
|
221
|
-
};
|
|
222
|
-
pendingToolCalls.delete(index);
|
|
223
|
-
}
|
|
224
|
-
} else if (event.type === "message_delta" && event.usage) {
|
|
225
|
-
yield {
|
|
226
|
-
type: "usage",
|
|
227
|
-
usage: {
|
|
228
|
-
promptTokens: event.usage.input_tokens ?? 0,
|
|
229
|
-
completionTokens: event.usage.output_tokens ?? 0,
|
|
230
|
-
totalTokens: (event.usage.input_tokens ?? 0) + (event.usage.output_tokens ?? 0)
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
} else if (event.type === "message_start" && event.message?.usage) {
|
|
234
|
-
yield {
|
|
235
|
-
type: "usage",
|
|
236
|
-
usage: {
|
|
237
|
-
promptTokens: event.message.usage.input_tokens ?? 0,
|
|
238
|
-
completionTokens: 0,
|
|
239
|
-
totalTokens: event.message.usage.input_tokens ?? 0
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
} else if (event.type === "message_stop") {
|
|
243
|
-
for (const [, tc] of pendingToolCalls) {
|
|
244
|
-
yield { type: "tool_call", toolCall: { id: tc.id, name: tc.name, args: tc.args || "{}" } };
|
|
245
|
-
}
|
|
246
|
-
pendingToolCalls.clear();
|
|
247
|
-
yield { type: "done" };
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
} catch {
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
for (const [, tc] of pendingToolCalls) {
|
|
254
|
-
yield { type: "tool_call", toolCall: { id: tc.id, name: tc.name, args: tc.args || "{}" } };
|
|
255
|
-
}
|
|
256
|
-
pendingToolCalls.clear();
|
|
257
|
-
yield { type: "done" };
|
|
258
|
-
}
|
|
259
|
-
async function* parseGeminiStream(stream) {
|
|
260
|
-
for await (const data of readSSELines(stream)) {
|
|
261
|
-
try {
|
|
262
|
-
const event = JSON.parse(data);
|
|
263
|
-
if (event.usageMetadata) {
|
|
264
|
-
yield {
|
|
265
|
-
type: "usage",
|
|
266
|
-
usage: {
|
|
267
|
-
promptTokens: event.usageMetadata.promptTokenCount ?? 0,
|
|
268
|
-
completionTokens: event.usageMetadata.candidatesTokenCount ?? 0,
|
|
269
|
-
totalTokens: event.usageMetadata.totalTokenCount ?? 0
|
|
270
|
-
}
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
const parts = event.candidates?.[0]?.content?.parts;
|
|
274
|
-
if (!Array.isArray(parts)) continue;
|
|
275
|
-
for (const part of parts) {
|
|
276
|
-
if (typeof part.text === "string" && part.text) {
|
|
277
|
-
yield { type: "text", content: part.text };
|
|
278
|
-
} else if (part.functionCall) {
|
|
279
|
-
const fc = part.functionCall;
|
|
280
|
-
yield {
|
|
281
|
-
type: "tool_call",
|
|
282
|
-
toolCall: {
|
|
283
|
-
id: fc.id ?? `${fc.name}-${Date.now()}`,
|
|
284
|
-
name: fc.name,
|
|
285
|
-
args: JSON.stringify(fc.args ?? {})
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
} catch {
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
yield { type: "done" };
|
|
294
|
-
}
|
|
295
|
-
async function* parseOllamaStream(stream) {
|
|
296
|
-
for await (const data of readNDJSONLines(stream)) {
|
|
297
|
-
try {
|
|
298
|
-
const event = JSON.parse(data);
|
|
299
|
-
if (event.message?.content) {
|
|
300
|
-
yield { type: "text", content: event.message.content };
|
|
301
|
-
}
|
|
302
|
-
if (Array.isArray(event.message?.tool_calls)) {
|
|
303
|
-
for (const tc of event.message.tool_calls) {
|
|
304
|
-
if (tc?.function?.name) {
|
|
305
|
-
yield {
|
|
306
|
-
type: "tool_call",
|
|
307
|
-
toolCall: {
|
|
308
|
-
id: tc.id ?? `${tc.function.name}-${Date.now()}`,
|
|
309
|
-
name: tc.function.name,
|
|
310
|
-
args: typeof tc.function.arguments === "string" ? tc.function.arguments : JSON.stringify(tc.function.arguments ?? {})
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
if (event.done) {
|
|
317
|
-
if (typeof event.prompt_eval_count === "number" || typeof event.eval_count === "number") {
|
|
318
|
-
const promptTokens = event.prompt_eval_count ?? 0;
|
|
319
|
-
const completionTokens = event.eval_count ?? 0;
|
|
320
|
-
yield {
|
|
321
|
-
type: "usage",
|
|
322
|
-
usage: {
|
|
323
|
-
promptTokens,
|
|
324
|
-
completionTokens,
|
|
325
|
-
totalTokens: promptTokens + completionTokens
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
yield { type: "done" };
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
} catch {
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
yield { type: "done" };
|
|
336
|
-
}
|
|
337
|
-
var DEFAULT_RETRY = {
|
|
338
|
-
maxAttempts: 3,
|
|
339
|
-
baseDelayMs: 500,
|
|
340
|
-
maxDelayMs: 8e3,
|
|
341
|
-
jitter: true,
|
|
342
|
-
retryOn: ({ error, response }) => {
|
|
343
|
-
if (response) {
|
|
344
|
-
return [408, 429, 500, 502, 503, 504].includes(response.status);
|
|
345
|
-
}
|
|
346
|
-
if (error instanceof DOMException && error.name === "AbortError") return false;
|
|
347
|
-
return true;
|
|
348
|
-
}
|
|
349
|
-
};
|
|
350
|
-
function defaultSleep(ms) {
|
|
351
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
352
|
-
}
|
|
353
|
-
function computeDelay(attempt, opts) {
|
|
354
|
-
const exp = Math.min(opts.maxDelayMs, opts.baseDelayMs * Math.pow(2, attempt - 1));
|
|
355
|
-
if (!opts.jitter) return exp;
|
|
356
|
-
return Math.floor(Math.random() * exp);
|
|
357
|
-
}
|
|
358
|
-
function parseRetryAfter(value) {
|
|
359
|
-
if (!value) return void 0;
|
|
360
|
-
const n = Number(value);
|
|
361
|
-
if (!Number.isNaN(n)) return n * 1e3;
|
|
362
|
-
const date = Date.parse(value);
|
|
363
|
-
if (!Number.isNaN(date)) return Math.max(0, date - Date.now());
|
|
364
|
-
return void 0;
|
|
365
|
-
}
|
|
366
|
-
async function fetchWithRetry(doFetch, signal, retryOpt = {}) {
|
|
367
|
-
const opts = {
|
|
368
|
-
...DEFAULT_RETRY,
|
|
369
|
-
...retryOpt
|
|
370
|
-
};
|
|
371
|
-
const sleep = retryOpt.sleep ?? defaultSleep;
|
|
372
|
-
let lastError;
|
|
373
|
-
for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {
|
|
374
|
-
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
375
|
-
try {
|
|
376
|
-
const response = await doFetch(signal);
|
|
377
|
-
if (response.ok) return response;
|
|
378
|
-
if (attempt >= opts.maxAttempts || !opts.retryOn({ response, attempt })) {
|
|
379
|
-
return response;
|
|
380
|
-
}
|
|
381
|
-
const retryAfterMs = parseRetryAfter(response.headers.get("retry-after"));
|
|
382
|
-
const delay = retryAfterMs ?? computeDelay(attempt, opts);
|
|
383
|
-
retryOpt.onRetry?.({ attempt, delayMs: delay, reason: `HTTP ${response.status}` });
|
|
384
|
-
await sleep(delay);
|
|
385
|
-
response.body?.cancel().catch(() => {
|
|
386
|
-
});
|
|
387
|
-
} catch (err) {
|
|
388
|
-
lastError = err;
|
|
389
|
-
if (err instanceof DOMException && err.name === "AbortError") throw err;
|
|
390
|
-
if (attempt >= opts.maxAttempts || !opts.retryOn({ error: err, attempt })) throw err;
|
|
391
|
-
const delay = computeDelay(attempt, opts);
|
|
392
|
-
retryOpt.onRetry?.({ attempt, delayMs: delay, reason: err.message });
|
|
393
|
-
await sleep(delay);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
throw lastError ?? new Error("fetchWithRetry: exhausted attempts");
|
|
397
|
-
}
|
|
398
|
-
function createStreamSource(doFetch, parse, errorLabel, retry) {
|
|
399
|
-
let abortController = new AbortController();
|
|
400
|
-
return {
|
|
401
|
-
stream: async function* () {
|
|
402
|
-
try {
|
|
403
|
-
const response = await fetchWithRetry(doFetch, abortController.signal, retry ?? {});
|
|
404
|
-
if (!response.ok || !response.body) {
|
|
405
|
-
yield { type: "error", content: `${errorLabel} error: ${response.status}` };
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
yield* parse(response.body);
|
|
409
|
-
} catch (err) {
|
|
410
|
-
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
411
|
-
yield {
|
|
412
|
-
type: "error",
|
|
413
|
-
content: err instanceof Error ? err.message : String(err)
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
},
|
|
417
|
-
abort: () => {
|
|
418
|
-
abortController?.abort();
|
|
419
|
-
abortController = null;
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
function chunkText(text, targetSize = 32) {
|
|
424
|
-
if (text.length <= targetSize) return [text];
|
|
425
|
-
const out = [];
|
|
426
|
-
let i = 0;
|
|
427
|
-
while (i < text.length) {
|
|
428
|
-
let end = Math.min(text.length, i + targetSize);
|
|
429
|
-
if (end < text.length) {
|
|
430
|
-
const nextSpace = text.indexOf(" ", end);
|
|
431
|
-
if (nextSpace !== -1 && nextSpace - end <= 8) end = nextSpace + 1;
|
|
432
|
-
}
|
|
433
|
-
out.push(text.slice(i, end));
|
|
434
|
-
i = end;
|
|
435
|
-
}
|
|
436
|
-
return out;
|
|
437
|
-
}
|
|
438
|
-
function simulateStream(doFetch, extractText, errorLabel, options = {}) {
|
|
439
|
-
const { chunkSize = 32, delayMs = 8, retry } = options;
|
|
440
|
-
let abortController = new AbortController();
|
|
441
|
-
return {
|
|
442
|
-
stream: async function* () {
|
|
443
|
-
try {
|
|
444
|
-
const response = await fetchWithRetry(doFetch, abortController.signal, retry ?? {});
|
|
445
|
-
if (!response.ok) {
|
|
446
|
-
yield { type: "error", content: `${errorLabel} error: ${response.status}` };
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
449
|
-
const text = await extractText(response);
|
|
450
|
-
const chunks = chunkText(text, chunkSize);
|
|
451
|
-
for (const chunk of chunks) {
|
|
452
|
-
if (abortController === null) return;
|
|
453
|
-
if (delayMs > 0) {
|
|
454
|
-
await new Promise((resolve2, reject) => {
|
|
455
|
-
const timer = setTimeout(resolve2, delayMs);
|
|
456
|
-
abortController?.signal.addEventListener(
|
|
457
|
-
"abort",
|
|
458
|
-
() => {
|
|
459
|
-
clearTimeout(timer);
|
|
460
|
-
reject(new DOMException("Aborted", "AbortError"));
|
|
461
|
-
},
|
|
462
|
-
{ once: true }
|
|
463
|
-
);
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
yield { type: "text", content: chunk };
|
|
467
|
-
}
|
|
468
|
-
yield { type: "done" };
|
|
469
|
-
} catch (err) {
|
|
470
|
-
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
471
|
-
yield {
|
|
472
|
-
type: "error",
|
|
473
|
-
content: err instanceof Error ? err.message : String(err)
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
},
|
|
477
|
-
abort: () => {
|
|
478
|
-
abortController?.abort();
|
|
479
|
-
abortController = null;
|
|
480
|
-
}
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
|
|
484
41
|
// src/anthropic.ts
|
|
485
42
|
function anthropic(config) {
|
|
486
43
|
const { apiKey, model, baseUrl = "https://api.anthropic.com", maxTokens = 4096, retry } = config;
|
|
@@ -524,55 +81,6 @@ function anthropic(config) {
|
|
|
524
81
|
};
|
|
525
82
|
}
|
|
526
83
|
|
|
527
|
-
// src/openai.ts
|
|
528
|
-
function openai(config) {
|
|
529
|
-
const { apiKey, model, baseUrl = "https://api.openai.com", retry } = config;
|
|
530
|
-
const includeUsage = config.includeUsage ?? baseUrl.startsWith("https://api.openai.com");
|
|
531
|
-
return {
|
|
532
|
-
capabilities: {
|
|
533
|
-
streaming: true,
|
|
534
|
-
tools: true,
|
|
535
|
-
// o1 / o3 models emit reasoning; older models don't. Accurate per-model
|
|
536
|
-
// detection would need a model registry; 'true' is the safer default here.
|
|
537
|
-
reasoning: model.startsWith("o1") || model.startsWith("o3"),
|
|
538
|
-
multiModal: model.startsWith("gpt-4") || model.startsWith("o"),
|
|
539
|
-
usage: true
|
|
540
|
-
},
|
|
541
|
-
createSource: (request) => {
|
|
542
|
-
const body = {
|
|
543
|
-
model,
|
|
544
|
-
messages: toProviderMessages(request.messages),
|
|
545
|
-
tools: request.context?.tools?.map((tool) => ({
|
|
546
|
-
type: "function",
|
|
547
|
-
function: {
|
|
548
|
-
name: tool.name,
|
|
549
|
-
description: tool.description,
|
|
550
|
-
parameters: tool.schema
|
|
551
|
-
}
|
|
552
|
-
})),
|
|
553
|
-
temperature: request.context?.temperature,
|
|
554
|
-
max_tokens: request.context?.maxTokens,
|
|
555
|
-
stream: true
|
|
556
|
-
};
|
|
557
|
-
if (includeUsage) body.stream_options = { include_usage: true };
|
|
558
|
-
return createStreamSource(
|
|
559
|
-
(signal) => fetch(`${baseUrl}/v1/chat/completions`, {
|
|
560
|
-
method: "POST",
|
|
561
|
-
headers: {
|
|
562
|
-
"Content-Type": "application/json",
|
|
563
|
-
"Authorization": `Bearer ${apiKey}`
|
|
564
|
-
},
|
|
565
|
-
body: JSON.stringify(body),
|
|
566
|
-
signal
|
|
567
|
-
}),
|
|
568
|
-
parseOpenAIStream,
|
|
569
|
-
"OpenAI API",
|
|
570
|
-
retry
|
|
571
|
-
);
|
|
572
|
-
}
|
|
573
|
-
};
|
|
574
|
-
}
|
|
575
|
-
|
|
576
84
|
// src/gemini.ts
|
|
577
85
|
function gemini(config) {
|
|
578
86
|
const { apiKey, model, baseUrl = "https://generativelanguage.googleapis.com", retry } = config;
|
|
@@ -584,15 +92,13 @@ function gemini(config) {
|
|
|
584
92
|
usage: true
|
|
585
93
|
},
|
|
586
94
|
createSource: (request) => {
|
|
95
|
+
const systemMessage = request.messages.find((message) => message.role === "system");
|
|
587
96
|
const body = {
|
|
588
97
|
contents: request.messages.filter((message) => message.role !== "system").map((message) => ({
|
|
589
98
|
role: message.role === "assistant" ? "model" : "user",
|
|
590
99
|
parts: [{ text: message.content }]
|
|
591
100
|
})),
|
|
592
|
-
systemInstruction:
|
|
593
|
-
role: "system",
|
|
594
|
-
parts: [{ text: request.messages.find((message) => message.role === "system").content }]
|
|
595
|
-
} : void 0
|
|
101
|
+
systemInstruction: systemMessage ? { role: "system", parts: [{ text: systemMessage.content }] } : void 0
|
|
596
102
|
};
|
|
597
103
|
return createStreamSource(
|
|
598
104
|
(signal) => fetch(
|
|
@@ -1058,15 +564,13 @@ function vertex(config) {
|
|
|
1058
564
|
reasoning: model.includes("pro")
|
|
1059
565
|
},
|
|
1060
566
|
createSource: (request) => {
|
|
567
|
+
const systemMessage = request.messages.find((message) => message.role === "system");
|
|
1061
568
|
const body = {
|
|
1062
569
|
contents: request.messages.filter((message) => message.role !== "system").map((message) => ({
|
|
1063
570
|
role: message.role === "assistant" ? "model" : "user",
|
|
1064
571
|
parts: [{ text: message.content }]
|
|
1065
572
|
})),
|
|
1066
|
-
systemInstruction:
|
|
1067
|
-
role: "system",
|
|
1068
|
-
parts: [{ text: request.messages.find((message) => message.role === "system").content }]
|
|
1069
|
-
} : void 0,
|
|
573
|
+
systemInstruction: systemMessage ? { role: "system", parts: [{ text: systemMessage.content }] } : void 0,
|
|
1070
574
|
tools: request.context?.tools && request.context.tools.length > 0 ? [{
|
|
1071
575
|
functionDeclarations: request.context.tools.map((tool) => ({
|
|
1072
576
|
name: tool.name,
|
|
@@ -1362,8 +866,28 @@ function pickSyncPolicy(pool, policy) {
|
|
|
1362
866
|
const c = pool.reduce((best, x) => (x.latencyMs ?? Infinity) < (best.latencyMs ?? Infinity) ? x : best, pool[0]);
|
|
1363
867
|
return { c, reason: "fastest" };
|
|
1364
868
|
}
|
|
869
|
+
if (policy === "greenest") {
|
|
870
|
+
const c = pool.reduce((best, x) => (x.gCO2PerKtok ?? Infinity) < (best.gCO2PerKtok ?? Infinity) ? x : best, pool[0]);
|
|
871
|
+
return { c, reason: "greenest" };
|
|
872
|
+
}
|
|
873
|
+
if (policy === "green-cost") {
|
|
874
|
+
const carbonValues = pool.map((p) => p.gCO2PerKtok).filter((v) => v != null);
|
|
875
|
+
const costValues = pool.map((p) => p.cost).filter((v) => v != null);
|
|
876
|
+
const maxC = Math.max(1, ...carbonValues);
|
|
877
|
+
const maxCost = Math.max(1, ...costValues);
|
|
878
|
+
const score = (x) => {
|
|
879
|
+
const carbon = (x.gCO2PerKtok ?? maxC / 2) / maxC;
|
|
880
|
+
const cost = (x.cost ?? maxCost / 2) / maxCost;
|
|
881
|
+
return carbon + cost;
|
|
882
|
+
};
|
|
883
|
+
const c = pool.reduce((best, x) => score(x) < score(best) ? x : best, pool[0]);
|
|
884
|
+
return { c, reason: "green-cost" };
|
|
885
|
+
}
|
|
1365
886
|
return { c: pool[0], reason: "capability-match" };
|
|
1366
887
|
}
|
|
888
|
+
function matchesRegion(candidate, region) {
|
|
889
|
+
return region === void 0 || candidate.region === region;
|
|
890
|
+
}
|
|
1367
891
|
function createRouter(options) {
|
|
1368
892
|
const { candidates } = options;
|
|
1369
893
|
if (candidates.length === 0) {
|
|
@@ -1377,22 +901,31 @@ function createRouter(options) {
|
|
|
1377
901
|
return {
|
|
1378
902
|
createSource: (request) => {
|
|
1379
903
|
const need = requireCapabilities(request);
|
|
904
|
+
const region = options.regionOf?.(request) ?? options.region;
|
|
1380
905
|
const capable = candidates.filter((c2) => matchesCapabilities(need, c2.capabilities ?? c2.adapter.capabilities));
|
|
906
|
+
const eligible = capable.filter((c2) => matchesRegion(c2, region));
|
|
907
|
+
if (capable.length > 0 && eligible.length === 0 && region !== void 0) {
|
|
908
|
+
throw new ConfigError({
|
|
909
|
+
code: ErrorCodes.AK_CONFIG_INVALID,
|
|
910
|
+
message: `no candidate satisfies required region: ${region}`,
|
|
911
|
+
hint: "Set candidate.region to the requested data-residency region, or remove the router region requirement."
|
|
912
|
+
});
|
|
913
|
+
}
|
|
1381
914
|
const classified = options.classify?.(request);
|
|
1382
915
|
if (typeof classified === "string") {
|
|
1383
|
-
const c2 =
|
|
916
|
+
const c2 = eligible.find((x) => x.id === classified);
|
|
1384
917
|
if (c2) {
|
|
1385
|
-
options.onRoute?.({ id: c2.id, reason: "classify:id", request });
|
|
918
|
+
options.onRoute?.({ id: c2.id, reason: region ? `classify:id:${region}` : "classify:id", request });
|
|
1386
919
|
return c2.adapter.createSource(request);
|
|
1387
920
|
}
|
|
1388
921
|
}
|
|
1389
|
-
let pool =
|
|
922
|
+
let pool = eligible;
|
|
1390
923
|
let pickedBy;
|
|
1391
924
|
if (Array.isArray(classified) && classified.length > 0) {
|
|
1392
|
-
const filtered =
|
|
925
|
+
const filtered = eligible.filter((c2) => c2.tags && classified.every((t) => c2.tags.includes(t)));
|
|
1393
926
|
if (filtered.length > 0) {
|
|
1394
927
|
pool = filtered;
|
|
1395
|
-
pickedBy = "classify:tags";
|
|
928
|
+
pickedBy = region ? `classify:tags:${region}` : "classify:tags";
|
|
1396
929
|
}
|
|
1397
930
|
}
|
|
1398
931
|
if (pool.length === 0) {
|
|
@@ -1440,6 +973,57 @@ function createRouter(options) {
|
|
|
1440
973
|
}
|
|
1441
974
|
};
|
|
1442
975
|
}
|
|
976
|
+
|
|
977
|
+
// src/carbon.ts
|
|
978
|
+
var DEFAULT_CARBON_TABLE = {
|
|
979
|
+
// Anthropic — primarily AWS us-east-* / eu-west-* via Bedrock-style fronts.
|
|
980
|
+
"anthropic:us-east-1": 0.42,
|
|
981
|
+
"anthropic:us-west-2": 0.18,
|
|
982
|
+
"anthropic:eu-central-1": 0.32,
|
|
983
|
+
"anthropic:eu-west-1": 0.27,
|
|
984
|
+
// OpenAI — Azure East US / West Europe / Sweden Central.
|
|
985
|
+
"openai:eastus": 0.4,
|
|
986
|
+
"openai:westus3": 0.19,
|
|
987
|
+
"openai:swedencentral": 0.04,
|
|
988
|
+
"openai:westeurope": 0.28,
|
|
989
|
+
// Google (Vertex / Gemini) — typically reports lowest PUE.
|
|
990
|
+
"google:us-central1": 0.34,
|
|
991
|
+
"google:us-west1": 0.16,
|
|
992
|
+
"google:europe-west1": 0.21,
|
|
993
|
+
"google:europe-north1": 0.05,
|
|
994
|
+
// AWS Bedrock direct.
|
|
995
|
+
"aws:us-east-1": 0.42,
|
|
996
|
+
"aws:us-west-2": 0.18,
|
|
997
|
+
"aws:eu-west-1": 0.27,
|
|
998
|
+
// Local / on-device — only the device's grid matters.
|
|
999
|
+
"ollama:local": 0.3,
|
|
1000
|
+
"webllm:browser": 0.3,
|
|
1001
|
+
"lmstudio:local": 0.3,
|
|
1002
|
+
// Self-hosted / community.
|
|
1003
|
+
"groq:us-east-1": 0.4,
|
|
1004
|
+
"fireworks:us-west-2": 0.18,
|
|
1005
|
+
"together:us-east-1": 0.42,
|
|
1006
|
+
"cerebras:us-west-2": 0.18
|
|
1007
|
+
};
|
|
1008
|
+
function defaultKey(candidate) {
|
|
1009
|
+
if (!candidate.region) return void 0;
|
|
1010
|
+
const provider = candidate.id.split(/[-:]/)[0];
|
|
1011
|
+
return `${provider}:${candidate.region}`;
|
|
1012
|
+
}
|
|
1013
|
+
function applyCarbonTable(candidates, options = {}) {
|
|
1014
|
+
const table = options.table ?? DEFAULT_CARBON_TABLE;
|
|
1015
|
+
const keyFor = options.keyFor ?? defaultKey;
|
|
1016
|
+
return candidates.map((c) => {
|
|
1017
|
+
if (c.gCO2PerKtok != null) return c;
|
|
1018
|
+
const key = keyFor(c);
|
|
1019
|
+
const value = key ? table[key] : void 0;
|
|
1020
|
+
return { ...c, gCO2PerKtok: value ?? options.fallback };
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
function estimateCO2Grams(gCO2PerKtok, tokens) {
|
|
1024
|
+
if (gCO2PerKtok == null) return 0;
|
|
1025
|
+
return tokens / 1e3 * gCO2PerKtok;
|
|
1026
|
+
}
|
|
1443
1027
|
async function drain(source, timeoutMs) {
|
|
1444
1028
|
const chunks = [];
|
|
1445
1029
|
let text = "";
|
|
@@ -1578,26 +1162,36 @@ function createFallbackAdapter(candidates, options = {}) {
|
|
|
1578
1162
|
}
|
|
1579
1163
|
active = source;
|
|
1580
1164
|
const iter = source.stream()[Symbol.asyncIterator]();
|
|
1581
|
-
let
|
|
1165
|
+
let firstReal;
|
|
1166
|
+
let branchError;
|
|
1582
1167
|
try {
|
|
1583
|
-
|
|
1168
|
+
while (true) {
|
|
1169
|
+
const r = await iter.next();
|
|
1170
|
+
if (r.done) {
|
|
1171
|
+
branchError = new Error(`candidate ${candidate.id} emitted no chunks`);
|
|
1172
|
+
break;
|
|
1173
|
+
}
|
|
1174
|
+
if (r.value.type === "error") {
|
|
1175
|
+
branchError = new Error(
|
|
1176
|
+
`candidate ${candidate.id}: ${r.value.content ?? "stream error"}`
|
|
1177
|
+
);
|
|
1178
|
+
break;
|
|
1179
|
+
}
|
|
1180
|
+
firstReal = r.value;
|
|
1181
|
+
break;
|
|
1182
|
+
}
|
|
1584
1183
|
} catch (err) {
|
|
1585
|
-
|
|
1586
|
-
errors.push({ id: candidate.id, error });
|
|
1587
|
-
options.onFallback?.({ id: candidate.id, index: i, error });
|
|
1588
|
-
if (options.shouldRetry && !options.shouldRetry(error, i)) throw error;
|
|
1589
|
-
active = void 0;
|
|
1590
|
-
continue;
|
|
1184
|
+
branchError = err instanceof Error ? err : new Error(String(err));
|
|
1591
1185
|
}
|
|
1592
|
-
if (
|
|
1593
|
-
const error = new Error(`candidate ${candidate.id} emitted no chunks`);
|
|
1186
|
+
if (branchError || !firstReal) {
|
|
1187
|
+
const error = branchError ?? new Error(`candidate ${candidate.id} emitted no chunks`);
|
|
1594
1188
|
errors.push({ id: candidate.id, error });
|
|
1595
1189
|
options.onFallback?.({ id: candidate.id, index: i, error });
|
|
1596
1190
|
if (options.shouldRetry && !options.shouldRetry(error, i)) throw error;
|
|
1597
1191
|
active = void 0;
|
|
1598
1192
|
continue;
|
|
1599
1193
|
}
|
|
1600
|
-
yield
|
|
1194
|
+
yield firstReal;
|
|
1601
1195
|
while (true) {
|
|
1602
1196
|
const next = await iter.next();
|
|
1603
1197
|
if (next.done) return;
|
|
@@ -1710,16 +1304,23 @@ function replayAdapter(fixture) {
|
|
|
1710
1304
|
});
|
|
1711
1305
|
}
|
|
1712
1306
|
|
|
1307
|
+
// src/embedders/shared.ts
|
|
1308
|
+
var ERROR_BODY_PREVIEW_CHARS = 200;
|
|
1309
|
+
async function throwIfNotOk(response, label, url) {
|
|
1310
|
+
if (response.ok) return;
|
|
1311
|
+
const body = await response.text().catch(() => "");
|
|
1312
|
+
throw new Error(
|
|
1313
|
+
`HTTP ${response.status} from ${label} ${url}: ${body.slice(0, ERROR_BODY_PREVIEW_CHARS)}`
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1713
1317
|
// src/embedders/openai.ts
|
|
1714
1318
|
async function fetchAvailableModels(baseUrl, apiKey) {
|
|
1715
1319
|
const url = `${baseUrl}/v1/models`;
|
|
1716
1320
|
const response = await fetch(url, {
|
|
1717
1321
|
headers: { "Authorization": `Bearer ${apiKey}` }
|
|
1718
1322
|
});
|
|
1719
|
-
|
|
1720
|
-
const body = await response.text().catch(() => "");
|
|
1721
|
-
throw new Error(`HTTP ${response.status} from ${url}: ${body.slice(0, 200)}`);
|
|
1722
|
-
}
|
|
1323
|
+
await throwIfNotOk(response, "openai", url);
|
|
1723
1324
|
const data = await response.json();
|
|
1724
1325
|
return data.data.map((m) => m.id).filter((id) => id.includes("embed")).sort();
|
|
1725
1326
|
}
|
|
@@ -1761,10 +1362,7 @@ function openaiEmbedder(config) {
|
|
|
1761
1362
|
async function fetchAvailableModels2(baseUrl, apiKey) {
|
|
1762
1363
|
const url = `${baseUrl}/v1beta/models?key=${apiKey}`;
|
|
1763
1364
|
const response = await fetch(url);
|
|
1764
|
-
|
|
1765
|
-
const body = await response.text().catch(() => "");
|
|
1766
|
-
throw new Error(`HTTP ${response.status} from gemini ${baseUrl}/v1beta/models: ${body.slice(0, 200)}`);
|
|
1767
|
-
}
|
|
1365
|
+
await throwIfNotOk(response, "gemini", `${baseUrl}/v1beta/models`);
|
|
1768
1366
|
const data = await response.json();
|
|
1769
1367
|
return data.models.filter((m) => m.supportedGenerationMethods.includes("embedContent")).map((m) => m.name.replace("models/", "")).sort();
|
|
1770
1368
|
}
|
|
@@ -1813,10 +1411,7 @@ function geminiEmbedder(config) {
|
|
|
1813
1411
|
async function fetchAvailableModels3(baseUrl) {
|
|
1814
1412
|
const url = `${baseUrl}/api/tags`;
|
|
1815
1413
|
const response = await fetch(url);
|
|
1816
|
-
|
|
1817
|
-
const body = await response.text().catch(() => "");
|
|
1818
|
-
throw new Error(`HTTP ${response.status} from ollama ${url}: ${body.slice(0, 200)}`);
|
|
1819
|
-
}
|
|
1414
|
+
await throwIfNotOk(response, "ollama", url);
|
|
1820
1415
|
const data = await response.json();
|
|
1821
1416
|
return data.models.map((m) => m.name).filter((name) => name.includes("embed")).sort();
|
|
1822
1417
|
}
|
|
@@ -1850,21 +1445,18 @@ function ollamaEmbedder(config) {
|
|
|
1850
1445
|
return data.embeddings[0];
|
|
1851
1446
|
};
|
|
1852
1447
|
}
|
|
1853
|
-
async function fetchAvailableModels4(baseUrl, apiKey) {
|
|
1448
|
+
async function fetchAvailableModels4(provider, baseUrl, apiKey) {
|
|
1854
1449
|
const url = `${baseUrl}/v1/models`;
|
|
1855
1450
|
const response = await fetch(url, {
|
|
1856
1451
|
headers: { "Authorization": `Bearer ${apiKey}` }
|
|
1857
1452
|
});
|
|
1858
|
-
|
|
1859
|
-
const body = await response.text().catch(() => "");
|
|
1860
|
-
throw new Error(`HTTP ${response.status} from ${url}: ${body.slice(0, 200)}`);
|
|
1861
|
-
}
|
|
1453
|
+
await throwIfNotOk(response, provider, url);
|
|
1862
1454
|
const data = await response.json();
|
|
1863
1455
|
return data.data.map((m) => m.id).filter((id) => id.includes("embed")).sort();
|
|
1864
1456
|
}
|
|
1865
1457
|
async function buildModelError4(provider, baseUrl, apiKey, originalError) {
|
|
1866
1458
|
try {
|
|
1867
|
-
const models = await fetchAvailableModels4(baseUrl, apiKey);
|
|
1459
|
+
const models = await fetchAvailableModels4(provider, baseUrl, apiKey);
|
|
1868
1460
|
const list = models.length > 0 ? models.join(", ") : "none found";
|
|
1869
1461
|
return new Error(
|
|
1870
1462
|
`${provider} embedding failed: ${originalError}. Available embedding models: ${list}`
|
|
@@ -1913,7 +1505,91 @@ var grokEmbedder = createOpenAICompatibleEmbedder("Grok", "https://api.x.ai");
|
|
|
1913
1505
|
|
|
1914
1506
|
// src/embedders/kimi.ts
|
|
1915
1507
|
var kimiEmbedder = createOpenAICompatibleEmbedder("Kimi", "https://api.moonshot.ai");
|
|
1508
|
+
var DEFAULT_DEPRECATION_TABLE = [
|
|
1509
|
+
// OpenAI
|
|
1510
|
+
{ provider: "openai", model: "gpt-3.5-turbo-0301", successor: "gpt-4o-mini", sunsetOn: "2024-09-13" },
|
|
1511
|
+
{ provider: "openai", model: "gpt-3.5-turbo-0613", successor: "gpt-4o-mini", sunsetOn: "2024-09-13" },
|
|
1512
|
+
{ provider: "openai", model: "gpt-4-0314", successor: "gpt-4o", sunsetOn: "2024-06-13" },
|
|
1513
|
+
{ provider: "openai", model: "gpt-4-32k", successor: "gpt-4o", sunsetOn: "2024-06-06" },
|
|
1514
|
+
{ provider: "openai", model: "text-davinci-003", successor: "gpt-4o-mini", sunsetOn: "2024-01-04" },
|
|
1515
|
+
// Anthropic
|
|
1516
|
+
{ provider: "anthropic", model: "claude-2.0", successor: "claude-3-5-sonnet-latest", sunsetOn: "2025-07-21" },
|
|
1517
|
+
{ provider: "anthropic", model: "claude-2.1", successor: "claude-3-5-sonnet-latest", sunsetOn: "2025-07-21" },
|
|
1518
|
+
{ provider: "anthropic", model: "claude-instant-1.2", successor: "claude-3-5-haiku-latest", sunsetOn: "2024-07-22" },
|
|
1519
|
+
{ provider: "anthropic", model: "claude-3-sonnet-20240229", successor: "claude-3-5-sonnet-latest", sunsetOn: "2025-07-21" },
|
|
1520
|
+
// Google
|
|
1521
|
+
{ provider: "google", model: "gemini-1.0-pro", successor: "gemini-1.5-pro", sunsetOn: "2025-02-15" },
|
|
1522
|
+
{ provider: "google", model: "gemini-pro-vision", successor: "gemini-1.5-pro", sunsetOn: "2024-07-12" }
|
|
1523
|
+
];
|
|
1524
|
+
function resolveModel(input, policy) {
|
|
1525
|
+
const table = policy.table ?? DEFAULT_DEPRECATION_TABLE;
|
|
1526
|
+
const hit = table.find((d) => d.provider === input.provider && d.model === input.model);
|
|
1527
|
+
if (!hit) return { model: input.model, remapped: false };
|
|
1528
|
+
const log = policy.logger ?? ((msg) => console.warn(msg));
|
|
1529
|
+
const sunset = hit.sunsetOn ? ` (sunset ${hit.sunsetOn})` : "";
|
|
1530
|
+
const successor = hit.successor ? ` Suggested successor: ${hit.successor}.` : "";
|
|
1531
|
+
const base = `[agentskit] Model "${input.provider}:${input.model}" is deprecated${sunset}.${successor}`;
|
|
1532
|
+
switch (policy.onDeprecation) {
|
|
1533
|
+
case "fail":
|
|
1534
|
+
throw new ConfigError({
|
|
1535
|
+
code: ErrorCodes.AK_CONFIG_INVALID,
|
|
1536
|
+
message: base,
|
|
1537
|
+
hint: hit.successor ? `Set model to "${hit.successor}".` : "Pick a supported model from the provider."
|
|
1538
|
+
});
|
|
1539
|
+
case "remap": {
|
|
1540
|
+
if (!hit.successor) {
|
|
1541
|
+
throw new ConfigError({
|
|
1542
|
+
code: ErrorCodes.AK_CONFIG_INVALID,
|
|
1543
|
+
message: `${base} No successor available \u2014 cannot remap.`
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1546
|
+
log(`${base} Auto-remapping to "${hit.successor}".`);
|
|
1547
|
+
return { model: hit.successor, remapped: true, deprecation: hit };
|
|
1548
|
+
}
|
|
1549
|
+
case "warn":
|
|
1550
|
+
default:
|
|
1551
|
+
log(base);
|
|
1552
|
+
return { model: input.model, remapped: false, deprecation: hit };
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
function withDeprecationPolicy(factory, options) {
|
|
1556
|
+
resolveModel({ provider: options.provider, model: options.model }, options);
|
|
1557
|
+
return factory;
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
// src/credential-rotation.ts
|
|
1561
|
+
function createRotatingCredentials(initial, options) {
|
|
1562
|
+
let value = initial;
|
|
1563
|
+
const handlers = /* @__PURE__ */ new Set();
|
|
1564
|
+
return {
|
|
1565
|
+
current: () => value,
|
|
1566
|
+
rotate: async (next) => {
|
|
1567
|
+
value = next;
|
|
1568
|
+
const event = {
|
|
1569
|
+
rotatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1570
|
+
id: options.id,
|
|
1571
|
+
fingerprint: next.slice(-4)
|
|
1572
|
+
};
|
|
1573
|
+
for (const h of handlers) h(event);
|
|
1574
|
+
return next;
|
|
1575
|
+
},
|
|
1576
|
+
onRotate: (handler) => {
|
|
1577
|
+
handlers.add(handler);
|
|
1578
|
+
return () => handlers.delete(handler);
|
|
1579
|
+
}
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
async function refreshCredentials(adapter, next, options) {
|
|
1583
|
+
const log = options?.logger ?? ((msg) => console.log(msg));
|
|
1584
|
+
if (adapter && typeof adapter === "object" && "refreshCredentials" in adapter && typeof adapter.refreshCredentials === "function") {
|
|
1585
|
+
await adapter.refreshCredentials(next);
|
|
1586
|
+
log(`[agentskit] credentials refreshed${options?.id ? ` (${options.id})` : ""}`);
|
|
1587
|
+
return true;
|
|
1588
|
+
}
|
|
1589
|
+
log(`[agentskit] adapter does not support credential rotation; restart required${options?.id ? ` (${options.id})` : ""}`);
|
|
1590
|
+
return false;
|
|
1591
|
+
}
|
|
1916
1592
|
|
|
1917
|
-
export { anthropic, azureOpenAI, azureOpenAIAdapter, bail, bailAdapter, bedrock, bedrockAdapter, cerebras, cerebrasAdapter,
|
|
1593
|
+
export { DEFAULT_CARBON_TABLE, DEFAULT_DEPRECATION_TABLE, anthropic, applyCarbonTable, azureOpenAI, azureOpenAIAdapter, bail, bailAdapter, bedrock, bedrockAdapter, cerebras, cerebrasAdapter, cohere, cohereAdapter, createEnsembleAdapter, createFallbackAdapter, createOpenAICompatibleEmbedder, createRotatingCredentials, createRouter, deepseek, deepseekEmbedder, estimateCO2Grams, fireworks, gemini, geminiEmbedder, generic, grok, grokEmbedder, groq, groqAdapter, huggingface, inMemorySink, kimi, kimiEmbedder, langchain, langgraph, llamacpp, lmstudio, mistral, mockAdapter, ollama, ollamaEmbedder, openaiEmbedder, openrouter, qwen, recordingAdapter, refreshCredentials, replayAdapter, replicate, replicateAdapter, resolveModel, together, vercelAI, vertex, vertexAdapter, vllm, webllm, webllmAdapter, withDeprecationPolicy };
|
|
1918
1594
|
//# sourceMappingURL=index.js.map
|
|
1919
1595
|
//# sourceMappingURL=index.js.map
|