@agentskit/adapters 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ import '@agentskit/core';
2
+ export { c as createAdapter } from './createAdapter-Dfnf3Iio.cjs';
@@ -0,0 +1,2 @@
1
+ import '@agentskit/core';
2
+ export { c as createAdapter } from './createAdapter-Dfnf3Iio.js';
@@ -0,0 +1,3 @@
1
+ export { createAdapter } from './chunk-6FPLWOVE.js';
2
+ //# sourceMappingURL=createAdapter.js.map
3
+ //# sourceMappingURL=createAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"createAdapter.js"}
package/dist/index.cjs CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ var core = require('@agentskit/core');
4
+
3
5
  // src/createAdapter.ts
4
6
  function createAdapter(config) {
5
7
  return {
@@ -399,8 +401,10 @@ function createStreamSource(doFetch, parse, errorLabel, retry) {
399
401
  let abortController = new AbortController();
400
402
  return {
401
403
  stream: async function* () {
404
+ const controller = abortController;
405
+ if (!controller) return;
402
406
  try {
403
- const response = await fetchWithRetry(doFetch, abortController.signal, retry ?? {});
407
+ const response = await fetchWithRetry(doFetch, controller.signal, retry ?? {});
404
408
  if (!response.ok || !response.body) {
405
409
  yield { type: "error", content: `${errorLabel} error: ${response.status}` };
406
410
  return;
@@ -440,8 +444,10 @@ function simulateStream(doFetch, extractText, errorLabel, options = {}) {
440
444
  let abortController = new AbortController();
441
445
  return {
442
446
  stream: async function* () {
447
+ const controller = abortController;
448
+ if (!controller) return;
443
449
  try {
444
- const response = await fetchWithRetry(doFetch, abortController.signal, retry ?? {});
450
+ const response = await fetchWithRetry(doFetch, controller.signal, retry ?? {});
445
451
  if (!response.ok) {
446
452
  yield { type: "error", content: `${errorLabel} error: ${response.status}` };
447
453
  return;
@@ -453,7 +459,7 @@ function simulateStream(doFetch, extractText, errorLabel, options = {}) {
453
459
  if (delayMs > 0) {
454
460
  await new Promise((resolve2, reject) => {
455
461
  const timer = setTimeout(resolve2, delayMs);
456
- abortController?.signal.addEventListener(
462
+ controller.signal.addEventListener(
457
463
  "abort",
458
464
  () => {
459
465
  clearTimeout(timer);
@@ -527,7 +533,14 @@ function anthropic(config) {
527
533
  // src/openai.ts
528
534
  function openai(config) {
529
535
  const { apiKey, model, baseUrl = "https://api.openai.com", retry } = config;
530
- const includeUsage = config.includeUsage ?? baseUrl.startsWith("https://api.openai.com");
536
+ const isCanonicalOpenAI = (() => {
537
+ try {
538
+ return new URL(baseUrl).host === "api.openai.com";
539
+ } catch {
540
+ return false;
541
+ }
542
+ })();
543
+ const includeUsage = config.includeUsage ?? isCanonicalOpenAI;
531
544
  return {
532
545
  capabilities: {
533
546
  streaming: true,
@@ -584,15 +597,13 @@ function gemini(config) {
584
597
  usage: true
585
598
  },
586
599
  createSource: (request) => {
600
+ const systemMessage = request.messages.find((message) => message.role === "system");
587
601
  const body = {
588
602
  contents: request.messages.filter((message) => message.role !== "system").map((message) => ({
589
603
  role: message.role === "assistant" ? "model" : "user",
590
604
  parts: [{ text: message.content }]
591
605
  })),
592
- systemInstruction: request.messages.find((message) => message.role === "system") ? {
593
- role: "system",
594
- parts: [{ text: request.messages.find((message) => message.role === "system").content }]
595
- } : void 0
606
+ systemInstruction: systemMessage ? { role: "system", parts: [{ text: systemMessage.content }] } : void 0
596
607
  };
597
608
  return createStreamSource(
598
609
  (signal) => fetch(
@@ -1058,15 +1069,13 @@ function vertex(config) {
1058
1069
  reasoning: model.includes("pro")
1059
1070
  },
1060
1071
  createSource: (request) => {
1072
+ const systemMessage = request.messages.find((message) => message.role === "system");
1061
1073
  const body = {
1062
1074
  contents: request.messages.filter((message) => message.role !== "system").map((message) => ({
1063
1075
  role: message.role === "assistant" ? "model" : "user",
1064
1076
  parts: [{ text: message.content }]
1065
1077
  })),
1066
- systemInstruction: request.messages.find((message) => message.role === "system") ? {
1067
- role: "system",
1068
- parts: [{ text: request.messages.find((message) => message.role === "system").content }]
1069
- } : void 0,
1078
+ systemInstruction: systemMessage ? { role: "system", parts: [{ text: systemMessage.content }] } : void 0,
1070
1079
  tools: request.context?.tools && request.context.tools.length > 0 ? [{
1071
1080
  functionDeclarations: request.context.tools.map((tool) => ({
1072
1081
  name: tool.name,
@@ -1096,8 +1105,6 @@ function vertex(config) {
1096
1105
  };
1097
1106
  }
1098
1107
  var vertexAdapter = vertex;
1099
-
1100
- // src/bedrock.ts
1101
1108
  var cachedSdk = null;
1102
1109
  async function loadSdk() {
1103
1110
  if (!cachedSdk) {
@@ -1109,9 +1116,11 @@ async function loadSdk() {
1109
1116
  moduleId
1110
1117
  );
1111
1118
  } catch {
1112
- throw new Error(
1113
- "Install @aws-sdk/client-bedrock-runtime to use the bedrock adapter: npm install @aws-sdk/client-bedrock-runtime"
1114
- );
1119
+ throw new core.AdapterError({
1120
+ code: core.ErrorCodes.AK_ADAPTER_MISSING,
1121
+ message: "Install @aws-sdk/client-bedrock-runtime to use the bedrock adapter: npm install @aws-sdk/client-bedrock-runtime",
1122
+ hint: "bedrock depends on the optional peer @aws-sdk/client-bedrock-runtime."
1123
+ });
1115
1124
  }
1116
1125
  })();
1117
1126
  }
@@ -1212,9 +1221,11 @@ async function* parseAnthropicBedrockEvents(events) {
1212
1221
  function bedrock(config) {
1213
1222
  const { model, region, maxTokens = 4096 } = config;
1214
1223
  if (!isAnthropicModel(model)) {
1215
- throw new Error(
1216
- `bedrock: model "${model}" is not supported in v1. Only anthropic.* models are wired up; Titan + others are tracked as a follow-up.`
1217
- );
1224
+ throw new core.ConfigError({
1225
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1226
+ message: `bedrock: model "${model}" is not supported in v1. Only anthropic.* models are wired up; Titan + others are tracked as a follow-up.`,
1227
+ hint: 'Pass an anthropic.* model id like "anthropic.claude-3-5-sonnet-20241022-v2:0".'
1228
+ });
1218
1229
  }
1219
1230
  let clientPromise = null;
1220
1231
  const getClient = async () => {
@@ -1273,8 +1284,6 @@ function bedrock(config) {
1273
1284
  };
1274
1285
  }
1275
1286
  var bedrockAdapter = bedrock;
1276
-
1277
- // src/webllm.ts
1278
1287
  var cachedSdk2 = null;
1279
1288
  async function loadSdk2() {
1280
1289
  if (!cachedSdk2) {
@@ -1286,7 +1295,11 @@ async function loadSdk2() {
1286
1295
  moduleId
1287
1296
  );
1288
1297
  } catch {
1289
- throw new Error("Install @mlc-ai/web-llm to use the webllm adapter: npm install @mlc-ai/web-llm");
1298
+ throw new core.AdapterError({
1299
+ code: core.ErrorCodes.AK_ADAPTER_MISSING,
1300
+ message: "Install @mlc-ai/web-llm to use the webllm adapter: npm install @mlc-ai/web-llm",
1301
+ hint: "webllm is browser-only and depends on the optional peer @mlc-ai/web-llm."
1302
+ });
1290
1303
  }
1291
1304
  })();
1292
1305
  }
@@ -1336,8 +1349,6 @@ function webllm(config) {
1336
1349
  };
1337
1350
  }
1338
1351
  var webllmAdapter = webllm;
1339
-
1340
- // src/router.ts
1341
1352
  function requireCapabilities(request) {
1342
1353
  const needs = {};
1343
1354
  if (request.context?.tools && request.context.tools.length > 0) needs.tools = true;
@@ -1360,34 +1371,75 @@ function pickSyncPolicy(pool, policy) {
1360
1371
  const c = pool.reduce((best, x) => (x.latencyMs ?? Infinity) < (best.latencyMs ?? Infinity) ? x : best, pool[0]);
1361
1372
  return { c, reason: "fastest" };
1362
1373
  }
1374
+ if (policy === "greenest") {
1375
+ const c = pool.reduce((best, x) => (x.gCO2PerKtok ?? Infinity) < (best.gCO2PerKtok ?? Infinity) ? x : best, pool[0]);
1376
+ return { c, reason: "greenest" };
1377
+ }
1378
+ if (policy === "green-cost") {
1379
+ const carbonValues = pool.map((p) => p.gCO2PerKtok).filter((v) => v != null);
1380
+ const costValues = pool.map((p) => p.cost).filter((v) => v != null);
1381
+ const maxC = Math.max(1, ...carbonValues);
1382
+ const maxCost = Math.max(1, ...costValues);
1383
+ const score = (x) => {
1384
+ const carbon = (x.gCO2PerKtok ?? maxC / 2) / maxC;
1385
+ const cost = (x.cost ?? maxCost / 2) / maxCost;
1386
+ return carbon + cost;
1387
+ };
1388
+ const c = pool.reduce((best, x) => score(x) < score(best) ? x : best, pool[0]);
1389
+ return { c, reason: "green-cost" };
1390
+ }
1363
1391
  return { c: pool[0], reason: "capability-match" };
1364
1392
  }
1393
+ function matchesRegion(candidate, region) {
1394
+ return region === void 0 || candidate.region === region;
1395
+ }
1365
1396
  function createRouter(options) {
1366
1397
  const { candidates } = options;
1367
- if (candidates.length === 0) throw new Error("createRouter requires at least one candidate");
1398
+ if (candidates.length === 0) {
1399
+ throw new core.ConfigError({
1400
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1401
+ message: "createRouter requires at least one candidate",
1402
+ hint: "Pass at least one candidate, e.g. createRouter({ candidates: [{ id, adapter, capabilities }] })."
1403
+ });
1404
+ }
1368
1405
  const policy = options.policy ?? "cheapest";
1369
1406
  return {
1370
1407
  createSource: (request) => {
1371
1408
  const need = requireCapabilities(request);
1409
+ const region = options.regionOf?.(request) ?? options.region;
1372
1410
  const capable = candidates.filter((c2) => matchesCapabilities(need, c2.capabilities ?? c2.adapter.capabilities));
1411
+ const eligible = capable.filter((c2) => matchesRegion(c2, region));
1412
+ if (capable.length > 0 && eligible.length === 0 && region !== void 0) {
1413
+ throw new core.ConfigError({
1414
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1415
+ message: `no candidate satisfies required region: ${region}`,
1416
+ hint: "Set candidate.region to the requested data-residency region, or remove the router region requirement."
1417
+ });
1418
+ }
1373
1419
  const classified = options.classify?.(request);
1374
1420
  if (typeof classified === "string") {
1375
- const c2 = capable.find((x) => x.id === classified);
1421
+ const c2 = eligible.find((x) => x.id === classified);
1376
1422
  if (c2) {
1377
- options.onRoute?.({ id: c2.id, reason: "classify:id", request });
1423
+ options.onRoute?.({ id: c2.id, reason: region ? `classify:id:${region}` : "classify:id", request });
1378
1424
  return c2.adapter.createSource(request);
1379
1425
  }
1380
1426
  }
1381
- let pool = capable;
1427
+ let pool = eligible;
1382
1428
  let pickedBy;
1383
1429
  if (Array.isArray(classified) && classified.length > 0) {
1384
- const filtered = capable.filter((c2) => c2.tags && classified.every((t) => c2.tags.includes(t)));
1430
+ const filtered = eligible.filter((c2) => c2.tags && classified.every((t) => c2.tags.includes(t)));
1385
1431
  if (filtered.length > 0) {
1386
1432
  pool = filtered;
1387
- pickedBy = "classify:tags";
1433
+ pickedBy = region ? `classify:tags:${region}` : "classify:tags";
1388
1434
  }
1389
1435
  }
1390
- if (pool.length === 0) throw new Error("no candidate satisfies the request");
1436
+ if (pool.length === 0) {
1437
+ throw new core.AdapterError({
1438
+ code: core.ErrorCodes.AK_ADAPTER_STREAM_FAILED,
1439
+ message: "no candidate satisfies the request",
1440
+ hint: "Ensure at least one candidate declares the required capabilities (tools, json, etc.)."
1441
+ });
1442
+ }
1391
1443
  if (typeof policy === "function") {
1392
1444
  const maybe = policy({ request, candidates: pool });
1393
1445
  if (maybe instanceof Promise) {
@@ -1397,14 +1449,26 @@ function createRouter(options) {
1397
1449
  stream: async function* () {
1398
1450
  const id = await maybe;
1399
1451
  const c3 = pool.find((x) => x.id === id);
1400
- if (!c3) throw new Error(`policy returned unknown id: ${id}`);
1452
+ if (!c3) {
1453
+ throw new core.ConfigError({
1454
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1455
+ message: `policy returned unknown id: ${id}`,
1456
+ hint: "Custom policy functions must return one of the candidate ids."
1457
+ });
1458
+ }
1401
1459
  options.onRoute?.({ id: c3.id, reason: pickedBy ?? "custom policy", request });
1402
1460
  for await (const chunk of c3.adapter.createSource(request).stream()) yield chunk;
1403
1461
  }
1404
1462
  };
1405
1463
  }
1406
1464
  const c2 = pool.find((x) => x.id === maybe);
1407
- if (!c2) throw new Error(`policy returned unknown id: ${maybe}`);
1465
+ if (!c2) {
1466
+ throw new core.ConfigError({
1467
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1468
+ message: `policy returned unknown id: ${maybe}`,
1469
+ hint: "Custom policy functions must return one of the candidate ids."
1470
+ });
1471
+ }
1408
1472
  options.onRoute?.({ id: c2.id, reason: pickedBy ?? "custom policy", request });
1409
1473
  return c2.adapter.createSource(request);
1410
1474
  }
@@ -1415,7 +1479,56 @@ function createRouter(options) {
1415
1479
  };
1416
1480
  }
1417
1481
 
1418
- // src/ensemble.ts
1482
+ // src/carbon.ts
1483
+ var DEFAULT_CARBON_TABLE = {
1484
+ // Anthropic — primarily AWS us-east-* / eu-west-* via Bedrock-style fronts.
1485
+ "anthropic:us-east-1": 0.42,
1486
+ "anthropic:us-west-2": 0.18,
1487
+ "anthropic:eu-central-1": 0.32,
1488
+ "anthropic:eu-west-1": 0.27,
1489
+ // OpenAI — Azure East US / West Europe / Sweden Central.
1490
+ "openai:eastus": 0.4,
1491
+ "openai:westus3": 0.19,
1492
+ "openai:swedencentral": 0.04,
1493
+ "openai:westeurope": 0.28,
1494
+ // Google (Vertex / Gemini) — typically reports lowest PUE.
1495
+ "google:us-central1": 0.34,
1496
+ "google:us-west1": 0.16,
1497
+ "google:europe-west1": 0.21,
1498
+ "google:europe-north1": 0.05,
1499
+ // AWS Bedrock direct.
1500
+ "aws:us-east-1": 0.42,
1501
+ "aws:us-west-2": 0.18,
1502
+ "aws:eu-west-1": 0.27,
1503
+ // Local / on-device — only the device's grid matters.
1504
+ "ollama:local": 0.3,
1505
+ "webllm:browser": 0.3,
1506
+ "lmstudio:local": 0.3,
1507
+ // Self-hosted / community.
1508
+ "groq:us-east-1": 0.4,
1509
+ "fireworks:us-west-2": 0.18,
1510
+ "together:us-east-1": 0.42,
1511
+ "cerebras:us-west-2": 0.18
1512
+ };
1513
+ function defaultKey(candidate) {
1514
+ if (!candidate.region) return void 0;
1515
+ const provider = candidate.id.split(/[-:]/)[0];
1516
+ return `${provider}:${candidate.region}`;
1517
+ }
1518
+ function applyCarbonTable(candidates, options = {}) {
1519
+ const table = options.table ?? DEFAULT_CARBON_TABLE;
1520
+ const keyFor = options.keyFor ?? defaultKey;
1521
+ return candidates.map((c) => {
1522
+ if (c.gCO2PerKtok != null) return c;
1523
+ const key = keyFor(c);
1524
+ const value = key ? table[key] : void 0;
1525
+ return { ...c, gCO2PerKtok: value ?? options.fallback };
1526
+ });
1527
+ }
1528
+ function estimateCO2Grams(gCO2PerKtok, tokens) {
1529
+ if (gCO2PerKtok == null) return 0;
1530
+ return tokens / 1e3 * gCO2PerKtok;
1531
+ }
1419
1532
  async function drain(source, timeoutMs) {
1420
1533
  const chunks = [];
1421
1534
  let text = "";
@@ -1460,7 +1573,11 @@ function majorityVote(branches, candidates) {
1460
1573
  }
1461
1574
  function createEnsembleAdapter(options) {
1462
1575
  if (options.candidates.length === 0) {
1463
- throw new Error("createEnsembleAdapter requires at least one candidate");
1576
+ throw new core.ConfigError({
1577
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1578
+ message: "createEnsembleAdapter requires at least one candidate",
1579
+ hint: "Pass at least one candidate, e.g. createEnsembleAdapter({ candidates: [{ id, adapter }] })."
1580
+ });
1464
1581
  }
1465
1582
  const aggregate = options.aggregate ?? "majority-vote";
1466
1583
  return {
@@ -1500,7 +1617,14 @@ function createEnsembleAdapter(options) {
1500
1617
  if (aborted) return;
1501
1618
  const text = await finalText(branches);
1502
1619
  if (!text && branches.every((b) => b.error)) {
1503
- throw new Error("all ensemble branches failed");
1620
+ const summary = branches.map((b) => `${b.id}: ${b.error?.message ?? "unknown"}`).join("; ");
1621
+ const err = new core.AdapterError({
1622
+ code: core.ErrorCodes.AK_ADAPTER_STREAM_FAILED,
1623
+ message: `all ensemble branches failed (${summary})`,
1624
+ hint: "Inspect each branch error via options.onBranches or the err.branchErrors field."
1625
+ });
1626
+ err.branchErrors = branches.map((b) => ({ id: b.id, error: b.error }));
1627
+ throw err;
1504
1628
  }
1505
1629
  yield { type: "text", content: text, metadata: { ensemble: branches.map((b) => ({ id: b.id, bytes: b.text.length, error: b.error?.message })) } };
1506
1630
  yield { type: "done" };
@@ -1509,11 +1633,13 @@ function createEnsembleAdapter(options) {
1509
1633
  }
1510
1634
  };
1511
1635
  }
1512
-
1513
- // src/fallback.ts
1514
1636
  function createFallbackAdapter(candidates, options = {}) {
1515
1637
  if (candidates.length === 0) {
1516
- throw new Error("createFallbackAdapter requires at least one candidate");
1638
+ throw new core.ConfigError({
1639
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1640
+ message: "createFallbackAdapter requires at least one candidate",
1641
+ hint: 'Pass at least one candidate, e.g. createFallbackAdapter([{ id: "primary", adapter }]).'
1642
+ });
1517
1643
  }
1518
1644
  return {
1519
1645
  createSource: (request) => {
@@ -1568,14 +1694,16 @@ function createFallbackAdapter(candidates, options = {}) {
1568
1694
  }
1569
1695
  }
1570
1696
  const summary = errors.map((e) => `${e.id}: ${e.error.message}`).join("; ");
1571
- throw new Error(`all fallback candidates failed (${summary})`);
1697
+ throw new core.AdapterError({
1698
+ code: core.ErrorCodes.AK_ADAPTER_STREAM_FAILED,
1699
+ message: `all fallback candidates failed (${summary})`,
1700
+ hint: "Check each candidate adapter's configuration and provider keys."
1701
+ });
1572
1702
  }
1573
1703
  };
1574
1704
  }
1575
1705
  };
1576
1706
  }
1577
-
1578
- // src/mock.ts
1579
1707
  function mockAdapter(options) {
1580
1708
  const { response, delayMs = 0, history } = options;
1581
1709
  let callIndex = 0;
@@ -1660,21 +1788,34 @@ function inMemorySink() {
1660
1788
  }
1661
1789
  function replayAdapter(fixture) {
1662
1790
  if (fixture.length === 0) {
1663
- throw new Error("replayAdapter: fixture is empty");
1791
+ throw new core.ConfigError({
1792
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1793
+ message: "replayAdapter: fixture is empty",
1794
+ hint: "Pass a non-empty fixture; record one with recordingAdapter() first."
1795
+ });
1664
1796
  }
1665
1797
  return mockAdapter({
1666
1798
  response: fixture.map((turn) => turn.chunks)
1667
1799
  });
1668
1800
  }
1669
1801
 
1802
+ // src/embedders/shared.ts
1803
+ var ERROR_BODY_PREVIEW_CHARS = 200;
1804
+ async function throwIfNotOk(response, label, url) {
1805
+ if (response.ok) return;
1806
+ const body = await response.text().catch(() => "");
1807
+ throw new Error(
1808
+ `HTTP ${response.status} from ${label} ${url}: ${body.slice(0, ERROR_BODY_PREVIEW_CHARS)}`
1809
+ );
1810
+ }
1811
+
1670
1812
  // src/embedders/openai.ts
1671
1813
  async function fetchAvailableModels(baseUrl, apiKey) {
1672
- const response = await fetch(`${baseUrl}/v1/models`, {
1814
+ const url = `${baseUrl}/v1/models`;
1815
+ const response = await fetch(url, {
1673
1816
  headers: { "Authorization": `Bearer ${apiKey}` }
1674
1817
  });
1675
- if (!response.ok) {
1676
- throw new Error(`HTTP ${response.status}`);
1677
- }
1818
+ await throwIfNotOk(response, "openai", url);
1678
1819
  const data = await response.json();
1679
1820
  return data.data.map((m) => m.id).filter((id) => id.includes("embed")).sort();
1680
1821
  }
@@ -1714,10 +1855,9 @@ function openaiEmbedder(config) {
1714
1855
 
1715
1856
  // src/embedders/gemini.ts
1716
1857
  async function fetchAvailableModels2(baseUrl, apiKey) {
1717
- const response = await fetch(`${baseUrl}/v1beta/models?key=${apiKey}`);
1718
- if (!response.ok) {
1719
- throw new Error(`HTTP ${response.status}`);
1720
- }
1858
+ const url = `${baseUrl}/v1beta/models?key=${apiKey}`;
1859
+ const response = await fetch(url);
1860
+ await throwIfNotOk(response, "gemini", `${baseUrl}/v1beta/models`);
1721
1861
  const data = await response.json();
1722
1862
  return data.models.filter((m) => m.supportedGenerationMethods.includes("embedContent")).map((m) => m.name.replace("models/", "")).sort();
1723
1863
  }
@@ -1764,10 +1904,9 @@ function geminiEmbedder(config) {
1764
1904
 
1765
1905
  // src/embedders/ollama.ts
1766
1906
  async function fetchAvailableModels3(baseUrl) {
1767
- const response = await fetch(`${baseUrl}/api/tags`);
1768
- if (!response.ok) {
1769
- throw new Error(`HTTP ${response.status}`);
1770
- }
1907
+ const url = `${baseUrl}/api/tags`;
1908
+ const response = await fetch(url);
1909
+ await throwIfNotOk(response, "ollama", url);
1771
1910
  const data = await response.json();
1772
1911
  return data.models.map((m) => m.name).filter((name) => name.includes("embed")).sort();
1773
1912
  }
@@ -1801,21 +1940,18 @@ function ollamaEmbedder(config) {
1801
1940
  return data.embeddings[0];
1802
1941
  };
1803
1942
  }
1804
-
1805
- // src/embedders/openai-compatible.ts
1806
- async function fetchAvailableModels4(baseUrl, apiKey) {
1807
- const response = await fetch(`${baseUrl}/v1/models`, {
1943
+ async function fetchAvailableModels4(provider, baseUrl, apiKey) {
1944
+ const url = `${baseUrl}/v1/models`;
1945
+ const response = await fetch(url, {
1808
1946
  headers: { "Authorization": `Bearer ${apiKey}` }
1809
1947
  });
1810
- if (!response.ok) {
1811
- throw new Error(`HTTP ${response.status}`);
1812
- }
1948
+ await throwIfNotOk(response, provider, url);
1813
1949
  const data = await response.json();
1814
1950
  return data.data.map((m) => m.id).filter((id) => id.includes("embed")).sort();
1815
1951
  }
1816
1952
  async function buildModelError4(provider, baseUrl, apiKey, originalError) {
1817
1953
  try {
1818
- const models = await fetchAvailableModels4(baseUrl, apiKey);
1954
+ const models = await fetchAvailableModels4(provider, baseUrl, apiKey);
1819
1955
  const list = models.length > 0 ? models.join(", ") : "none found";
1820
1956
  return new Error(
1821
1957
  `${provider} embedding failed: ${originalError}. Available embedding models: ${list}`
@@ -1829,7 +1965,11 @@ async function buildModelError4(provider, baseUrl, apiKey, originalError) {
1829
1965
  function createOpenAICompatibleEmbedder(provider, defaultBaseUrl) {
1830
1966
  return function embedder(config) {
1831
1967
  if (!config.model) {
1832
- throw new Error(`Model is required for ${provider}. Pass { model: "<model-name>" }.`);
1968
+ throw new core.ConfigError({
1969
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1970
+ message: `Model is required for ${provider}. Pass { model: "<model-name>" }.`,
1971
+ hint: `${provider} does not infer a default; pick a recent embedding model and pass it explicitly.`
1972
+ });
1833
1973
  }
1834
1974
  const { apiKey, model, baseUrl = defaultBaseUrl } = config;
1835
1975
  return async (text) => {
@@ -1860,8 +2000,95 @@ var grokEmbedder = createOpenAICompatibleEmbedder("Grok", "https://api.x.ai");
1860
2000
 
1861
2001
  // src/embedders/kimi.ts
1862
2002
  var kimiEmbedder = createOpenAICompatibleEmbedder("Kimi", "https://api.moonshot.ai");
2003
+ var DEFAULT_DEPRECATION_TABLE = [
2004
+ // OpenAI
2005
+ { provider: "openai", model: "gpt-3.5-turbo-0301", successor: "gpt-4o-mini", sunsetOn: "2024-09-13" },
2006
+ { provider: "openai", model: "gpt-3.5-turbo-0613", successor: "gpt-4o-mini", sunsetOn: "2024-09-13" },
2007
+ { provider: "openai", model: "gpt-4-0314", successor: "gpt-4o", sunsetOn: "2024-06-13" },
2008
+ { provider: "openai", model: "gpt-4-32k", successor: "gpt-4o", sunsetOn: "2024-06-06" },
2009
+ { provider: "openai", model: "text-davinci-003", successor: "gpt-4o-mini", sunsetOn: "2024-01-04" },
2010
+ // Anthropic
2011
+ { provider: "anthropic", model: "claude-2.0", successor: "claude-3-5-sonnet-latest", sunsetOn: "2025-07-21" },
2012
+ { provider: "anthropic", model: "claude-2.1", successor: "claude-3-5-sonnet-latest", sunsetOn: "2025-07-21" },
2013
+ { provider: "anthropic", model: "claude-instant-1.2", successor: "claude-3-5-haiku-latest", sunsetOn: "2024-07-22" },
2014
+ { provider: "anthropic", model: "claude-3-sonnet-20240229", successor: "claude-3-5-sonnet-latest", sunsetOn: "2025-07-21" },
2015
+ // Google
2016
+ { provider: "google", model: "gemini-1.0-pro", successor: "gemini-1.5-pro", sunsetOn: "2025-02-15" },
2017
+ { provider: "google", model: "gemini-pro-vision", successor: "gemini-1.5-pro", sunsetOn: "2024-07-12" }
2018
+ ];
2019
+ function resolveModel(input, policy) {
2020
+ const table = policy.table ?? DEFAULT_DEPRECATION_TABLE;
2021
+ const hit = table.find((d) => d.provider === input.provider && d.model === input.model);
2022
+ if (!hit) return { model: input.model, remapped: false };
2023
+ const log = policy.logger ?? ((msg) => console.warn(msg));
2024
+ const sunset = hit.sunsetOn ? ` (sunset ${hit.sunsetOn})` : "";
2025
+ const successor = hit.successor ? ` Suggested successor: ${hit.successor}.` : "";
2026
+ const base = `[agentskit] Model "${input.provider}:${input.model}" is deprecated${sunset}.${successor}`;
2027
+ switch (policy.onDeprecation) {
2028
+ case "fail":
2029
+ throw new core.ConfigError({
2030
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
2031
+ message: base,
2032
+ hint: hit.successor ? `Set model to "${hit.successor}".` : "Pick a supported model from the provider."
2033
+ });
2034
+ case "remap": {
2035
+ if (!hit.successor) {
2036
+ throw new core.ConfigError({
2037
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
2038
+ message: `${base} No successor available \u2014 cannot remap.`
2039
+ });
2040
+ }
2041
+ log(`${base} Auto-remapping to "${hit.successor}".`);
2042
+ return { model: hit.successor, remapped: true, deprecation: hit };
2043
+ }
2044
+ case "warn":
2045
+ default:
2046
+ log(base);
2047
+ return { model: input.model, remapped: false, deprecation: hit };
2048
+ }
2049
+ }
2050
+ function withDeprecationPolicy(factory, options) {
2051
+ resolveModel({ provider: options.provider, model: options.model }, options);
2052
+ return factory;
2053
+ }
2054
+
2055
+ // src/credential-rotation.ts
2056
+ function createRotatingCredentials(initial, options) {
2057
+ let value = initial;
2058
+ const handlers = /* @__PURE__ */ new Set();
2059
+ return {
2060
+ current: () => value,
2061
+ rotate: async (next) => {
2062
+ value = next;
2063
+ const event = {
2064
+ rotatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2065
+ id: options.id,
2066
+ fingerprint: next.slice(-4)
2067
+ };
2068
+ for (const h of handlers) h(event);
2069
+ return next;
2070
+ },
2071
+ onRotate: (handler) => {
2072
+ handlers.add(handler);
2073
+ return () => handlers.delete(handler);
2074
+ }
2075
+ };
2076
+ }
2077
+ async function refreshCredentials(adapter, next, options) {
2078
+ const log = options?.logger ?? ((msg) => console.log(msg));
2079
+ if (adapter && typeof adapter === "object" && "refreshCredentials" in adapter && typeof adapter.refreshCredentials === "function") {
2080
+ await adapter.refreshCredentials(next);
2081
+ log(`[agentskit] credentials refreshed${options?.id ? ` (${options.id})` : ""}`);
2082
+ return true;
2083
+ }
2084
+ log(`[agentskit] adapter does not support credential rotation; restart required${options?.id ? ` (${options.id})` : ""}`);
2085
+ return false;
2086
+ }
1863
2087
 
2088
+ exports.DEFAULT_CARBON_TABLE = DEFAULT_CARBON_TABLE;
2089
+ exports.DEFAULT_DEPRECATION_TABLE = DEFAULT_DEPRECATION_TABLE;
1864
2090
  exports.anthropic = anthropic;
2091
+ exports.applyCarbonTable = applyCarbonTable;
1865
2092
  exports.azureOpenAI = azureOpenAI;
1866
2093
  exports.azureOpenAIAdapter = azureOpenAIAdapter;
1867
2094
  exports.bail = bail;
@@ -1877,9 +2104,11 @@ exports.createAdapter = createAdapter;
1877
2104
  exports.createEnsembleAdapter = createEnsembleAdapter;
1878
2105
  exports.createFallbackAdapter = createFallbackAdapter;
1879
2106
  exports.createOpenAICompatibleEmbedder = createOpenAICompatibleEmbedder;
2107
+ exports.createRotatingCredentials = createRotatingCredentials;
1880
2108
  exports.createRouter = createRouter;
1881
2109
  exports.deepseek = deepseek;
1882
2110
  exports.deepseekEmbedder = deepseekEmbedder;
2111
+ exports.estimateCO2Grams = estimateCO2Grams;
1883
2112
  exports.fetchWithRetry = fetchWithRetry;
1884
2113
  exports.fireworks = fireworks;
1885
2114
  exports.gemini = gemini;
@@ -1906,9 +2135,11 @@ exports.openaiEmbedder = openaiEmbedder;
1906
2135
  exports.openrouter = openrouter;
1907
2136
  exports.qwen = qwen;
1908
2137
  exports.recordingAdapter = recordingAdapter;
2138
+ exports.refreshCredentials = refreshCredentials;
1909
2139
  exports.replayAdapter = replayAdapter;
1910
2140
  exports.replicate = replicate;
1911
2141
  exports.replicateAdapter = replicateAdapter;
2142
+ exports.resolveModel = resolveModel;
1912
2143
  exports.simulateStream = simulateStream;
1913
2144
  exports.together = together;
1914
2145
  exports.vercelAI = vercelAI;
@@ -1917,5 +2148,6 @@ exports.vertexAdapter = vertexAdapter;
1917
2148
  exports.vllm = vllm;
1918
2149
  exports.webllm = webllm;
1919
2150
  exports.webllmAdapter = webllmAdapter;
2151
+ exports.withDeprecationPolicy = withDeprecationPolicy;
1920
2152
  //# sourceMappingURL=index.cjs.map
1921
2153
  //# sourceMappingURL=index.cjs.map