@t2000/engine 0.46.16 → 0.47.1
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/README.md +59 -24
- package/dist/index.d.ts +121 -71
- package/dist/index.js +444 -500
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { ALL_NAVI_ASSETS, resolveSymbol,
|
|
2
|
+
import { ALL_NAVI_ASSETS, getDecimalsForCoinType, resolveSymbol, normalizeCoinType, assertAllowedAsset, SUPPORTED_ASSETS, getSwapQuote, extractTransferDetails, classifyTransaction } from '@t2000/sdk';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
3
4
|
import { readdirSync, readFileSync } from 'fs';
|
|
4
5
|
import { join } from 'path';
|
|
5
6
|
import yaml from 'js-yaml';
|
|
@@ -225,44 +226,6 @@ function applyToolFlags(tools) {
|
|
|
225
226
|
function getToolFlags(name) {
|
|
226
227
|
return TOOL_FLAGS[name] ?? {};
|
|
227
228
|
}
|
|
228
|
-
var SUI_MAINNET_URL = "https://fullnode.mainnet.sui.io:443";
|
|
229
|
-
var EXTRA_COINS = {
|
|
230
|
-
"0xc060006111016b8a020ad5b33834984a437aaa7d3c74c18e09a95d48aceab08c::coin::COIN": { symbol: "USDT", decimals: 6 }
|
|
231
|
-
};
|
|
232
|
-
async function fetchWalletCoins(address, rpcUrl) {
|
|
233
|
-
const url = rpcUrl || SUI_MAINNET_URL;
|
|
234
|
-
const res = await fetch(url, {
|
|
235
|
-
method: "POST",
|
|
236
|
-
headers: { "Content-Type": "application/json" },
|
|
237
|
-
body: JSON.stringify({
|
|
238
|
-
jsonrpc: "2.0",
|
|
239
|
-
id: 1,
|
|
240
|
-
method: "suix_getAllBalances",
|
|
241
|
-
params: [address]
|
|
242
|
-
}),
|
|
243
|
-
signal: AbortSignal.timeout(8e3)
|
|
244
|
-
});
|
|
245
|
-
if (!res.ok) {
|
|
246
|
-
throw new Error(`Sui RPC error: ${res.status} ${res.statusText}`);
|
|
247
|
-
}
|
|
248
|
-
const json = await res.json();
|
|
249
|
-
if (json.error) {
|
|
250
|
-
throw new Error(`Sui RPC error: ${json.error.message}`);
|
|
251
|
-
}
|
|
252
|
-
const balances = json.result ?? [];
|
|
253
|
-
return balances.map((b) => {
|
|
254
|
-
const extra = EXTRA_COINS[b.coinType];
|
|
255
|
-
const symbol = extra?.symbol ?? resolveSymbol(b.coinType);
|
|
256
|
-
const decimals = extra?.decimals ?? getDecimalsForCoinType(b.coinType);
|
|
257
|
-
return {
|
|
258
|
-
coinType: b.coinType,
|
|
259
|
-
symbol,
|
|
260
|
-
decimals,
|
|
261
|
-
totalBalance: b.totalBalance,
|
|
262
|
-
coinObjectCount: b.coinObjectCount
|
|
263
|
-
};
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
229
|
|
|
267
230
|
// src/navi-config.ts
|
|
268
231
|
var NAVI_SERVER_NAME = "navi";
|
|
@@ -494,59 +457,277 @@ function parseMcpJson(content) {
|
|
|
494
457
|
return text;
|
|
495
458
|
}
|
|
496
459
|
}
|
|
460
|
+
var SUI_MAINNET_URL = "https://fullnode.mainnet.sui.io:443";
|
|
461
|
+
var EXTRA_COINS = {
|
|
462
|
+
"0xc060006111016b8a020ad5b33834984a437aaa7d3c74c18e09a95d48aceab08c::coin::COIN": { symbol: "USDT", decimals: 6 }
|
|
463
|
+
};
|
|
464
|
+
async function fetchWalletCoins(address, rpcUrl) {
|
|
465
|
+
const url = rpcUrl || SUI_MAINNET_URL;
|
|
466
|
+
const res = await fetch(url, {
|
|
467
|
+
method: "POST",
|
|
468
|
+
headers: { "Content-Type": "application/json" },
|
|
469
|
+
body: JSON.stringify({
|
|
470
|
+
jsonrpc: "2.0",
|
|
471
|
+
id: 1,
|
|
472
|
+
method: "suix_getAllBalances",
|
|
473
|
+
params: [address]
|
|
474
|
+
}),
|
|
475
|
+
signal: AbortSignal.timeout(8e3)
|
|
476
|
+
});
|
|
477
|
+
if (!res.ok) {
|
|
478
|
+
throw new Error(`Sui RPC error: ${res.status} ${res.statusText}`);
|
|
479
|
+
}
|
|
480
|
+
const json = await res.json();
|
|
481
|
+
if (json.error) {
|
|
482
|
+
throw new Error(`Sui RPC error: ${json.error.message}`);
|
|
483
|
+
}
|
|
484
|
+
const balances = json.result ?? [];
|
|
485
|
+
return balances.map((b) => {
|
|
486
|
+
const extra = EXTRA_COINS[b.coinType];
|
|
487
|
+
const symbol = extra?.symbol ?? resolveSymbol(b.coinType);
|
|
488
|
+
const decimals = extra?.decimals ?? getDecimalsForCoinType(b.coinType);
|
|
489
|
+
return {
|
|
490
|
+
coinType: b.coinType,
|
|
491
|
+
symbol,
|
|
492
|
+
decimals,
|
|
493
|
+
totalBalance: b.totalBalance,
|
|
494
|
+
coinObjectCount: b.coinObjectCount
|
|
495
|
+
};
|
|
496
|
+
});
|
|
497
|
+
}
|
|
497
498
|
|
|
498
|
-
// src/
|
|
499
|
-
var
|
|
500
|
-
var
|
|
501
|
-
var
|
|
502
|
-
var
|
|
503
|
-
|
|
504
|
-
|
|
499
|
+
// src/blockvision-prices.ts
|
|
500
|
+
var BLOCKVISION_BASE = "https://api.blockvision.org/v2/sui";
|
|
501
|
+
var PORTFOLIO_TIMEOUT_MS = 4e3;
|
|
502
|
+
var PRICES_TIMEOUT_MS = 3e3;
|
|
503
|
+
var CACHE_TTL_MS = 6e4;
|
|
504
|
+
var PRICE_LIST_CHUNK = 10;
|
|
505
|
+
var STABLE_USD_PRICES = {
|
|
506
|
+
"0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC": 1,
|
|
507
|
+
"0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT": 1,
|
|
508
|
+
"0x41d587e5336f1c86cad50d38a7136db99333bb9bda91cea4ba69115defeb1402::sui_usde::SUI_USDE": 1,
|
|
509
|
+
"0x44f838219cf67b058f3b37907b655f226153c18e33dfcd0da559a844fea9b1c1::usdsui::USDSUI": 1,
|
|
510
|
+
"0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN": 1,
|
|
511
|
+
"0xc060006111016b8a020ad5b33834984a437aaa7d3c74c18e09a95d48aceab08c::coin::COIN": 1
|
|
512
|
+
};
|
|
513
|
+
var portfolioCache = /* @__PURE__ */ new Map();
|
|
514
|
+
var portfolioInflight = /* @__PURE__ */ new Map();
|
|
515
|
+
var priceMapCache = null;
|
|
516
|
+
async function fetchAddressPortfolio(address, apiKey, fallbackRpcUrl) {
|
|
505
517
|
const now = Date.now();
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
518
|
+
const cached = portfolioCache.get(address);
|
|
519
|
+
if (cached && now - cached.ts < CACHE_TTL_MS) {
|
|
520
|
+
return cached.data;
|
|
521
|
+
}
|
|
522
|
+
let inflight = portfolioInflight.get(address);
|
|
523
|
+
if (inflight) return inflight;
|
|
524
|
+
inflight = (async () => {
|
|
525
|
+
try {
|
|
526
|
+
if (apiKey && apiKey.trim().length > 0) {
|
|
527
|
+
const blockvision = await fetchPortfolioFromBlockVision(address, apiKey);
|
|
528
|
+
if (blockvision) {
|
|
529
|
+
portfolioCache.set(address, { data: blockvision, ts: Date.now() });
|
|
530
|
+
return blockvision;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
const degraded = await fetchPortfolioFromSuiRpc(address, fallbackRpcUrl);
|
|
534
|
+
portfolioCache.set(address, { data: degraded, ts: Date.now() });
|
|
535
|
+
return degraded;
|
|
536
|
+
} finally {
|
|
537
|
+
portfolioInflight.delete(address);
|
|
538
|
+
}
|
|
539
|
+
})();
|
|
540
|
+
portfolioInflight.set(address, inflight);
|
|
541
|
+
return inflight;
|
|
542
|
+
}
|
|
543
|
+
async function fetchPortfolioFromBlockVision(address, apiKey) {
|
|
544
|
+
const url = `${BLOCKVISION_BASE}/account/coins?account=${encodeURIComponent(address)}`;
|
|
545
|
+
let res;
|
|
546
|
+
try {
|
|
547
|
+
res = await fetch(url, {
|
|
548
|
+
headers: { "x-api-key": apiKey, accept: "application/json" },
|
|
549
|
+
signal: AbortSignal.timeout(PORTFOLIO_TIMEOUT_MS)
|
|
515
550
|
});
|
|
516
|
-
|
|
551
|
+
} catch (err) {
|
|
552
|
+
console.warn("[blockvision-prices] portfolio fetch threw, degrading:", err);
|
|
553
|
+
return null;
|
|
517
554
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
555
|
+
if (!res.ok) {
|
|
556
|
+
console.warn(`[blockvision-prices] portfolio HTTP ${res.status}, degrading`);
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
let json;
|
|
560
|
+
try {
|
|
561
|
+
json = await res.json();
|
|
562
|
+
} catch (err) {
|
|
563
|
+
console.warn("[blockvision-prices] portfolio JSON parse failed, degrading:", err);
|
|
564
|
+
return null;
|
|
565
|
+
}
|
|
566
|
+
if (json.code !== 200 || !json.result) {
|
|
567
|
+
console.warn(`[blockvision-prices] portfolio code=${json.code} msg=${json.message}, degrading`);
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
const rawCoins = json.result.coins ?? [];
|
|
571
|
+
const coins = rawCoins.map((c) => {
|
|
572
|
+
const coinType = c.coinType;
|
|
573
|
+
const symbol = c.symbol || resolveSymbol(coinType);
|
|
574
|
+
const decimals = typeof c.decimals === "number" ? c.decimals : getDecimalsForCoinType(coinType);
|
|
575
|
+
const stablePrice = STABLE_USD_PRICES[coinType];
|
|
576
|
+
const apiPrice = parseNumberOrNull(c.price);
|
|
577
|
+
const apiUsd = parseNumberOrNull(c.usdValue);
|
|
578
|
+
const price = apiPrice ?? stablePrice ?? null;
|
|
579
|
+
let usdValue = apiUsd;
|
|
580
|
+
if (usdValue == null && price != null) {
|
|
581
|
+
const amount = Number(c.balance) / 10 ** decimals;
|
|
582
|
+
usdValue = Number.isFinite(amount) ? amount * price : null;
|
|
583
|
+
}
|
|
584
|
+
return {
|
|
585
|
+
coinType,
|
|
586
|
+
symbol,
|
|
587
|
+
decimals,
|
|
588
|
+
balance: c.balance,
|
|
589
|
+
price,
|
|
590
|
+
usdValue
|
|
591
|
+
};
|
|
592
|
+
});
|
|
593
|
+
const apiTotal = parseNumberOrNull(json.result.usdValue);
|
|
594
|
+
const totalUsd = apiTotal ?? coins.reduce((sum, c) => sum + (c.usdValue ?? 0), 0);
|
|
595
|
+
return {
|
|
596
|
+
coins,
|
|
597
|
+
totalUsd,
|
|
598
|
+
pricedAt: Date.now(),
|
|
599
|
+
source: "blockvision"
|
|
600
|
+
};
|
|
522
601
|
}
|
|
523
|
-
async function
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
signal: AbortSignal.timeout(1e4)
|
|
602
|
+
async function fetchPortfolioFromSuiRpc(address, fallbackRpcUrl) {
|
|
603
|
+
const walletCoins = await fetchWalletCoins(address, fallbackRpcUrl).catch((err) => {
|
|
604
|
+
console.warn("[blockvision-prices] sui rpc coin fetch failed:", err);
|
|
605
|
+
return [];
|
|
528
606
|
});
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
607
|
+
const coins = walletCoins.map((c) => {
|
|
608
|
+
const stablePrice = STABLE_USD_PRICES[c.coinType] ?? null;
|
|
609
|
+
const amount = Number(c.totalBalance) / 10 ** c.decimals;
|
|
610
|
+
const usdValue = stablePrice != null && Number.isFinite(amount) ? amount * stablePrice : null;
|
|
611
|
+
return {
|
|
612
|
+
coinType: c.coinType,
|
|
613
|
+
symbol: c.symbol,
|
|
614
|
+
decimals: c.decimals,
|
|
615
|
+
balance: c.totalBalance,
|
|
616
|
+
price: stablePrice,
|
|
617
|
+
usdValue
|
|
618
|
+
};
|
|
619
|
+
});
|
|
620
|
+
const totalUsd = coins.reduce((sum, c) => sum + (c.usdValue ?? 0), 0);
|
|
621
|
+
return {
|
|
622
|
+
coins,
|
|
623
|
+
totalUsd,
|
|
624
|
+
pricedAt: Date.now(),
|
|
625
|
+
source: "sui-rpc-degraded"
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
async function fetchTokenPrices(coinTypes, apiKey) {
|
|
629
|
+
if (coinTypes.length === 0) return {};
|
|
630
|
+
const now = Date.now();
|
|
631
|
+
const cacheValid = priceMapCache !== null && now - priceMapCache.ts < CACHE_TTL_MS;
|
|
632
|
+
const cached = cacheValid ? priceMapCache.prices : {};
|
|
633
|
+
const result = {};
|
|
634
|
+
const stillMissing = [];
|
|
635
|
+
for (const original of coinTypes) {
|
|
636
|
+
const norm = normalizeCoinType(original);
|
|
637
|
+
if (cached[norm]) {
|
|
638
|
+
result[original] = cached[norm];
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
const stable = STABLE_USD_PRICES[norm];
|
|
642
|
+
if (typeof stable === "number") {
|
|
643
|
+
result[original] = { price: stable };
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
stillMissing.push(original);
|
|
532
647
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
648
|
+
if (stillMissing.length === 0) return result;
|
|
649
|
+
if (!apiKey || apiKey.trim().length === 0) {
|
|
650
|
+
return result;
|
|
651
|
+
}
|
|
652
|
+
const fetched = await fetchPricesFromBlockVision(stillMissing, apiKey);
|
|
653
|
+
Object.assign(result, fetched);
|
|
654
|
+
const cacheUpdates = {};
|
|
655
|
+
for (const [original, value] of Object.entries(fetched)) {
|
|
656
|
+
cacheUpdates[normalizeCoinType(original)] = value;
|
|
657
|
+
}
|
|
658
|
+
const merged = { ...cached, ...cacheUpdates };
|
|
659
|
+
priceMapCache = { prices: merged, ts: cacheValid ? priceMapCache.ts : now };
|
|
660
|
+
return result;
|
|
661
|
+
}
|
|
662
|
+
async function fetchPricesFromBlockVision(coinTypes, apiKey) {
|
|
663
|
+
const out = {};
|
|
664
|
+
const longToOriginal = /* @__PURE__ */ new Map();
|
|
665
|
+
for (const original of coinTypes) {
|
|
666
|
+
const long = normalizeCoinType(original);
|
|
667
|
+
if (!longToOriginal.has(long)) longToOriginal.set(long, original);
|
|
668
|
+
}
|
|
669
|
+
const longForms = Array.from(longToOriginal.keys());
|
|
670
|
+
for (let i = 0; i < longForms.length; i += PRICE_LIST_CHUNK) {
|
|
671
|
+
const chunk = longForms.slice(i, i + PRICE_LIST_CHUNK);
|
|
672
|
+
const tokenIds = encodeURIComponent(chunk.join(","));
|
|
673
|
+
const url = `${BLOCKVISION_BASE}/coin/price/list?tokenIds=${tokenIds}&show24hChange=true`;
|
|
674
|
+
let res;
|
|
675
|
+
try {
|
|
676
|
+
res = await fetch(url, {
|
|
677
|
+
headers: { "x-api-key": apiKey, accept: "application/json" },
|
|
678
|
+
signal: AbortSignal.timeout(PRICES_TIMEOUT_MS)
|
|
679
|
+
});
|
|
680
|
+
} catch (err) {
|
|
681
|
+
console.warn("[blockvision-prices] price chunk threw, skipping:", err);
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
if (!res.ok) {
|
|
685
|
+
console.warn(`[blockvision-prices] price chunk HTTP ${res.status}`);
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
let json;
|
|
689
|
+
try {
|
|
690
|
+
json = await res.json();
|
|
691
|
+
} catch (err) {
|
|
692
|
+
console.warn("[blockvision-prices] price chunk JSON parse failed:", err);
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
if (json.code !== 200 || !json.result) continue;
|
|
696
|
+
const prices = json.result.prices ?? {};
|
|
697
|
+
const changes = json.result.coin24HChange ?? {};
|
|
698
|
+
for (const [returnedType, priceStr] of Object.entries(prices)) {
|
|
699
|
+
const price = parseNumberOrNull(priceStr);
|
|
700
|
+
if (price == null) continue;
|
|
701
|
+
const original = longToOriginal.get(returnedType) ?? returnedType;
|
|
702
|
+
const change24h = parseNumberOrNull(changes[returnedType]);
|
|
703
|
+
out[original] = change24h == null ? { price } : { price, change24h };
|
|
539
704
|
}
|
|
540
705
|
}
|
|
541
|
-
|
|
542
|
-
|
|
706
|
+
return out;
|
|
707
|
+
}
|
|
708
|
+
function parseNumberOrNull(input) {
|
|
709
|
+
if (typeof input === "number") return Number.isFinite(input) ? input : null;
|
|
710
|
+
if (typeof input !== "string" || input.trim().length === 0) return null;
|
|
711
|
+
const n = Number(input);
|
|
712
|
+
return Number.isFinite(n) ? n : null;
|
|
713
|
+
}
|
|
714
|
+
function clearPortfolioCache() {
|
|
715
|
+
portfolioCache.clear();
|
|
716
|
+
portfolioInflight.clear();
|
|
543
717
|
}
|
|
544
|
-
function
|
|
545
|
-
|
|
718
|
+
function clearPortfolioCacheFor(address) {
|
|
719
|
+
portfolioCache.delete(address);
|
|
720
|
+
portfolioInflight.delete(address);
|
|
721
|
+
}
|
|
722
|
+
function clearPriceMapCache() {
|
|
723
|
+
priceMapCache = null;
|
|
546
724
|
}
|
|
547
725
|
|
|
548
726
|
// src/tools/balance.ts
|
|
549
727
|
var GAS_RESERVE_SUI2 = 0.05;
|
|
728
|
+
var VSUI_COIN_TYPE = "0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT";
|
|
729
|
+
var SUI_COIN_TYPE = "0x2::sui::SUI";
|
|
730
|
+
var VSUI_FALLBACK_RATE = 1.05;
|
|
550
731
|
async function callNavi(manager, tool, args = {}) {
|
|
551
732
|
const result = await manager.callTool(NAVI_SERVER_NAME, tool, args);
|
|
552
733
|
if (result.isError) {
|
|
@@ -555,83 +736,103 @@ async function callNavi(manager, tool, args = {}) {
|
|
|
555
736
|
}
|
|
556
737
|
return parseMcpJson(result.content);
|
|
557
738
|
}
|
|
739
|
+
async function applyVsuiPriceFallback(portfolio) {
|
|
740
|
+
const vsuiIdx = portfolio.coins.findIndex((c) => c.coinType === VSUI_COIN_TYPE);
|
|
741
|
+
if (vsuiIdx === -1) return;
|
|
742
|
+
const vsui = portfolio.coins[vsuiIdx];
|
|
743
|
+
if (vsui.price != null) return;
|
|
744
|
+
const suiCoin = portfolio.coins.find((c) => c.coinType === SUI_COIN_TYPE);
|
|
745
|
+
const suiPrice = suiCoin?.price ?? null;
|
|
746
|
+
if (suiPrice == null) return;
|
|
747
|
+
let rate = VSUI_FALLBACK_RATE;
|
|
748
|
+
try {
|
|
749
|
+
const statsRes = await fetch("https://open-api.naviprotocol.io/api/volo/stats", {
|
|
750
|
+
signal: AbortSignal.timeout(5e3)
|
|
751
|
+
});
|
|
752
|
+
if (statsRes.ok) {
|
|
753
|
+
const json = await statsRes.json();
|
|
754
|
+
const data = json.data ?? json;
|
|
755
|
+
rate = data.exchange_rate ?? data.exchangeRate ?? VSUI_FALLBACK_RATE;
|
|
756
|
+
}
|
|
757
|
+
} catch {
|
|
758
|
+
}
|
|
759
|
+
const price = rate * suiPrice;
|
|
760
|
+
const amount = Number(vsui.balance) / 10 ** vsui.decimals;
|
|
761
|
+
const usdValue = Number.isFinite(amount) ? amount * price : null;
|
|
762
|
+
const previousUsd = vsui.usdValue ?? 0;
|
|
763
|
+
portfolio.coins[vsuiIdx] = { ...vsui, price, usdValue };
|
|
764
|
+
if (usdValue != null) {
|
|
765
|
+
portfolio.totalUsd = portfolio.totalUsd - previousUsd + usdValue;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
async function loadPortfolio(address, blockvisionApiKey, fallbackRpcUrl, cache) {
|
|
769
|
+
if (cache) {
|
|
770
|
+
const hit = cache.get(address);
|
|
771
|
+
if (hit) return hit;
|
|
772
|
+
}
|
|
773
|
+
const portfolio = await fetchAddressPortfolio(address, blockvisionApiKey, fallbackRpcUrl);
|
|
774
|
+
if (cache) cache.set(address, portfolio);
|
|
775
|
+
return portfolio;
|
|
776
|
+
}
|
|
558
777
|
var balanceCheckTool = buildTool({
|
|
559
778
|
name: "balance_check",
|
|
560
779
|
description: "Get the user's full balance breakdown. Returns wallet holdings (tokens the user owns \u2014 NOT savings), NAVI savings deposits (USDC deposited into NAVI Protocol earning yield), outstanding debt, pending rewards, gas reserve, total net worth, and saveableUsdc (only USDC can be deposited into savings). IMPORTANT: wallet holdings like GOLD, SUI, USDT are NOT savings positions \u2014 they are just tokens sitting in the wallet.",
|
|
561
780
|
inputSchema: z.object({}),
|
|
562
781
|
jsonSchema: { type: "object", properties: {}, required: [] },
|
|
563
782
|
isReadOnly: true,
|
|
564
|
-
// [v1.
|
|
565
|
-
//
|
|
566
|
-
//
|
|
783
|
+
// [v1.4 BlockVision] Wallet contents change after every send / swap /
|
|
784
|
+
// save / etc. and the price half of this result is sourced from
|
|
785
|
+
// BlockVision's Indexer REST API. Microcompact must NEVER dedupe these
|
|
786
|
+
// calls — each one reflects a different on-chain + market snapshot.
|
|
567
787
|
cacheable: false,
|
|
568
788
|
async call(_input, context) {
|
|
569
789
|
if (hasNaviMcp(context)) {
|
|
570
790
|
const address = getWalletAddress(context);
|
|
571
791
|
const mgr = getMcpManager(context);
|
|
572
792
|
const hasPositionFetcher = !!(context.positionFetcher && context.walletAddress);
|
|
573
|
-
const [
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
793
|
+
const [portfolio, positions, rewards, serverPositions] = await Promise.all([
|
|
794
|
+
loadPortfolio(
|
|
795
|
+
address,
|
|
796
|
+
context.blockvisionApiKey,
|
|
797
|
+
context.suiRpcUrl,
|
|
798
|
+
context.portfolioCache
|
|
799
|
+
).catch((err) => {
|
|
800
|
+
console.warn("[balance_check] portfolio fetch failed, returning empty:", err);
|
|
801
|
+
const fallback = {
|
|
802
|
+
coins: [],
|
|
803
|
+
totalUsd: 0,
|
|
804
|
+
pricedAt: Date.now(),
|
|
805
|
+
source: "sui-rpc-degraded"
|
|
806
|
+
};
|
|
807
|
+
return fallback;
|
|
577
808
|
}),
|
|
578
809
|
hasPositionFetcher ? Promise.resolve(null) : callNavi(mgr, NaviTools.GET_POSITIONS, {
|
|
579
810
|
address,
|
|
580
811
|
protocols: "navi",
|
|
581
812
|
format: "json"
|
|
813
|
+
}).catch((err) => {
|
|
814
|
+
console.warn("[balance_check] NAVI GET_POSITIONS failed:", err);
|
|
815
|
+
return null;
|
|
582
816
|
}),
|
|
583
|
-
hasPositionFetcher ? Promise.resolve(null) : callNavi(mgr, NaviTools.GET_AVAILABLE_REWARDS, { address })
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
if (!coins || coins.length === 0) {
|
|
587
|
-
const mcpCoins = await callNavi(mgr, NaviTools.GET_COINS, { address }).catch(() => []);
|
|
588
|
-
const coinArr = Array.isArray(mcpCoins) ? mcpCoins : [];
|
|
589
|
-
coins = coinArr.map((c) => ({
|
|
590
|
-
coinType: c.coinType ?? "",
|
|
591
|
-
symbol: c.symbol ?? "",
|
|
592
|
-
decimals: c.decimals ?? getDecimalsForCoinType(c.coinType ?? ""),
|
|
593
|
-
totalBalance: c.totalBalance ?? "0",
|
|
594
|
-
coinObjectCount: 0
|
|
595
|
-
}));
|
|
596
|
-
}
|
|
597
|
-
const VSUI_COIN_TYPE = "0x549e8b69270defbfafd4f94e17ec44cdbdd99820b33bda2278dea3b9a32d3f55::cert::CERT";
|
|
598
|
-
const coinTypes = coins.map((c) => c.coinType).filter(Boolean);
|
|
599
|
-
const [prices, serverPositions] = await Promise.all([
|
|
600
|
-
fetchTokenPrices(coinTypes).catch((err) => {
|
|
601
|
-
console.warn("[balance_check] DefiLlama price fetch failed:", err);
|
|
602
|
-
return {};
|
|
817
|
+
hasPositionFetcher ? Promise.resolve(null) : callNavi(mgr, NaviTools.GET_AVAILABLE_REWARDS, { address }).catch((err) => {
|
|
818
|
+
console.warn("[balance_check] NAVI GET_AVAILABLE_REWARDS failed:", err);
|
|
819
|
+
return null;
|
|
603
820
|
}),
|
|
604
821
|
hasPositionFetcher ? context.positionFetcher(context.walletAddress).catch((err) => {
|
|
605
822
|
console.warn("[balance_check] positionFetcher failed:", err);
|
|
606
823
|
return null;
|
|
607
824
|
}) : Promise.resolve(null)
|
|
608
825
|
]);
|
|
609
|
-
|
|
610
|
-
try {
|
|
611
|
-
const statsRes = await fetch("https://open-api.naviprotocol.io/api/volo/stats", {
|
|
612
|
-
signal: AbortSignal.timeout(5e3)
|
|
613
|
-
});
|
|
614
|
-
if (statsRes.ok) {
|
|
615
|
-
const statsJson = await statsRes.json();
|
|
616
|
-
const d = statsJson.data ?? statsJson;
|
|
617
|
-
const rate = d.exchange_rate ?? d.exchangeRate ?? 1.05;
|
|
618
|
-
const suiPrice = prices["0x2::sui::SUI"] ?? 0;
|
|
619
|
-
prices[VSUI_COIN_TYPE] = rate * suiPrice;
|
|
620
|
-
}
|
|
621
|
-
} catch {
|
|
622
|
-
const suiPrice = prices["0x2::sui::SUI"] ?? 0;
|
|
623
|
-
prices[VSUI_COIN_TYPE] = suiPrice * 1.05;
|
|
624
|
-
}
|
|
625
|
-
}
|
|
826
|
+
await applyVsuiPriceFallback(portfolio);
|
|
626
827
|
let availableUsd = 0;
|
|
627
828
|
let stablesUsd = 0;
|
|
628
829
|
let gasReserveUsd2 = 0;
|
|
629
830
|
const STABLE_SYMBOLS = /* @__PURE__ */ new Set(["USDC", "USDT", "USDe", "USDsui", "wUSDC", "wUSDT"]);
|
|
630
831
|
const holdings = [];
|
|
631
|
-
for (const coin of coins) {
|
|
632
|
-
const balance2 = Number(coin.
|
|
633
|
-
const price =
|
|
634
|
-
if (coin.symbol === "SUI" || coin.coinType ===
|
|
832
|
+
for (const coin of portfolio.coins) {
|
|
833
|
+
const balance2 = Number(coin.balance) / 10 ** coin.decimals;
|
|
834
|
+
const price = coin.price ?? 0;
|
|
835
|
+
if (coin.symbol === "SUI" || coin.coinType === SUI_COIN_TYPE) {
|
|
635
836
|
const reserveAmount = Math.min(balance2, GAS_RESERVE_SUI2);
|
|
636
837
|
gasReserveUsd2 = reserveAmount * price;
|
|
637
838
|
availableUsd += (balance2 - reserveAmount) * price;
|
|
@@ -676,7 +877,8 @@ var balanceCheckTool = buildTool({
|
|
|
676
877
|
total: availableUsd + savings + gasReserveUsd2 + pendingRewardsUsd - debt,
|
|
677
878
|
stables: stablesUsd,
|
|
678
879
|
holdings: visibleHoldings,
|
|
679
|
-
saveableUsdc
|
|
880
|
+
saveableUsdc,
|
|
881
|
+
priceSource: portfolio.source
|
|
680
882
|
};
|
|
681
883
|
const holdingsList = visibleHoldings.map((h) => `${h.symbol}: ${h.balance < 1 ? h.balance.toFixed(6) : h.balance.toFixed(2)} ($${h.usdValue.toFixed(2)})`).join(", ");
|
|
682
884
|
return {
|
|
@@ -993,7 +1195,6 @@ var healthCheckTool = buildTool({
|
|
|
993
1195
|
};
|
|
994
1196
|
}
|
|
995
1197
|
});
|
|
996
|
-
var YIELDS_API = "https://yields.llama.fi";
|
|
997
1198
|
var STABLECOIN_SYMBOLS2 = /* @__PURE__ */ new Set([
|
|
998
1199
|
"usdc",
|
|
999
1200
|
"wusdc",
|
|
@@ -1027,24 +1228,9 @@ function applyFilters(rates, opts) {
|
|
|
1027
1228
|
function formatRatesSummary(rates) {
|
|
1028
1229
|
return Object.entries(rates).map(([asset, r]) => `${asset}: Save ${(r.saveApy * 100).toFixed(2)}% / Borrow ${(r.borrowApy * 100).toFixed(2)}%`).join(", ");
|
|
1029
1230
|
}
|
|
1030
|
-
async function fetchRatesFromDefiLlama() {
|
|
1031
|
-
const res = await fetch(`${YIELDS_API}/pools`, { signal: AbortSignal.timeout(15e3) });
|
|
1032
|
-
if (!res.ok) throw new Error(`DefiLlama API error: HTTP ${res.status}`);
|
|
1033
|
-
const data = await res.json();
|
|
1034
|
-
const naviPools = (data.data ?? []).filter(
|
|
1035
|
-
(p) => p.chain === "Sui" && p.project === "navi-lending" && p.tvlUsd > 1e4
|
|
1036
|
-
);
|
|
1037
|
-
const result = {};
|
|
1038
|
-
for (const pool of naviPools) {
|
|
1039
|
-
const saveApy = (pool.apy ?? 0) / 100;
|
|
1040
|
-
const borrowApy = pool.apyBorrow != null ? Math.abs(pool.apyBorrow) / 100 : 0;
|
|
1041
|
-
result[pool.symbol] = { saveApy, borrowApy };
|
|
1042
|
-
}
|
|
1043
|
-
return result;
|
|
1044
|
-
}
|
|
1045
1231
|
var ratesInfoTool = buildTool({
|
|
1046
1232
|
name: "rates_info",
|
|
1047
|
-
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).
|
|
1233
|
+
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).',
|
|
1048
1234
|
inputSchema: z.object({
|
|
1049
1235
|
assets: z.array(z.string()).optional().describe('Filter to specific asset symbols (e.g. ["USDC"], ["USDC","USDT","USDSUI"]). Case-insensitive.'),
|
|
1050
1236
|
stableOnly: z.boolean().optional().describe("When true, return only stablecoin markets (USDC, USDT, USDSUI, USDY, suiUSDT, etc.). Ignored when `assets` is supplied."),
|
|
@@ -1077,19 +1263,19 @@ var ratesInfoTool = buildTool({
|
|
|
1077
1263
|
topN: input.topN ?? 8
|
|
1078
1264
|
};
|
|
1079
1265
|
if (hasNaviMcpGlobal(context)) {
|
|
1080
|
-
const
|
|
1081
|
-
const
|
|
1082
|
-
return { data:
|
|
1266
|
+
const all = await fetchRates(getMcpManager(context));
|
|
1267
|
+
const filtered = applyFilters(all, opts);
|
|
1268
|
+
return { data: filtered, displayText: formatRatesSummary(filtered) };
|
|
1083
1269
|
}
|
|
1084
1270
|
if (hasAgent(context)) {
|
|
1085
1271
|
const agent = requireAgent(context);
|
|
1086
|
-
const
|
|
1087
|
-
const
|
|
1088
|
-
return { data:
|
|
1272
|
+
const all = await agent.rates();
|
|
1273
|
+
const filtered = applyFilters(all, opts);
|
|
1274
|
+
return { data: filtered, displayText: formatRatesSummary(filtered) };
|
|
1089
1275
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1276
|
+
throw new Error(
|
|
1277
|
+
"rates_info: NAVI lending data is currently unavailable. Try again shortly."
|
|
1278
|
+
);
|
|
1093
1279
|
}
|
|
1094
1280
|
});
|
|
1095
1281
|
function parseRpcTx(tx, address) {
|
|
@@ -1759,10 +1945,10 @@ Always use ISO-3166 country codes (GB not UK, US not USA). A return address ("fr
|
|
|
1759
1945
|
});
|
|
1760
1946
|
var MPP_GATEWAY2 = "https://mpp.t2000.ai";
|
|
1761
1947
|
var CATALOG_URL = `${MPP_GATEWAY2}/api/services`;
|
|
1762
|
-
var
|
|
1948
|
+
var CACHE_TTL = 12e4;
|
|
1763
1949
|
var catalogCache = null;
|
|
1764
1950
|
async function fetchCatalog() {
|
|
1765
|
-
if (catalogCache && Date.now() - catalogCache.ts <
|
|
1951
|
+
if (catalogCache && Date.now() - catalogCache.ts < CACHE_TTL) {
|
|
1766
1952
|
return catalogCache.data;
|
|
1767
1953
|
}
|
|
1768
1954
|
const res = await fetch(CATALOG_URL, { signal: AbortSignal.timeout(1e4) });
|
|
@@ -2256,11 +2442,31 @@ var portfolioAnalysisTool = buildTool({
|
|
|
2256
2442
|
if (!address) {
|
|
2257
2443
|
throw new Error("No wallet address provided. Sign in first.");
|
|
2258
2444
|
}
|
|
2259
|
-
const rpcUrl = context.suiRpcUrl ?? "https://fullnode.mainnet.sui.io:443";
|
|
2260
2445
|
const DUST_USD = 0.01;
|
|
2261
2446
|
const apiUrl = context.env?.AUDRIC_INTERNAL_API_URL;
|
|
2262
|
-
const [
|
|
2263
|
-
|
|
2447
|
+
const [portfolio, positions, weekHistResult] = await Promise.all([
|
|
2448
|
+
(async () => {
|
|
2449
|
+
if (context.portfolioCache) {
|
|
2450
|
+
const hit = context.portfolioCache.get(address);
|
|
2451
|
+
if (hit) return hit;
|
|
2452
|
+
}
|
|
2453
|
+
const fresh = await fetchAddressPortfolio(
|
|
2454
|
+
address,
|
|
2455
|
+
context.blockvisionApiKey,
|
|
2456
|
+
context.suiRpcUrl
|
|
2457
|
+
);
|
|
2458
|
+
context.portfolioCache?.set(address, fresh);
|
|
2459
|
+
return fresh;
|
|
2460
|
+
})().catch((err) => {
|
|
2461
|
+
console.warn("[portfolio_analysis] portfolio fetch failed:", err);
|
|
2462
|
+
const empty = {
|
|
2463
|
+
coins: [],
|
|
2464
|
+
totalUsd: 0,
|
|
2465
|
+
pricedAt: Date.now(),
|
|
2466
|
+
source: "sui-rpc-degraded"
|
|
2467
|
+
};
|
|
2468
|
+
return empty;
|
|
2469
|
+
}),
|
|
2264
2470
|
context.positionFetcher ? context.positionFetcher(address).catch((err) => {
|
|
2265
2471
|
console.warn("[portfolio_analysis] positionFetcher failed:", err);
|
|
2266
2472
|
return null;
|
|
@@ -2270,14 +2476,12 @@ var portfolioAnalysisTool = buildTool({
|
|
|
2270
2476
|
{ headers: { "x-sui-address": address }, signal: context.signal }
|
|
2271
2477
|
).then((res) => res.ok ? res.json() : null).catch(() => null) : Promise.resolve(null)
|
|
2272
2478
|
]);
|
|
2273
|
-
const nonZero = coins.filter((c) => Number(c.totalBalance) > 0);
|
|
2274
|
-
const prices = await fetchTokenPrices(nonZero.map((c) => c.coinType)).catch(() => ({}));
|
|
2275
2479
|
let walletValue = 0;
|
|
2276
2480
|
const allAllocations = [];
|
|
2277
|
-
for (const coin of
|
|
2278
|
-
const amount = Number(coin.
|
|
2279
|
-
|
|
2280
|
-
const usdValue = amount * price;
|
|
2481
|
+
for (const coin of portfolio.coins) {
|
|
2482
|
+
const amount = Number(coin.balance) / 10 ** coin.decimals;
|
|
2483
|
+
if (!Number.isFinite(amount) || amount <= 0) continue;
|
|
2484
|
+
const usdValue = coin.usdValue ?? (coin.price != null ? amount * coin.price : 0);
|
|
2281
2485
|
walletValue += usdValue;
|
|
2282
2486
|
allAllocations.push({ symbol: coin.symbol, amount, usdValue, percentage: 0 });
|
|
2283
2487
|
}
|
|
@@ -2349,7 +2553,8 @@ var portfolioAnalysisTool = buildTool({
|
|
|
2349
2553
|
insights,
|
|
2350
2554
|
savingsApy,
|
|
2351
2555
|
dailyEarning,
|
|
2352
|
-
weekChange
|
|
2556
|
+
weekChange,
|
|
2557
|
+
priceSource: portfolio.source
|
|
2353
2558
|
};
|
|
2354
2559
|
const topLine = `Total: $${totalValue.toFixed(2)} | Wallet: $${walletValue.toFixed(2)} | Savings: $${savingsValue.toFixed(2)}`;
|
|
2355
2560
|
const insightLines = insights.map((i) => `${i.type === "warning" ? "\u26A0" : "\u2192"} ${i.message}`).join("\n");
|
|
@@ -3095,335 +3300,59 @@ var activitySummaryTool = buildTool({
|
|
|
3095
3300
|
}
|
|
3096
3301
|
}
|
|
3097
3302
|
});
|
|
3098
|
-
var
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
var CACHE_TTL3 = 6e4;
|
|
3102
|
-
var apiCache = /* @__PURE__ */ new Map();
|
|
3103
|
-
async function cachedFetch(url) {
|
|
3104
|
-
const hit = apiCache.get(url);
|
|
3105
|
-
if (hit && Date.now() - hit.ts < CACHE_TTL3) return hit.data;
|
|
3106
|
-
const res = await fetch(url, { signal: AbortSignal.timeout(15e3) });
|
|
3107
|
-
if (!res.ok) throw new Error(`DefiLlama API error: HTTP ${res.status}`);
|
|
3108
|
-
const data = await res.json();
|
|
3109
|
-
apiCache.set(url, { data, ts: Date.now() });
|
|
3110
|
-
return data;
|
|
3111
|
-
}
|
|
3112
|
-
async function fetchDefillamaYieldPools() {
|
|
3113
|
-
const data = await cachedFetch(`${YIELDS_API2}/pools`);
|
|
3114
|
-
return data.data ?? [];
|
|
3115
|
-
}
|
|
3116
|
-
function fmtToolTvl(tvl) {
|
|
3117
|
-
if (tvl >= 1e9) return `$${(tvl / 1e9).toFixed(1)}B`;
|
|
3118
|
-
if (tvl >= 1e6) return `$${(tvl / 1e6).toFixed(1)}M`;
|
|
3119
|
-
if (tvl >= 1e3) return `$${(tvl / 1e3).toFixed(0)}K`;
|
|
3120
|
-
return `$${tvl}`;
|
|
3121
|
-
}
|
|
3122
|
-
var POOL_STABLE_LEGS = /* @__PURE__ */ new Set([
|
|
3123
|
-
"USDC",
|
|
3124
|
-
"WUSDC",
|
|
3125
|
-
"USDT",
|
|
3126
|
-
"WUSDT",
|
|
3127
|
-
"SUIUSDT",
|
|
3128
|
-
"USDY",
|
|
3129
|
-
"USDSUI",
|
|
3130
|
-
"USDE",
|
|
3131
|
-
"AUSD",
|
|
3132
|
-
"FDUSD",
|
|
3133
|
-
"BUCK",
|
|
3134
|
-
"DAI",
|
|
3135
|
-
"LUSD",
|
|
3136
|
-
"FRAX",
|
|
3137
|
-
"GUSD",
|
|
3138
|
-
"PYUSD",
|
|
3139
|
-
"USDS",
|
|
3140
|
-
"CRVUSD"
|
|
3141
|
-
]);
|
|
3142
|
-
var defillamaYieldPoolsTool = buildTool({
|
|
3143
|
-
name: "defillama_yield_pools",
|
|
3144
|
-
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.',
|
|
3303
|
+
var tokenPricesTool = buildTool({
|
|
3304
|
+
name: "token_prices",
|
|
3305
|
+
description: 'Get current USD prices for Sui tokens, with optional 24h change. Accepts full coin type strings (e.g. "0x2::sui::SUI"). Returns price per token and (when requested) 24h change percentage. Use for "what is X worth?" or "did Y move today?". For balance + portfolio rendering, prefer balance_check / portfolio_analysis instead \u2014 they bundle the same prices into the standard cards.',
|
|
3145
3306
|
inputSchema: z.object({
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
limit: z.number().min(1).max(20).optional().describe("Max results (default 5)"),
|
|
3149
|
-
minTvl: z.number().optional().describe("Minimum TVL in USD to filter out small/risky pools (default 100000)"),
|
|
3150
|
-
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.')
|
|
3307
|
+
coinTypes: z.array(z.string()).min(1).max(10).describe("Array of Sui coin type strings (max 10 per call)."),
|
|
3308
|
+
include24hChange: z.boolean().optional().describe("When true, include 24h change percentage per token in the output.")
|
|
3151
3309
|
}),
|
|
3152
3310
|
jsonSchema: {
|
|
3153
3311
|
type: "object",
|
|
3154
3312
|
properties: {
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
isReadOnly: true,
|
|
3164
|
-
maxResultSizeChars: 6e3,
|
|
3165
|
-
async call(input) {
|
|
3166
|
-
if (!input.chain && !input.project) {
|
|
3167
|
-
const all = await fetchDefillamaYieldPools();
|
|
3168
|
-
const chainCounts = /* @__PURE__ */ new Map();
|
|
3169
|
-
for (const p of all) {
|
|
3170
|
-
chainCounts.set(p.chain, (chainCounts.get(p.chain) ?? 0) + 1);
|
|
3313
|
+
coinTypes: {
|
|
3314
|
+
type: "array",
|
|
3315
|
+
items: { type: "string" },
|
|
3316
|
+
description: "Sui coin type strings (max 10)."
|
|
3317
|
+
},
|
|
3318
|
+
include24hChange: {
|
|
3319
|
+
type: "boolean",
|
|
3320
|
+
description: "Include 24h change percentage per token."
|
|
3171
3321
|
}
|
|
3172
|
-
const topChains = [...chainCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 8).map(([chain, count]) => ({ chain, pools: count }));
|
|
3173
|
-
return {
|
|
3174
|
-
data: {
|
|
3175
|
-
_refine: {
|
|
3176
|
-
reason: "Cross-chain yield search is too broad; pick a chain.",
|
|
3177
|
-
suggestedParams: { chain: "Sui" },
|
|
3178
|
-
availableChains: topChains
|
|
3179
|
-
}
|
|
3180
|
-
},
|
|
3181
|
-
displayText: "Yield query needs a chain filter. Common chains: " + topChains.map((c) => c.chain).join(", ")
|
|
3182
|
-
};
|
|
3183
|
-
}
|
|
3184
|
-
let pools = await fetchDefillamaYieldPools();
|
|
3185
|
-
if (input.chain) {
|
|
3186
|
-
const chain = input.chain.toLowerCase();
|
|
3187
|
-
pools = pools.filter((p) => p.chain.toLowerCase() === chain);
|
|
3188
|
-
}
|
|
3189
|
-
if (input.project) {
|
|
3190
|
-
const project = input.project.toLowerCase();
|
|
3191
|
-
pools = pools.filter((p) => p.project.toLowerCase() === project);
|
|
3192
|
-
}
|
|
3193
|
-
const minTvl = input.minTvl ?? 1e5;
|
|
3194
|
-
pools = pools.filter((p) => p.tvlUsd >= minTvl);
|
|
3195
|
-
if (input.stableOnly) {
|
|
3196
|
-
pools = pools.filter((p) => {
|
|
3197
|
-
const legs = p.symbol.split("-");
|
|
3198
|
-
return legs.every((leg) => POOL_STABLE_LEGS.has(leg.trim().toUpperCase()));
|
|
3199
|
-
});
|
|
3200
|
-
}
|
|
3201
|
-
pools.sort((a, b) => b.apy - a.apy);
|
|
3202
|
-
const limit = input.limit ?? 5;
|
|
3203
|
-
const top = pools.slice(0, limit);
|
|
3204
|
-
const results = top.map((p) => ({
|
|
3205
|
-
pool: p.symbol,
|
|
3206
|
-
protocol: p.project,
|
|
3207
|
-
chain: p.chain,
|
|
3208
|
-
apy: Math.round(p.apy * 100) / 100,
|
|
3209
|
-
apyBase: p.apyBase != null ? Math.round(p.apyBase * 100) / 100 : void 0,
|
|
3210
|
-
apyReward: p.apyReward != null ? Math.round(p.apyReward * 100) / 100 : void 0,
|
|
3211
|
-
tvl: Math.round(p.tvlUsd)
|
|
3212
|
-
}));
|
|
3213
|
-
return {
|
|
3214
|
-
data: results,
|
|
3215
|
-
displayText: results.map((r) => `${r.pool} (${r.protocol}): ${r.apy}% APY, ${fmtToolTvl(r.tvl)} TVL`).join("\n")
|
|
3216
|
-
};
|
|
3217
|
-
}
|
|
3218
|
-
});
|
|
3219
|
-
var defillamaProtocolInfoTool = buildTool({
|
|
3220
|
-
name: "defillama_protocol_info",
|
|
3221
|
-
description: 'Get detailed info about a DeFi protocol: TVL, category, chains it operates on, and TVL changes. Use for "Is this protocol safe?" or "Tell me about NAVI."',
|
|
3222
|
-
inputSchema: z.object({
|
|
3223
|
-
name: z.string().describe('Protocol name (e.g. "navi-lending", "cetus")')
|
|
3224
|
-
}),
|
|
3225
|
-
jsonSchema: {
|
|
3226
|
-
type: "object",
|
|
3227
|
-
properties: {
|
|
3228
|
-
name: { type: "string", description: 'Protocol slug (e.g. "navi-lending")' }
|
|
3229
|
-
},
|
|
3230
|
-
required: ["name"]
|
|
3231
|
-
},
|
|
3232
|
-
isReadOnly: true,
|
|
3233
|
-
maxResultSizeChars: 4e3,
|
|
3234
|
-
async call(input) {
|
|
3235
|
-
const data = await cachedFetch(`${LLAMA_API2}/protocol/${encodeURIComponent(input.name)}`);
|
|
3236
|
-
const result = {
|
|
3237
|
-
name: data.name,
|
|
3238
|
-
category: data.category,
|
|
3239
|
-
chains: data.chains,
|
|
3240
|
-
tvl: Math.round(data.tvl),
|
|
3241
|
-
change1d: data.change_1d,
|
|
3242
|
-
change7d: data.change_7d,
|
|
3243
|
-
url: data.url,
|
|
3244
|
-
description: data.description
|
|
3245
|
-
};
|
|
3246
|
-
return {
|
|
3247
|
-
data: result,
|
|
3248
|
-
displayText: `${result.name}: ${fmtToolTvl(result.tvl)} TVL (${result.category}) on ${result.chains.join(", ")}`
|
|
3249
|
-
};
|
|
3250
|
-
}
|
|
3251
|
-
});
|
|
3252
|
-
var defillamaTokenPricesTool = buildTool({
|
|
3253
|
-
name: "defillama_token_prices",
|
|
3254
|
-
description: 'Get current USD prices for Sui tokens. Accepts full coin type strings (e.g. "0x2::sui::SUI"). Returns price per token.',
|
|
3255
|
-
inputSchema: z.object({
|
|
3256
|
-
coinTypes: z.array(z.string()).min(1).max(10).describe("Array of Sui coin type strings")
|
|
3257
|
-
}),
|
|
3258
|
-
jsonSchema: {
|
|
3259
|
-
type: "object",
|
|
3260
|
-
properties: {
|
|
3261
|
-
coinTypes: { type: "array", items: { type: "string" }, description: "Sui coin type strings" }
|
|
3262
3322
|
},
|
|
3263
3323
|
required: ["coinTypes"]
|
|
3264
3324
|
},
|
|
3265
3325
|
isReadOnly: true,
|
|
3266
|
-
async call(input) {
|
|
3267
|
-
const prices = await fetchTokenPrices(input.coinTypes);
|
|
3268
|
-
const results = input.coinTypes.map((
|
|
3269
|
-
coinType
|
|
3270
|
-
symbol
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
}
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
description: "Get price change for a Sui token over a period. Shows current price and historical price to calculate % change.",
|
|
3282
|
-
inputSchema: z.object({
|
|
3283
|
-
coinType: z.string().describe('Sui coin type (e.g. "0x2::sui::SUI")'),
|
|
3284
|
-
period: z.enum(["1h", "24h", "7d", "30d"]).optional().describe('Period (default "24h")')
|
|
3285
|
-
}),
|
|
3286
|
-
jsonSchema: {
|
|
3287
|
-
type: "object",
|
|
3288
|
-
properties: {
|
|
3289
|
-
coinType: { type: "string", description: "Sui coin type string" },
|
|
3290
|
-
period: { type: "string", description: "Period: 1h, 24h, 7d, 30d" }
|
|
3291
|
-
},
|
|
3292
|
-
required: ["coinType"]
|
|
3293
|
-
},
|
|
3294
|
-
isReadOnly: true,
|
|
3295
|
-
async call(input) {
|
|
3296
|
-
const period = input.period ?? "24h";
|
|
3297
|
-
const hoursMap = { "1h": 1, "24h": 24, "7d": 168, "30d": 720 };
|
|
3298
|
-
const hours = hoursMap[period] ?? 24;
|
|
3299
|
-
const historicalTs = Math.floor(Date.now() / 1e3) - hours * 3600;
|
|
3300
|
-
const coinKey = `sui:${input.coinType}`;
|
|
3301
|
-
const [current, historical] = await Promise.all([
|
|
3302
|
-
cachedFetch(
|
|
3303
|
-
`${COINS_API}/prices/current/${encodeURIComponent(coinKey)}`
|
|
3304
|
-
),
|
|
3305
|
-
cachedFetch(
|
|
3306
|
-
`${COINS_API}/prices/historical/${historicalTs}/${encodeURIComponent(coinKey)}`
|
|
3307
|
-
)
|
|
3308
|
-
]);
|
|
3309
|
-
const currentPrice = current.coins[coinKey]?.price;
|
|
3310
|
-
const historicalPrice = historical.coins[coinKey]?.price;
|
|
3311
|
-
const symbol = input.coinType.split("::").pop() ?? input.coinType;
|
|
3312
|
-
if (currentPrice == null) {
|
|
3313
|
-
return {
|
|
3314
|
-
data: { symbol, currentPrice: 0, historicalPrice: null, change: null, period },
|
|
3315
|
-
displayText: "Token price not available on DefiLlama."
|
|
3316
|
-
};
|
|
3317
|
-
}
|
|
3318
|
-
const change = historicalPrice ? Math.round((currentPrice - historicalPrice) / historicalPrice * 1e4) / 100 : null;
|
|
3319
|
-
return {
|
|
3320
|
-
data: {
|
|
3326
|
+
async call(input, context) {
|
|
3327
|
+
const prices = await fetchTokenPrices(input.coinTypes, context.blockvisionApiKey);
|
|
3328
|
+
const results = input.coinTypes.map((coinType) => {
|
|
3329
|
+
const entry = prices[coinType];
|
|
3330
|
+
const symbol = coinType.split("::").pop() ?? coinType;
|
|
3331
|
+
if (!entry) {
|
|
3332
|
+
return {
|
|
3333
|
+
coinType,
|
|
3334
|
+
symbol,
|
|
3335
|
+
price: null,
|
|
3336
|
+
priceUnavailable: true
|
|
3337
|
+
};
|
|
3338
|
+
}
|
|
3339
|
+
const out = {
|
|
3340
|
+
coinType,
|
|
3321
3341
|
symbol,
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
}
|
|
3327
|
-
|
|
3328
|
-
};
|
|
3329
|
-
}
|
|
3330
|
-
});
|
|
3331
|
-
var defillamaChainTvlTool = buildTool({
|
|
3332
|
-
name: "defillama_chain_tvl",
|
|
3333
|
-
description: 'Get chain TVL rankings. Shows top chains by total value locked. Use for "How big is Sui?" or "Compare chains."',
|
|
3334
|
-
inputSchema: z.object({
|
|
3335
|
-
limit: z.number().min(1).max(20).optional().describe("Max results (default 10)")
|
|
3336
|
-
}),
|
|
3337
|
-
jsonSchema: {
|
|
3338
|
-
type: "object",
|
|
3339
|
-
properties: {
|
|
3340
|
-
limit: { type: "number", description: "Max results (default 10)" }
|
|
3341
|
-
},
|
|
3342
|
-
required: []
|
|
3343
|
-
},
|
|
3344
|
-
isReadOnly: true,
|
|
3345
|
-
async call(input) {
|
|
3346
|
-
const data = await cachedFetch(`${LLAMA_API2}/v2/chains`);
|
|
3347
|
-
const sorted = [...data].sort((a, b) => b.tvl - a.tvl);
|
|
3348
|
-
const limit = input.limit ?? 10;
|
|
3349
|
-
const top = sorted.slice(0, limit);
|
|
3350
|
-
const results = top.map((c, i) => ({
|
|
3351
|
-
rank: i + 1,
|
|
3352
|
-
chain: c.name,
|
|
3353
|
-
tvl: Math.round(c.tvl)
|
|
3354
|
-
}));
|
|
3355
|
-
return {
|
|
3356
|
-
data: results,
|
|
3357
|
-
displayText: results.map((r) => `#${r.rank} ${r.chain}: $${(r.tvl / 1e9).toFixed(2)}B`).join("\n")
|
|
3358
|
-
};
|
|
3359
|
-
}
|
|
3360
|
-
});
|
|
3361
|
-
var defillamaProtocolFeesTool = buildTool({
|
|
3362
|
-
name: "defillama_protocol_fees",
|
|
3363
|
-
description: 'Get protocol fee/revenue rankings. Shows which protocols earn the most in fees. Use for "Which protocols are most profitable?"',
|
|
3364
|
-
inputSchema: z.object({
|
|
3365
|
-
chain: z.string().optional().describe("Filter by chain"),
|
|
3366
|
-
limit: z.number().min(1).max(20).optional().describe("Max results (default 5)")
|
|
3367
|
-
}),
|
|
3368
|
-
jsonSchema: {
|
|
3369
|
-
type: "object",
|
|
3370
|
-
properties: {
|
|
3371
|
-
chain: { type: "string", description: "Filter by chain" },
|
|
3372
|
-
limit: { type: "number", description: "Max results (default 5)" }
|
|
3373
|
-
},
|
|
3374
|
-
required: []
|
|
3375
|
-
},
|
|
3376
|
-
isReadOnly: true,
|
|
3377
|
-
async call(input) {
|
|
3378
|
-
const data = await cachedFetch(`${LLAMA_API2}/overview/fees`);
|
|
3379
|
-
let protocols = data.protocols ?? [];
|
|
3380
|
-
if (input.chain) {
|
|
3381
|
-
const chain = input.chain.toLowerCase();
|
|
3382
|
-
protocols = protocols.filter(
|
|
3383
|
-
(p) => p.chains?.some((c) => c.toLowerCase() === chain)
|
|
3384
|
-
);
|
|
3385
|
-
}
|
|
3386
|
-
protocols.sort((a, b) => (b.total24h ?? 0) - (a.total24h ?? 0));
|
|
3387
|
-
const limit = input.limit ?? 5;
|
|
3388
|
-
const top = protocols.slice(0, limit);
|
|
3389
|
-
const results = top.map((p) => ({
|
|
3390
|
-
name: p.name,
|
|
3391
|
-
fees24h: p.total24h != null ? Math.round(p.total24h) : null,
|
|
3392
|
-
fees7d: p.total7d != null ? Math.round(p.total7d) : null,
|
|
3393
|
-
category: p.category
|
|
3394
|
-
}));
|
|
3395
|
-
return {
|
|
3396
|
-
data: results,
|
|
3397
|
-
displayText: results.map((r) => `${r.name}: $${r.fees24h != null ? (r.fees24h / 1e3).toFixed(1) + "K" : "?"}/day`).join("\n")
|
|
3398
|
-
};
|
|
3399
|
-
}
|
|
3400
|
-
});
|
|
3401
|
-
var defillamaSuiProtocolsTool = buildTool({
|
|
3402
|
-
name: "defillama_sui_protocols",
|
|
3403
|
-
description: "List top DeFi protocols on Sui by TVL. Shows name, TVL, category, and slug for each protocol. Use to discover protocols before calling defillama_protocol_info.",
|
|
3404
|
-
inputSchema: z.object({
|
|
3405
|
-
limit: z.number().int().min(1).max(50).optional().describe("Max protocols to return (default 10)")
|
|
3406
|
-
}),
|
|
3407
|
-
jsonSchema: {
|
|
3408
|
-
type: "object",
|
|
3409
|
-
properties: {
|
|
3410
|
-
limit: { type: "number", description: "Max protocols to return (default 10)" }
|
|
3411
|
-
}
|
|
3412
|
-
},
|
|
3413
|
-
isReadOnly: true,
|
|
3414
|
-
async call(input) {
|
|
3415
|
-
const limit = input.limit ?? 10;
|
|
3416
|
-
const data = await cachedFetch(`${LLAMA_API2}/protocols`);
|
|
3417
|
-
const suiProtocols = data.filter((p) => p.chains?.includes("Sui") && p.tvl > 0).sort((a, b) => b.tvl - a.tvl).slice(0, limit);
|
|
3418
|
-
const results = suiProtocols.map((p) => ({
|
|
3419
|
-
name: p.name,
|
|
3420
|
-
slug: p.slug,
|
|
3421
|
-
tvl: Math.round(p.tvl),
|
|
3422
|
-
category: p.category
|
|
3423
|
-
}));
|
|
3342
|
+
price: entry.price
|
|
3343
|
+
};
|
|
3344
|
+
if (input.include24hChange && entry.change24h !== void 0) {
|
|
3345
|
+
out.change24h = entry.change24h;
|
|
3346
|
+
}
|
|
3347
|
+
return out;
|
|
3348
|
+
});
|
|
3424
3349
|
return {
|
|
3425
3350
|
data: results,
|
|
3426
|
-
displayText: results.map((r
|
|
3351
|
+
displayText: results.map((r) => {
|
|
3352
|
+
if (r.price === null) return `${r.symbol}: price unavailable`;
|
|
3353
|
+
const change = r.change24h;
|
|
3354
|
+
return change !== void 0 ? `${r.symbol}: $${r.price.toFixed(4)} (${change >= 0 ? "+" : ""}${change.toFixed(2)}% 24h)` : `${r.symbol}: $${r.price.toFixed(4)}`;
|
|
3355
|
+
}).join(", ")
|
|
3427
3356
|
};
|
|
3428
3357
|
}
|
|
3429
3358
|
});
|
|
@@ -3443,13 +3372,7 @@ var READ_TOOLS = [
|
|
|
3443
3372
|
explainTxTool,
|
|
3444
3373
|
portfolioAnalysisTool,
|
|
3445
3374
|
protocolDeepDiveTool,
|
|
3446
|
-
|
|
3447
|
-
defillamaProtocolInfoTool,
|
|
3448
|
-
defillamaTokenPricesTool,
|
|
3449
|
-
defillamaPriceChangeTool,
|
|
3450
|
-
defillamaChainTvlTool,
|
|
3451
|
-
defillamaProtocolFeesTool,
|
|
3452
|
-
defillamaSuiProtocolsTool,
|
|
3375
|
+
tokenPricesTool,
|
|
3453
3376
|
listPaymentLinksTool,
|
|
3454
3377
|
cancelPaymentLinkTool,
|
|
3455
3378
|
listInvoicesTool,
|
|
@@ -3512,7 +3435,7 @@ function getModifiableFields(toolName) {
|
|
|
3512
3435
|
}
|
|
3513
3436
|
|
|
3514
3437
|
// src/prompt.ts
|
|
3515
|
-
var DEFAULT_SYSTEM_PROMPT = `You are Audric \u2014 a financial agent on Sui. Audric is exactly five products: Audric Passport (the trust layer \u2014 Google sign-in, non-custodial wallet, tap-to-confirm consent, sponsored gas \u2014 wraps every other product), Audric Intelligence (you \u2014 the 5-system brain: Agent Harness with
|
|
3438
|
+
var DEFAULT_SYSTEM_PROMPT = `You are Audric \u2014 a financial agent on Sui. Audric is exactly five products: Audric Passport (the trust layer \u2014 Google sign-in, non-custodial wallet, tap-to-confirm consent, sponsored gas \u2014 wraps every other product), Audric Intelligence (you \u2014 the 5-system brain: Agent Harness with 34 tools, Reasoning Engine with 9 guards and 7 skill recipes, Silent Profile, Chain Memory, AdviceLog), Audric Finance (manage money on Sui \u2014 Save via NAVI lending at 3-8% APY USDC, Credit via NAVI borrowing with health factor, Swap via Cetus aggregator across 20+ DEXs at 0.1% fee, Charts for yield/health/portfolio viz), Audric Pay (move money \u2014 send USDC, receive via payment links / invoices / QR; free, global, instant on Sui), and Audric Store (creator marketplace, ships Phase 5 \u2014 say "coming soon" if asked). Save, swap, borrow, repay, withdraw, charts \u2192 Audric Finance. Send, receive, payment-link, invoice, QR \u2192 Audric Pay. Your silent context (profile, memory, chain facts, advice log) shapes your replies but never surfaces as a notification \u2014 you act only when the user asks, and every write waits on their tap-to-confirm via Passport. You can also call 41 paid APIs (music, image, research, translation, weather, fulfilment) via MPP micropayments using the pay_api tool \u2014 this is an internal capability, not a promoted product, so only mention it when the user asks for something that needs it.
|
|
3516
3439
|
|
|
3517
3440
|
## Response rules
|
|
3518
3441
|
- 1-2 sentences max. No bullet lists unless asked. No preambles.
|
|
@@ -3532,8 +3455,8 @@ Only offer to execute actions you have tools for. If you retrieved a quote, data
|
|
|
3532
3455
|
## Tool usage
|
|
3533
3456
|
- Use tools proactively \u2014 don't refuse requests you can handle.
|
|
3534
3457
|
- For real-world questions (weather, search, news, prices), use pay_api. Tell the user the cost first.
|
|
3535
|
-
- For
|
|
3536
|
-
-
|
|
3458
|
+
- For NAVI lending APYs, use rates_info; for VOLO liquid staking stats, use volo_stats; for spot token prices, use token_prices.
|
|
3459
|
+
- For protocol-level due diligence (TVL, fees, audits, safety) on Sui DeFi protocols, use protocol_deep_dive with the slug.
|
|
3537
3460
|
- Run multiple read-only tools in parallel when you need several data points.
|
|
3538
3461
|
- If a tool errors, say what went wrong and what to try instead. One sentence.
|
|
3539
3462
|
|
|
@@ -3546,11 +3469,11 @@ Only offer to execute actions you have tools for. If you retrieved a quote, data
|
|
|
3546
3469
|
## Multi-step flows
|
|
3547
3470
|
- "How much X for Y?": swap_quote first, then swap_execute if user confirms.
|
|
3548
3471
|
- "Swap then save": swap_execute \u2192 balance_check \u2192 save_deposit. Confirm each step.
|
|
3549
|
-
- "Buy $X of token":
|
|
3550
|
-
- "Best yield on SUI": compare rates_info (NAVI lending) +
|
|
3472
|
+
- "Buy $X of token": token_prices \u2192 calculate amount \u2192 swap_execute.
|
|
3473
|
+
- "Best yield on SUI": compare rates_info (NAVI lending) + volo_stats (vSUI liquid staking).
|
|
3551
3474
|
- withdraw supports legacy positions: USDC, USDe, USDsui, SUI. Pass asset param to withdraw a specific token.
|
|
3552
3475
|
- "Deposit SUI to earn yield": volo_stake for SUI liquid staking. save_deposit is USDC only.
|
|
3553
|
-
- "
|
|
3476
|
+
- "Is protocol X safe?" / "Tell me about NAVI": protocol_deep_dive with the slug.
|
|
3554
3477
|
- "Full account report" / "account summary" / "give me everything" / "complete overview": triggers the \`account_report\` recipe \u2014 when the recipe block appears, follow EVERY step including all six tool calls. Each step renders a distinct rich card; skipping a step means a missing card.
|
|
3555
3478
|
|
|
3556
3479
|
## Safety
|
|
@@ -4701,6 +4624,12 @@ var QueryEngine = class {
|
|
|
4701
4624
|
sessionSpendUsd;
|
|
4702
4625
|
onAutoExecuted;
|
|
4703
4626
|
onGuardFired;
|
|
4627
|
+
// [v1.4 BlockVision] BlockVision Indexer API key + per-request portfolio
|
|
4628
|
+
// cache. Forwarded into every `ToolContext` build site so read tools
|
|
4629
|
+
// (`balance_check`, `portfolio_analysis`, future `token_prices`) hit the
|
|
4630
|
+
// shared host-paid endpoint and dedupe across each other within a turn.
|
|
4631
|
+
blockvisionApiKey;
|
|
4632
|
+
portfolioCache;
|
|
4704
4633
|
// [v1.5] See `EngineConfig.postWriteRefresh` — drives the post-write
|
|
4705
4634
|
// synthetic read injection in `resumeWithToolResult`.
|
|
4706
4635
|
postWriteRefresh;
|
|
@@ -4750,6 +4679,8 @@ var QueryEngine = class {
|
|
|
4750
4679
|
this.onAutoExecuted = config.onAutoExecuted;
|
|
4751
4680
|
this.onGuardFired = config.onGuardFired;
|
|
4752
4681
|
this.postWriteRefresh = config.postWriteRefresh;
|
|
4682
|
+
this.blockvisionApiKey = config.blockvisionApiKey;
|
|
4683
|
+
this.portfolioCache = config.portfolioCache;
|
|
4753
4684
|
this.tools = config.tools ?? (config.agent ? getDefaultTools() : []);
|
|
4754
4685
|
}
|
|
4755
4686
|
/**
|
|
@@ -4867,8 +4798,14 @@ var QueryEngine = class {
|
|
|
4867
4798
|
signal,
|
|
4868
4799
|
priceCache: this.priceCache,
|
|
4869
4800
|
permissionConfig: this.permissionConfig,
|
|
4870
|
-
sessionSpendUsd: this.sessionSpendUsd
|
|
4801
|
+
sessionSpendUsd: this.sessionSpendUsd,
|
|
4802
|
+
blockvisionApiKey: this.blockvisionApiKey,
|
|
4803
|
+
portfolioCache: this.portfolioCache
|
|
4871
4804
|
};
|
|
4805
|
+
if (this.walletAddress) {
|
|
4806
|
+
this.portfolioCache?.delete(this.walletAddress);
|
|
4807
|
+
clearPortfolioCacheFor(this.walletAddress);
|
|
4808
|
+
}
|
|
4872
4809
|
if (!signal.aborted) {
|
|
4873
4810
|
await new Promise((resolve) => {
|
|
4874
4811
|
const t = setTimeout(resolve, 1500);
|
|
@@ -5014,7 +4951,9 @@ var QueryEngine = class {
|
|
|
5014
4951
|
signal,
|
|
5015
4952
|
priceCache: this.priceCache,
|
|
5016
4953
|
permissionConfig: this.permissionConfig,
|
|
5017
|
-
sessionSpendUsd: this.sessionSpendUsd
|
|
4954
|
+
sessionSpendUsd: this.sessionSpendUsd,
|
|
4955
|
+
blockvisionApiKey: this.blockvisionApiKey,
|
|
4956
|
+
portfolioCache: this.portfolioCache
|
|
5018
4957
|
};
|
|
5019
4958
|
try {
|
|
5020
4959
|
const result = await tool.call(parsed.data, context);
|
|
@@ -5057,7 +4996,9 @@ var QueryEngine = class {
|
|
|
5057
4996
|
signal,
|
|
5058
4997
|
priceCache: this.priceCache,
|
|
5059
4998
|
permissionConfig: this.permissionConfig,
|
|
5060
|
-
sessionSpendUsd: this.sessionSpendUsd
|
|
4999
|
+
sessionSpendUsd: this.sessionSpendUsd,
|
|
5000
|
+
blockvisionApiKey: this.blockvisionApiKey,
|
|
5001
|
+
portfolioCache: this.portfolioCache
|
|
5061
5002
|
};
|
|
5062
5003
|
let turns = 0;
|
|
5063
5004
|
let hasRetriedWithCleanHistory = false;
|
|
@@ -5421,7 +5362,8 @@ ${recipeCtx}`;
|
|
|
5421
5362
|
);
|
|
5422
5363
|
Promise.resolve().then(() => this.onAutoExecuted({
|
|
5423
5364
|
toolName: toolEvent.toolName,
|
|
5424
|
-
usdValue
|
|
5365
|
+
usdValue,
|
|
5366
|
+
walletAddress: this.walletAddress
|
|
5425
5367
|
})).catch((err) => {
|
|
5426
5368
|
console.warn("[engine] onAutoExecuted callback failed:", err);
|
|
5427
5369
|
});
|
|
@@ -5476,6 +5418,7 @@ ${recipeCtx}`;
|
|
|
5476
5418
|
const writeGuardInjections = pendingWrite.call._guardInjections;
|
|
5477
5419
|
const modifiableFields = getModifiableFields(pendingWrite.call.name);
|
|
5478
5420
|
const turnIndex = this.messages.filter((m) => m.role === "assistant").length;
|
|
5421
|
+
const attemptId = randomUUID();
|
|
5479
5422
|
this.turnPaused = true;
|
|
5480
5423
|
yield {
|
|
5481
5424
|
type: "pending_action",
|
|
@@ -5492,7 +5435,8 @@ ${recipeCtx}`;
|
|
|
5492
5435
|
})),
|
|
5493
5436
|
...writeGuardInjections?.length ? { guardInjections: writeGuardInjections } : {},
|
|
5494
5437
|
...modifiableFields?.length ? { modifiableFields } : {},
|
|
5495
|
-
turnIndex
|
|
5438
|
+
turnIndex,
|
|
5439
|
+
attemptId
|
|
5496
5440
|
}
|
|
5497
5441
|
};
|
|
5498
5442
|
return;
|
|
@@ -6748,6 +6692,6 @@ function sanitizeAnthropicMessages(messages) {
|
|
|
6748
6692
|
return merged;
|
|
6749
6693
|
}
|
|
6750
6694
|
|
|
6751
|
-
export { AnthropicProvider, BalanceTracker, CANVAS_TEMPLATES, ContextBudget, CostTracker, DEFAULT_GUARD_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_SYSTEM_PROMPT, EarlyToolDispatcher, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, NaviTools, PERMISSION_PRESETS, QueryEngine, READ_TOOLS, RecipeRegistry, RetryTracker, TOOL_FLAGS, TOOL_MODIFIABLE_FIELDS, TxMutex, WRITE_TOOLS, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, applyToolFlags, balanceCheckTool, borrowTool, budgetToolResult, buildCachedSystemPrompt, buildMcpTools, buildProactivenessInstructions, buildProfileContext, buildSelfEvaluationInstruction, buildStateContext, buildTool, claimRewardsTool, classifyEffort,
|
|
6695
|
+
export { AnthropicProvider, BalanceTracker, CANVAS_TEMPLATES, ContextBudget, CostTracker, DEFAULT_GUARD_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_SYSTEM_PROMPT, EarlyToolDispatcher, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, NaviTools, PERMISSION_PRESETS, QueryEngine, READ_TOOLS, RecipeRegistry, RetryTracker, TOOL_FLAGS, TOOL_MODIFIABLE_FIELDS, TxMutex, WRITE_TOOLS, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, applyToolFlags, balanceCheckTool, borrowTool, budgetToolResult, buildCachedSystemPrompt, buildMcpTools, buildProactivenessInstructions, buildProfileContext, buildSelfEvaluationInstruction, buildStateContext, buildTool, claimRewardsTool, classifyEffort, clearPortfolioCache, clearPortfolioCacheFor, clearPriceMapCache, compactMessages, createGuardRunnerState, engineToSSE, estimateTokens, explainTxTool, extractConversationText, extractMcpText, fetchAddressPortfolio, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchTokenPrices, fetchWalletCoins, findTool, getDefaultTools, getMcpManager, getModifiableFields, getToolFlags, getWalletAddress, guardArtifactPreview, guardStaleData, hasNaviMcp, healthCheckTool, loadRecipes, microcompact, mppServicesTool, parseMcpJson, parseRecipe, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, resolvePermissionTier, resolveUsdValue, runGuards, runTools, saveContactTool, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, spendingAnalyticsTool, swapExecuteTool, swapQuoteTool, tokenPricesTool, toolNameToOperation, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, updateGuardStateAfterToolResult, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
|
|
6752
6696
|
//# sourceMappingURL=index.js.map
|
|
6753
6697
|
//# sourceMappingURL=index.js.map
|