@t2000/engine 0.46.4 → 0.46.6

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/dist/index.d.ts CHANGED
@@ -1598,13 +1598,17 @@ interface AnthropicProviderConfig {
1598
1598
  apiKey: string;
1599
1599
  defaultModel?: string;
1600
1600
  defaultMaxTokens?: number;
1601
+ /** Max retry attempts for retriable errors (overloaded, rate-limited, network). Default 3. */
1602
+ maxRetries?: number;
1601
1603
  }
1602
1604
  declare class AnthropicProvider implements LLMProvider {
1603
1605
  private client;
1604
1606
  private defaultModel;
1605
1607
  private defaultMaxTokens;
1608
+ private maxRetries;
1606
1609
  constructor(config: AnthropicProviderConfig);
1607
1610
  chat(params: ChatParams): AsyncGenerator<ProviderEvent>;
1611
+ private streamOnce;
1608
1612
  }
1609
1613
 
1610
1614
  declare const CANVAS_TEMPLATES: readonly ["activity_heatmap", "portfolio_timeline", "yield_projector", "health_simulator", "dca_planner", "spending_breakdown", "watch_address", "full_portfolio"];
@@ -1640,12 +1644,23 @@ declare const healthCheckTool: Tool<{}, {
1640
1644
  status: string;
1641
1645
  }>;
1642
1646
 
1643
- declare const ratesInfoTool: Tool<{}, _t2000_sdk.RatesResult>;
1647
+ type RateMap = Record<string, {
1648
+ saveApy: number;
1649
+ borrowApy: number;
1650
+ }>;
1651
+ declare const ratesInfoTool: Tool<{
1652
+ assets?: string[] | undefined;
1653
+ stableOnly?: boolean | undefined;
1654
+ topN?: number | undefined;
1655
+ }, RateMap>;
1644
1656
 
1645
1657
  declare const transactionHistoryTool: Tool<{
1646
1658
  action?: "send" | "swap" | "transaction" | "lending" | undefined;
1647
1659
  date?: string | undefined;
1660
+ direction?: "out" | "in" | undefined;
1648
1661
  limit?: number | undefined;
1662
+ minUsd?: number | undefined;
1663
+ assetSymbol?: string | undefined;
1649
1664
  }, Record<string, unknown>>;
1650
1665
 
