@t2000/engine 0.46.8 → 0.46.10

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
@@ -1757,7 +1757,7 @@ declare const balanceCheckTool: Tool<{}, {
1757
1757
  declare const savingsInfoTool: Tool<{}, SavingsResult>;
1758
1758
 
1759
1759
  declare const healthCheckTool: Tool<{}, {
1760
- healthFactor: number;
1760
+ healthFactor: number | null;
1761
1761
  supplied: number;
1762
1762
  borrowed: number;
1763
1763
  maxBorrow: number;
package/dist/index.js CHANGED
@@ -915,15 +915,28 @@ var savingsInfoTool = buildTool({
915
915
  return { data: result, displayText: formatSavingsDisplay(result) };
916
916
  }
917
917
  });
918
- function hfStatus(hf) {
918
+ var DEBT_DUST_USD = 0.01;
919
+ function hfStatus(hf, borrowed) {
920
+ if (borrowed <= DEBT_DUST_USD) return "healthy";
919
921
  if (hf >= 2) return "healthy";
920
922
  if (hf >= 1.5) return "moderate";
921
923
  if (hf >= 1.2) return "warning";
922
924
  return "critical";
923
925
  }
926
+ function serializeHf(hf, borrowed) {
927
+ if (borrowed <= DEBT_DUST_USD) return null;
928
+ if (hf == null || !Number.isFinite(hf)) return null;
929
+ return hf;
930
+ }
931
+ function displayHfText(hf, borrowed, status) {
932
+ if (hf == null) {
933
+ return `Health Factor: \u221E (${status} \u2014 no debt)`;
934
+ }
935
+ return `Health Factor: ${hf.toFixed(2)} (${status})`;
936
+ }
924
937
  var healthCheckTool = buildTool({
925
938
  name: "health_check",
926
- description: "Check the lending health factor: current HF ratio, total supplied collateral, total borrowed, max additional borrow capacity, and liquidation threshold. HF < 1.5 is risky, < 1.2 is critical.",
939
+ description: 'Check the lending health factor: current HF ratio, total supplied collateral, total borrowed, max additional borrow capacity, and liquidation threshold. HF < 1.5 is risky, < 1.2 is critical. When the user has no debt the tool returns healthFactor=null (semantically infinity) \u2014 render that as "Healthy" / \u221E, never as 0 or "Critical".',
927
940
  inputSchema: z.object({}),
928
941
  jsonSchema: { type: "object", properties: {}, required: [] },
929
942
  isReadOnly: true,
@@ -933,19 +946,20 @@ var healthCheckTool = buildTool({
933
946
  async call(_input, context) {
934
947
  if (context.positionFetcher && context.walletAddress) {
935
948
  const sp = await context.positionFetcher(context.walletAddress);
936
- const hfVal = sp.healthFactor ?? (sp.borrows > 0 ? 0 : Infinity);
937
- const status2 = hfStatus(hfVal);
938
- const displayHf = Number.isFinite(hfVal) ? hfVal.toFixed(2) : "\u221E";
949
+ const borrowed2 = sp.borrows;
950
+ const rawHf = sp.healthFactor ?? (borrowed2 > 0 ? 0 : Infinity);
951
+ const status2 = hfStatus(rawHf, borrowed2);
952
+ const transportHf2 = serializeHf(rawHf, borrowed2);
939
953
  return {
940
954
  data: {
941
- healthFactor: hfVal,
955
+ healthFactor: transportHf2,
942
956
  supplied: sp.savings,
943
- borrowed: sp.borrows,
957
+ borrowed: borrowed2,
944
958
  maxBorrow: sp.maxBorrow,
945
959
  liquidationThreshold: 0,
946
960
  status: status2
947
961
  },
948
- displayText: `Health Factor: ${displayHf} (${status2})`
962
+ displayText: displayHfText(transportHf2, borrowed2, status2)
949
963
  };
950
964
  }
951
965
  if (hasNaviMcp(context)) {
@@ -953,26 +967,29 @@ var healthCheckTool = buildTool({
953
967
  getMcpManager(context),
954
968
  getWalletAddress(context)
955
969
  );
956
- const status2 = hfStatus(hf2.healthFactor);
957
- const displayHf = Number.isFinite(hf2.healthFactor) ? hf2.healthFactor.toFixed(2) : "\u221E";
970
+ const borrowed2 = hf2.borrowed;
971
+ const status2 = hfStatus(hf2.healthFactor, borrowed2);
972
+ const transportHf2 = serializeHf(hf2.healthFactor, borrowed2);
958
973
  return {
959
- data: { ...hf2, status: status2 },
960
- displayText: `Health Factor: ${displayHf} (${status2})`
974
+ data: { ...hf2, healthFactor: transportHf2, status: status2 },
975
+ displayText: displayHfText(transportHf2, borrowed2, status2)
961
976
  };
962
977
  }
963
978
  const agent = requireAgent(context);
964
979
  const hf = await agent.healthFactor();
965
- const status = hfStatus(hf.healthFactor);
980
+ const borrowed = hf.borrowed;
981
+ const status = hfStatus(hf.healthFactor, borrowed);
982
+ const transportHf = serializeHf(hf.healthFactor, borrowed);
966
983
  return {
967
984
  data: {
968
- healthFactor: hf.healthFactor,
985
+ healthFactor: transportHf,
969
986
  supplied: hf.supplied,
970
- borrowed: hf.borrowed,
987
+ borrowed,
971
988
  maxBorrow: hf.maxBorrow,
972
989
  liquidationThreshold: hf.liquidationThreshold,
973
990
  status
974
991
  },
975
- displayText: `Health Factor: ${hf.healthFactor.toFixed(2)} (${status})`
992
+ displayText: displayHfText(transportHf, borrowed, status)
976
993
  };
977
994
  }
978
995
  });
@@ -1571,9 +1588,15 @@ var repayDebtTool = buildTool({
1571
1588
  };
1572
1589
  }
1573
1590
  });
1591
+ function formatAmount(amount) {
1592
+ if (!Number.isFinite(amount) || amount <= 0) return "0";
1593
+ if (amount >= 1) return amount.toFixed(4).replace(/\.?0+$/, "");
1594
+ if (amount >= 1e-4) return amount.toFixed(6).replace(/\.?0+$/, "");
1595
+ return amount.toExponential(2);
1596
+ }
1574
1597
  var claimRewardsTool = buildTool({
1575
1598
  name: "claim_rewards",
1576
- description: "Claim all pending protocol rewards across lending adapters. Returns claimed reward details and total USD value.",
1599
+ description: 'Claim all pending protocol rewards across lending adapters. Returns the claimed reward breakdown (per-asset symbol + amount), total USD value (best effort \u2014 may be 0 when oracle prices are unavailable), and the on-chain tx hash. When the rewards list is empty the response will explicitly say "no pending rewards"; when it is non-empty narrate the per-symbol amounts even if totalValueUsd is 0 (the on-chain credit still happened).',
1577
1600
  inputSchema: z.object({}),
1578
1601
  jsonSchema: { type: "object", properties: {}, required: [] },
1579
1602
  isReadOnly: false,
@@ -1582,15 +1605,36 @@ var claimRewardsTool = buildTool({
1582
1605
  async call(_input, context) {
1583
1606
  const agent = requireAgent(context);
1584
1607
  const result = await agent.claimRewards();
1608
+ const priceCache = context.priceCache;
1609
+ const enrichedRewards = result.rewards.map((r) => {
1610
+ if (r.estimatedValueUsd > 0) return r;
1611
+ const price = priceCache?.get(r.symbol.toUpperCase());
1612
+ if (!price || !Number.isFinite(price) || price <= 0) return r;
1613
+ return { ...r, estimatedValueUsd: r.amount * price };
1614
+ });
1615
+ const totalValueUsd = enrichedRewards.reduce(
1616
+ (s, r) => s + (Number.isFinite(r.estimatedValueUsd) ? r.estimatedValueUsd : 0),
1617
+ 0
1618
+ );
1619
+ const txShort = result.tx ? `${result.tx.slice(0, 8)}\u2026` : "";
1620
+ let displayText;
1621
+ if (enrichedRewards.length === 0) {
1622
+ displayText = "No pending rewards to claim.";
1623
+ } else {
1624
+ const breakdown = enrichedRewards.map((r) => `${formatAmount(r.amount)} ${r.symbol}`).join(", ");
1625
+ const usdSuffix = totalValueUsd > 0 ? ` (~$${totalValueUsd.toFixed(2)})` : "";
1626
+ const txSuffix = txShort ? ` (tx: ${txShort})` : "";
1627
+ displayText = `Claimed ${breakdown}${usdSuffix}${txSuffix}`;
1628
+ }
1585
1629
  return {
1586
1630
  data: {
1587
1631
  success: result.success,
1588
1632
  tx: result.tx || null,
1589
- rewards: result.rewards,
1590
- totalValueUsd: result.totalValueUsd,
1633
+ rewards: enrichedRewards,
1634
+ totalValueUsd,
1591
1635
  gasCost: result.gasCost
1592
1636
  },
1593
- displayText: result.rewards.length === 0 ? "No pending rewards to claim." : `Claimed $${result.totalValueUsd.toFixed(2)} in rewards (tx: ${result.tx.slice(0, 8)}\u2026)`
1637
+ displayText
1594
1638
  };
1595
1639
  }
1596
1640
  });
@@ -2118,8 +2162,7 @@ var explainTxTool = buildTool({
2118
2162
  if (balanceChanges?.length) {
2119
2163
  for (const bc of balanceChanges) {
2120
2164
  const ownerAddr = bc.owner?.AddressOwner ?? bc.owner?.ObjectOwner ?? "unknown";
2121
- const coinParts = bc.coinType.split("::");
2122
- const symbol = coinParts[coinParts.length - 1] ?? bc.coinType;
2165
+ const symbol = resolveSymbol(bc.coinType);
2123
2166
  const amount = Number(bc.amount);
2124
2167
  const isNegative = amount < 0;
2125
2168
  const decimals = getDecimalsForCoinType(bc.coinType);