@t2000/engine 0.46.5 → 0.46.7
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 +40 -1
- package/dist/index.js +251 -41
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -922,6 +922,32 @@ declare class QueryEngine {
|
|
|
922
922
|
reset(): void;
|
|
923
923
|
getGuardEvents(): readonly GuardEvent[];
|
|
924
924
|
loadMessages(messages: Message[]): void;
|
|
925
|
+
/**
|
|
926
|
+
* [v0.46.7] Run a read-only tool out-of-band, using the engine's tool
|
|
927
|
+
* registry and ToolContext. Used by hosts to deterministically pre-dispatch
|
|
928
|
+
* tools based on user-message intent (e.g. always call `balance_check` when
|
|
929
|
+
* the user says "what's my net worth?", regardless of whether the LLM would
|
|
930
|
+
* have otherwise re-called it).
|
|
931
|
+
*
|
|
932
|
+
* The host is responsible for:
|
|
933
|
+
* - Streaming the synthetic `tool_start` + `tool_result` events to the UI
|
|
934
|
+
* (so cards render as if the LLM had called the tool).
|
|
935
|
+
* - Appending matching `tool_use` + `tool_result` ContentBlocks to the
|
|
936
|
+
* engine's message history via `loadMessages([...getMessages(), ...synth])`
|
|
937
|
+
* BEFORE calling `submitMessage`, so the LLM sees the fresh data and
|
|
938
|
+
* doesn't re-call.
|
|
939
|
+
*
|
|
940
|
+
* Throws if the tool isn't registered, isn't read-only, or fails input
|
|
941
|
+
* validation. Tool execution errors are returned as `{ data, isError: true }`
|
|
942
|
+
* for the caller to handle (typically: skip the injection so the LLM falls
|
|
943
|
+
* back to its normal flow).
|
|
944
|
+
*/
|
|
945
|
+
invokeReadTool(toolName: string, input: unknown, options?: {
|
|
946
|
+
signal?: AbortSignal;
|
|
947
|
+
}): Promise<{
|
|
948
|
+
data: unknown;
|
|
949
|
+
isError: boolean;
|
|
950
|
+
}>;
|
|
925
951
|
setServerPositions(data: EngineConfig['serverPositions']): void;
|
|
926
952
|
getUsage(): CostSnapshot;
|
|
927
953
|
/**
|
|
@@ -1644,12 +1670,23 @@ declare const healthCheckTool: Tool<{}, {
|
|
|
1644
1670
|
status: string;
|
|
1645
1671
|
}>;
|
|
1646
1672
|
|
|
1647
|
-
|
|
1673
|
+
type RateMap = Record<string, {
|
|
1674
|
+
saveApy: number;
|
|
1675
|
+
borrowApy: number;
|
|
1676
|
+
}>;
|
|
1677
|
+
declare const ratesInfoTool: Tool<{
|
|
1678
|
+
assets?: string[] | undefined;
|
|
1679
|
+
stableOnly?: boolean | undefined;
|
|
1680
|
+
topN?: number | undefined;
|
|
1681
|
+
}, RateMap>;
|
|
1648
1682
|
|
|
1649
1683
|
declare const transactionHistoryTool: Tool<{
|
|
1650
1684
|
action?: "send" | "swap" | "transaction" | "lending" | undefined;
|
|
1651
1685
|
date?: string | undefined;
|
|
1686
|
+
direction?: "out" | "in" | undefined;
|
|
1652
1687
|
limit?: number | undefined;
|
|
1688
|
+
minUsd?: number | undefined;
|
|
1689
|
+
assetSymbol?: string | undefined;
|
|
1653
1690
|
}, Record<string, unknown>>;
|
|
1654
1691
|
|
|
1655
1692
|
declare const saveDepositTool: Tool<{
|
|
@@ -1743,6 +1780,7 @@ declare const payApiTool: Tool<{
|
|
|
1743
1780
|
declare const mppServicesTool: Tool<{
|
|
1744
1781
|
query?: string | undefined;
|
|
1745
1782
|
category?: string | undefined;
|
|
1783
|
+
mode?: "summary" | "full" | undefined;
|
|
1746
1784
|
}, Record<string, unknown>>;
|
|
1747
1785
|
|
|
1748
1786
|
declare const swapExecuteTool: Tool<{
|
|
@@ -1930,6 +1968,7 @@ declare const activitySummaryTool: Tool<{
|
|
|
1930
1968
|
}, ActivitySummary>;
|
|
1931
1969
|
|
|
1932
1970
|
declare const defillamaYieldPoolsTool: Tool<{
|
|
1971
|
+
stableOnly?: boolean | undefined;
|
|
1933
1972
|
limit?: number | undefined;
|
|
1934
1973
|
chain?: string | undefined;
|
|
1935
1974
|
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:
|
|
1001
|
-
inputSchema: z.object({
|
|
1002
|
-
|
|
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(
|
|
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
|
|
1007
|
-
|
|
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
|
|
1012
|
-
|
|
1069
|
+
const all2 = await agent.rates();
|
|
1070
|
+
const filtered2 = applyFilters(all2, opts);
|
|
1071
|
+
return { data: filtered2, displayText: formatRatesSummary(filtered2) };
|
|
1013
1072
|
}
|
|
1014
|
-
const
|
|
1015
|
-
|
|
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:
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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`
|
|
@@ -1604,16 +1710,31 @@ async function fetchCatalog() {
|
|
|
1604
1710
|
catalogCache = { data, ts: Date.now() };
|
|
1605
1711
|
return data;
|
|
1606
1712
|
}
|
|
1713
|
+
function renderServices(catalog) {
|
|
1714
|
+
return catalog.map((s) => ({
|
|
1715
|
+
id: s.id,
|
|
1716
|
+
name: s.name,
|
|
1717
|
+
description: s.description,
|
|
1718
|
+
categories: s.categories,
|
|
1719
|
+
endpoints: s.endpoints.map((e) => ({
|
|
1720
|
+
url: `${MPP_GATEWAY2}/${s.id}${e.path}`,
|
|
1721
|
+
method: e.method,
|
|
1722
|
+
description: e.description,
|
|
1723
|
+
price: `$${e.price}`
|
|
1724
|
+
}))
|
|
1725
|
+
}));
|
|
1726
|
+
}
|
|
1607
1727
|
function matchesQuery(service, q) {
|
|
1608
1728
|
const lower = q.toLowerCase();
|
|
1609
1729
|
return service.id.toLowerCase().includes(lower) || service.name.toLowerCase().includes(lower) || service.description.toLowerCase().includes(lower) || service.categories.some((c) => c.toLowerCase().includes(lower)) || service.endpoints.some((e) => e.description.toLowerCase().includes(lower));
|
|
1610
1730
|
}
|
|
1611
1731
|
var mppServicesTool = buildTool({
|
|
1612
1732
|
name: "mpp_services",
|
|
1613
|
-
description:
|
|
1733
|
+
description: 'Discover available MPP gateway services. Returns service names, descriptions, endpoints with required parameters, and pricing. Use BEFORE calling pay_api. With no args, returns the FULL catalog as a single card (default behavior \u2014 covers "show me available MPP services", "what services exist", "show me all MPP services"). Use `query` to keyword-search a specific need ("translate", "weather", "postcard"). Use `category` to filter to one category. Use `mode: "summary"` only if you explicitly want a category-counts overview without the full list.',
|
|
1614
1734
|
inputSchema: z.object({
|
|
1615
|
-
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").
|
|
1735
|
+
query: z.string().optional().describe('Filter by keyword (e.g. "postcard", "translate", "weather"). Returns matching services in one card.'),
|
|
1736
|
+
category: z.string().optional().describe('Filter by category exactly (e.g. "weather", "image"). Use mode:"summary" first if you need to see the category list.'),
|
|
1737
|
+
mode: z.enum(["summary", "full"]).optional().describe('"full" (default) returns the entire catalog in one card. "summary" returns category counts only \u2014 use this only when the user explicitly asks for a category overview.')
|
|
1617
1738
|
}),
|
|
1618
1739
|
jsonSchema: {
|
|
1619
1740
|
type: "object",
|
|
@@ -1625,15 +1746,30 @@ var mppServicesTool = buildTool({
|
|
|
1625
1746
|
category: {
|
|
1626
1747
|
type: "string",
|
|
1627
1748
|
description: 'Filter by category exactly (e.g. "weather", "image").'
|
|
1749
|
+
},
|
|
1750
|
+
mode: {
|
|
1751
|
+
type: "string",
|
|
1752
|
+
enum: ["summary", "full"],
|
|
1753
|
+
description: '"full" (default) returns the entire catalog in one card. "summary" returns category counts only.'
|
|
1628
1754
|
}
|
|
1629
1755
|
},
|
|
1630
1756
|
required: []
|
|
1631
1757
|
},
|
|
1632
1758
|
isReadOnly: true,
|
|
1633
|
-
|
|
1759
|
+
// [v0.46.6] Bumped to fit the full catalog (~40 services) in one
|
|
1760
|
+
// shot when `mode: 'full'` is used. The summarizeOnTruncate path
|
|
1761
|
+
// still applies if the catalog ever exceeds the budget.
|
|
1762
|
+
maxResultSizeChars: 12e3,
|
|
1634
1763
|
async call(input) {
|
|
1635
1764
|
const catalog = await fetchCatalog();
|
|
1636
|
-
if (!input.query && !input.category) {
|
|
1765
|
+
if (input.mode !== "summary" && !input.query && !input.category) {
|
|
1766
|
+
const services2 = renderServices(catalog);
|
|
1767
|
+
return {
|
|
1768
|
+
data: { services: services2, total: services2.length, mode: "full" },
|
|
1769
|
+
displayText: `Full MPP catalog: ${services2.length} services.`
|
|
1770
|
+
};
|
|
1771
|
+
}
|
|
1772
|
+
if (input.mode === "summary" && !input.query && !input.category) {
|
|
1637
1773
|
const counts = /* @__PURE__ */ new Map();
|
|
1638
1774
|
for (const svc of catalog) {
|
|
1639
1775
|
for (const cat of svc.categories) {
|
|
@@ -1644,13 +1780,14 @@ var mppServicesTool = buildTool({
|
|
|
1644
1780
|
return {
|
|
1645
1781
|
data: {
|
|
1646
1782
|
_refine: {
|
|
1647
|
-
reason:
|
|
1648
|
-
suggestedParams: { category: categories[0]?.category ?? "weather" }
|
|
1783
|
+
reason: 'Category summary (mode:"summary"). Re-call with a category or omit mode for the full catalog.',
|
|
1784
|
+
suggestedParams: { category: categories[0]?.category ?? "weather" },
|
|
1785
|
+
allModes: ["summary", "full"]
|
|
1649
1786
|
},
|
|
1650
1787
|
categories,
|
|
1651
1788
|
totalServices: catalog.length
|
|
1652
1789
|
},
|
|
1653
|
-
displayText: `${catalog.length} services across ${categories.length} categories
|
|
1790
|
+
displayText: `${catalog.length} services across ${categories.length} categories.`
|
|
1654
1791
|
};
|
|
1655
1792
|
}
|
|
1656
1793
|
let filtered = catalog;
|
|
@@ -1661,18 +1798,7 @@ var mppServicesTool = buildTool({
|
|
|
1661
1798
|
if (input.query) {
|
|
1662
1799
|
filtered = filtered.filter((s) => matchesQuery(s, input.query));
|
|
1663
1800
|
}
|
|
1664
|
-
const services = filtered
|
|
1665
|
-
id: s.id,
|
|
1666
|
-
name: s.name,
|
|
1667
|
-
description: s.description,
|
|
1668
|
-
categories: s.categories,
|
|
1669
|
-
endpoints: s.endpoints.map((e) => ({
|
|
1670
|
-
url: `${MPP_GATEWAY2}/${s.id}${e.path}`,
|
|
1671
|
-
method: e.method,
|
|
1672
|
-
description: e.description,
|
|
1673
|
-
price: `$${e.price}`
|
|
1674
|
-
}))
|
|
1675
|
-
}));
|
|
1801
|
+
const services = renderServices(filtered);
|
|
1676
1802
|
const filterDesc = [
|
|
1677
1803
|
input.query ? `query "${input.query}"` : null,
|
|
1678
1804
|
input.category ? `category "${input.category}"` : null
|
|
@@ -2933,22 +3059,44 @@ function fmtToolTvl(tvl) {
|
|
|
2933
3059
|
if (tvl >= 1e3) return `$${(tvl / 1e3).toFixed(0)}K`;
|
|
2934
3060
|
return `$${tvl}`;
|
|
2935
3061
|
}
|
|
3062
|
+
var POOL_STABLE_LEGS = /* @__PURE__ */ new Set([
|
|
3063
|
+
"USDC",
|
|
3064
|
+
"WUSDC",
|
|
3065
|
+
"USDT",
|
|
3066
|
+
"WUSDT",
|
|
3067
|
+
"SUIUSDT",
|
|
3068
|
+
"USDY",
|
|
3069
|
+
"USDSUI",
|
|
3070
|
+
"USDE",
|
|
3071
|
+
"AUSD",
|
|
3072
|
+
"FDUSD",
|
|
3073
|
+
"BUCK",
|
|
3074
|
+
"DAI",
|
|
3075
|
+
"LUSD",
|
|
3076
|
+
"FRAX",
|
|
3077
|
+
"GUSD",
|
|
3078
|
+
"PYUSD",
|
|
3079
|
+
"USDS",
|
|
3080
|
+
"CRVUSD"
|
|
3081
|
+
]);
|
|
2936
3082
|
var defillamaYieldPoolsTool = buildTool({
|
|
2937
3083
|
name: "defillama_yield_pools",
|
|
2938
|
-
description: '
|
|
3084
|
+
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
3085
|
inputSchema: z.object({
|
|
2940
3086
|
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. "
|
|
3087
|
+
project: z.string().optional().describe('Filter by protocol project name (e.g. "cetus-clmm", "bluefin-spot")'),
|
|
2942
3088
|
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)")
|
|
3089
|
+
minTvl: z.number().optional().describe("Minimum TVL in USD to filter out small/risky pools (default 100000)"),
|
|
3090
|
+
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
3091
|
}),
|
|
2945
3092
|
jsonSchema: {
|
|
2946
3093
|
type: "object",
|
|
2947
3094
|
properties: {
|
|
2948
3095
|
chain: { type: "string", description: "Filter by chain name" },
|
|
2949
|
-
project: { type: "string", description: 'Filter by protocol project name (e.g. "
|
|
3096
|
+
project: { type: "string", description: 'Filter by protocol project name (e.g. "cetus-clmm")' },
|
|
2950
3097
|
limit: { type: "number", description: "Max results (default 5)" },
|
|
2951
|
-
minTvl: { type: "number", description: "Minimum TVL in USD (default 100000)" }
|
|
3098
|
+
minTvl: { type: "number", description: "Minimum TVL in USD (default 100000)" },
|
|
3099
|
+
stableOnly: { type: "boolean", description: "When true, only return all-stablecoin pools." }
|
|
2952
3100
|
},
|
|
2953
3101
|
required: []
|
|
2954
3102
|
},
|
|
@@ -2984,6 +3132,12 @@ var defillamaYieldPoolsTool = buildTool({
|
|
|
2984
3132
|
}
|
|
2985
3133
|
const minTvl = input.minTvl ?? 1e5;
|
|
2986
3134
|
pools = pools.filter((p) => p.tvlUsd >= minTvl);
|
|
3135
|
+
if (input.stableOnly) {
|
|
3136
|
+
pools = pools.filter((p) => {
|
|
3137
|
+
const legs = p.symbol.split("-");
|
|
3138
|
+
return legs.every((leg) => POOL_STABLE_LEGS.has(leg.trim().toUpperCase()));
|
|
3139
|
+
});
|
|
3140
|
+
}
|
|
2987
3141
|
pools.sort((a, b) => b.apy - a.apy);
|
|
2988
3142
|
const limit = input.limit ?? 5;
|
|
2989
3143
|
const top = pools.slice(0, limit);
|
|
@@ -4433,6 +4587,62 @@ var QueryEngine = class {
|
|
|
4433
4587
|
loadMessages(messages) {
|
|
4434
4588
|
this.messages = [...messages];
|
|
4435
4589
|
}
|
|
4590
|
+
/**
|
|
4591
|
+
* [v0.46.7] Run a read-only tool out-of-band, using the engine's tool
|
|
4592
|
+
* registry and ToolContext. Used by hosts to deterministically pre-dispatch
|
|
4593
|
+
* tools based on user-message intent (e.g. always call `balance_check` when
|
|
4594
|
+
* the user says "what's my net worth?", regardless of whether the LLM would
|
|
4595
|
+
* have otherwise re-called it).
|
|
4596
|
+
*
|
|
4597
|
+
* The host is responsible for:
|
|
4598
|
+
* - Streaming the synthetic `tool_start` + `tool_result` events to the UI
|
|
4599
|
+
* (so cards render as if the LLM had called the tool).
|
|
4600
|
+
* - Appending matching `tool_use` + `tool_result` ContentBlocks to the
|
|
4601
|
+
* engine's message history via `loadMessages([...getMessages(), ...synth])`
|
|
4602
|
+
* BEFORE calling `submitMessage`, so the LLM sees the fresh data and
|
|
4603
|
+
* doesn't re-call.
|
|
4604
|
+
*
|
|
4605
|
+
* Throws if the tool isn't registered, isn't read-only, or fails input
|
|
4606
|
+
* validation. Tool execution errors are returned as `{ data, isError: true }`
|
|
4607
|
+
* for the caller to handle (typically: skip the injection so the LLM falls
|
|
4608
|
+
* back to its normal flow).
|
|
4609
|
+
*/
|
|
4610
|
+
async invokeReadTool(toolName, input, options = {}) {
|
|
4611
|
+
const tool = findTool(this.tools, toolName);
|
|
4612
|
+
if (!tool) throw new Error(`invokeReadTool: tool not found: ${toolName}`);
|
|
4613
|
+
if (!tool.isReadOnly) {
|
|
4614
|
+
throw new Error(`invokeReadTool: tool is not read-only: ${toolName} (write tools must go through the permission gate)`);
|
|
4615
|
+
}
|
|
4616
|
+
const parsed = tool.inputSchema.safeParse(input);
|
|
4617
|
+
if (!parsed.success) {
|
|
4618
|
+
throw new Error(
|
|
4619
|
+
`invokeReadTool: invalid input for ${toolName}: ${parsed.error.issues.map((i) => i.message).join(", ")}`
|
|
4620
|
+
);
|
|
4621
|
+
}
|
|
4622
|
+
const signal = options.signal ?? new AbortController().signal;
|
|
4623
|
+
const context = {
|
|
4624
|
+
agent: this.agent,
|
|
4625
|
+
mcpManager: this.mcpManager,
|
|
4626
|
+
walletAddress: this.walletAddress,
|
|
4627
|
+
suiRpcUrl: this.suiRpcUrl,
|
|
4628
|
+
serverPositions: this.serverPositions,
|
|
4629
|
+
positionFetcher: this.positionFetcher,
|
|
4630
|
+
env: this.env,
|
|
4631
|
+
signal,
|
|
4632
|
+
priceCache: this.priceCache,
|
|
4633
|
+
permissionConfig: this.permissionConfig,
|
|
4634
|
+
sessionSpendUsd: this.sessionSpendUsd
|
|
4635
|
+
};
|
|
4636
|
+
try {
|
|
4637
|
+
const result = await tool.call(parsed.data, context);
|
|
4638
|
+
return { data: result.data, isError: false };
|
|
4639
|
+
} catch (err) {
|
|
4640
|
+
return {
|
|
4641
|
+
data: { error: err instanceof Error ? err.message : "Tool execution failed" },
|
|
4642
|
+
isError: true
|
|
4643
|
+
};
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4436
4646
|
setServerPositions(data) {
|
|
4437
4647
|
this.serverPositions = data;
|
|
4438
4648
|
}
|