1651
1666
  declare const saveDepositTool: Tool<{
@@ -1739,6 +1754,7 @@ declare const payApiTool: Tool<{
1739
1754
  declare const mppServicesTool: Tool<{
1740
1755
  query?: string | undefined;
1741
1756
  category?: string | undefined;
1757
+ mode?: "summary" | "full" | undefined;
1742
1758
  }, Record<string, unknown>>;
1743
1759
 
1744
1760
  declare const swapExecuteTool: Tool<{
@@ -1926,6 +1942,7 @@ declare const activitySummaryTool: Tool<{
1926
1942
  }, ActivitySummary>;
1927
1943
 
1928
1944
  declare const defillamaYieldPoolsTool: Tool<{
1945
+ stableOnly?: boolean | undefined;
1929
1946
  limit?: number | undefined;
1930
1947
  chain?: string | undefined;
1931
1948
  project?: string | undefined;
package/dist/index.js CHANGED
@@ -977,6 +977,36 @@ var healthCheckTool = buildTool({
977
977
  }
978
978
  });
979
979
  var YIELDS_API = "https://yields.llama.fi";
980
+ var STABLECOIN_SYMBOLS2 = /* @__PURE__ */ new Set([
981
+ "usdc",
982
+ "wusdc",
983
+ "usdt",
984
+ "wusdt",
985
+ "suiusdt",
986
+ "usdy",
987
+ "usdsui",
988
+ "usde",
989
+ "ausd",
990
+ "fdusd",
991
+ "buck"
992
+ ]);
993
+ function isStable(symbol) {
994
+ return STABLECOIN_SYMBOLS2.has(symbol.toLowerCase());
995
+ }
996
+ function applyFilters(rates, opts) {
997
+ let entries = Object.entries(rates);
998
+ if (opts.assets && opts.assets.length) {
999
+ const wanted = new Set(opts.assets.map((a) => a.toLowerCase()));
1000
+ entries = entries.filter(([sym]) => wanted.has(sym.toLowerCase()));
1001
+ } else if (opts.stableOnly) {
1002
+ entries = entries.filter(([sym]) => isStable(sym));
1003
+ }
1004
+ entries.sort(([, a], [, b]) => b.saveApy - a.saveApy);
1005
+ if (opts.topN && opts.topN > 0) {
1006
+ entries = entries.slice(0, opts.topN);
1007
+ }
1008
+ return Object.fromEntries(entries);
1009
+ }
980
1010
  function formatRatesSummary(rates) {
981
1011
  return Object.entries(rates).map(([asset, r]) => `${asset}: Save ${(r.saveApy * 100).toFixed(2)}% / Borrow ${(r.borrowApy * 100).toFixed(2)}%`).join(", ");
982
1012
  }
@@ -997,22 +1027,52 @@ async function fetchRatesFromDefiLlama() {
997
1027
  }
998
1028
  var ratesInfoTool = buildTool({
999
1029
  name: "rates_info",
1000
- description: "Get current NAVI Protocol lending/savings rates (APY) for supported assets on Sui. Returns save APY and borrow APY per asset.",
1001
- inputSchema: z.object({}),
1002
- jsonSchema: { type: "object", properties: {}, required: [] },
1030
+ description: 'NAVI Protocol lending markets ONLY (single-sided save/borrow, no impermanent-loss risk). Use this for stablecoin and bluechip lending yields. Renders a rich rates card. Filter args: `assets` (specific symbols like ["USDC"]), `stableOnly` (true to show only USD-pegged assets), `topN` (max rows in card, default 8, max 50). Do NOT call defillama_yield_pools in the same turn \u2014 that tool is for LP/farming pools with IL risk, not lending.',
1031
+ inputSchema: z.object({
1032
+ assets: z.array(z.string()).optional().describe('Filter to specific asset symbols (e.g. ["USDC"], ["USDC","USDT","USDSUI"]). Case-insensitive.'),
1033
+ stableOnly: z.boolean().optional().describe("When true, return only stablecoin markets (USDC, USDT, USDSUI, USDY, suiUSDT, etc.). Ignored when `assets` is supplied."),
1034
+ topN: z.number().int().min(1).max(50).optional().describe("Cap the number of rows in the card (default 8). Use 50 to render the full NAVI catalog.")
1035
+ }),
1036
+ jsonSchema: {
1037
+ type: "object",
1038
+ properties: {
1039
+ assets: {
1040
+ type: "array",
1041
+ items: { type: "string" },
1042
+ description: "Filter to specific asset symbols (case-insensitive)."
1043
+ },
1044
+ stableOnly: {
1045
+ type: "boolean",
1046
+ description: "When true, return only stablecoin markets. Ignored when `assets` is supplied."
1047
+ },
1048
+ topN: {
1049
+ type: "number",
1050
+ description: "Cap the number of rows in the card (default 8, max 50)."
1051
+ }
1052
+ },
1053
+ required: []
1054
+ },
1003
1055
  isReadOnly: true,
1004
- async call(_input, context) {
1056
+ async call(input, context) {
1057
+ const opts = {
1058
+ assets: input.assets,
1059
+ stableOnly: input.stableOnly,
1060
+ topN: input.topN ?? 8
1061
+ };
1005
1062
  if (hasNaviMcpGlobal(context)) {
1006
- const rates2 = await fetchRates(getMcpManager(context));
1007
- return { data: rates2, displayText: formatRatesSummary(rates2) };
1063
+ const all2 = await fetchRates(getMcpManager(context));
1064
+ const filtered2 = applyFilters(all2, opts);
1065
+ return { data: filtered2, displayText: formatRatesSummary(filtered2) };
1008
1066
  }
1009
1067
  if (hasAgent(context)) {
1010
1068
  const agent = requireAgent(context);
1011
- const rates2 = await agent.rates();
1012
- return { data: rates2, displayText: formatRatesSummary(rates2) };
1069
+ const all2 = await agent.rates();
1070
+ const filtered2 = applyFilters(all2, opts);
1071
+ return { data: filtered2, displayText: formatRatesSummary(filtered2) };
1013
1072
  }
1014
- const rates = await fetchRatesFromDefiLlama();
1015
- return { data: rates, displayText: formatRatesSummary(rates) };
1073
+ const all = await fetchRatesFromDefiLlama();
1074
+ const filtered = applyFilters(all, opts);
1075
+ return { data: filtered, displayText: formatRatesSummary(filtered) };
1016
1076
  }
1017
1077
  });
1018
1078
  function parseRpcTx(tx, address) {
@@ -1114,11 +1174,14 @@ var HISTORY_ACTIONS = ["send", "lending", "swap", "transaction"];
1114
1174
  var DEFAULT_LOOKBACK_DAYS = 30;
1115
1175
  var transactionHistoryTool = buildTool({
1116
1176
  name: "transaction_history",
1117
- description: "Retrieve recent transaction history (last 30 days by default): sends, saves, withdrawals, borrows, repayments, and rewards claims. Pass `date` (YYYY-MM-DD) for a specific day, `action` to filter by category (send/lending/swap), or both.",
1177
+ description: 'Retrieve recent transaction history (last 30 days by default): sends, saves, withdrawals, borrows, repayments, swaps, and rewards claims. Renders a rich transaction card. Filter args: `date` (YYYY-MM-DD), `action` (send/lending/swap), `minUsd` (minimum amount in USD \u2014 use this for "transactions over $X" instead of post-filtering), `assetSymbol` (e.g. "USDC", "SUI"), `direction` ("in" or "out"). The card itself respects all filters \u2014 never re-list the rows in narration.',
1118
1178
  inputSchema: z.object({
1119
1179
  limit: z.number().int().min(1).max(50).optional(),
1120
1180
  date: z.string().optional().describe("Specific date to search for transactions (YYYY-MM-DD format). Paginates back to find that day."),
1121
- action: z.enum(HISTORY_ACTIONS).optional().describe("Filter by action: send, lending, swap, or transaction.")
1181
+ action: z.enum(HISTORY_ACTIONS).optional().describe("Filter by action: send, lending, swap, or transaction."),
1182
+ minUsd: z.number().min(0).optional().describe('Minimum transaction amount in USD. Use this for "transactions over $X" \u2014 the amount is converted to USD using the asset price snapshot.'),
1183
+ assetSymbol: z.string().optional().describe('Filter to a single asset symbol (case-insensitive, e.g. "USDC", "SUI", "LOFI"). Matches `tx.asset` exactly.'),
1184
+ direction: z.enum(["in", "out"]).optional().describe('Filter by user-side balance flow: "in" = received, "out" = spent.')
1122
1185
  }),
1123
1186
  jsonSchema: {
1124
1187
  type: "object",
@@ -1135,6 +1198,19 @@ var transactionHistoryTool = buildTool({
1135
1198
  type: "string",
1136
1199
  enum: [...HISTORY_ACTIONS],
1137
1200
  description: "Filter results by action category: send, lending, swap, or transaction."
1201
+ },
1202
+ minUsd: {
1203
+ type: "number",
1204
+ description: 'Minimum transaction amount in USD. Use this for "transactions over $X" queries.'
1205
+ },
1206
+ assetSymbol: {
1207
+ type: "string",
1208
+ description: 'Filter to a single asset symbol (case-insensitive, e.g. "USDC", "SUI").'
1209
+ },
1210
+ direction: {
1211
+ type: "string",
1212
+ enum: ["in", "out"],
1213
+ description: 'Filter by direction of user balance change: "in" = received, "out" = spent.'
1138
1214
  }
1139
1215
  }
1140
1216
  },
@@ -1183,17 +1259,48 @@ var transactionHistoryTool = buildTool({
1183
1259
  async call(input, context) {
1184
1260
  const limit = input.limit ?? 10;
1185
1261
  const action = input.action;
1262
+ const assetSymbol = input.assetSymbol?.toLowerCase();
1263
+ const direction = input.direction;
1264
+ const minUsd = input.minUsd;
1265
+ const prices = context.tokenPrices;
1266
+ const priceFor = (sym) => {
1267
+ if (!sym || !prices) return void 0;
1268
+ return prices[sym.toUpperCase()] ?? prices[sym.toLowerCase()] ?? prices[sym];
1269
+ };
1186
1270
  const finalize = (records2) => {
1187
1271
  let scoped = records2;
1188
1272
  if (action) scoped = scoped.filter((r) => r.action === action);
1273
+ if (assetSymbol) {
1274
+ scoped = scoped.filter((r) => r.asset?.toLowerCase() === assetSymbol);
1275
+ }
1276
+ if (direction) {
1277
+ scoped = scoped.filter((r) => r.direction === direction);
1278
+ }
1279
+ if (minUsd != null && minUsd > 0) {
1280
+ scoped = scoped.filter((r) => {
1281
+ if (r.amount == null) return false;
1282
+ const sym = r.asset?.toUpperCase() ?? "";
1283
+ const isStableLike = sym === "USDC" || sym === "USDT" || sym === "WUSDC" || sym === "WUSDT" || sym === "SUIUSDT" || sym === "USDY" || sym === "USDSUI" || sym === "USDE" || sym === "AUSD" || sym === "FDUSD" || sym === "BUCK";
1284
+ const usd = isStableLike ? r.amount : (priceFor(sym) ?? 0) * r.amount;
1285
+ if (!isStableLike && priceFor(sym) == null) return true;
1286
+ return usd >= minUsd;
1287
+ });
1288
+ }
1189
1289
  return scoped.slice(0, limit);
1190
1290
  };
1291
+ const filterMeta = {
1292
+ date: input.date ?? null,
1293
+ action: action ?? null,
1294
+ minUsd: minUsd ?? null,
1295
+ assetSymbol: input.assetSymbol ?? null,
1296
+ direction: direction ?? null
1297
+ };
1191
1298
  if (context.agent) {
1192
1299
  const agent = requireAgent(context);
1193
1300
  const records2 = await agent.history({ limit: input.date ? limit : Math.max(limit * 4, 50) });
1194
1301
  const filtered2 = finalize(records2);
1195
1302
  return {
1196
- data: { transactions: filtered2, count: filtered2.length, date: input.date ?? null, action: action ?? null },
1303
+ data: { transactions: filtered2, count: filtered2.length, ...filterMeta },
1197
1304
  displayText: `${filtered2.length} recent transaction(s)`
1198
1305
  };
1199
1306
  }
@@ -1210,7 +1317,7 @@ var transactionHistoryTool = buildTool({
1210
1317
  const filtered2 = finalize(records2);
1211
1318
  const dateLabel = new Date(input.date).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
1212
1319
  return {
1213
- data: { transactions: filtered2, count: filtered2.length, date: input.date, action: action ?? null },
1320
+ data: { transactions: filtered2, count: filtered2.length, ...filterMeta },
1214
1321
  displayText: filtered2.length > 0 ? `${filtered2.length} transaction(s) on ${dateLabel}` : `No transactions found on ${dateLabel}`
1215
1322
  };
1216
1323
  }
@@ -1226,8 +1333,7 @@ var transactionHistoryTool = buildTool({
1226
1333
  data: {
1227
1334
  transactions: filtered,
1228
1335
  count: filtered.length,
1229
- date: null,
1230
- action: action ?? null,
1336
+ ...filterMeta,
1231
1337
  lookbackDays: DEFAULT_LOOKBACK_DAYS
1232
1338
  },
1233
1339
  displayText: `${filtered.length} transaction(s) in the last ${DEFAULT_LOOKBACK_DAYS} days`
@@ -1610,10 +1716,11 @@ function matchesQuery(service, q) {
1610
1716
  }
1611
1717
  var mppServicesTool = buildTool({
1612
1718
  name: "mpp_services",
1613
- description: "Discover available MPP gateway services. Returns service names, descriptions, endpoints with required parameters, and pricing. Pass `query` for keyword search or `category` to filter by category. Calling with NO filters returns a category summary (not the full catalog) \u2014 narrow first, then fetch endpoints. Use this BEFORE calling pay_api.",
1719
+ description: 'Discover available MPP gateway services. Returns service names, descriptions, endpoints with required parameters, and pricing. Use BEFORE calling pay_api. Modes: pass `query` for keyword search, `category` to filter by category, or `mode: "full"` to fetch the ENTIRE catalog in one card (for "show me all MPP services" / "full catalog" requests \u2014 never enumerate per category in a loop). Calling with no args returns a category summary so you can narrow.',
1614
1720
  inputSchema: z.object({
1615
1721
  query: z.string().optional().describe('Filter by keyword (e.g. "postcard", "translate", "weather").'),
1616
- category: z.string().optional().describe('Filter by category exactly (e.g. "weather", "image"). See category summary returned when called without filters.')
1722
+ category: z.string().optional().describe('Filter by category exactly (e.g. "weather", "image"). See category summary returned when called without filters.'),
1723
+ mode: z.enum(["summary", "full"]).optional().describe('"full" returns the entire catalog in a single card \u2014 use this for "show me all MPP services" / "full catalog" requests instead of looping per category. Default is "summary" (category counts only when no filter is supplied).')
1617
1724
  }),
1618
1725
  jsonSchema: {
1619
1726
  type: "object",
@@ -1625,14 +1732,40 @@ var mppServicesTool = buildTool({
1625
1732
  category: {
1626
1733
  type: "string",
1627
1734
  description: 'Filter by category exactly (e.g. "weather", "image").'
1735
+ },
1736
+ mode: {
1737
+ type: "string",
1738
+ enum: ["summary", "full"],
1739
+ description: '"full" returns the entire catalog in one card. Use for "show me all" requests.'
1628
1740
  }
1629
1741
  },
1630
1742
  required: []
1631
1743
  },
1632
1744
  isReadOnly: true,
1633
- maxResultSizeChars: 5e3,
1745
+ // [v0.46.6] Bumped to fit the full catalog (~40 services) in one
1746
+ // shot when `mode: 'full'` is used. The summarizeOnTruncate path
1747
+ // still applies if the catalog ever exceeds the budget.
1748
+ maxResultSizeChars: 12e3,
1634
1749
  async call(input) {
1635
1750
  const catalog = await fetchCatalog();
1751
+ if (input.mode === "full") {
1752
+ const services2 = catalog.map((s) => ({
1753
+ id: s.id,
1754
+ name: s.name,
1755
+ description: s.description,
1756
+ categories: s.categories,
1757
+ endpoints: s.endpoints.map((e) => ({
1758
+ url: `${MPP_GATEWAY2}/${s.id}${e.path}`,
1759
+ method: e.method,
1760
+ description: e.description,
1761
+ price: `$${e.price}`
1762
+ }))
1763
+ }));
1764
+ return {
1765
+ data: { services: services2, total: services2.length, mode: "full" },
1766
+ displayText: `Full MPP catalog: ${services2.length} services.`
1767
+ };
1768
+ }
1636
1769
  if (!input.query && !input.category) {
1637
1770
  const counts = /* @__PURE__ */ new Map();
1638
1771
  for (const svc of catalog) {
@@ -1644,13 +1777,14 @@ var mppServicesTool = buildTool({
1644
1777
  return {
1645
1778
  data: {
1646
1779
  _refine: {
1647
- reason: "MPP catalog has many services \u2014 pick a category or supply a query first.",
1648
- suggestedParams: { category: categories[0]?.category ?? "weather" }
1780
+ reason: 'MPP catalog has many services \u2014 pick a category, supply a query, or pass mode:"full" to fetch everything.',
1781
+ suggestedParams: { category: categories[0]?.category ?? "weather" },
1782
+ allModes: ["summary", "full"]
1649
1783
  },
1650
1784
  categories,
1651
1785
  totalServices: catalog.length
1652
1786
  },
1653
- displayText: `${catalog.length} services across ${categories.length} categories. Re-call with a category or query.`
1787
+ displayText: `${catalog.length} services across ${categories.length} categories. Re-call with a category, query, or mode:"full".`
1654
1788
  };
1655
1789
  }
1656
1790
  let filtered = catalog;
@@ -2933,22 +3067,44 @@ function fmtToolTvl(tvl) {
2933
3067
  if (tvl >= 1e3) return `$${(tvl / 1e3).toFixed(0)}K`;
2934
3068
  return `$${tvl}`;
2935
3069
  }
3070
+ var POOL_STABLE_LEGS = /* @__PURE__ */ new Set([
3071
+ "USDC",
3072
+ "WUSDC",
3073
+ "USDT",
3074
+ "WUSDT",
3075
+ "SUIUSDT",
3076
+ "USDY",
3077
+ "USDSUI",
3078
+ "USDE",
3079
+ "AUSD",
3080
+ "FDUSD",
3081
+ "BUCK",
3082
+ "DAI",
3083
+ "LUSD",
3084
+ "FRAX",
3085
+ "GUSD",
3086
+ "PYUSD",
3087
+ "USDS",
3088
+ "CRVUSD"
3089
+ ]);
2936
3090
  var defillamaYieldPoolsTool = buildTool({
2937
3091
  name: "defillama_yield_pools",
2938
- description: 'Get top DeFi yield pools across protocols. Filter by chain (e.g. "Sui"), project (e.g. "navi-lending"), and minimum TVL. For NAVI lending rates, use project "navi-lending".',
3092
+ description: 'Cross-protocol LP / vault yields with IMPERMANENT-LOSS RISK (Cetus, Bluefin, Full Sail, etc.). ONLY call when the user explicitly asks about LP pools, DeFi farming, or "higher yield with more risk". For safe single-sided lending yields (USDC save, NAVI, etc.) use rates_info instead \u2014 NEVER both in the same turn. Filter by chain (e.g. "Sui"), project, and minimum TVL.',
2939
3093
  inputSchema: z.object({
2940
3094
  chain: z.string().optional().describe('Filter by chain name (e.g. "Sui", "Ethereum")'),
2941
- project: z.string().optional().describe('Filter by protocol project name (e.g. "navi-lending", "cetus-clmm")'),
3095
+ project: z.string().optional().describe('Filter by protocol project name (e.g. "cetus-clmm", "bluefin-spot")'),
2942
3096
  limit: z.number().min(1).max(20).optional().describe("Max results (default 5)"),
2943
- minTvl: z.number().optional().describe("Minimum TVL in USD to filter out small/risky pools (default 100000)")
3097
+ minTvl: z.number().optional().describe("Minimum TVL in USD to filter out small/risky pools (default 100000)"),
3098
+ stableOnly: z.boolean().optional().describe('When true, only return pools where every leg is a stablecoin (USDC, USDT, USDSUI, etc.). Use this for "show stablecoin yield options" \u2014 keeps volatile-pair LPs (WAL-SUI, DEEP-SUI) out.')
2944
3099
  }),
2945
3100
  jsonSchema: {
2946
3101
  type: "object",
2947
3102
  properties: {
2948
3103
  chain: { type: "string", description: "Filter by chain name" },
2949
- project: { type: "string", description: 'Filter by protocol project name (e.g. "navi-lending")' },
3104
+ project: { type: "string", description: 'Filter by protocol project name (e.g. "cetus-clmm")' },
2950
3105
  limit: { type: "number", description: "Max results (default 5)" },
2951
- minTvl: { type: "number", description: "Minimum TVL in USD (default 100000)" }
3106
+ minTvl: { type: "number", description: "Minimum TVL in USD (default 100000)" },
3107
+ stableOnly: { type: "boolean", description: "When true, only return all-stablecoin pools." }
2952
3108
  },
2953
3109
  required: []
2954
3110
  },
@@ -2984,6 +3140,12 @@ var defillamaYieldPoolsTool = buildTool({
2984
3140
  }
2985
3141
  const minTvl = input.minTvl ?? 1e5;
2986
3142
  pools = pools.filter((p) => p.tvlUsd >= minTvl);
3143
+ if (input.stableOnly) {
3144
+ pools = pools.filter((p) => {
3145
+ const legs = p.symbol.split("-");
3146
+ return legs.every((leg) => POOL_STABLE_LEGS.has(leg.trim().toUpperCase()));
3147
+ });
3148
+ }
2987
3149
  pools.sort((a, b) => b.apy - a.apy);
2988
3150
  const limit = input.limit ?? 5;
2989
3151
  const top = pools.slice(0, limit);
@@ -5729,16 +5891,51 @@ function adaptAllServerTools(manager, serverConfigs) {
5729
5891
  }
5730
5892
  var DEFAULT_MODEL = "claude-sonnet-4-20250514";
5731
5893
  var DEFAULT_MAX_TOKENS2 = 4096;
5894
+ var DEFAULT_MAX_RETRIES = 3;
5895
+ var RETRY_BASE_DELAY_MS = 1e3;
5896
+ var RETRY_MAX_DELAY_MS = 8e3;
5732
5897
  var AnthropicProvider = class {
5733
5898
  client;
5734
5899
  defaultModel;
5735
5900
  defaultMaxTokens;
5901
+ maxRetries;
5736
5902
  constructor(config) {
5737
5903
  this.client = new Anthropic({ apiKey: config.apiKey });
5738
5904
  this.defaultModel = config.defaultModel ?? DEFAULT_MODEL;
5739
5905
  this.defaultMaxTokens = config.defaultMaxTokens ?? DEFAULT_MAX_TOKENS2;
5906
+ this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
5740
5907
  }
5741
5908
  async *chat(params) {
5909
+ let attempt = 0;
5910
+ while (true) {
5911
+ let yieldedAnything = false;
5912
+ const inner = this.streamOnce(params);
5913
+ try {
5914
+ for (; ; ) {
5915
+ const next = await inner.next();
5916
+ if (next.done) return;
5917
+ yieldedAnything = true;
5918
+ yield next.value;
5919
+ }
5920
+ } catch (err) {
5921
+ try {
5922
+ await inner.return?.(void 0);
5923
+ } catch {
5924
+ }
5925
+ if (!yieldedAnything && isRetriableError(err) && attempt < this.maxRetries) {
5926
+ attempt++;
5927
+ const delayMs = computeBackoffMs(attempt);
5928
+ console.warn(
5929
+ `[anthropic] retriable error (attempt ${attempt}/${this.maxRetries}, retrying in ${delayMs}ms): ${rawErrorMessage(err)}`
5930
+ );
5931
+ await sleep(delayMs);
5932
+ continue;
5933
+ }
5934
+ throw new Error(friendlyErrorMessage(err));
5935
+ }
5936
+ }
5937
+ }
5938
+ async *streamOnce(params) {
5742
5939
  const messages = sanitizeAnthropicMessages(
5743
5940
  params.messages.map(toAnthropicMessage)
5744
5941
  );
@@ -5895,6 +6092,59 @@ var AnthropicProvider = class {
5895
6092
  }
5896
6093
  }
5897
6094
  };
6095
+ function isRetriableError(err) {
6096
+ if (!err) return false;
6097
+ if (err instanceof Anthropic.APIError) {
6098
+ if (err.status === 529 || err.status === 408) return true;
6099
+ if (err.status === 502 || err.status === 503 || err.status === 504) return true;
6100
+ if (err.status === 429) return true;
6101
+ return false;
6102
+ }
6103
+ const msg = rawErrorMessage(err).toLowerCase();
6104
+ if (msg.includes("overloaded_error") || msg.includes('"overloaded"') || msg.includes("rate_limit_error") || msg.includes("econnreset") || msg.includes("etimedout") || msg.includes("socket hang up") || msg.includes("fetch failed") || msg.includes("network error")) {
6105
+ return true;
6106
+ }
6107
+ return false;
6108
+ }
6109
+ function rawErrorMessage(err) {
6110
+ if (err instanceof Error) return err.message;
6111
+ if (typeof err === "string") return err;
6112
+ try {
6113
+ return JSON.stringify(err);
6114
+ } catch {
6115
+ return String(err);
6116
+ }
6117
+ }
6118
+ function friendlyErrorMessage(err) {
6119
+ const msg = rawErrorMessage(err).toLowerCase();
6120
+ if (msg.includes("overloaded_error") || msg.includes('"overloaded"') || err instanceof Anthropic.APIError && err.status === 529) {
6121
+ return "Anthropic's servers are over capacity right now. Please try again in 30 seconds.";
6122
+ }
6123
+ if (msg.includes("rate_limit_error") || err instanceof Anthropic.APIError && err.status === 429) {
6124
+ return "Too many requests in a short window. Please wait a moment and try again.";
6125
+ }
6126
+ if (msg.includes("econnreset") || msg.includes("etimedout") || msg.includes("socket hang up") || msg.includes("fetch failed") || msg.includes("network error")) {
6127
+ return "Couldn't reach Anthropic. Check your connection and try again.";
6128
+ }
6129
+ if (err instanceof Anthropic.APIError && err.status === 401) {
6130
+ return "Authentication failed. Please check the Anthropic API key configuration.";
6131
+ }
6132
+ if (err instanceof Anthropic.APIError && err.status === 400) {
6133
+ return "The request was rejected by Anthropic. This is likely a bug \u2014 please retry, and if it persists, contact support.";
6134
+ }
6135
+ if (err instanceof Anthropic.APIError && err.status >= 500) {
6136
+ return "Anthropic returned a server error. Please try again in a moment.";
6137
+ }
6138
+ return "Something went wrong. Please try again.";
6139
+ }
6140
+ function computeBackoffMs(attempt) {
6141
+ const base = Math.min(RETRY_BASE_DELAY_MS * 2 ** (attempt - 1), RETRY_MAX_DELAY_MS);
6142
+ const jitter = Math.floor(Math.random() * 250);
6143
+ return base + jitter;
6144
+ }
6145
+ function sleep(ms) {
6146
+ return new Promise((resolve) => setTimeout(resolve, ms));
6147
+ }
5898
6148
  function toAnthropicSystem(prompt) {
5899
6149
  if (typeof prompt === "string") return prompt;
5900
6150
  return prompt.map((block) => ({