@agentskit/adapters 0.12.2 → 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
@@ -401,8 +401,10 @@ function createStreamSource(doFetch, parse, errorLabel, retry) {
401
401
  let abortController = new AbortController();
402
402
  return {
403
403
  stream: async function* () {
404
+ const controller = abortController;
405
+ if (!controller) return;
404
406
  try {
405
- const response = await fetchWithRetry(doFetch, abortController.signal, retry ?? {});
407
+ const response = await fetchWithRetry(doFetch, controller.signal, retry ?? {});
406
408
  if (!response.ok || !response.body) {
407
409
  yield { type: "error", content: `${errorLabel} error: ${response.status}` };
408
410
  return;
@@ -442,8 +444,10 @@ function simulateStream(doFetch, extractText, errorLabel, options = {}) {
442
444
  let abortController = new AbortController();
443
445
  return {
444
446
  stream: async function* () {
447
+ const controller = abortController;
448
+ if (!controller) return;
445
449
  try {
446
- const response = await fetchWithRetry(doFetch, abortController.signal, retry ?? {});
450
+ const response = await fetchWithRetry(doFetch, controller.signal, retry ?? {});
447
451
  if (!response.ok) {
448
452
  yield { type: "error", content: `${errorLabel} error: ${response.status}` };
449
453
  return;
@@ -455,7 +459,7 @@ function simulateStream(doFetch, extractText, errorLabel, options = {}) {
455
459
  if (delayMs > 0) {
456
460
  await new Promise((resolve2, reject) => {
457
461
  const timer = setTimeout(resolve2, delayMs);
458
- abortController?.signal.addEventListener(
462
+ controller.signal.addEventListener(
459
463
  "abort",
460
464
  () => {
461
465
  clearTimeout(timer);
@@ -529,7 +533,14 @@ function anthropic(config) {
529
533
  // src/openai.ts
530
534
  function openai(config) {
531
535
  const { apiKey, model, baseUrl = "https://api.openai.com", retry } = config;
532
- 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;
533
544
  return {
534
545
  capabilities: {
535
546
  streaming: true,
@@ -586,15 +597,13 @@ function gemini(config) {
586
597
  usage: true
587
598
  },
588
599
  createSource: (request) => {
600
+ const systemMessage = request.messages.find((message) => message.role === "system");
589
601
  const body = {
590
602
  contents: request.messages.filter((message) => message.role !== "system").map((message) => ({
591
603
  role: message.role === "assistant" ? "model" : "user",
592
604
  parts: [{ text: message.content }]
593
605
  })),
594
- systemInstruction: request.messages.find((message) => message.role === "system") ? {
595
- role: "system",
596
- parts: [{ text: request.messages.find((message) => message.role === "system").content }]
597
- } : void 0
606
+ systemInstruction: systemMessage ? { role: "system", parts: [{ text: systemMessage.content }] } : void 0
598
607
  };
599
608
  return createStreamSource(
600
609
  (signal) => fetch(
@@ -1060,15 +1069,13 @@ function vertex(config) {
1060
1069
  reasoning: model.includes("pro")
1061
1070
  },
1062
1071
  createSource: (request) => {
1072
+ const systemMessage = request.messages.find((message) => message.role === "system");
1063
1073
  const body = {
1064
1074
  contents: request.messages.filter((message) => message.role !== "system").map((message) => ({
1065
1075
  role: message.role === "assistant" ? "model" : "user",
1066
1076
  parts: [{ text: message.content }]
1067
1077
  })),
1068
- systemInstruction: request.messages.find((message) => message.role === "system") ? {
1069
- role: "system",
1070
- parts: [{ text: request.messages.find((message) => message.role === "system").content }]
1071
- } : void 0,
1078
+ systemInstruction: systemMessage ? { role: "system", parts: [{ text: systemMessage.content }] } : void 0,
1072
1079
  tools: request.context?.tools && request.context.tools.length > 0 ? [{
1073
1080
  functionDeclarations: request.context.tools.map((tool) => ({
1074
1081
  name: tool.name,
@@ -1364,8 +1371,28 @@ function pickSyncPolicy(pool, policy) {
1364
1371
  const c = pool.reduce((best, x) => (x.latencyMs ?? Infinity) < (best.latencyMs ?? Infinity) ? x : best, pool[0]);
1365
1372
  return { c, reason: "fastest" };
1366
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
+ }
1367
1391
  return { c: pool[0], reason: "capability-match" };
1368
1392
  }
1393
+ function matchesRegion(candidate, region) {
1394
+ return region === void 0 || candidate.region === region;
1395
+ }
1369
1396
  function createRouter(options) {
1370
1397
  const { candidates } = options;
1371
1398
  if (candidates.length === 0) {
@@ -1379,22 +1406,31 @@ function createRouter(options) {
1379
1406
  return {
1380
1407
  createSource: (request) => {
1381
1408
  const need = requireCapabilities(request);
1409
+ const region = options.regionOf?.(request) ?? options.region;
1382
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
+ }
1383
1419
  const classified = options.classify?.(request);
1384
1420
  if (typeof classified === "string") {
1385
- const c2 = capable.find((x) => x.id === classified);
1421
+ const c2 = eligible.find((x) => x.id === classified);
1386
1422
  if (c2) {
1387
- options.onRoute?.({ id: c2.id, reason: "classify:id", request });
1423
+ options.onRoute?.({ id: c2.id, reason: region ? `classify:id:${region}` : "classify:id", request });
1388
1424
  return c2.adapter.createSource(request);
1389
1425
  }
1390
1426
  }
1391
- let pool = capable;
1427
+ let pool = eligible;
1392
1428
  let pickedBy;
1393
1429
  if (Array.isArray(classified) && classified.length > 0) {
1394
- 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)));
1395
1431
  if (filtered.length > 0) {
1396
1432
  pool = filtered;
1397
- pickedBy = "classify:tags";
1433
+ pickedBy = region ? `classify:tags:${region}` : "classify:tags";
1398
1434
  }
1399
1435
  }
1400
1436
  if (pool.length === 0) {
@@ -1442,6 +1478,57 @@ function createRouter(options) {
1442
1478
  }
1443
1479
  };
1444
1480
  }
1481
+
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
+ }
1445
1532
  async function drain(source, timeoutMs) {
1446
1533
  const chunks = [];
1447
1534
  let text = "";
@@ -1712,16 +1799,23 @@ function replayAdapter(fixture) {
1712
1799
  });
1713
1800
  }
1714
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
+
1715
1812
  // src/embedders/openai.ts
1716
1813
  async function fetchAvailableModels(baseUrl, apiKey) {
1717
1814
  const url = `${baseUrl}/v1/models`;
1718
1815
  const response = await fetch(url, {
1719
1816
  headers: { "Authorization": `Bearer ${apiKey}` }
1720
1817
  });
1721
- if (!response.ok) {
1722
- const body = await response.text().catch(() => "");
1723
- throw new Error(`HTTP ${response.status} from ${url}: ${body.slice(0, 200)}`);
1724
- }
1818
+ await throwIfNotOk(response, "openai", url);
1725
1819
  const data = await response.json();
1726
1820
  return data.data.map((m) => m.id).filter((id) => id.includes("embed")).sort();
1727
1821
  }
@@ -1763,10 +1857,7 @@ function openaiEmbedder(config) {
1763
1857
  async function fetchAvailableModels2(baseUrl, apiKey) {
1764
1858
  const url = `${baseUrl}/v1beta/models?key=${apiKey}`;
1765
1859
  const response = await fetch(url);
1766
- if (!response.ok) {
1767
- const body = await response.text().catch(() => "");
1768
- throw new Error(`HTTP ${response.status} from gemini ${baseUrl}/v1beta/models: ${body.slice(0, 200)}`);
1769
- }
1860
+ await throwIfNotOk(response, "gemini", `${baseUrl}/v1beta/models`);
1770
1861
  const data = await response.json();
1771
1862
  return data.models.filter((m) => m.supportedGenerationMethods.includes("embedContent")).map((m) => m.name.replace("models/", "")).sort();
1772
1863
  }
@@ -1815,10 +1906,7 @@ function geminiEmbedder(config) {
1815
1906
  async function fetchAvailableModels3(baseUrl) {
1816
1907
  const url = `${baseUrl}/api/tags`;
1817
1908
  const response = await fetch(url);
1818
- if (!response.ok) {
1819
- const body = await response.text().catch(() => "");
1820
- throw new Error(`HTTP ${response.status} from ollama ${url}: ${body.slice(0, 200)}`);
1821
- }
1909
+ await throwIfNotOk(response, "ollama", url);
1822
1910
  const data = await response.json();
1823
1911
  return data.models.map((m) => m.name).filter((name) => name.includes("embed")).sort();
1824
1912
  }
@@ -1852,21 +1940,18 @@ function ollamaEmbedder(config) {
1852
1940
  return data.embeddings[0];
1853
1941
  };
1854
1942
  }
1855
- async function fetchAvailableModels4(baseUrl, apiKey) {
1943
+ async function fetchAvailableModels4(provider, baseUrl, apiKey) {
1856
1944
  const url = `${baseUrl}/v1/models`;
1857
1945
  const response = await fetch(url, {
1858
1946
  headers: { "Authorization": `Bearer ${apiKey}` }
1859
1947
  });
1860
- if (!response.ok) {
1861
- const body = await response.text().catch(() => "");
1862
- throw new Error(`HTTP ${response.status} from ${url}: ${body.slice(0, 200)}`);
1863
- }
1948
+ await throwIfNotOk(response, provider, url);
1864
1949
  const data = await response.json();
1865
1950
  return data.data.map((m) => m.id).filter((id) => id.includes("embed")).sort();
1866
1951
  }
1867
1952
  async function buildModelError4(provider, baseUrl, apiKey, originalError) {
1868
1953
  try {
1869
- const models = await fetchAvailableModels4(baseUrl, apiKey);
1954
+ const models = await fetchAvailableModels4(provider, baseUrl, apiKey);
1870
1955
  const list = models.length > 0 ? models.join(", ") : "none found";
1871
1956
  return new Error(
1872
1957
  `${provider} embedding failed: ${originalError}. Available embedding models: ${list}`
@@ -1915,8 +2000,95 @@ var grokEmbedder = createOpenAICompatibleEmbedder("Grok", "https://api.x.ai");
1915
2000
 
1916
2001
  // src/embedders/kimi.ts
1917
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
+ }
1918
2087
 
2088
+ exports.DEFAULT_CARBON_TABLE = DEFAULT_CARBON_TABLE;
2089
+ exports.DEFAULT_DEPRECATION_TABLE = DEFAULT_DEPRECATION_TABLE;
1919
2090
  exports.anthropic = anthropic;
2091
+ exports.applyCarbonTable = applyCarbonTable;
1920
2092
  exports.azureOpenAI = azureOpenAI;
1921
2093
  exports.azureOpenAIAdapter = azureOpenAIAdapter;
1922
2094
  exports.bail = bail;
@@ -1932,9 +2104,11 @@ exports.createAdapter = createAdapter;
1932
2104
  exports.createEnsembleAdapter = createEnsembleAdapter;
1933
2105
  exports.createFallbackAdapter = createFallbackAdapter;
1934
2106
  exports.createOpenAICompatibleEmbedder = createOpenAICompatibleEmbedder;
2107
+ exports.createRotatingCredentials = createRotatingCredentials;
1935
2108
  exports.createRouter = createRouter;
1936
2109
  exports.deepseek = deepseek;
1937
2110
  exports.deepseekEmbedder = deepseekEmbedder;
2111
+ exports.estimateCO2Grams = estimateCO2Grams;
1938
2112
  exports.fetchWithRetry = fetchWithRetry;
1939
2113
  exports.fireworks = fireworks;
1940
2114
  exports.gemini = gemini;
@@ -1961,9 +2135,11 @@ exports.openaiEmbedder = openaiEmbedder;
1961
2135
  exports.openrouter = openrouter;
1962
2136
  exports.qwen = qwen;
1963
2137
  exports.recordingAdapter = recordingAdapter;
2138
+ exports.refreshCredentials = refreshCredentials;
1964
2139
  exports.replayAdapter = replayAdapter;
1965
2140
  exports.replicate = replicate;
1966
2141
  exports.replicateAdapter = replicateAdapter;
2142
+ exports.resolveModel = resolveModel;
1967
2143
  exports.simulateStream = simulateStream;
1968
2144
  exports.together = together;
1969
2145
  exports.vercelAI = vercelAI;
@@ -1972,5 +2148,6 @@ exports.vertexAdapter = vertexAdapter;
1972
2148
  exports.vllm = vllm;
1973
2149
  exports.webllm = webllm;
1974
2150
  exports.webllmAdapter = webllmAdapter;
2151
+ exports.withDeprecationPolicy = withDeprecationPolicy;
1975
2152
  //# sourceMappingURL=index.cjs.map
1976
2153
  //# sourceMappingURL=index.cjs.map