@t2000/engine 0.46.5 → 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
@@ -1644,12 +1644,23 @@ declare const healthCheckTool: Tool<{}, {
1644
1644
  status: string;
1645
1645
  }>;
1646
1646
 
1647
- 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>;
1648
1656
 
1649
1657
  declare const transactionHistoryTool: Tool<{
1650
1658
  action?: "send" | "swap" | "transaction" | "lending" | undefined;
1651
1659
  date?: string | undefined;
1660
+ direction?: "out" | "in" | undefined;
1652
1661
  limit?: number | undefined;
1662
+ minUsd?: number | undefined;
1663
+ assetSymbol?: string | undefined;
1653
1664
  }, Record<string, unknown>>;
1654
1665
 
1655
1666
  declare const saveDepositTool: Tool<{
@@ -1743,6 +1754,7 @@ declare const payApiTool: Tool<{
1743
1754
  declare const mppServicesTool: Tool<{
1744
1755
  query?: string | undefined;
1745
1756
  category?: string | undefined;
1757
+ mode?: "summary" | "full" | undefined;
1746
1758
  }, Record<string, unknown>>;
1747
1759
 
1748
1760
  declare const swapExecuteTool: Tool<{
@@ -1930,6 +1942,7 @@ declare const activitySummaryTool: Tool<{
1930
1942
  }, ActivitySummary>;
1931
1943
 
1932
1944
  declare const defillamaYieldPoolsTool: Tool<{
1945
+ stableOnly?: boolean | undefined;
1933
1946
  limit?: number | undefined;
1934
1947
  chain?: string | undefined;
1935
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);