@t2000/engine 0.50.2 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1969,6 +1969,7 @@ declare const balanceCheckTool: Tool<{
1969
1969
  stables: number;
1970
1970
  holdings: any[];
1971
1971
  saveableUsdc: number;
1972
+ saveableUsdsui: number;
1972
1973
  address: string;
1973
1974
  isSelfQuery: boolean;
1974
1975
  }>;
@@ -2030,12 +2031,12 @@ declare const transactionHistoryTool: Tool<{
2030
2031
 
2031
2032
  declare const saveDepositTool: Tool<{
2032
2033
  amount: number;
2033
- asset?: string | undefined;
2034
+ asset?: "USDC" | "USDsui" | undefined;
2034
2035
  }, {
2035
2036
  success: boolean;
2036
2037
  tx: string;
2037
2038
  amount: number;
2038
- asset: string;
2039
+ asset: "USDC" | "USDsui";
2039
2040
  apy: number;
2040
2041
  fee: number;
2041
2042
  gasCost: number;
@@ -2073,11 +2074,12 @@ declare const sendTransferTool: Tool<{
2073
2074
 
2074
2075
  declare const borrowTool: Tool<{
2075
2076
  amount: number;
2076
- asset?: string | undefined;
2077
+ asset?: "USDC" | "USDsui" | undefined;
2077
2078
  }, {
2078
2079
  success: boolean;
2079
2080
  tx: string;
2080
2081
  amount: number;
2082
+ asset: string;
2081
2083
  fee: number;
2082
2084
  healthFactor: number;
2083
2085
  gasCost: number;
@@ -2390,6 +2392,6 @@ interface WalletCoin {
2390
2392
  */
2391
2393
  declare function fetchWalletCoins(address: string, rpcUrl?: string): Promise<WalletCoin[]>;
2392
2394
 
2393
- declare const 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.\n\n## Response rules\n- 1-2 sentences max. No bullet lists unless asked. No preambles.\n- Never say \"Would you like me to...\", \"Sure!\", \"Great question!\", \"Absolutely!\" \u2014 just do it or say you can't.\n- Lead with the result. After tool calls, state the outcome with real numbers. Done.\n- Present amounts as $1,234.56 and rates as X.XX% APY.\n- Show top 3 results unless asked for more. Summarize totals in one line.\n\n## Execution rule\nOnly offer to execute actions you have tools for. If you retrieved a quote, data, or information but have no tool to act on it, give the user the result and tell them where to execute manually \u2014 in one sentence. Never say \"Would you like me to proceed?\" unless you have a tool that can actually proceed.\n\n## Before acting\n- ALWAYS call a read tool first before any write tool \u2014 balance_check before save/send/borrow, savings_info before withdraw.\n- Show real numbers from tools \u2014 never fabricate rates, amounts, or balances.\n- When user says \"all\" or an imprecise amount, call the read tool first to get the exact number.\n\n## Tool usage\n- Use tools proactively \u2014 don't refuse requests you can handle.\n- For real-world questions (weather, search, news, prices), use pay_api. Tell the user the cost first.\n- For NAVI lending APYs, use rates_info; for VOLO liquid staking stats, use volo_stats; for spot token prices, use token_prices.\n- For protocol-level due diligence (TVL, fees, audits, safety) on Sui DeFi protocols, use protocol_deep_dive with the slug.\n- Run multiple read-only tools in parallel when you need several data points.\n- If a tool errors, say what went wrong and what to try instead. One sentence.\n\n## Savings = USDC only (critical)\n- save_deposit accepts ONLY USDC. No other token can be deposited into savings.\n- When asked \"how much can I save?\", report only the user's USDC wallet balance (saveableUsdc field from balance_check). Other tokens like GOLD, SUI, USDT are NOT saveable and NOT savings positions \u2014 they are just wallet holdings.\n- NEVER say a non-USDC token is \"in savings\" or \"earning APY in savings\" unless it appears in the savings_info positions list. Wallet holdings \u2260 savings.\n- If user wants to save non-USDC tokens, tell them to swap to USDC first. Do NOT auto-chain swap + deposit.\n\n## Multi-step flows\n- \"How much X for Y?\": swap_quote first, then swap_execute if user confirms.\n- \"Swap then save\": swap_execute \u2192 balance_check \u2192 save_deposit. Confirm each step.\n- \"Buy $X of token\": token_prices \u2192 calculate amount \u2192 swap_execute.\n- \"Best yield on SUI\": compare rates_info (NAVI lending) + volo_stats (vSUI liquid staking).\n- withdraw supports legacy positions: USDC, USDe, USDsui, SUI. Pass asset param to withdraw a specific token.\n- \"Deposit SUI to earn yield\": volo_stake for SUI liquid staking. save_deposit is USDC only.\n- \"Is protocol X safe?\" / \"Tell me about NAVI\": protocol_deep_dive with the slug.\n- \"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.\n\n## Safety\n- Never encourage risky financial behavior.\n- Warn when health factor < 1.5.\n- All amounts in USDC unless stated otherwise.";
2395
+ declare const 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.\n\n## Response rules\n- 1-2 sentences max. No bullet lists unless asked. No preambles.\n- Never say \"Would you like me to...\", \"Sure!\", \"Great question!\", \"Absolutely!\" \u2014 just do it or say you can't.\n- Lead with the result. After tool calls, state the outcome with real numbers. Done.\n- Present amounts as $1,234.56 and rates as X.XX% APY.\n- Show top 3 results unless asked for more. Summarize totals in one line.\n\n## Execution rule\nOnly offer to execute actions you have tools for. If you retrieved a quote, data, or information but have no tool to act on it, give the user the result and tell them where to execute manually \u2014 in one sentence. Never say \"Would you like me to proceed?\" unless you have a tool that can actually proceed.\n\n## Before acting\n- ALWAYS call a read tool first before any write tool \u2014 balance_check before save/send/borrow, savings_info before withdraw.\n- Show real numbers from tools \u2014 never fabricate rates, amounts, or balances.\n- When user says \"all\" or an imprecise amount, call the read tool first to get the exact number.\n\n## Tool usage\n- Use tools proactively \u2014 don't refuse requests you can handle.\n- For real-world questions (weather, search, news, prices), use pay_api. Tell the user the cost first.\n- For NAVI lending APYs, use rates_info; for VOLO liquid staking stats, use volo_stats; for spot token prices, use token_prices.\n- For protocol-level due diligence (TVL, fees, audits, safety) on Sui DeFi protocols, use protocol_deep_dive with the slug.\n- Run multiple read-only tools in parallel when you need several data points.\n- If a tool errors, say what went wrong and what to try instead. One sentence.\n\n## Savings = USDC or USDsui (critical)\n- save_deposit and borrow accept ONLY USDC or USDsui. No other token can be deposited or borrowed.\n- USDC is the canonical default. USDsui is permitted because it has a productive NAVI pool (often a higher APY than USDC). All other holdings (GOLD, SUI, USDT, USDe, ETH, NAVX, WAL) are NOT saveable.\n- When asked \"how much can I save?\":\n - Report saveableUsdc from balance_check (the user's USDC wallet balance \u2014 canonical saveable).\n - If the user also holds USDsui in their wallet, report that separately as \"USDsui (saveable): X.XX\". Do NOT roll the two together \u2014 the LLM must keep the per-asset distinction so the user can pick.\n- When the user says \"save 10 USDC\" \u2192 call save_deposit with asset=\"USDC\". When they say \"save 10 USDsui\" \u2192 call with asset=\"USDsui\". Never silently substitute.\n- When the user says \"save 10\" (no asset) \u2192 call balance_check first and ask which stable they want, OR pick whichever they hold more of with a one-line explanation.\n- \"Best stable to save right now?\" \u2192 call rates_info to compare USDC vs USDsui APY on NAVI; let the user pick.\n- NEVER say a non-saveable token (GOLD, SUI, USDT, etc.) is \"in savings\" or \"earning APY in savings\". Wallet holdings \u2260 savings positions, even for stables we don't accept.\n- If user wants to save a non-saveable token, tell them to swap to USDC or USDsui first. Do NOT auto-chain swap + deposit.\n\n## Multi-step flows\n- \"How much X for Y?\": swap_quote first, then swap_execute if user confirms.\n- \"Swap then save\": swap_execute \u2192 balance_check \u2192 save_deposit. Confirm each step.\n- \"Buy $X of token\": token_prices \u2192 calculate amount \u2192 swap_execute.\n- \"Best yield on SUI\": compare rates_info (NAVI lending) + volo_stats (vSUI liquid staking).\n- withdraw supports legacy positions: USDC, USDe, USDsui, SUI. Pass asset param to withdraw a specific token.\n- \"Deposit SUI to earn yield\": volo_stake for SUI liquid staking. save_deposit only accepts USDC or USDsui.\n- \"Is protocol X safe?\" / \"Tell me about NAVI\": protocol_deep_dive with the slug.\n- \"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.\n\n## Safety\n- Never encourage risky financial behavior.\n- Warn when health factor < 1.5.\n- All amounts in USDC unless stated otherwise.";
2394
2396
 
2395
2397
  export { type AddressPortfolio, AnthropicProvider, type AnthropicProviderConfig, type BalancePrices, type BalanceResult, BalanceTracker, type BuildToolOptions, CANVAS_TEMPLATES, type CanvasTemplate, type ChatParams, type CompactOptions, type ContentBlock, ContextBudget, type ContextBudgetConfig, type ConversationState, type ConversationStateStore, type CostSnapshot, CostTracker, type CostTrackerConfig, DEFAULT_GUARD_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_SYSTEM_PROMPT, EarlyToolDispatcher, type EngineConfig, type EngineEvent, type GuardCheckResult, type GuardConfig, type GuardEvent, type GuardInjection, type GuardResult, type GuardRunnerState, type GuardTier, type GuardVerdict, type HealthFactorResult, type LLMProvider, type McpCallResult, McpClientManager, McpResponseCache, type McpServerConfig, type McpServerConnection, type McpToolAdapterConfig, type McpToolDescriptor, MemorySessionStore, type Message, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, type NaviRawCoin, type NaviRawHealthFactor, type NaviRawPool, type NaviRawPosition, type NaviRawPositionsResponse, type NaviRawProtocolStats, type NaviRawRewardsResponse, type NaviReadOptions, NaviTools, type OutputConfig, PERMISSION_PRESETS, type PendingAction, type PendingActionModifiableField, type PendingReward, type PendingToolCall, type PermissionLevel, type PermissionOperation, type PermissionResponse, type PermissionRule, type PortfolioCoin, type PositionEntry, type PreflightResult, type ProtocolStats, type ProviderEvent, QueryEngine, READ_TOOLS, type RatesResult, type Recipe, type RecipePrerequisite, RecipeRegistry, type RecipeStep, type RecipeStepOnError, RetryTracker, type SSEEvent, type SavingsResult, type ServerPositionData, type SessionData, type SessionStore, type StateType, type StopReason, type SuiCoinBalance, type SystemBlock, type SystemPrompt, TOOL_FLAGS, TOOL_MODIFIABLE_FIELDS, type ThinkingConfig, type ThinkingEffort, type Tool, type ToolChoice, type ToolContext, type ToolDefinition, type ToolFlags, type ToolJsonSchema, type ToolResult, TxMutex, type UserFinancialProfile, type UserPermissionConfig, WRITE_TOOLS, type WalletCoin, 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 };
package/dist/index.js CHANGED
@@ -530,7 +530,7 @@ async function fetchAddressPortfolio(address, apiKey, fallbackRpcUrl) {
530
530
  return blockvision;
531
531
  }
532
532
  }
533
- const degraded = await fetchPortfolioFromSuiRpc(address, fallbackRpcUrl);
533
+ const degraded = await fetchPortfolioFromSuiRpc(address, apiKey, fallbackRpcUrl);
534
534
  portfolioCache.set(address, { data: degraded, ts: Date.now() });
535
535
  return degraded;
536
536
  } finally {
@@ -599,21 +599,28 @@ async function fetchPortfolioFromBlockVision(address, apiKey) {
599
599
  source: "blockvision"
600
600
  };
601
601
  }
602
- async function fetchPortfolioFromSuiRpc(address, fallbackRpcUrl) {
602
+ async function fetchPortfolioFromSuiRpc(address, apiKey, fallbackRpcUrl) {
603
603
  const walletCoins = await fetchWalletCoins(address, fallbackRpcUrl).catch((err) => {
604
604
  console.warn("[blockvision-prices] sui rpc coin fetch failed:", err);
605
605
  return [];
606
606
  });
607
+ const nonStableCoinTypes = walletCoins.map((c) => c.coinType).filter((coinType) => !(coinType in STABLE_USD_PRICES));
608
+ const livePrices = apiKey && apiKey.trim().length > 0 && nonStableCoinTypes.length > 0 ? await fetchTokenPrices(nonStableCoinTypes, apiKey).catch((err) => {
609
+ console.warn("[blockvision-prices] price-list fallback failed:", err);
610
+ return {};
611
+ }) : {};
607
612
  const coins = walletCoins.map((c) => {
608
613
  const stablePrice = STABLE_USD_PRICES[c.coinType] ?? null;
614
+ const livePrice = livePrices[c.coinType]?.price ?? null;
615
+ const price = stablePrice ?? livePrice;
609
616
  const amount = Number(c.totalBalance) / 10 ** c.decimals;
610
- const usdValue = stablePrice != null && Number.isFinite(amount) ? amount * stablePrice : null;
617
+ const usdValue = price != null && Number.isFinite(amount) ? amount * price : null;
611
618
  return {
612
619
  coinType: c.coinType,
613
620
  symbol: c.symbol,
614
621
  decimals: c.decimals,
615
622
  balance: c.totalBalance,
616
- price: stablePrice,
623
+ price,
617
624
  usdValue
618
625
  };
619
626
  });
@@ -1148,7 +1155,7 @@ async function loadPortfolio(address, blockvisionApiKey, fallbackRpcUrl, cache)
1148
1155
  }
1149
1156
  var balanceCheckTool = buildTool({
1150
1157
  name: "balance_check",
1151
- description: "Get the full balance breakdown for the signed-in user OR any public Sui address. Returns wallet holdings (tokens the address 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. Pass `address` to inspect a contact / watched / public wallet; defaults to the signed-in user when omitted.",
1158
+ description: "Get the full balance breakdown for the signed-in user OR any public Sui address. Returns wallet holdings (tokens the address owns \u2014 NOT savings), NAVI savings deposits (USDC and/or USDsui deposited into NAVI Protocol earning yield), outstanding debt, pending rewards, gas reserve, total net worth, saveableUsdc (USDC wallet balance available to save), and saveableUsdsui (USDsui wallet balance available to save \u2014 surfaces only when > 0). IMPORTANT: wallet holdings like GOLD, SUI, USDT, USDe are NOT savings positions and are NOT saveable \u2014 only USDC and USDsui can be saved/borrowed. Pass `address` to inspect a contact / watched / public wallet; defaults to the signed-in user when omitted.",
1152
1159
  inputSchema: z.object({
1153
1160
  address: z.string().regex(SUI_ADDRESS_REGEX).optional().describe("Sui address to inspect (defaults to the signed-in wallet)")
1154
1161
  }),
@@ -1272,6 +1279,8 @@ var balanceCheckTool = buildTool({
1272
1279
  const visibleHoldings = holdings.filter((h) => h.usdValue >= 0.01).sort((a, b) => b.usdValue - a.usdValue);
1273
1280
  const usdcHolding2 = holdings.find((h) => h.symbol === "USDC");
1274
1281
  const saveableUsdc = usdcHolding2 ? usdcHolding2.balance : 0;
1282
+ const usdsuiHolding2 = holdings.find((h) => h.symbol === "USDsui");
1283
+ const saveableUsdsui = usdsuiHolding2 ? usdsuiHolding2.balance : 0;
1275
1284
  const defi2 = defiPortfolio;
1276
1285
  const bal = {
1277
1286
  available: availableUsd,
@@ -1286,6 +1295,7 @@ var balanceCheckTool = buildTool({
1286
1295
  stables: stablesUsd,
1287
1296
  holdings: visibleHoldings,
1288
1297
  saveableUsdc,
1298
+ saveableUsdsui,
1289
1299
  priceSource: portfolio.source,
1290
1300
  address,
1291
1301
  isSelfQuery
@@ -1293,9 +1303,10 @@ var balanceCheckTool = buildTool({
1293
1303
  const holdingsList = visibleHoldings.map((h) => `${h.symbol}: ${h.balance < 1 ? h.balance.toFixed(6) : h.balance.toFixed(2)} ($${h.usdValue.toFixed(2)})`).join(", ");
1294
1304
  const subjectPrefix = isSelfQuery ? "Balance" : `Balance for ${address.slice(0, 6)}\u2026${address.slice(-4)}`;
1295
1305
  const defiSummaryText = defi2.totalUsd > 0 ? ` Other DeFi positions (LPs/staking/lending across ${Object.keys(defi2.perProtocol).join("/")}): $${defi2.totalUsd.toFixed(2)}.` : "";
1306
+ const saveableSummary = saveableUsdsui > 0 ? `Saveable: ${saveableUsdc.toFixed(2)} USDC + ${saveableUsdsui.toFixed(saveableUsdsui < 1 ? 4 : 2)} USDsui (only USDC and USDsui can be saved/borrowed).` : `Saveable USDC (only USDC and USDsui can be saved): ${saveableUsdc.toFixed(2)} USDC.`;
1296
1307
  return {
1297
1308
  data: bal,
1298
- displayText: `${subjectPrefix}: $${bal.total.toFixed(2)} total. Wallet holdings (NOT savings): ${holdingsList || "none"}. NAVI savings deposits: $${bal.savings.toFixed(2)}.${defiSummaryText} Saveable USDC (only USDC can be saved): ${saveableUsdc.toFixed(2)} USDC.`
1309
+ displayText: `${subjectPrefix}: $${bal.total.toFixed(2)} total. Wallet holdings (NOT savings): ${holdingsList || "none"}. NAVI savings deposits: $${bal.savings.toFixed(2)}.${defiSummaryText} ${saveableSummary}`
1299
1310
  };
1300
1311
  }
1301
1312
  if (input.address && context.walletAddress && input.address.toLowerCase() !== context.walletAddress.toLowerCase()) {
@@ -1324,6 +1335,8 @@ var balanceCheckTool = buildTool({
1324
1335
  const holdingsArr = Array.isArray(sdkHoldings) ? sdkHoldings : [];
1325
1336
  const usdcHolding = holdingsArr.find((h) => h.symbol === "USDC");
1326
1337
  const sdkSaveableUsdc = usdcHolding ? usdcHolding.balance ?? 0 : 0;
1338
+ const usdsuiHolding = holdingsArr.find((h) => h.symbol === "USDsui");
1339
+ const sdkSaveableUsdsui = usdsuiHolding ? usdsuiHolding.balance ?? 0 : 0;
1327
1340
  const sdkDefiSummaryText = defi.totalUsd > 0 ? ` Other DeFi positions (LPs/staking/lending across ${Object.keys(defi.perProtocol).join("/")}): $${defi.totalUsd.toFixed(2)}.` : "";
1328
1341
  const sdkTotal = balance.total + defi.totalUsd;
1329
1342
  return {
@@ -1340,10 +1353,11 @@ var balanceCheckTool = buildTool({
1340
1353
  stables: stablesTotal,
1341
1354
  holdings: holdingsArr,
1342
1355
  saveableUsdc: sdkSaveableUsdc,
1356
+ saveableUsdsui: sdkSaveableUsdsui,
1343
1357
  address: targetAddress ?? "",
1344
1358
  isSelfQuery: true
1345
1359
  },
1346
- displayText: `Balance: $${sdkTotal.toFixed(2)} total. Wallet: $${balance.available.toFixed(2)} available. NAVI savings deposits: $${balance.savings.toFixed(2)}.${sdkDefiSummaryText} Saveable USDC (only USDC can be saved): ${sdkSaveableUsdc.toFixed(2)} USDC.`
1360
+ displayText: `Balance: $${sdkTotal.toFixed(2)} total. Wallet: $${balance.available.toFixed(2)} available. NAVI savings deposits: $${balance.savings.toFixed(2)}.${sdkDefiSummaryText} ${sdkSaveableUsdsui > 0 ? `Saveable: ${sdkSaveableUsdc.toFixed(2)} USDC + ${sdkSaveableUsdsui.toFixed(sdkSaveableUsdsui < 1 ? 4 : 2)} USDsui (only USDC and USDsui can be saved/borrowed).` : `Saveable USDC (only USDC and USDsui can be saved): ${sdkSaveableUsdc.toFixed(2)} USDC.`}`
1347
1361
  };
1348
1362
  }
1349
1363
  });
@@ -2073,22 +2087,24 @@ var transactionHistoryTool = buildTool({
2073
2087
  };
2074
2088
  }
2075
2089
  });
2090
+ var SAVE_ASSETS = ["USDC", "USDsui"];
2076
2091
  var saveDepositTool = buildTool({
2077
2092
  name: "save_deposit",
2078
- description: "Deposit USDC into NAVI savings to earn yield. ONLY USDC is accepted. If the user asks to save/deposit any other token (USDT, SUI, USDe, etc.), do NOT call this tool and do NOT automatically swap their tokens and deposit. Instead, tell the user that only USDC deposits are supported and ask if they would like to swap to USDC first. Let the user decide \u2014 never auto-chain swap + deposit.",
2093
+ description: 'Deposit USDC or USDsui into NAVI savings to earn yield. ONLY these two stables are accepted. If the user asks to save/deposit any other token (GOLD, SUI, USDT, USDe, ETH, etc.), do NOT call this tool and do NOT automatically swap their tokens and deposit. Instead, tell the user that only USDC and USDsui deposits are supported and ask if they would like to swap first. Let the user decide \u2014 never auto-chain swap + deposit. When the user says "save 10 USDC" pass asset="USDC". When they say "save 10 USDsui" pass asset="USDsui". When they say "save 10" with no asset, ALWAYS call balance_check first and ask which stable they want to deposit (or default to whichever they hold more of, with a one-line note). Never silently substitute USDsui for USDC or vice versa.',
2079
2094
  inputSchema: z.object({
2080
2095
  amount: z.number().positive(),
2081
- asset: z.string().optional().describe("Must be USDC or omitted. Any other asset is rejected.")
2096
+ asset: z.enum(SAVE_ASSETS).optional().describe('"USDC" or "USDsui". Defaults to USDC when omitted.')
2082
2097
  }),
2083
2098
  jsonSchema: {
2084
2099
  type: "object",
2085
2100
  properties: {
2086
2101
  amount: {
2087
- description: "Exact amount of USDC to deposit"
2102
+ description: "Exact amount to deposit (in units of the chosen asset)"
2088
2103
  },
2089
2104
  asset: {
2090
2105
  type: "string",
2091
- description: "Must be USDC or omitted. Any other asset is rejected."
2106
+ enum: ["USDC", "USDsui"],
2107
+ description: 'Stable to deposit. "USDC" or "USDsui". Defaults to USDC when omitted.'
2092
2108
  }
2093
2109
  },
2094
2110
  required: ["amount"]
@@ -2097,27 +2113,31 @@ var saveDepositTool = buildTool({
2097
2113
  permissionLevel: "confirm",
2098
2114
  flags: { mutating: true, requiresBalance: true },
2099
2115
  preflight: (input) => {
2100
- if (input.asset && input.asset.toUpperCase() !== "USDC") {
2101
- return { valid: false, error: `Only USDC deposits are supported. Got: "${input.asset}"` };
2116
+ if (input.asset) {
2117
+ const allowed = SAVE_ASSETS.map((a) => a.toUpperCase());
2118
+ if (!allowed.includes(input.asset.toUpperCase())) {
2119
+ return { valid: false, error: `Only USDC or USDsui deposits are supported. Got: "${input.asset}"` };
2120
+ }
2102
2121
  }
2103
2122
  return { valid: true };
2104
2123
  },
2105
2124
  async call(input, context) {
2106
2125
  assertAllowedAsset("save", input.asset);
2107
2126
  const agent = requireAgent(context);
2108
- const result = await agent.save({ amount: input.amount });
2127
+ const asset = input.asset ?? "USDC";
2128
+ const result = await agent.save({ amount: input.amount, asset });
2109
2129
  return {
2110
2130
  data: {
2111
2131
  success: result.success,
2112
2132
  tx: result.tx,
2113
2133
  amount: result.amount,
2114
- asset: "USDC",
2134
+ asset,
2115
2135
  apy: result.apy,
2116
2136
  fee: result.fee,
2117
2137
  gasCost: result.gasCost,
2118
2138
  savingsBalance: result.savingsBalance
2119
2139
  },
2120
- displayText: `Saved ${result.amount.toFixed(result.amount < 1 ? 6 : 2)} USDC at ${(result.apy * 100).toFixed(2)}% APY (tx: ${result.tx.slice(0, 8)}\u2026)`
2140
+ displayText: `Saved ${result.amount.toFixed(result.amount < 1 ? 6 : 2)} ${asset} at ${(result.apy * 100).toFixed(2)}% APY (tx: ${result.tx.slice(0, 8)}\u2026)`
2121
2141
  };
2122
2142
  }
2123
2143
  });
@@ -2241,23 +2261,25 @@ var sendTransferTool = buildTool({
2241
2261
  };
2242
2262
  }
2243
2263
  });
2264
+ var BORROW_ASSETS = ["USDC", "USDsui"];
2244
2265
  var borrowTool = buildTool({
2245
2266
  name: "borrow",
2246
- description: "Borrow USDC against savings collateral. ONLY USDC borrows are supported. Requires existing savings deposits. Checks max safe borrow and health factor. Returns tx hash, fee, and post-borrow health factor.",
2267
+ description: 'Borrow USDC or USDsui against savings collateral. ONLY these two stables are supported. Requires existing savings deposits as collateral. Checks max safe borrow and health factor. Returns tx hash, fee, asset borrowed, and post-borrow health factor. When the user says "borrow 10 USDC" pass asset="USDC". When they say "borrow 10 USDsui" pass asset="USDsui". When they say "borrow 10" with no asset, default to USDC unless the user has only USDsui collateral.',
2247
2268
  inputSchema: z.object({
2248
2269
  amount: z.number().positive(),
2249
- asset: z.string().optional().describe("Must be USDC or omitted. Any other asset is rejected.")
2270
+ asset: z.enum(BORROW_ASSETS).optional().describe('"USDC" or "USDsui". Defaults to USDC when omitted.')
2250
2271
  }),
2251
2272
  jsonSchema: {
2252
2273
  type: "object",
2253
2274
  properties: {
2254
2275
  amount: {
2255
2276
  type: "number",
2256
- description: "Amount in USDC to borrow"
2277
+ description: "Amount to borrow (in units of the chosen asset)"
2257
2278
  },
2258
2279
  asset: {
2259
2280
  type: "string",
2260
- description: "Must be USDC or omitted. Any other asset is rejected."
2281
+ enum: ["USDC", "USDsui"],
2282
+ description: 'Stable to borrow. "USDC" or "USDsui". Defaults to USDC when omitted.'
2261
2283
  }
2262
2284
  },
2263
2285
  required: ["amount"]
@@ -2266,25 +2288,30 @@ var borrowTool = buildTool({
2266
2288
  permissionLevel: "confirm",
2267
2289
  flags: { mutating: true, affectsHealth: true },
2268
2290
  preflight: (input) => {
2269
- if (input.asset && input.asset.toUpperCase() !== "USDC") {
2270
- return { valid: false, error: `Only USDC borrows are supported. Got: "${input.asset}"` };
2291
+ if (input.asset) {
2292
+ const allowed = BORROW_ASSETS.map((a) => a.toUpperCase());
2293
+ if (!allowed.includes(input.asset.toUpperCase())) {
2294
+ return { valid: false, error: `Only USDC or USDsui borrows are supported. Got: "${input.asset}"` };
2295
+ }
2271
2296
  }
2272
2297
  return { valid: true };
2273
2298
  },
2274
2299
  async call(input, context) {
2275
2300
  assertAllowedAsset("borrow", input.asset);
2276
2301
  const agent = requireAgent(context);
2277
- const result = await agent.borrow({ amount: input.amount });
2302
+ const asset = input.asset ?? "USDC";
2303
+ const result = await agent.borrow({ amount: input.amount, asset });
2278
2304
  return {
2279
2305
  data: {
2280
2306
  success: result.success,
2281
2307
  tx: result.tx,
2282
2308
  amount: result.amount,
2309
+ asset: result.asset ?? asset,
2283
2310
  fee: result.fee,
2284
2311
  healthFactor: result.healthFactor,
2285
2312
  gasCost: result.gasCost
2286
2313
  },
2287
- displayText: `Borrowed $${result.amount.toFixed(2)} \u2014 HF: ${result.healthFactor.toFixed(2)} (tx: ${result.tx.slice(0, 8)}\u2026)`
2314
+ displayText: `Borrowed ${result.amount.toFixed(2)} ${asset} \u2014 HF: ${result.healthFactor.toFixed(2)} (tx: ${result.tx.slice(0, 8)}\u2026)`
2288
2315
  };
2289
2316
  }
2290
2317
  });
@@ -4078,11 +4105,17 @@ Only offer to execute actions you have tools for. If you retrieved a quote, data
4078
4105
  - Run multiple read-only tools in parallel when you need several data points.
4079
4106
  - If a tool errors, say what went wrong and what to try instead. One sentence.
4080
4107
 
4081
- ## Savings = USDC only (critical)
4082
- - save_deposit accepts ONLY USDC. No other token can be deposited into savings.
4083
- - When asked "how much can I save?", report only the user's USDC wallet balance (saveableUsdc field from balance_check). Other tokens like GOLD, SUI, USDT are NOT saveable and NOT savings positions \u2014 they are just wallet holdings.
4084
- - NEVER say a non-USDC token is "in savings" or "earning APY in savings" unless it appears in the savings_info positions list. Wallet holdings \u2260 savings.
4085
- - If user wants to save non-USDC tokens, tell them to swap to USDC first. Do NOT auto-chain swap + deposit.
4108
+ ## Savings = USDC or USDsui (critical)
4109
+ - save_deposit and borrow accept ONLY USDC or USDsui. No other token can be deposited or borrowed.
4110
+ - USDC is the canonical default. USDsui is permitted because it has a productive NAVI pool (often a higher APY than USDC). All other holdings (GOLD, SUI, USDT, USDe, ETH, NAVX, WAL) are NOT saveable.
4111
+ - When asked "how much can I save?":
4112
+ - Report saveableUsdc from balance_check (the user's USDC wallet balance \u2014 canonical saveable).
4113
+ - If the user also holds USDsui in their wallet, report that separately as "USDsui (saveable): X.XX". Do NOT roll the two together \u2014 the LLM must keep the per-asset distinction so the user can pick.
4114
+ - When the user says "save 10 USDC" \u2192 call save_deposit with asset="USDC". When they say "save 10 USDsui" \u2192 call with asset="USDsui". Never silently substitute.
4115
+ - When the user says "save 10" (no asset) \u2192 call balance_check first and ask which stable they want, OR pick whichever they hold more of with a one-line explanation.
4116
+ - "Best stable to save right now?" \u2192 call rates_info to compare USDC vs USDsui APY on NAVI; let the user pick.
4117
+ - NEVER say a non-saveable token (GOLD, SUI, USDT, etc.) is "in savings" or "earning APY in savings". Wallet holdings \u2260 savings positions, even for stables we don't accept.
4118
+ - If user wants to save a non-saveable token, tell them to swap to USDC or USDsui first. Do NOT auto-chain swap + deposit.
4086
4119
 
4087
4120
  ## Multi-step flows
4088
4121
  - "How much X for Y?": swap_quote first, then swap_execute if user confirms.
@@ -4090,7 +4123,7 @@ Only offer to execute actions you have tools for. If you retrieved a quote, data
4090
4123
  - "Buy $X of token": token_prices \u2192 calculate amount \u2192 swap_execute.
4091
4124
  - "Best yield on SUI": compare rates_info (NAVI lending) + volo_stats (vSUI liquid staking).
4092
4125
  - withdraw supports legacy positions: USDC, USDe, USDsui, SUI. Pass asset param to withdraw a specific token.
4093
- - "Deposit SUI to earn yield": volo_stake for SUI liquid staking. save_deposit is USDC only.
4126
+ - "Deposit SUI to earn yield": volo_stake for SUI liquid staking. save_deposit only accepts USDC or USDsui.
4094
4127
  - "Is protocol X safe?" / "Tell me about NAVI": protocol_deep_dive with the slug.
4095
4128
  - "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.
4096
4129