keyring-agent-core 0.2.13 → 0.2.14
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 +18 -4
- package/dist/index.js +6 -6
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1521,6 +1521,14 @@ declare class AgentCore {
|
|
|
1521
1521
|
private suggestionsEnabled;
|
|
1522
1522
|
private historyLoaded;
|
|
1523
1523
|
private historyLoadingPromise;
|
|
1524
|
+
/**
|
|
1525
|
+
* The currently-running chat() turn, if any. A turn writes the user + assistant
|
|
1526
|
+
* (and tool) messages into history at its END, so a clearHistory() that lands
|
|
1527
|
+
* mid-turn must wait for it to finish before wiping — otherwise the turn
|
|
1528
|
+
* repopulates the working window (which the Router/Subagents read) right after
|
|
1529
|
+
* the clear. Null when no turn is in flight.
|
|
1530
|
+
*/
|
|
1531
|
+
private inFlightTurn;
|
|
1524
1532
|
/**
|
|
1525
1533
|
* Resolves once the initial persisted-history load attempt has finished
|
|
1526
1534
|
* (success or failure). Only meaningful when `persistHistory: true` and a
|
|
@@ -3484,19 +3492,25 @@ declare class WalletTokenBalancesTool extends BaseTool {
|
|
|
3484
3492
|
parameters: ToolParameter[];
|
|
3485
3493
|
private service;
|
|
3486
3494
|
constructor(config?: WalletTokenBalancesToolConfig);
|
|
3495
|
+
/**
|
|
3496
|
+
* Format a USD number to EXACTLY 2 decimals by TRUNCATING (never rounding).
|
|
3497
|
+
* Uses string slicing rather than `Math.trunc(v * 100) / 100`, which is unsafe
|
|
3498
|
+
* for values like 0.29 (0.29 * 100 === 28.999999999999996 → would yield 0.28).
|
|
3499
|
+
*/
|
|
3500
|
+
private truncateUsd;
|
|
3487
3501
|
protected run(args: Record<string, unknown>, userContext?: UserContext): Promise<{
|
|
3488
3502
|
error: string;
|
|
3503
|
+
_instructions?: undefined;
|
|
3489
3504
|
walletAddress?: undefined;
|
|
3490
3505
|
chain?: undefined;
|
|
3491
|
-
tokenCount?: undefined;
|
|
3492
|
-
tokens?: undefined;
|
|
3493
3506
|
totalUsdValue?: undefined;
|
|
3507
|
+
tokens?: undefined;
|
|
3494
3508
|
} | {
|
|
3509
|
+
_instructions: string;
|
|
3495
3510
|
walletAddress: string;
|
|
3496
3511
|
chain: string;
|
|
3497
|
-
|
|
3512
|
+
totalUsdValue: string;
|
|
3498
3513
|
tokens: string[];
|
|
3499
|
-
totalUsdValue: number;
|
|
3500
3514
|
error?: undefined;
|
|
3501
3515
|
}>;
|
|
3502
3516
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var cr=Object.create;var hn=Object.defineProperty;var ur=Object.getOwnPropertyDescriptor;var dr=Object.getOwnPropertyNames;var mr=Object.getPrototypeOf,pr=Object.prototype.hasOwnProperty;var hr=(c,e)=>{for(var t in e)hn(c,t,{get:e[t],enumerable:!0})},uo=(c,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of dr(e))!pr.call(c,r)&&r!==t&&hn(c,r,{get:()=>e[r],enumerable:!(n=ur(e,r))||n.enumerable});return c};var gr=(c,e,t)=>(t=c!=null?cr(mr(c)):{},uo(e||!c||!c.__esModule?hn(t,"default",{value:c,enumerable:!0}):t,c)),fr=c=>uo(hn({},"__esModule",{value:!0}),c);var Ra={};hr(Ra,{AI_AGENT_TOOL_NAMES:()=>On,AgentCore:()=>Hn,ApproveTokenTool:()=>qt,BaseNftMessageTool:()=>fe,BaseSwapService:()=>Ue,BaseTool:()=>v,BaseWalletActionTool:()=>le,BuyTokenTool:()=>Vt,ChatHistory:()=>Yt,DEFAULT_CHAIN:()=>ge,DEFAULT_PROVIDER:()=>on,DEFAULT_RPC_BY_CHAIN:()=>ie,DebridgeAdapter:()=>vt,EstimatePoolYieldTool:()=>_t,GeminiProvider:()=>se,GeminiSearchAiTool:()=>mt,HEX_TO_PANTOGRAPH:()=>Co,KnowledgeBase:()=>jt,MoralisService:()=>E,NFTContractInfoTool:()=>ut,NFTMetadataTool:()=>dt,NFT_AGENT_TOOL_NAMES:()=>Bn,OpenAddLiquidityFormTool:()=>At,POOL_AGENT_TOOL_NAMES:()=>qn,PantographService:()=>ee,PoolByAddressTool:()=>yt,PoolDetailTool:()=>gt,PoolFallbackAiTool:()=>pt,PoolSearchTool:()=>ft,PoolService:()=>Me,PreviewAddLiquidityTool:()=>Pt,RelayAdapter:()=>St,Router:()=>zt,SUPPORTED_CHAINS:()=>$e,SUPPORTED_CHAINS_LABEL:()=>Ne,SWAP_PROVIDER_CONFIG:()=>Cn,SendNativeTool:()=>Bt,SendNftTool:()=>Gt,SendTokenTool:()=>Ot,Subagent:()=>j,SubgraphAddPoolTool:()=>Dt,SubgraphCoinPoolPairsTool:()=>It,SubgraphPoolByAddressTool:()=>Rt,SubgraphPoolByPositionIdTool:()=>Et,SubgraphPoolSearchTool:()=>Ct,SubgraphPositionDetailTool:()=>Nt,SubgraphTrendingPoolsTool:()=>Ut,Summarizer:()=>Kt,SwapServiceFactory:()=>Le,SwapTokenTool:()=>Ht,Synthesizer:()=>Qt,TOKEN_AGENT_TOOL_NAMES:()=>Mn,TRANSFER_TOPIC:()=>Ko,TRENDING_DEFAULT_BY_HEX_CHAIN:()=>Uo,TokenAnalyticsTool:()=>je,TokenHoldersTool:()=>Ke,TokenInfoTool:()=>Ye,TokenScoreTool:()=>ze,ToolRegistry:()=>Fe,TopGainersTool:()=>Xe,TopPoolsTool:()=>ht,TransactionByHashTool:()=>lt,TrendingTokensTool:()=>Qe,UNISWAP_CHAIN_SLUG:()=>sn,UpstashKnowledgeBase:()=>Re,WALLET_ACTION_AGENT_TOOL_NAMES:()=>Fn,WALLET_AGENT_TOOL_NAMES:()=>Ln,WalletApprovalsTool:()=>rt,WalletDefiPositionsTool:()=>at,WalletDefiProtocolPositionsTool:()=>it,WalletDefiSummaryTool:()=>st,WalletHistoryTool:()=>Ze,WalletNFTsTool:()=>ct,WalletNetWorthTool:()=>kn,WalletNftTransfersTool:()=>tt,WalletPnlSummaryTool:()=>nt,WalletPnlTool:()=>ot,WalletTokenBalancesTool:()=>Je,WalletTokenTransfersTool:()=>et,ZERO_ADDRESS:()=>O,buildRangePresets:()=>ao,buildUniswapPoolUrl:()=>oe,clampTick:()=>ve,configureSupportedChains:()=>yn,createAiAgent:()=>dn,createDefaultSubagents:()=>$n,createNftAgent:()=>un,createPoolAgent:()=>mn,createTokenAgent:()=>cn,createWalletActionAgent:()=>pn,createWalletAgent:()=>ln,ethCallAt:()=>Ho,ethCallByChain:()=>so,getAffiliateFee:()=>kt,getChainMeta:()=>te,getDefaultRpcUrl:()=>Us,getGatewayAddress:()=>Rn,getNativeTokenInfo:()=>xt,getPositionManagerAddress:()=>En,getProviderByChain:()=>_n,ingestKnowledgeBase:()=>ir,priceToTick:()=>De,resolveRpcUrl:()=>Tt,roundTickToSpacing:()=>Te,rpcCall:()=>xe,setRpcOverrides:()=>ro,swapServiceFactory:()=>ye,tickToPrice:()=>ue,toPantographChain:()=>en});module.exports=fr(Ra);var po=gr(require("axios"));var mo="0.2.
|
|
1
|
+
"use strict";var cr=Object.create;var hn=Object.defineProperty;var ur=Object.getOwnPropertyDescriptor;var dr=Object.getOwnPropertyNames;var mr=Object.getPrototypeOf,pr=Object.prototype.hasOwnProperty;var hr=(c,e)=>{for(var t in e)hn(c,t,{get:e[t],enumerable:!0})},uo=(c,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of dr(e))!pr.call(c,r)&&r!==t&&hn(c,r,{get:()=>e[r],enumerable:!(n=ur(e,r))||n.enumerable});return c};var gr=(c,e,t)=>(t=c!=null?cr(mr(c)):{},uo(e||!c||!c.__esModule?hn(t,"default",{value:c,enumerable:!0}):t,c)),fr=c=>uo(hn({},"__esModule",{value:!0}),c);var Ra={};hr(Ra,{AI_AGENT_TOOL_NAMES:()=>On,AgentCore:()=>Hn,ApproveTokenTool:()=>qt,BaseNftMessageTool:()=>fe,BaseSwapService:()=>Ue,BaseTool:()=>v,BaseWalletActionTool:()=>le,BuyTokenTool:()=>Vt,ChatHistory:()=>Yt,DEFAULT_CHAIN:()=>ge,DEFAULT_PROVIDER:()=>on,DEFAULT_RPC_BY_CHAIN:()=>ie,DebridgeAdapter:()=>vt,EstimatePoolYieldTool:()=>_t,GeminiProvider:()=>se,GeminiSearchAiTool:()=>mt,HEX_TO_PANTOGRAPH:()=>Co,KnowledgeBase:()=>jt,MoralisService:()=>E,NFTContractInfoTool:()=>ut,NFTMetadataTool:()=>dt,NFT_AGENT_TOOL_NAMES:()=>Bn,OpenAddLiquidityFormTool:()=>At,POOL_AGENT_TOOL_NAMES:()=>qn,PantographService:()=>ee,PoolByAddressTool:()=>yt,PoolDetailTool:()=>gt,PoolFallbackAiTool:()=>pt,PoolSearchTool:()=>ft,PoolService:()=>Me,PreviewAddLiquidityTool:()=>Pt,RelayAdapter:()=>St,Router:()=>zt,SUPPORTED_CHAINS:()=>$e,SUPPORTED_CHAINS_LABEL:()=>Ne,SWAP_PROVIDER_CONFIG:()=>Cn,SendNativeTool:()=>Bt,SendNftTool:()=>Gt,SendTokenTool:()=>Ot,Subagent:()=>j,SubgraphAddPoolTool:()=>Dt,SubgraphCoinPoolPairsTool:()=>It,SubgraphPoolByAddressTool:()=>Rt,SubgraphPoolByPositionIdTool:()=>Et,SubgraphPoolSearchTool:()=>Ct,SubgraphPositionDetailTool:()=>Nt,SubgraphTrendingPoolsTool:()=>Ut,Summarizer:()=>Kt,SwapServiceFactory:()=>Le,SwapTokenTool:()=>Ht,Synthesizer:()=>Qt,TOKEN_AGENT_TOOL_NAMES:()=>Mn,TRANSFER_TOPIC:()=>Ko,TRENDING_DEFAULT_BY_HEX_CHAIN:()=>Uo,TokenAnalyticsTool:()=>je,TokenHoldersTool:()=>Ke,TokenInfoTool:()=>Ye,TokenScoreTool:()=>ze,ToolRegistry:()=>Fe,TopGainersTool:()=>Xe,TopPoolsTool:()=>ht,TransactionByHashTool:()=>lt,TrendingTokensTool:()=>Qe,UNISWAP_CHAIN_SLUG:()=>sn,UpstashKnowledgeBase:()=>Re,WALLET_ACTION_AGENT_TOOL_NAMES:()=>Fn,WALLET_AGENT_TOOL_NAMES:()=>Ln,WalletApprovalsTool:()=>rt,WalletDefiPositionsTool:()=>at,WalletDefiProtocolPositionsTool:()=>it,WalletDefiSummaryTool:()=>st,WalletHistoryTool:()=>Ze,WalletNFTsTool:()=>ct,WalletNetWorthTool:()=>kn,WalletNftTransfersTool:()=>tt,WalletPnlSummaryTool:()=>nt,WalletPnlTool:()=>ot,WalletTokenBalancesTool:()=>Je,WalletTokenTransfersTool:()=>et,ZERO_ADDRESS:()=>O,buildRangePresets:()=>ao,buildUniswapPoolUrl:()=>oe,clampTick:()=>ve,configureSupportedChains:()=>yn,createAiAgent:()=>dn,createDefaultSubagents:()=>$n,createNftAgent:()=>un,createPoolAgent:()=>mn,createTokenAgent:()=>cn,createWalletActionAgent:()=>pn,createWalletAgent:()=>ln,ethCallAt:()=>Ho,ethCallByChain:()=>so,getAffiliateFee:()=>kt,getChainMeta:()=>te,getDefaultRpcUrl:()=>Us,getGatewayAddress:()=>Rn,getNativeTokenInfo:()=>xt,getPositionManagerAddress:()=>En,getProviderByChain:()=>_n,ingestKnowledgeBase:()=>ir,priceToTick:()=>De,resolveRpcUrl:()=>Tt,roundTickToSpacing:()=>Te,rpcCall:()=>xe,setRpcOverrides:()=>ro,swapServiceFactory:()=>ye,tickToPrice:()=>ue,toPantographChain:()=>en});module.exports=fr(Ra);var po=gr(require("axios"));var mo="0.2.14";var br=`keyring-agent-core/${mo} (Keyring Chatbot Agent; +https://keyring.app)`,wr=3e4,kr=typeof process<"u"&&process.versions?.node!=null,Yn=class{instance;constructor(e={}){this.instance=po.default.create({baseURL:e.baseURL,timeout:e.timeout??wr,validateStatus:()=>!0,headers:{Accept:"application/json",...kr?{"User-Agent":e.userAgent??br}:{},...e.headers}})}async request(e,t,n,r={}){let o=await this.instance.request({...r,method:e,url:t,data:n}),s={};for(let[a,i]of Object.entries(o.headers??{}))i!=null&&(s[a.toLowerCase()]=String(i));return{ok:o.status>=200&&o.status<300,status:o.status,statusText:o.statusText,data:o.data,headers:s}}get(e,t){return this.request("GET",e,void 0,t)}post(e,t,n){return this.request("POST",e,t,n)}put(e,t,n){return this.request("PUT",e,t,n)}patch(e,t,n){return this.request("PATCH",e,t,n)}delete(e,t){return this.request("DELETE",e,void 0,t)}},_=new Yn;function N(c){let{data:e,status:t,statusText:n}=c,r=n?`HTTP ${t} ${n}`:`HTTP ${t}`;if(typeof e=="string")return e.trim()||r;if(e&&typeof e=="object"){let o=e,s=i=>i&&typeof i=="object"?i.message:void 0,a=[o.message,o.errorMessage,o.error,o.error_description,o.detail,s(o.error),s(o.data)];for(let i of a)if(typeof i=="string"&&i.trim())return i.trim()}return r}var ho={string:"STRING",number:"NUMBER",boolean:"BOOLEAN",object:"OBJECT",array:"ARRAY"},Tr="https://nft-demo.keyring.app/api/gemini-stable",vr=new Set([408,429,500,502,503,504]),go=3e4,gn=c=>new Promise(e=>setTimeout(e,c));function fn(c,e,t){if(t!=null&&t>0)return Math.min(t,go);let n=Math.min(e*2**(c-1),go);return n/2+Math.random()*(n/2)}function Sr(c){if(!c)return null;let e=Number(c);if(Number.isFinite(e))return Math.max(0,e*1e3);let t=Date.parse(c);return Number.isNaN(t)?null:Math.max(0,t-Date.now())}var se=class{model;maxTokens;temperature;baseUrl;constructor(e){this.model=e.model??"gemini-2.5-flash-lite",this.maxTokens=e.maxTokens??4096,this.temperature=e.temperature??1,this.baseUrl=e.baseUrl??Tr}async chat(e,t,n){let{systemInstruction:r,contents:o}=this.toContents(e),{maxRetries:s=5,retryDelayMs:a=1e3}=n??{},i=o.length>0?o:[{role:"user",parts:[{text:"(continue)"}]}];if(n?._debug){console.log("[GeminiProvider] turn sequence:");for(let m of i){let p=m.parts.map(h=>h.functionCall?`fc:${h.functionCall.name}`:h.functionResponse?`fr:${h.functionResponse.name}`:`text:${(h.text??"").slice(0,40)}`).join(", ");console.log(` ${m.role}: [${p}]`)}}let l={contents:i,generationConfig:{maxOutputTokens:this.maxTokens,temperature:this.temperature}};r&&(l.systemInstruction=r),t?.length?(l.tools=[{functionDeclarations:this.toFunctionDeclarations(t)}],n?.forceToolUse&&(l.toolConfig={functionCallingConfig:{mode:"ANY"}})):n?.googleSearch&&(l.tools=[{googleSearch:{}}]);let u=`${this.baseUrl}/v1beta/models/${this.model}:generateContent`,d="Unknown error";for(let m=1;m<=s;m++){let p;try{p=await _.post(u,l,{headers:{"Content-Type":"application/json"}})}catch(b){if(d=b instanceof Error?b.message:String(b),m>=s)break;await gn(fn(m,a));continue}if(!p.ok){let b=typeof p.data=="string"?p.data:JSON.stringify(p.data)||p.statusText;if(d=`Gemini proxy error ${p.status}: ${b}`,!vr.has(p.status))throw new Error(d);if(m>=s)break;let T=Sr(p.headers["retry-after"]??null);await gn(fn(m,a,T));continue}if(p.data==null||typeof p.data!="object"){if(d="Gemini proxy returned invalid JSON",m>=s)break;await gn(fn(m,a));continue}let h=p.data,g=h.candidates?.[0];if(!g)return{text:"",toolCalls:[]};let f="",y=[],k=g.content?.parts;if(!Array.isArray(k)||k.length===0){let b=g.finishReason;if(!(b==="SAFETY"||b==="RECITATION")&&m<s){d=`Gemini returned an empty turn (finishReason=${b??"none"})`,await gn(fn(m,a));continue}return{text:"",toolCalls:[]}}for(let b of k)b.text&&(f+=b.text),b.functionCall&&y.push({toolName:b.functionCall.name,args:b.functionCall.args??{},callId:b.functionCall.id??`call_${Date.now()}_${Math.random().toString(36).slice(2,8)}`});let w=h.usageMetadata?{promptTokens:h.usageMetadata.promptTokenCount??0,completionTokens:h.usageMetadata.candidatesTokenCount??0,totalTokens:h.usageMetadata.totalTokenCount??0}:void 0;return{text:f,toolCalls:y,usage:w}}throw new Error(d)}toContents(e){let t=[],n=[];for(let a of e){if(a.role==="system"){t.push(a.content);continue}if(a.role==="tool"){n.push({role:"function",parts:[{functionResponse:{name:a.toolName??"unknown",response:{result:a.content},...a.toolCallId?{id:a.toolCallId}:{}}}]});continue}if(a.role==="assistant"&&a.toolCalls?.length){n.push({role:"model",parts:a.toolCalls.map(i=>({functionCall:{name:i.toolName,args:i.args,...i.callId?{id:i.callId}:{}}}))});continue}n.push({role:a.role==="assistant"?"model":"user",parts:[{text:a.content}]})}let r=[];for(let a of n){let i=r[r.length-1],l=a.parts.some(d=>d.functionCall),u=i?.parts.some(d=>d.functionCall);i&&i.role===a.role&&!l&&!u?i.parts.push(...a.parts):r.push({...a,parts:[...a.parts]})}let o=[];for(let a=0;a<r.length;a++){let i=r[a],l=o[o.length-1];i.role==="function"&&!l?.parts.some(d=>d.functionCall)||i.role==="model"&&i.parts.some(d=>d.functionCall)&&!(r[a+1]?.role==="function")||o.push(i)}for(;o.length>0&&o[0].role!=="user";)o.shift();return{systemInstruction:t.length?{role:"user",parts:[{text:t.join(`
|
|
2
2
|
`)}]}:null,contents:o}}toFunctionDeclarations(e){return e.map(t=>{let n={},r=[];for(let o of t.parameters){let s={type:ho[o.type]??"STRING",description:o.description};o.type==="array"&&(s.items={type:ho[o.items?.type??"string"]??"STRING"}),n[o.name]=s,o.required&&r.push(o.name)}return{name:t.name,description:t.description,parameters:{type:"OBJECT",properties:n,required:r}}})}};var Fe=class{tools=new Map;register(e){if(this.tools.has(e.name))throw new Error(`Tool "${e.name}" is already registered`);this.tools.set(e.name,e)}unregister(e){return this.tools.delete(e)}get(e){return this.tools.get(e)}has(e){return this.tools.has(e)}getDefinitions(){return Array.from(this.tools.values()).map(e=>({name:e.name,description:e.description,parameters:e.parameters,category:e.category,kind:e.kind}))}getDefinitionsByCategory(e){return this.getDefinitions().filter(t=>t.category===e)}async execute(e,t,n){let r=this.tools.get(e);if(!r)return{toolName:e,callId:`err_${Date.now()}`,success:!1,error:`Tool "${e}" not found in registry`,duration:0};let o=Date.now();try{return{...await r.execute(t,n),duration:Date.now()-o}}catch(s){return{toolName:e,callId:`err_${Date.now()}`,success:!1,error:s instanceof Error?s.message:String(s),duration:Date.now()-o}}}get size(){return this.tools.size}listNames(){return Array.from(this.tools.keys())}};var $e=["0x1","0xa","0x38","0x89","0x2105","0xa4b1","0xa86a","0xe708"],xr=new Set($e),Ee=[...$e],fo=new Set(Ee),ge="0x1",Ne="Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea";function Ar(c){return c.map(e=>Ve[e]??e).join(", ")}function yn(c){let e=new Set;if(c)for(let n of c){let r=Kn(n);r&&e.add(r)}let t=$e.filter(n=>!e.has(n));Ee=t.length>0?[...t]:[...$e],fo=new Set(Ee),ge=Ee.includes("0x1")?"0x1":Ee[0],Ne=Ar(Ee)}var Pr={"0x1":"0x1",1:"0x1",eth:"0x1",ether:"0x1",ethereum:"0x1","ethereum mainnet":"0x1",mainnet:"0x1","0xa":"0xa",10:"0xa",op:"0xa",optimism:"0xa","op mainnet":"0xa","optimism mainnet":"0xa","0x38":"0x38",56:"0x38",bsc:"0x38",bnb:"0x38",binance:"0x38","bnb chain":"0x38","bnb smart chain":"0x38","binance chain":"0x38","binance smart chain":"0x38","0x89":"0x89",137:"0x89",matic:"0x89",polygon:"0x89","polygon mainnet":"0x89","polygon pos":"0x89","0x2105":"0x2105",8453:"0x2105",base:"0x2105","base mainnet":"0x2105","0xa4b1":"0xa4b1",42161:"0xa4b1",arb:"0xa4b1",arbitrum:"0xa4b1","arbitrum one":"0xa4b1","arbitrum mainnet":"0xa4b1","0xa86a":"0xa86a",43114:"0xa86a",avax:"0xa86a",avalanche:"0xa86a","avalanche c-chain":"0xa86a","avalanche cchain":"0xa86a","avax c-chain":"0xa86a","0xe708":"0xe708",59144:"0xe708",linea:"0xe708","linea mainnet":"0xe708"};function he(c){let e=Kn(c);return e&&fo.has(e)?e:null}function Kn(c){if(typeof c!="string")return null;let e=c.trim().toLowerCase().replace(/\s+/g," ");if(!e)return null;let t=Pr[e];if(t)return t;let n=null;return/^0x[0-9a-f]+$/.test(e)?n=e:/^[0-9]+$/.test(e)&&(n="0x"+Number(e).toString(16)),n&&xr.has(n)?n:null}function bn(c){return he(c)!==null}var We=class extends Error{constructor(t){super(`Chain "${t}" is not supported. Supported chains: ${Ne}.`);this.requested=t;this.name="UnsupportedChainError"}requested;code="unsupported_chain"},_e=c=>typeof c=="string"&&c.trim()!=="";function yo(c,e){if(_e(c)){let t=he(c);if(t)return t;throw new We(c.trim())}if(_e(e?.chain)){let t=he(e.chain);if(t)return t;throw new We(e.chain.trim())}return null}function wn(c,e){return he(c)??he(e?.chain)??void 0}var Ve={"0x1":"Ethereum","0xa":"Optimism","0x38":"BSC","0x89":"Polygon","0x2105":"Base","0xa4b1":"Arbitrum","0xa86a":"Avalanche","0xe708":"Linea"};function I(c){let e=Kn(c);return e&&Ve[e]?Ve[e]:typeof c=="string"&&c.trim()?c.trim():"the requested chain"}var _r={bnb:"0x38",matic:"0x89",pol:"0x89",avax:"0xa86a"};function bo(c){if(typeof c!="string")return null;let e=c.trim().toLowerCase();return e?_r[e]??null:null}var Cr={"0x1":"ETH","0xa":"ETH","0x38":"BNB","0x89":"POL","0x2105":"ETH","0xa4b1":"ETH","0xa86a":"AVAX","0xe708":"ETH"};function wo(c){let e=he(c);return e?Cr[e]??null:null}function He(c,e){if(!_e(c))return null;let t=he(c),n=he(e?.chain);return!t||!n||t===n?null:{requested:t,connected:n,requestedLabel:Ve[t]??t,connectedLabel:Ve[n]??n}}function Ur(){return Ee.map(c=>{let e=Ve[c]??c;return{label:e,prompt:e}})}var K=class extends Error{code="needs_chain_selection";buttons;constructor(e){super("Wallet is connected but no chain is set \u2014 ask the user to pick one."),this.name="NeedsChainSelectionError",this.buttons=e??Ur()}},Xt=class extends Error{code="no_wallet_connected";constructor(){super("No wallet address available \u2014 ask the user to connect a wallet or supply one."),this.name="NoWalletConnectedError"}};function Y(c,e){if(_e(c))return c.trim();if(_e(e?.walletAddress))return e.walletAddress.trim();throw new Xt}function R(c,e){if(_e(c)){let t=he(c);if(t)return t;throw new We(c.trim())}if(_e(e?.chain)){let t=he(e.chain);if(t)return t;throw new We(e.chain.trim())}if(_e(e?.walletAddress))throw new K;return ge}var v=class{category;async execute(e,t){let n=`call_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,r=Date.now();try{let o=await this.run(e,t),s=Rr(o);return{toolName:this.name,callId:n,success:!0,data:s.data,duration:Date.now()-r,...s.actionButtons?{actionButtons:s.actionButtons}:{}}}catch(o){return o instanceof K?{toolName:this.name,callId:n,success:!0,data:{_instructions:"The user has a connected wallet but no chain is set. Ask them which chain to use \u2014 the chain-picker buttons rendered below your reply let them choose. Keep the message short in the user's language and do NOT list the chain names yourself (the buttons already show them)."},duration:Date.now()-r,actionButtons:o.buttons}:o instanceof Xt?{toolName:this.name,callId:n,success:!0,data:{_instructions:"The user has not connected a wallet. In the user's language, tell them this action needs a wallet \u2014 they can either connect their wallet or include a wallet address (0x\u2026) directly in their question. Keep it short and friendly."},duration:Date.now()-r}:{toolName:this.name,callId:n,success:!1,error:o instanceof Error?o.message:String(o),duration:Date.now()-r}}}};function Rr(c){if(!c||typeof c!="object")return{data:c};let e=c,t=e.actionButtons;if(!Array.isArray(t)||t.length===0)return{data:c};let{actionButtons:n,...r}=e;return{data:r,actionButtons:t}}var ko=require("js-sha3");function B(c){return typeof c=="string"&&/^0x[0-9a-fA-F]{40}$/.test(c)}function Er(c){return new Uint8Array(ko.keccak256.arrayBuffer(c))}function Jt(c){let e=c.startsWith("0x")?c.slice(2):c,t=e.length%2?"0"+e:e,n=new Uint8Array(t.length/2);for(let r=0;r<n.length;r++)n[r]=parseInt(t.slice(r*2,r*2+2),16);return n}function To(c){return"0x"+Array.from(c).map(e=>e.toString(16).padStart(2,"0")).join("")}function vo(c){return new TextEncoder().encode(c)}function Ie(...c){let e=c.reduce((r,o)=>r+o.length,0),t=new Uint8Array(e),n=0;for(let r of c)t.set(r,n),n+=r.length;return t}function Nr(c,e=32){let t=new Uint8Array(e);return t.set(c,e-c.length),t}function Ir(c,e=32){let t=new Uint8Array(e);return t.set(c),t}function So(c){let e=((c%(1n<<256n)+(1n<<256n))%(1n<<256n)).toString(16).padStart(64,"0");return Jt(e)}function Zt(c){return So(BigInt(c))}function xo(c){return c==="uint"?"uint256":c==="int"?"int256":c.match(/^uint$/)?"uint256":c.match(/^int$/)?"int256":c.replace(/^uint(\[|$)/,"uint256$1").replace(/^int(\[|$)/,"int256$1")}function Ao(c){let e=xo(c.type);if(e==="tuple"||e.startsWith("tuple[")){let t=(c.components??[]).map(Ao).join(","),n=e.startsWith("tuple[")?e.slice(5):"";return`(${t})${n}`}return e}function Dr(c){let e=(c.inputs??[]).map(Ao).join(",");return`${c.name??""}(${e})`}function jn(c,e){let t=Br(c.type);if(t){let[r,o]=t;return Lr({...c,type:o},e,r)}if(c.type==="tuple")return Mr(c,e);if(c.type==="address"){let r=String(e),o=r.startsWith("0x")?r.slice(2):r;return{dynamic:!1,encoded:Nr(Jt(o.toLowerCase()))}}if(c.type==="bool"){let r=new Uint8Array(32);return r[31]=e?1:0,{dynamic:!1,encoded:r}}let n=xo(c.type);if(/^uint\d*$/.test(n))return{dynamic:!1,encoded:Zt(BigInt(e))};if(/^int\d*$/.test(n)){let r=BigInt(e);return r<0n&&(r=r+(1n<<256n)),{dynamic:!1,encoded:So(r)}}if(/^bytes(\d+)$/.test(n)){let r=parseInt(n.slice(5),10),o=typeof e=="string"?Jt(e):e;if(o.length!==r)throw new Error(`bytes${r} expects exactly ${r} bytes, got ${o.length}`);return{dynamic:!1,encoded:Ir(o)}}if(n==="bytes"){let r=typeof e=="string"?Jt(e):e,o=Math.ceil(r.length/32)*32,s=new Uint8Array(o);return s.set(r),{dynamic:!0,encoded:Ie(Zt(r.length),s)}}if(n==="string"){let r=typeof e=="string"?vo(e):e,o=Math.ceil(r.length/32)*32,s=new Uint8Array(o);return s.set(r),{dynamic:!0,encoded:Ie(Zt(r.length),s)}}throw new Error(`Unsupported ABI type: ${c.type}`)}function zn(c){let e=0;for(let{dynamic:o,encoded:s}of c)e+=o?32:s.length;let t=[],n=[],r=0;for(let{dynamic:o,encoded:s}of c)o?(t.push(Zt(e+r)),n.push(s),r+=s.length):t.push(s);return Ie(...t,...n)}function Lr(c,e,t){let n=t===null;if(!n&&e.length!==t)throw new Error(`Array length mismatch: expected ${t}, got ${e.length}`);let r=!1,o=[];for(let s of e){let a=jn(c,s);a.dynamic&&(r=!0),o.push(a)}if(n||r){let s=zn(o);if(n){let a=Zt(o.length);return{dynamic:!0,encoded:o.length>0?Ie(a,s):a}}return{dynamic:!0,encoded:s}}return{dynamic:!1,encoded:Ie(...o.map(s=>s.encoded))}}function Mr(c,e){let t=c.components??[],n=!1,r=[];for(let o=0;o<t.length;o++){let s=t[o],a=Array.isArray(e)?e[o]:e[s.name??""],i=jn(s,a);i.dynamic&&(n=!0),r.push(i)}return{dynamic:n,encoded:n?zn(r):Ie(...r.map(o=>o.encoded))}}function Br(c){let e=c.match(/^(.*)\[(\d+)?\]$/);return e?[e[2]?Number(e[2]):null,e[1]]:void 0}function Or(c,e){if(c.length!==e.length)throw new Error(`Expected ${c.length} values, got ${e.length}`);if(c.length===0)return"0x";let t=c.map((r,o)=>jn(r,e[o])),n=zn(t);return To(n)}function Ge({abi:c,functionName:e,args:t=[]}){let n=c.find(i=>(i.type==="function"||i.type===void 0)&&i.name===e);if(!n)throw new Error(`Function "${e}" not found in ABI`);let r=Dr(n),o=Er(vo(r)).slice(0,4),s=n.inputs??[],a=s.length===0||t.length===0?new Uint8Array(0):Jt(Or(s,t).slice(2));return To(Ie(o,a))}var qr="https://wallet-api.pantograph.app",Fr="0x0000000000000000000000000000000000000000",Co={"0x1":"ether","0xa":"optimism","0x38":"bsc","0x89":"matic","0x2105":"base","0xa4b1":"arbitrum","0xa86a":"avax","0xe708":"linea"},Uo={"0x1":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","0x2260fac5e5542a773aa44fbcfedf7c193bc2c599"],"0xa":["0x4200000000000000000000000000000000000006","0x68f180fcce6836688e9084f035309e29bf0a2095","0xc47da4cb96ce65a96844a01bfae509f9d5454534"],"0x38":["0x2170ed0880ac9a755fd29b2688956bd959f933f8","0x7130d2a12b9bcbfae4f2634d864a1ee1ce3ead9c"],"0x89":["0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6"],"0x2105":["0x4200000000000000000000000000000000000006","0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf","0xc47da4cb96ce65a96844a01bfae509f9d5454534"],"0xa4b1":["0x82af49447d8a07e3bd95bd0d56f35241523fbab1","0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f"],"0xa86a":["0x49d5c2bdffac6ce2bfdb6640f4f80f226bc10bab","0x0555e30da8f98308edb960aa94c0db47230d2b9c"],"0xe708":["0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f","0x3aab2285ddcddad8edf438c1bab47e1a9d05a9b4"]};function en(c){return Co[c.toLowerCase()]||c}function Po(c){let e=[];for(let[t,n]of Object.entries(c))if(n!=null)if(Array.isArray(n))for(let r of n)e.push(`${encodeURIComponent(t)}=${encodeURIComponent(String(r))}`);else e.push(`${encodeURIComponent(t)}=${encodeURIComponent(String(n))}`);return e.join("&")}function Qn(c){let e=c,t=e.decimals,n=typeof t=="number"?t:typeof t=="string"?parseInt(t,10):NaN,r=e.price,o=r!=null?parseFloat(String(r)):NaN;return{...e,token_address:e.token_address??e.address??"",decimals:Number.isFinite(n)?n:0,...Number.isFinite(o)?{usd_price:o}:{}}}function Z(c){if(c==null)return null;let e=typeof c=="number"?c:parseFloat(String(c));return Number.isFinite(e)?e:null}function _o(c,e){let t=c.decimals,n=typeof t=="number"?t:typeof t=="string"?parseInt(t,10):null,r=Z(c.price_change_percentage_24h)??Z(c.priceChange24h)??Z(c.usd_price_24hr_percent_change)??Z(c.price_change_24h)??Z(c.priceChange);return{chainId:e,tokenAddress:c.address??c.token_address??"",name:c.name??null,symbol:c.symbol??null,decimals:n!=null&&Number.isFinite(n)?n:null,logo:c.logoURI??c.icon_image??c.logo??null,usdPrice:Z(c.price)??Z(c.usd_price),marketCap:Z(c.market_cap)??Z(c.marketCap),totalVolume:{"24h":Z(c.total_volume)??Z(c.volume24h)},pricePercentChange:{"24h":r}}}var ee=class{baseUrl;constructor(e){this.baseUrl=(e?.baseUrl??qr).replace(/\/+$/,"")}async enrichTokenPrices(e,t){if(e.length!==0)try{let n=en(t),r=e.map(u=>u.token_address).join(","),o=`${this.baseUrl}/keyrings/tokens/${n}/v2?addresses=${encodeURIComponent(r)}`,s=await _.get(o);if(!s.ok)return;let a=s.data,i=Array.isArray(a)?a:Array.isArray(a.data)?a.data:[],l=new Map;for(let u of i)u.address&&l.set(u.address.toLowerCase(),{price:u.price!=null?parseFloat(String(u.price)):NaN,icon_image:u.icon_image});for(let u=0;u<e.length;u++){let d=l.get(e[u].token_address.toLowerCase());d&&(d.icon_image&&(e[u].logo=d.icon_image,e[u].thumbnail=d.icon_image),isNaN(d.price)||(e[u].usd_price=d.price,e[u].usd_value=parseFloat(e[u].balance_formatted||"0")*d.price))}}catch{}}async getTokenMetadata(e,t){try{let n=en(t),r=`${this.baseUrl}/keyrings/tokens/${n}/v2?addresses=${encodeURIComponent(e)}`,o=await _.get(r);if(!o.ok)return null;let s=o.data,a=Array.isArray(s)?s:Array.isArray(s.data)?s.data:[],i=e.toLowerCase()===Fr,l=a.find(u=>u.address?.toLowerCase()===e.toLowerCase()||i&&u.address===""||u.token_address?.toLowerCase()===e.toLowerCase()||i&&u.token_address==="");return l?Qn(l):null}catch{return null}}async getTokensMetadata(e,t){let n={};if(e.length===0)return n;try{let r=en(t),o=`${this.baseUrl}/keyrings/tokens/${r}/v2?addresses=${encodeURIComponent(e.join(","))}`,s=await _.get(o);if(!s.ok)return n;let a=s.data,i=Array.isArray(a)?a:Array.isArray(a.data)?a.data:[],l=new Set(e.map(u=>u.toLowerCase()));for(let u of i){let d=u.address?.toLowerCase()||u.token_address?.toLowerCase()||(u.address===""?"":null);d&&l.has(d)&&(n[d]=Qn(u))}}catch{}return n}async searchTokensByKey(e){let{key:t,chain:n}=e;if(!t)return{success:!1,error:"Search key is required"};let o=parseInt(n||ge,16);if(isNaN(o))return{success:!1,error:`Invalid hex chain: ${n}`};try{let s=Po({chainId:o,key:t}),a=`${this.baseUrl}/token-list?${s}`,i=await _.get(a);if(!i.ok)throw new Error(N(i));let l=i.data,u=[];return l?.data?u=Array.isArray(l.data)?l.data:Object.values(l.data).flat():typeof l=="object"&&!Array.isArray(l)&&(u=Object.values(l).flat()),{success:!0,data:u.map(Qn)}}catch(s){return{success:!1,error:s instanceof Error?s.message:"Unknown error"}}}async getTrendingTokens(e){let t=e?.chain||ge,n=5,r=e?.limit&&e.limit>0?Math.floor(e.limit):void 0;try{let o=Uo[t.toLowerCase()]??[],s=r!=null?r+o.length:n+o.length,[a,i]=await Promise.allSettled([this.fetchTopGainers(t,s),o.length>0?this.getTokensMetadata(o,t):Promise.resolve({})]),l=a.status==="fulfilled"?a.value:[],u=i.status==="fulfilled"?o.map(g=>i.value[g.toLowerCase()]).filter(g=>g!=null).map(g=>_o(g,t)):[],d=new Set,m=[];for(let g of u){let f=g.tokenAddress?.toLowerCase();!f||d.has(f)||(d.add(f),m.push(g))}let p=[];for(let g of l){let f=g.tokenAddress?.toLowerCase();!f||d.has(f)||(d.add(f),p.push(g))}let h=r!=null?[...m,...p].slice(0,r):[...m,...p.slice(0,n)];return await this.enrichTrendingMarketData(h,t),{success:!0,data:h}}catch(o){return{success:!1,error:o instanceof Error?o.message:"Unknown error"}}}async enrichTrendingMarketData(e,t){let n=e.filter(o=>o.tokenAddress&&(o.marketCap==null||o.totalVolume?.["24h"]==null));if(n.length===0)return;let r=await this.getTokensMetadata(n.map(o=>o.tokenAddress),t);for(let o of n){let s=r[o.tokenAddress.toLowerCase()];s&&(o.marketCap==null&&(o.marketCap=Z(s.market_cap)??Z(s.marketCap)),o.totalVolume?.["24h"]==null&&(o.totalVolume={"24h":Z(s.total_volume)??Z(s.volume24h)}))}}async fetchTopGainers(e,t,n="24h"){let r=en(e),o=Po({duration:n,limit:t}),s=`${this.baseUrl}/token-list/top-gainers/${r}${o?`?${o}`:""}`,a=[];for(let i=0;i<5;i++){let l=await _.get(s);if(!l.ok)throw new Error(N(l));let u=l.data;if(a=Array.isArray(u)?u:Array.isArray(u.data)?u.data:[],a.length>0)break;i<4&&await new Promise(d=>setTimeout(d,2e3))}return a.map(i=>_o(i,e))}async getTopGainers(e){let t=e?.chain||ge,n=e?.limit&&e.limit>0?Math.floor(e.limit):void 0,r=e?.duration||"24h";try{let o=await this.fetchTopGainers(t,n,r);return await this.enrichTrendingMarketData(o,t),{success:!0,data:o}}catch(o){return{success:!1,error:o instanceof Error?o.message:"Unknown error"}}}};var $r="https://nft.keyring.app",Wr="https://nft-demo.keyring.app",Vr=.01,U=5,F=1e3,Hr="0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",Gr="0x0000000000000000000000000000000000000000";function V(c){return c||ge}function $(c){let e=[];for(let[t,n]of Object.entries(c))if(n!=null)if(Array.isArray(n))for(let r of n)e.push(`${encodeURIComponent(t)}=${encodeURIComponent(String(r))}`);else e.push(`${encodeURIComponent(t)}=${encodeURIComponent(String(n))}`);return e.join("&")}function W(c){return new Promise(e=>setTimeout(e,c))}function Yr(c){if(Array.isArray(c))return c;if(c&&typeof c=="object"){let e=c;return Array.isArray(e.result)?e.result.map(t=>({protocol_id:t.protocolId,protocol_name:t.protocolName,protocol_url:t.protocolUrl??"",protocol_logo:t.protocolLogo??"",position:{label:t.position.label,address:t.position.address,balance_usd:t.position.balanceUsd??0,total_unclaimed_usd_value:t.position.unclaimedUsd??0,position_details:t.position.details,tokens:t.position.tokens.map(n=>({token_type:n.tokenType,address:n.address,contract_address:n.address,name:n.name??"",symbol:n.symbol??"",decimals:n.decimals??18,logo:n.logo,balance:n.balance??"0",balance_formatted:n.balanceFormatted??"0",usd_price:n.usdPrice,usd_value:n.usdValue}))}})):Object.keys(e).filter(t=>/^\d+$/.test(t)).sort((t,n)=>Number(t)-Number(n)).map(t=>e[t]).filter(t=>!!t&&typeof t=="object")}return[]}function Xn(c){if(Array.isArray(c))return c;if(c&&typeof c=="object"){let e=c;return Array.isArray(e.result)?e.result:Object.keys(e).filter(t=>/^\d+$/.test(t)).sort((t,n)=>Number(t)-Number(n)).map(t=>e[t]).filter(t=>!!t&&typeof t=="object")}return[]}var E=class{baseUrl;v1BaseUrl;pantograph;constructor(e){this.baseUrl=(e?.baseUrl??$r).replace(/\/+$/,""),this.v1BaseUrl=(e?.v1BaseUrl??Wr).replace(/\/+$/,""),this.pantograph=new ee({baseUrl:e?.pantographUrl})}async getWalletTokenBalances(e){let{address:t,chain:n,tokenAddresses:r,excludeSpam:o=!1,excludeUnverifiedContracts:s=!1}=e;if(!t)return{success:!1,error:"Address is required"};let a=V(n),i="Unknown error";for(let l=1;l<=U;l++)try{let u={chain:a,exclude_spam:o,exclude_unverified_contracts:s,limit:100};r&&(u.token_addresses=r);let d=[],m=null;do{m&&(u.cursor=m);let h=$(u),g=`${this.baseUrl}/api/moralis/proxy/wallets/${encodeURIComponent(t)}/tokens?${h}`,f=await _.get(g);if(!f.ok)throw new Error(N(f));let y=f.data,k=y?.data??y;k?.result?.length>0&&d.push(...k.result),m=k?.cursor??null}while(m);let p={result:d};return p?.result?.length>0&&(p.result=p.result.filter(h=>parseFloat(h.balance||"0")>0),p.result=p.result.map(h=>({...h,token_address:h.token_address.toLowerCase()===Hr?Gr:h.token_address})),await this.enrichTokenPrices(p.result,a),p.result=p.result.filter(h=>h.usd_value==null||h.usd_value>=Vr)),{success:!0,data:p}}catch(u){i=u instanceof Error?u.message:"Unknown error",l<U&&await W(F)}return{success:!1,error:i}}async getTokenMetadata(e){let{address:t,chain:n}=e;if(!t)return{success:!1,error:"Token address is required"};let r=V(n),o="Unknown error",s=await this.pantograph.getTokenMetadata(t,r);if(s)return{success:!0,data:s};for(let a=1;a<=U;a++)try{let[i,l]=await Promise.allSettled([_.get(`${this.baseUrl}/api/moralis/proxy/erc20/metadata?${$({chain:r,addresses:[t]})}`),_.get(`${this.baseUrl}/api/moralis/proxy/erc20/${encodeURIComponent(t)}/price?${$({chain:r,include:"percent_change"})}`)]),u=null;if(i.status==="fulfilled"&&i.value.ok){let m=i.value.data;u=(Array.isArray(m)?m:Array.isArray(m?.data)?m.data:[])[0]??null}if(!u){o="Token metadata not found",a<U&&await W(F);continue}let d=null;if(l.status==="fulfilled"&&l.value.ok){let m=l.value.data;d=m?.data??m}return{success:!0,data:{...u,...d?.usd_price?{usd_price:d.usd_price}:{},...d?.usd_price_change_percentage_24h?{usd_price_change_percentage_24h:d.usd_price_change_percentage_24h}:{}}}}catch(i){o=i instanceof Error?i.message:"Unknown error",a<U&&await W(F)}return{success:!1,error:o}}async getWalletNFTs(e){let{address:t,chain:n,limit:r=10,excludeSpam:o=!0,cursor:s,tokenAddresses:a,includePrices:i,format:l="decimal"}=e;if(!t)return{success:!1,error:"Address is required"};let u=V(n),d="Unknown error";for(let m=1;m<=U;m++)try{let p={chain:u,format:l,limit:r,exclude_spam:o,media_items:!0,normalizeMetadata:!0};s&&(p.cursor=s),i&&(p.include_prices=!0),a&&a.length>0&&(p.token_addresses=a);let h=$(p),g=`${this.baseUrl}/api/moralis/proxy/${encodeURIComponent(t)}/nft?${h}`,f=await _.get(g);if(!f.ok)throw new Error(N(f));let y=f.data;return{success:!0,data:y?.data??y}}catch(p){d=p instanceof Error?p.message:"Unknown error",m<U&&await W(F)}return{success:!1,error:d}}async getNftMetadata(e){let{address:t,tokenId:n,chain:r,format:o="decimal",normalizeMetadata:s=!0,mediaItems:a=!0,include:i}=e;if(!t)return{success:!1,error:"NFT contract address is required"};if(n==null||n==="")return{success:!1,error:"Token ID is required"};if(!B(t))return{success:!1,error:"NFT metadata lookup by token ID is only supported on EVM chains"};let l=V(r),u="Unknown error";for(let d=1;d<=U;d++)try{let m={chain:l,format:o,normalizeMetadata:s,media_items:a};i&&(m.include=i);let p=$(m),h=`${this.baseUrl}/api/moralis/proxy/nft/${encodeURIComponent(t)}/${encodeURIComponent(n)}?${p}`,g=await _.get(h);if(!g.ok)throw new Error(N(g));let f=g.data;return{success:!0,data:f?.data??f}}catch(m){u=m instanceof Error?m.message:"Unknown error",d<U&&await W(F)}return{success:!1,error:u}}async getNftContractMetadata(e){let{address:t,chain:n}=e;if(!t)return{success:!1,error:"Contract address is required"};let r=V(n),o="Unknown error";for(let s=1;s<=U;s++)try{let a=$({chain:r}),i=`${this.baseUrl}/api/moralis/proxy/nft/${encodeURIComponent(t)}/metadata?${a}`,l=await _.get(i);if(!l.ok)throw new Error(N(l));let u=l.data;return{success:!0,data:u?.data??u}}catch(a){o=a instanceof Error?a.message:"Unknown error",s<U&&await W(F)}return{success:!1,error:o}}async getWalletHistory(e){let{address:t,chain:n,limit:r=25,fromDate:o,toDate:s,fromBlock:a,toBlock:i,cursor:l,order:u="DESC",includeInternalTransactions:d,nftMetadata:m}=e;if(!t)return{success:!1,error:"Address is required"};if(!B(t))return{success:!1,error:"Wallet history is only supported for EVM addresses"};let p=V(n),h=Math.max(1,Math.min(100,Math.floor(r))),g="Unknown error";for(let f=1;f<=U;f++)try{let y={chain:p,limit:h,order:u};o&&(y.from_date=o),s&&(y.to_date=s),a!=null&&(y.from_block=a),i!=null&&(y.to_block=i),l&&(y.cursor=l),d!=null&&(y.include_internal_transactions=d),m!=null&&(y.nft_metadata=m);let k=$(y),w=`${this.baseUrl}/api/moralis/proxy/wallets/${encodeURIComponent(t)}/history?${k}`,b=await _.get(w);if(!b.ok)throw new Error(N(b));let T=b.data;return{success:!0,data:T?.data??T}}catch(y){g=y instanceof Error?y.message:"Unknown error",f<U&&await W(F)}return{success:!1,error:g}}async getWalletTokenTransfers(e){let{address:t,chain:n,contractAddresses:r,limit:o=25,fromDate:s,toDate:a,fromBlock:i,toBlock:l,cursor:u,order:d="DESC"}=e;if(!t)return{success:!1,error:"Address is required"};if(!B(t))return{success:!1,error:"ERC-20 transfers are only supported for EVM addresses"};let m=V(n),p=Math.max(1,Math.min(100,Math.floor(o))),h="Unknown error";for(let g=1;g<=U;g++)try{let f={chain:m,limit:p,order:d};s&&(f.from_date=s),a&&(f.to_date=a),i!=null&&(f.from_block=i),l!=null&&(f.to_block=l),u&&(f.cursor=u),r?.length&&(f.contract_addresses=r);let y=$(f),k=`${this.baseUrl}/api/moralis/proxy/${encodeURIComponent(t)}/erc20/transfers?${y}`,w=await _.get(k);if(!w.ok)throw new Error(N(w));let b=w.data;return{success:!0,data:b?.data??b}}catch(f){h=f instanceof Error?f.message:"Unknown error",g<U&&await W(F)}return{success:!1,error:h}}async getWalletNftTransfers(e){let{address:t,chain:n,contractAddresses:r,limit:o=25,fromDate:s,toDate:a,fromBlock:i,toBlock:l,cursor:u,order:d="DESC",includePrices:m,format:p="decimal"}=e;if(!t)return{success:!1,error:"Address is required"};if(!B(t))return{success:!1,error:"NFT transfers are only supported for EVM addresses"};let h=V(n),g=Math.max(1,Math.min(100,Math.floor(o))),f="Unknown error";for(let y=1;y<=U;y++)try{let k={chain:h,limit:g,order:d,format:p};s&&(k.from_date=s),a&&(k.to_date=a),i!=null&&(k.from_block=i),l!=null&&(k.to_block=l),u&&(k.cursor=u),r?.length&&(k.contract_addresses=r),m!=null&&(k.include_prices=m);let w=$(k),b=`${this.baseUrl}/api/moralis/proxy/${encodeURIComponent(t)}/nft/transfers?${w}`,T=await _.get(b);if(!T.ok)throw new Error(N(T));let P=T.data;return{success:!0,data:P?.data??P}}catch(k){f=k instanceof Error?k.message:"Unknown error",y<U&&await W(F)}return{success:!1,error:f}}async getTokenHolders(e){let{address:t,chain:n}=e;if(!t)return{success:!1,error:"Contract address is required"};if(!B(t))return{success:!1,error:"Token holders is only supported for EVM contract addresses"};let r=V(n),o="Unknown error";for(let s=1;s<=U;s++)try{let a=$({chain:r}),i=`${this.baseUrl}/api/moralis/proxy/erc20/${encodeURIComponent(t)}/holders?${a}`,l=await _.get(i);if(!l.ok)throw new Error(N(l));let u=l.data;return{success:!0,data:u?.data??u}}catch(a){o=a instanceof Error?a.message:"Unknown error",s<U&&await W(F)}return{success:!1,error:o}}async getWalletNetWorth(e){let{address:t,chains:n,excludeSpam:r,excludeUnverifiedContracts:o,maxTokenInactivity:s,minPairSideLiquidityUsd:a}=e;if(!t)return{success:!1,error:"Address is required"};if(!B(t))return{success:!1,error:"Wallet net worth is only supported for EVM addresses"};let i="Unknown error";for(let l=1;l<=U;l++)try{let u={};n&&n.length>0&&(u.chains=n.map(y=>V(y))),r!=null&&(u.exclude_spam=r),o!=null&&(u.exclude_unverified_contracts=o),s!=null&&(u.max_token_inactivity=s),a!=null&&(u.min_pair_side_liquidity_usd=a);let d=$(u),m=`${this.baseUrl}/api/moralis/proxy/wallets/${encodeURIComponent(t)}/net-worth${d?`?${d}`:""}`,p=await _.get(m);if(!p.ok)throw new Error(N(p));let h=p.data;return{success:!0,data:h?.data??h}}catch(u){i=u instanceof Error?u.message:"Unknown error",l<U&&await W(F)}return{success:!1,error:i}}async getWalletPnlSummary(e){let{address:t,chain:n,days:r}=e;if(!t)return{success:!1,error:"Address is required"};if(!B(t))return{success:!1,error:"Wallet PnL summary is only supported for EVM addresses"};let o=V(n),s="Unknown error";for(let a=1;a<=U;a++)try{let i={chain:o};r&&(i.days=r);let l=$(i),u=`${this.baseUrl}/api/moralis/proxy/wallets/${encodeURIComponent(t)}/profitability/summary?${l}`,d=await _.get(u);if(!d.ok)throw new Error(N(d));let m=d.data;return{success:!0,data:m?.data??m}}catch(i){s=i instanceof Error?i.message:"Unknown error",a<U&&await W(F)}return{success:!1,error:s}}async getWalletPnl(e){let{address:t,chain:n,days:r,tokenAddresses:o}=e;if(!t)return{success:!1,error:"Address is required"};if(!B(t))return{success:!1,error:"Wallet PnL is only supported for EVM addresses"};let s=V(n),a="Unknown error";for(let i=1;i<=U;i++)try{let l={chain:s};r&&(l.days=r),o&&o.length>0&&(l.token_addresses=o.slice(0,25));let u=$(l),d=`${this.baseUrl}/api/moralis/proxy/wallets/${encodeURIComponent(t)}/profitability?${u}`,m=await _.get(d);if(!m.ok)throw new Error(N(m));let p=m.data;return{success:!0,data:p?.data??p}}catch(l){a=l instanceof Error?l.message:"Unknown error",i<U&&await W(F)}return{success:!1,error:a}}async getTransactionByHash(e){let{transactionHash:t,chain:n}=e;if(!t)return{success:!1,error:"Transaction hash is required"};let r=V(n),o="Unknown error";for(let s=1;s<=U;s++)try{let a=$({chain:r}),i=`${this.baseUrl}/api/moralis/proxy/transaction/${encodeURIComponent(t)}/verbose?${a}`,l=await _.get(i);if(!l.ok)throw new Error(N(l));let u=l.data;return{success:!0,data:u?.data??u}}catch(a){o=a instanceof Error?a.message:"Unknown error",s<U&&await W(F)}return{success:!1,error:o}}async getWalletApprovals(e){let{address:t,chain:n,limit:r,cursor:o}=e;if(!t)return{success:!1,error:"Address is required"};if(!B(t))return{success:!1,error:"Wallet approvals are only supported for EVM addresses"};let s=V(n),a="Unknown error";for(let i=1;i<=U;i++)try{let l={chain:s};r!=null&&(l.limit=r),o&&(l.cursor=o);let u=$(l),d=`${this.baseUrl}/api/moralis/proxy/wallets/${encodeURIComponent(t)}/approvals?${u}`,m=await _.get(d);if(!m.ok)throw new Error(N(m));let p=m.data;return{success:!0,data:p?.data??p}}catch(l){a=l instanceof Error?l.message:"Unknown error",i<U&&await W(F)}return{success:!1,error:a}}async getWalletDefiSummary(e){let{address:t,chain:n}=e;if(!t)return{success:!1,error:"Address is required"};if(!B(t))return{success:!1,error:"Wallet DeFi summary is only supported for EVM addresses"};let r=V(n),o="Unknown error";for(let s=1;s<=U;s++)try{let a=$({chains:r}),i=`${this.v1BaseUrl}/api/moralis-v1/proxy/wallets/${encodeURIComponent(t)}/defi/summary?${a}`,l=await _.get(i);if(!l.ok)throw new Error(N(l));let u=l.data;return{success:!0,data:u?.data??u}}catch(a){o=a instanceof Error?a.message:"Unknown error",s<U&&await W(F)}return{success:!1,error:o}}async getWalletDefiPositions(e){let{address:t,chain:n}=e;if(!t)return{success:!1,error:"Address is required"};if(!B(t))return{success:!1,error:"Wallet DeFi positions are only supported for EVM addresses"};let r=V(n),o="Unknown error";for(let s=1;s<=U;s++)try{let a=$({chains:r}),i=`${this.v1BaseUrl}/api/moralis-v1/proxy/wallets/${encodeURIComponent(t)}/defi/positions?${a}`,l=await _.get(i);if(!l.ok)throw new Error(N(l));let u=l.data,d=u?.data??u;return{success:!0,data:Yr(d)}}catch(a){o=a instanceof Error?a.message:"Unknown error",s<U&&await W(F)}return{success:!1,error:o}}async getWalletDefiProtocolPositions(e){let{address:t,protocol:n,chain:r}=e;if(!t)return{success:!1,error:"Address is required"};if(!n)return{success:!1,error:"Protocol identifier is required"};if(!B(t))return{success:!1,error:"Wallet DeFi protocol positions are only supported for EVM addresses"};let o=V(r),s="Unknown error";for(let a=1;a<=U;a++)try{let i=$({chains:o}),l=`${this.v1BaseUrl}/api/moralis-v1/proxy/wallets/${encodeURIComponent(t)}/defi/${encodeURIComponent(n)}/positions?${i}`,u=await _.get(l);if(!u.ok)throw new Error(N(u));let p=u.data.result;return{success:!0,data:{protocol_id:p.protocolId,protocol_name:p.protocolName,protocol_url:p.protocolUrl??"",protocol_logo:p.protocolLogo??"",total_usd_value:p.totalUsd??0,total_unclaimed_usd_value:p.totalUnclaimedUsd??null,positions:p.positions.map(g=>({label:g.label,address:g.address,balance_usd:g.balanceUsd??0,total_unclaimed_usd_value:g.unclaimedUsd??0,position_details:g.details,tokens:g.tokens.map(f=>({token_type:f.tokenType,address:f.address,contract_address:f.address,name:f.name??"",symbol:f.symbol??"",decimals:f.decimals??18,logo:f.logo,balance:f.balance??"0",balance_formatted:f.balanceFormatted??"0",usd_price:f.usdPrice,usd_value:f.usdValue}))}))}}}catch(i){s=i instanceof Error?i.message:"Unknown error",a<U&&await W(F)}return{success:!1,error:s}}async searchTokensByKey(e){return this.pantograph.searchTokensByKey(e)}async getTokenAnalytics(e){let{address:t,chain:n}=e;if(!t)return{success:!1,error:"Token contract address is required"};if(!B(t))return{success:!1,error:"Token analytics is only supported for EVM contract addresses"};let r=V(n),o="Unknown error";for(let s=1;s<=U;s++)try{let a=$({chain:r}),i=`${this.baseUrl}/api/moralis/proxy/tokens/${encodeURIComponent(t)}/analytics?${a}`,l=await _.get(i);if(!l.ok)throw new Error(N(l));let u=l.data;return{success:!0,data:u?.data??u}}catch(a){o=a instanceof Error?a.message:"Unknown error",s<U&&await W(F)}return{success:!1,error:o}}async getTokenScore(e){let{address:t,chain:n}=e;if(!t)return{success:!1,error:"Token contract address is required"};if(!B(t))return{success:!1,error:"Token score is only supported for EVM contract addresses"};let r=V(n),o="Unknown error";for(let s=1;s<=U;s++)try{let a=$({chain:r}),i=`${this.baseUrl}/api/moralis/proxy/tokens/${encodeURIComponent(t)}/score?${a}`,l=await _.get(i);if(!l.ok)throw new Error(N(l));let u=l.data;return{success:!0,data:u?.data??u}}catch(a){o=a instanceof Error?a.message:"Unknown error",s<U&&await W(F)}return{success:!1,error:o}}async getTrendingTokens(e){let t=e?.chain,n=e?.limit,r="Unknown error";for(let o=1;o<=U;o++)try{let s={};t&&(s.chain=V(t)),n!=null&&(s.limit=n);let a=$(s),i=`${this.baseUrl}/api/moralis/proxy/tokens/trending${a?`?${a}`:""}`,l=await _.get(i);if(!l.ok)throw new Error(N(l));let u=l.data,d=u?.data??u;return{success:!0,data:Xn(d)}}catch(s){r=s instanceof Error?s.message:"Unknown error",o<U&&await W(F)}return{success:!1,error:r}}async getTopGainers(e){let{chain:t,timeFrame:n,minMarketCap:r,securityScore:o}=e??{},s="Unknown error";for(let a=1;a<=U;a++)try{let i={};t&&(i.chain=V(t)),n&&(i.time_frame=n),r!=null&&(i.min_market_cap=r),o!=null&&(i.security_score=o);let l=$(i),u=`${this.baseUrl}/api/moralis/proxy/discovery/tokens/top-gainers${l?`?${l}`:""}`,d=await _.get(u);if(!d.ok)throw new Error(N(d));let m=d.data,p=m?.data??m;return{success:!0,data:Xn(p)}}catch(i){s=i instanceof Error?i.message:"Unknown error",a<U&&await W(F)}return{success:!1,error:s}}async getTopLosers(e){let{chain:t,timeFrame:n,minMarketCap:r,securityScore:o}=e??{},s="Unknown error";for(let a=1;a<=U;a++)try{let i={};t&&(i.chain=V(t)),n&&(i.time_frame=n),r!=null&&(i.min_market_cap=r),o!=null&&(i.security_score=o);let l=$(i),u=`${this.baseUrl}/api/moralis/proxy/discovery/tokens/top-losers${l?`?${l}`:""}`,d=await _.get(u);if(!d.ok)throw new Error(N(d));let m=d.data,p=m?.data??m;return{success:!0,data:Xn(p)}}catch(i){s=i instanceof Error?i.message:"Unknown error",a<U&&await W(F)}return{success:!1,error:s}}async enrichTokenPrices(e,t){return this.pantograph.enrichTokenPrices(e,t)}};var Ye=class extends v{name="get-token-info";description='Get information about a specific cryptocurrency token: price, metadata, 24h change, market data, and user holdings. Use this when the user asks about: token price, token info, "what is X token", "tell me about X", "how much is X worth", or any token-specific question. Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea';category="blockchain-data";parameters=[{name:"keyword",type:"string",description:'Token symbol, name, or contract address (e.g. "USDC", "Pepe", "ETH", "0x1234\u2026"). If a 0x address is provided, performs a precise contract lookup. Otherwise searches by name/symbol.',required:!0},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"prompt",type:"string",description:`A rich, multi-angle research prompt sent to Gemini with Google Search grounding (real-time web access). The prompt must be self-contained \u2014 Gemini does NOT see the user's original message, only this prompt. ALWAYS include: the token symbol/name, the chain, and an instruction to use web search for up-to-date info. When the user asks an open/broad question (e.g. "show me X", "tell me about X", "what is X"), expand the prompt to cover ALL of these angles in one request: (1) what the token/project is and its core utility, (2) current USD price, 24h change, market cap, FDV, 24h volume, (3) recent news, announcements, or notable events in the last 7-30 days, (4) on-chain activity signals (holders, liquidity, unusual flows), (5) team/protocol updates or roadmap items, (6) key risks, red flags, or controversies, (7) sentiment and notable community discussion. When the user asks a narrow question (e.g. "price of X"), still include 2-3 supporting angles for context. Aim for 3-6 sentences. Be specific to the token. Do not use generic filler. Example for "show me JPYT": "Research the JPYT token on Ethereum using up-to-date web sources. Cover: what JPYT is and who issues it; current USD price, 24h change, market cap, FDV, and 24h volume; recent news or announcements in the last 30 days; on-chain signals such as holder count, liquidity, and unusual volume patterns; team or protocol updates; key risks or red flags; and overall sentiment."`,required:!0},{name:"buy_button_label",type:"string",description:`Label for the "Buy" suggestion button shown under the token info, IN THE USER'S CURRENT LANGUAGE. Use the exact placeholder "{token}" (do not translate the braces) for the token symbol; put the localized verb directly in the text. English example: "Buy {token}". Vietnamese example: "Mua {token}". Japanese example: "{token} \u8CFC\u5165". Always include {token}.`,required:!0},{name:"buy_prompt_template",type:"string",description:`A short "buy" command IN THE USER'S CURRENT LANGUAGE, submitted as the next user turn when the Buy button is clicked. Use the exact placeholder "{token}" (do not translate the braces) for the token symbol; put the localized verb directly in the text. English example: "buy {token}". Vietnamese example: "mua {token}". Japanese example: "{token} \u8CFC\u5165". Always include {token}.`,required:!0}];service;llm;constructor(e){super(),this.service=new E(e),this.llm=new se({})}async run(e,t){let n=e.keyword||"",r=R(e.chain,t),o=e.prompt||"",s=e.buy_button_label||"",a=e.buy_prompt_template||"",i=t?.walletAddress||void 0;return n?await this.searchToken(n,r,o,s,a,i):{error:"Missing required parameter: keyword"}}async execute(e,t){let n=await super.execute(e,t),r=n.data;return n.success&&r&&Array.isArray(r.actionButtons)&&r.actionButtons.length>0&&(n.actionButtons=r.actionButtons),n}async searchToken(e,t,n,r,o,s){let a=[s?`User's connected wallet address: ${s}`:null,t?`Current chain (hex chain ID): ${t}, only consider tokens on this chain`:null,"Use this context to personalize your answer where relevant (e.g. whether the user holds the token, chain-specific data)."].filter(Boolean).join(`
|
|
3
3
|
`),[i,l,u]=await Promise.all([this.service.searchTokensByKey({key:e,chain:t}),s?this.findTokenInWallet(s,t,e):Promise.resolve(null),n?this.askGeminiWithSearch(n,a):Promise.resolve(null)]),d=i.success&&i.data?Array.isArray(i.data)?i.data:[]:[],m=e.toLowerCase(),p=b=>b.symbol?.toLowerCase()===m||b.token_address?.toLowerCase()===m,h=[...d].sort((b,T)=>(p(b)?0:1)-(p(T)?0:1)),g=null,f=h[0];if(f?.token_address){let b=await this.service.getTokenMetadata({address:f.token_address,chain:t});b.success&&b.data&&(g=b.data)}!g&&f&&(g={...f});let y=g?.symbol?.trim(),k=y?[{label:this.fillTemplate(r,y,"Buy {token}"),prompt:this.fillTemplate(o,y,"buy {token}")}]:[];return{_instructions:'Present the token info in a clear summary. Include: token name & symbol, contract address (shortened), current USD price, 24h price change % (prefix "+" for positive, "-" for negative), market cap, fully diluted valuation, 24h trading volume, liquidity, and holder count (if available). If the user holds this token, prominently show their balance and USD value. If research is present, weave its substance naturally into your answer \u2014 fold the relevant points into the description, context, and any notable news or risks. Do NOT add a labelled "AI Analysis" section or any similar heading, and do NOT mention that the analysis came from AI; just write it as part of the token summary. Format numbers in a human-readable way (e.g. $1.23, +5.67%, $12.5M). If a field is null, omit it. A "Buy" button is shown below your reply automatically \u2014 do NOT mention it, list it, or repeat its text.',chain:t,userHoldsToken:!!l,walletBalance:l,token:g,...d.length>1?{searchResults:h.slice(0,10)}:{},research:u,...k.length>0?{actionButtons:k}:{}}}fillTemplate(e,t,n){return(e&&e.includes("{token}")?e:n).replace(/\{token\}/g,t).replace(/\s+/g," ").trim()}async askGeminiWithSearch(e,t){let n=Date.now();try{return(await this.llm.chat([...t?[{role:"system",content:t,timestamp:n}]:[],{role:"user",content:e,timestamp:n}],void 0,{googleSearch:!0,maxRetries:1})).text?.trim()||null}catch{return null}}async findTokenInWallet(e,t,n){if(!n)return null;let r=await this.service.getWalletTokenBalances({address:e,chain:t,excludeSpam:!0,excludeUnverifiedContracts:!0});if(!r.success||!r.data?.result)return null;let o=n.toLowerCase(),s=r.data.result.find(a=>a.token_address.toLowerCase()===o||a.symbol?.toLowerCase()===o||a.name?.toLowerCase().includes(o));return s||null}};var Ke=class extends v{name="get-token-holders";description='Get holder statistics and analytics for an ERC-20 token. Returns: total holder count, holder count changes over time (5min/1h/6h/24h/3d/7d/30d), how holders acquired the token (swap/transfer/airdrop), supply concentration (% held by top 10/25/50/100/250/500 holders), and holder size distribution (whales, sharks, dolphins, fish, octopus, crabs, shrimps). Use tokenSymbol (e.g. "USDC") to look up by name \u2014 the tool auto-resolves the contract address. Use contractAddress when you already have the exact 0x address. Use this tool for questions like: "How many holders does USDC have?" (tokenSymbol=USDC), "Is USDC gaining or losing holders?" (tokenSymbol=USDC \u2192 holderChange), "How many new holders did ETH get in the last 7 days?" (tokenSymbol=WETH), "How concentrated is USDC ownership?" (tokenSymbol=USDC \u2192 holderSupply), "What % of supply do the top 10 holders control?" (tokenSymbol=USDC), "How many whales hold USDT?" (tokenSymbol=USDT \u2192 holderDistribution), "Did most holders buy via swap or transfer?" (tokenSymbol=USDC \u2192 holdersByAcquisition). Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. ';category="blockchain-data";parameters=[{name:"tokenSymbol",type:"string",description:`Token symbol (e.g. "USDC", "USDT", "WETH"). The tool resolves the contract address automatically: first checks the connected wallet's balances, then searches by symbol. Takes precedence over contractAddress when both are given.`,required:!1},{name:"contractAddress",type:"string",description:"ERC-20 token contract address (0x\u2026). Use when the exact address is already known. Ignored if tokenSymbol is provided.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea . ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=R(e.chain,t),r=t?.walletAddress||void 0,o=typeof e.tokenSymbol=="string"&&e.tokenSymbol?e.tokenSymbol.trim():void 0,s=typeof e.contractAddress=="string"&&e.contractAddress?e.contractAddress.trim():void 0;if(!o&&!s)return{error:'Provide either tokenSymbol (e.g. "USDC") or contractAddress (0x\u2026).'};let a,i;if(o){let d=await this.resolveContractAddress(o,n,r);if(!d)return{error:`Cannot resolve token symbol "${o}" to a contract address on ${n?I(n):"the selected chain"}. Try passing contractAddress directly.`};s=d.address,a=d.symbol,i=d.name}let l=await this.service.getTokenHolders({address:s,chain:n});if(!l.success)return{error:l.error||"Failed to fetch token holder stats"};let u=l.data;return{token:{symbol:a??o??null,name:i??null,contractAddress:s,chain:n||"default"},totalHolders:u.totalHolders,holdersByAcquisition:u.holdersByAcquisition,holderChange:u.holderChange,holderSupply:u.holderSupply,holderDistribution:u.holderDistribution}}async resolveContractAddress(e,t,n){let r=e.toLowerCase();if(n){let s=await this.service.getWalletTokenBalances({address:n,chain:t});if(s.success&&s.data?.result?.length){let a=s.data.result.find(i=>(i.symbol??"").toLowerCase()===r);if(a)return{address:a.token_address,symbol:a.symbol,name:a.name}}}let o=await this.service.searchTokensByKey({key:e,chain:t});if(o.success&&o.data?.length){let a=o.data.find(i=>(i.symbol??"").toLowerCase()===r)??o.data[0];if(a?.token_address)return{address:a.token_address,symbol:a.symbol,name:a.name}}}};var je=class extends v{name="get-token-analytics";description=`Get detailed trading analytics for a single ERC-20 token, broken down across 5min / 1h / 6h / 24h windows. Returns: buy volume, sell volume, unique buyers, unique sellers, buy/sell transaction counts, unique wallets, price % change, current USD price, total liquidity and fully-diluted valuation (FDV). Use tokenSymbol (e.g. "PEPE") to look up by name \u2014 the tool auto-resolves the contract address. Use contractAddress when you already have the exact 0x address. Use this tool for questions like: "How is PEPE trading today?" (tokenSymbol=PEPE), "24h buy vs sell volume for USDC?" (tokenSymbol=USDC \u2192 totalBuyVolume vs totalSellVolume), "Is buying or selling pressure stronger for this token?", "How many unique wallets touched this token in the last hour?" (\u2192 uniqueWallets.1h), "What's the FDV and liquidity of X?" (\u2192 totalFullyDilutedValuation, totalLiquidity), "Price change over 6h?" (\u2192 pricePercentChange.6h). Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea.`;category="blockchain-data";parameters=[{name:"tokenSymbol",type:"string",description:`Token symbol (e.g. "PEPE", "USDC", "WETH"). The tool resolves the contract address automatically: first checks the connected wallet's balances, then searches by symbol. Takes precedence over contractAddress when both are given.`,required:!1},{name:"contractAddress",type:"string",description:"ERC-20 token contract address (0x\u2026). Use when the exact address is already known. Ignored if tokenSymbol is provided.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=R(e.chain,t),r=t?.walletAddress||void 0,o=typeof e.tokenSymbol=="string"&&e.tokenSymbol?e.tokenSymbol.trim():void 0,s=typeof e.contractAddress=="string"&&e.contractAddress?e.contractAddress.trim():void 0;if(!o&&!s)return{error:'Provide either tokenSymbol (e.g. "PEPE") or contractAddress (0x\u2026).'};let a,i;if(o){let d=await this.resolveContractAddress(o,n,r);if(!d)return{error:`Cannot resolve token symbol "${o}" to a contract address on ${n?I(n):"the selected chain"}. Try passing contractAddress directly.`};s=d.address,a=d.symbol,i=d.name}let l=await this.service.getTokenAnalytics({address:s,chain:n});if(!l.success)return{error:l.error||"Failed to fetch token analytics"};let u=l.data??{};return{token:{symbol:a??o??null,name:i??null,contractAddress:s,chain:n||"default"},usdPrice:u.usdPrice??null,totalLiquidity:u.totalLiquidity??null,totalFullyDilutedValuation:u.totalFullyDilutedValuation??null,totalBuyVolume:u.totalBuyVolume??null,totalSellVolume:u.totalSellVolume??null,totalBuyers:u.totalBuyers??null,totalSellers:u.totalSellers??null,totalBuys:u.totalBuys??null,totalSells:u.totalSells??null,uniqueWallets:u.uniqueWallets??null,pricePercentChange:u.pricePercentChange??null}}async resolveContractAddress(e,t,n){let r=e.toLowerCase();if(n){let s=await this.service.getWalletTokenBalances({address:n,chain:t});if(s.success&&s.data?.result?.length){let a=s.data.result.find(i=>(i.symbol??"").toLowerCase()===r);if(a)return{address:a.token_address,symbol:a.symbol,name:a.name}}}let o=await this.service.searchTokensByKey({key:e,chain:t});if(o.success&&o.data?.length){let a=o.data.find(i=>(i.symbol??"").toLowerCase()===r)??o.data[0];if(a?.token_address)return{address:a.token_address,symbol:a.symbol,name:a.name}}}};var ze=class extends v{name="get-token-score";description=`Get a composite 0\u2013100 health/safety score for a single ERC-20 token, plus the metrics behind it. Returns: overall score, last-updated timestamp, current USD price, paired liquidity, multi-timeframe volume buckets (10m / 30m / 1h / 4h / 12h / 1d / 7d / 30d), same buckets for transaction counts, and supply info (total supply + % held by top 10 holders). Use tokenSymbol (e.g. "PEPE") to look up by name \u2014 the tool auto-resolves the contract address. Use contractAddress when you already have the exact 0x address. Use this tool for questions like: "Is PEPE a safe token?" (tokenSymbol=PEPE \u2192 score), "What's the health/score of USDC?", "How concentrated is X's supply among whales?" (\u2192 metrics.supply.top10Percent), "How much volume did this token do over the last 7 days?" (\u2192 metrics.volumeUsd.7d), "Transaction count for this token in the last hour?" (\u2192 metrics.transactions.1h). Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea.`;category="blockchain-data";parameters=[{name:"tokenSymbol",type:"string",description:`Token symbol (e.g. "PEPE", "USDC", "WETH"). The tool resolves the contract address automatically: first checks the connected wallet's balances, then searches by symbol. Takes precedence over contractAddress when both are given.`,required:!1},{name:"contractAddress",type:"string",description:"ERC-20 token contract address (0x\u2026). Use when the exact address is already known. Ignored if tokenSymbol is provided.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=R(e.chain,t),r=t?.walletAddress||void 0,o=typeof e.tokenSymbol=="string"&&e.tokenSymbol?e.tokenSymbol.trim():void 0,s=typeof e.contractAddress=="string"&&e.contractAddress?e.contractAddress.trim():void 0;if(!o&&!s)return{error:'Provide either tokenSymbol (e.g. "PEPE") or contractAddress (0x\u2026).'};let a,i;if(o){let m=await this.resolveContractAddress(o,n,r);if(!m)return{error:`Cannot resolve token symbol "${o}" to a contract address on ${n?I(n):"the selected chain"}. Try passing contractAddress directly.`};s=m.address,a=m.symbol,i=m.name}let l=await this.service.getTokenScore({address:s,chain:n});if(!l.success)return{error:l.error||"Failed to fetch token score"};let u=l.data??{},d=u.metrics??{};return{token:{symbol:a??o??null,name:i??null,contractAddress:s,chain:n||"default"},score:u.score??null,updatedAt:u.updatedAt??null,metrics:{usdPrice:d.usdPrice??null,liquidityUsd:d.liquidityUsd??null,volumeUsd:d.volumeUsd??null,transactions:d.transactions??null,supply:d.supply??null}}}async resolveContractAddress(e,t,n){let r=e.toLowerCase();if(n){let s=await this.service.getWalletTokenBalances({address:n,chain:t});if(s.success&&s.data?.result?.length){let a=s.data.result.find(i=>(i.symbol??"").toLowerCase()===r);if(a)return{address:a.token_address,symbol:a.symbol,name:a.name}}}let o=await this.service.searchTokensByKey({key:e,chain:t});if(o.success&&o.data?.length){let a=o.data.find(i=>(i.symbol??"").toLowerCase()===r)??o.data[0];if(a?.token_address)return{address:a.token_address,symbol:a.symbol,name:a.name}}}};var Qe=class extends v{name="get-trending-tokens";description='List tokens trending on-chain right now, ranked by trading activity, volume, liquidity and holder growth. Returns price, market cap, liquidity, holder count, and multi-timeframe buckets (1h / 4h / 12h / 24h) of price change, volume, transaction counts, and unique buyers/sellers. Cross-chain by default \u2014 omit `chain` for a global ranking, or pass it to filter to one network. Use this tool for questions like: "What tokens are trending right now?", "Show me hot tokens", "What\'s popular on Base today?", "Which tokens have the highest 24h volume?", "Biggest movers in the last hour?". Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea, and more.';category="blockchain-data";parameters=[{name:"chain",type:"string",description:'Optional hex chain ID to scope results to a single network: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user names a chain. Omit to return cross-chain trending results.',required:!1},{name:"limit",type:"number",description:'Total number of trending tokens to return (chain default tokens + top gainers combined). Only set this when the user asks for a specific count (e.g. "show 20 trending tokens" \u2192 20). Omit otherwise \u2014 when omitted, returns all default tokens plus 5 top gainers.',required:!1},{name:"buy_button_label",type:"string",description:`Label template for the per-token "Buy" suggestion buttons, IN THE USER'S CURRENT LANGUAGE. One button is rendered per trending token, with "{token}" replaced by that token's symbol. Use the exact placeholder "{token}" (do not translate the braces); put the localized verb in the text. English example: "Buy {token}". Vietnamese example: "Mua {token}". Japanese example: "{token} \u8CFC\u5165". Always include {token}.`,required:!0},{name:"buy_prompt_template",type:"string",description:`A short "buy" command template IN THE USER'S CURRENT LANGUAGE, submitted as the next user turn when a token's Buy button is clicked. "{token}" is replaced by that token's symbol. Use the exact placeholder "{token}" (do not translate the braces); put the localized verb in the text. English example: "buy {token}". Vietnamese example: "mua {token}". Japanese example: "{token} \u8CFC\u5165". Always include {token}.`,required:!0}];service;constructor(e){super(),this.service=new ee({baseUrl:e?.pantographUrl})}async run(e,t){let n=wn(e.chain,t),r=e.buy_button_label||"",o=e.buy_prompt_template||"",s=typeof e.limit=="number"&&Number.isFinite(e.limit)&&e.limit>0?Math.floor(e.limit):void 0,a=await this.service.getTrendingTokens({chain:n,limit:s});if(!a.success)return{error:a.error||"Failed to fetch trending tokens"};let i=a.data??[],l=new Set,u=[];for(let d of i){let m=d.symbol?.trim();!m||l.has(m.toLowerCase())||(l.add(m.toLowerCase()),u.push({label:this.fillTemplate(r,m,"Buy {token}"),prompt:this.fillTemplate(o,m,"buy {token}")}))}return{_instructions:`Start with a one-line header like "Here are some of the top trending tokens on <chain name> right now:". Then present the tokens as a numbered list. For EACH token render exactly these lines (omit any line whose value is null):
|
|
4
4
|
<rank>. <name> (<symbol>)
|
|
@@ -12,7 +12,7 @@ Format numbers human-readably: price as $0.65 / $0.016 (more decimals for sub-ce
|
|
|
12
12
|
- Market Cap: <marketCap>
|
|
13
13
|
- Price Change: <pricePercentChange.24h> (prefix "+" for positive, "-" for negative)
|
|
14
14
|
- 24h Volume: <totalVolume.24h>
|
|
15
|
-
Format numbers human-readably: price as $0.65 / $0.016 (more decimals for sub-cent), market cap & volume compact ($12.8M, $6,474), price change signed with one or two decimals (+5.67%, -1.6%). Reply in the user's language and use the human-readable chain name. Do NOT mention tool names, UI, or forms.`,chain:n?I(n):"all",timeFrame:o??null,count:l.length,tokens:l}}};var Je=class extends v{name="get-wallet-token-balances";description='Get all ERC-20 token balances for a wallet address, including USD prices and 24h changes. Use this when the user asks about: "my tokens", "my balances", "what do I hold", "portfolio", "how much ETH/USDC/\u2026 do I have", or any wallet balance question. Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. ';category="blockchain-data";parameters=[{name:"address",type:"string",description:"Wallet address to query (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=await this.service.getWalletTokenBalances({address:n,chain:r,excludeSpam:!1,excludeUnverifiedContracts:!1});if(!o.success)return{error:o.error||"Failed to fetch token balances"};let s=o.data?.result||[],a=s.map((i,l)=>{let u=i.name||i.symbol||"Unknown",d=i.balance_formatted??"0",m=i.symbol||"",p=typeof i.usd_value=="number"?`$${i.usd_value}`:"$-";return`${l+1}. ${u}: ${d} ${m} (${p})`.trim()});return{walletAddress:n,chain:r||"default",tokenCount:s.length,tokens:a,totalUsdValue:s.reduce((i,l)=>i+(l.usd_value||0),0)}}};var Ze=class extends v{name="get-wallet-history";description=`Get a wallet's decoded on-chain transaction history. Always fetches the latest 100 transactions. Each transaction includes: category, summary, from_address, to_address, and nested arrays: native_transfers (each has direction="send"|"receive", from_address, to_address, value_formatted, token_symbol), erc20_transfers (each has direction, token_symbol, value_formatted), nft_transfers. To find ETH sends/receives, inspect native_transfers[].direction \u2014 ETH moves appear across many categories (e.g. "token swap", "send", "receive"), not just category="send". Use this tool for: native coin transfers, swaps, airdrops, deposits, withdrawals, contract interactions, mixed history. Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. Returns paginated results \u2014 pass cursor to get the next page. Do NOT use for: specific ERC-20 tokens \u2192 get-wallet-token-transfers; NFT transfers \u2192 get-wallet-nft-transfers; balances \u2192 get-wallet-token-balances.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea . ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"fromDate",type:"string",description:'Inclusive start date (ISO-8601 or "YYYY-MM-DD").',required:!1},{name:"toDate",type:"string",description:'Inclusive end date (ISO-8601 or "YYYY-MM-DD").',required:!1},{name:"fromBlock",type:"number",description:"Minimum block number.",required:!1},{name:"toBlock",type:"number",description:"Maximum block number.",required:!1},{name:"cursor",type:"string",description:"Pagination cursor from a previous response.",required:!1},{name:"order",type:"string",description:'"DESC" newest first (default) or "ASC" oldest first.',required:!1,default:"DESC"},{name:"includeInternalTransactions",type:"boolean",description:"Include decoded internal transactions on each item.",required:!1},{name:"nftMetadata",type:"boolean",description:"Include NFT normalized metadata in nft_transfers.",required:!1},{name:"limit",type:"number",description:"Number of transactions to return per page. Defaults to 10.",required:!1,default:10}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=typeof e.fromDate=="string"&&e.fromDate?e.fromDate:void 0,s=typeof e.toDate=="string"&&e.toDate?e.toDate:void 0,a=typeof e.fromBlock=="number"?e.fromBlock:typeof e.fromBlock=="string"&&e.fromBlock?Number(e.fromBlock):void 0,i=typeof e.toBlock=="number"?e.toBlock:typeof e.toBlock=="string"&&e.toBlock?Number(e.toBlock):void 0,l=Number.isFinite(a)?a:void 0,u=Number.isFinite(i)?i:void 0,d=typeof e.cursor=="string"&&e.cursor?e.cursor:void 0,p=(typeof e.order=="string"?e.order.toUpperCase():void 0)==="ASC"?"ASC":"DESC",h=typeof e.includeInternalTransactions=="boolean"?e.includeInternalTransactions:void 0,g=typeof e.nftMetadata=="boolean"?e.nftMetadata:void 0,f=typeof e.limit=="number"?e.limit:typeof e.limit=="string"?Number(e.limit):void 0,y=Number.isFinite(f)&&f>0?f:10,k=await this.service.getWalletHistory({address:n,chain:r,limit:y,fromDate:o,toDate:s,fromBlock:l,toBlock:u,cursor:d,order:p,includeInternalTransactions:h,nftMetadata:g});if(!k.success)return{error:k.error||"Failed to fetch wallet history"};let w=k.data?.result||[];return{walletAddress:n,chain:r||"default",pagination:{cursor:k.data?.cursor??null,hasMore:!!k.data?.cursor},transactionCount:w.length,transactions:w}}};function Kr(c){if(c.value_decimal)return c.value_decimal;let e=parseInt(c.token_decimals??"18",10);if(isNaN(e)||e===0)return c.value;try{let t=BigInt(c.value),n=BigInt(10)**BigInt(e),r=t/n,s=(t%n).toString().padStart(e,"0").replace(/0+$/,"");return s?`${r}.${s}`:`${r}`}catch{return c.value}}var et=class extends v{name="get-wallet-token-transfers";description=`Get all ERC-20 token transfers for a wallet from the dedicated Moralis transfers endpoint. Each transfer includes direction (send/receive), human-readable amount, and the exact counterparty address with its label/entity. The response includes a "counterparties" section that aggregates unique sender/recipient addresses with totals. Use tokenSymbol (e.g. "USDC") to filter by token name \u2014 the tool automatically resolves the contract address by checking the wallet's token balances first, then falling back to token search. Use contractAddresses when you already have the exact contract address. Use this tool for questions like: "When did I last send USDC and to whom?" (tokenSymbol=USDC, direction=send, limit=1), "Who have I sent token 0x\u2026 to?" (contractAddresses=[0x\u2026], direction=send), "Who sent me USDT?" (tokenSymbol=USDT, direction=receive), "Show all USDC transfers" (tokenSymbol=USDC), "What tokens did I receive this month?" (fromDate=..., direction=receive). Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. Returns paginated results \u2014 pass cursor to get the next page. IMPORTANT \u2014 this tool covers ERC-20 tokens ONLY. Do NOT use it for native coins (ETH, BNB, MATIC, AVAX, etc.) \u2014 native coin transfers are not ERC-20 and will not appear here. For native coin transfer history use get-wallet-history instead.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea . ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"tokenSymbol",type:"string",description:'Filter by token symbol (e.g. "USDC", "USDT", "WETH"). The tool resolves the contract address automatically: first checks wallet balances, then searches by symbol on the chain. Use this when the user mentions a token by name/symbol. Takes precedence over contractAddresses when both are given.',required:!1},{name:"contractAddresses",type:"array",description:"Filter by one or more ERC-20 token contract addresses (0x\u2026). Use when the exact contract address is already known. Ignored if tokenSymbol is provided.",required:!1,items:{type:"string"}},{name:"direction",type:"string",description:'Client-side direction filter: "send" (wallet is sender), "receive" (wallet is recipient), "all" (default).',required:!1,default:"all"},{name:"limit",type:"number",description:'Page size (1-100, default 25). Use limit=1 ONLY when the user asks for the single most recent transfer (e.g. "L\u1EA7n cu\u1ED1i c\xF9ng t\xF4i g\u1EEDi USDC l\xE0 khi n\xE0o?"). For "show recent history" or "list my transfers" questions use the default (25). Use 100 for bulk counterparty analysis.',required:!1,default:25},{name:"fromDate",type:"string",description:'Inclusive start date (ISO-8601 or "YYYY-MM-DD").',required:!1},{name:"toDate",type:"string",description:'Inclusive end date (ISO-8601 or "YYYY-MM-DD").',required:!1},{name:"fromBlock",type:"number",description:"Minimum block number.",required:!1},{name:"toBlock",type:"number",description:"Maximum block number.",required:!1},{name:"cursor",type:"string",description:"Pagination cursor from a previous response.",required:!1},{name:"order",type:"string",description:'"DESC" newest first (default) or "ASC" oldest first.',required:!1,default:"DESC"}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=typeof e.limit=="number"?e.limit:Number(e.limit),s=Number.isFinite(o)&&o>0?Math.min(100,Math.floor(o)):25,a=typeof e.fromDate=="string"&&e.fromDate?e.fromDate:void 0,i=typeof e.toDate=="string"&&e.toDate?e.toDate:void 0,l=this.parseBlock(e.fromBlock),u=this.parseBlock(e.toBlock),d=typeof e.cursor=="string"&&e.cursor?e.cursor:void 0,p=(typeof e.order=="string"?e.order.toUpperCase():"")==="ASC"?"ASC":"DESC",h=typeof e.direction=="string"?e.direction.trim().toLowerCase():"all",g=h==="send"?"send":h==="receive"?"receive":"all",f=typeof e.tokenSymbol=="string"&&e.tokenSymbol?e.tokenSymbol.trim():void 0,y=Array.isArray(e.contractAddresses)?e.contractAddresses.filter(x=>typeof x=="string"&&!!x).map(x=>x.trim()):void 0,k,w;if(f){let x=await this.resolveContractAddressBySymbol(f,n,r);x&&(y=[x.address],k=x.symbol,w=x.name)}let b=await this.service.getWalletTokenTransfers({address:n,chain:r,contractAddresses:y,limit:s,fromDate:a,toDate:i,fromBlock:l,toBlock:u,cursor:d,order:p});if(!b.success)return{error:b.error||"Failed to fetch token transfers"};let T=n.toLowerCase(),S=(b.data?.result||[]).map(x=>{let D=x.from_address.toLowerCase()===T,A=D?"send":"receive",H=D?x.to_address:x.from_address,Pe=D?x.to_address_label??void 0:x.from_address_label??void 0,ce=D?x.to_address_entity??void 0:x.from_address_entity??void 0;return{...x,direction:A,amount_formatted:Kr(x),counterparty:H,counterparty_label:Pe,counterparty_entity:ce}}),C=g==="all"?S:S.filter(x=>x.direction===g);if(f&&!y){let x=f.toLowerCase();C=C.filter(D=>(D.token_symbol??"").toLowerCase()===x)}let L=this.buildCounterparties(C);return{walletAddress:n,chain:r||"default",resolvedToken:k?{symbol:k,name:w,contractAddress:y?.[0]}:null,filters:{tokenSymbol:f||null,contractAddresses:y||null,direction:g,limit:s,order:p,fromDate:a||null,toDate:i||null,fromBlock:l??null,toBlock:u??null},pagination:{cursor:b.data?.cursor??null,pageSize:b.data?.page_size??s,page:b.data?.page??null,hasMore:!!b.data?.cursor},transferCount:C.length,transfers:C,counterparties:L}}async resolveContractAddressBySymbol(e,t,n){let r=e.toLowerCase(),o=await this.service.getWalletTokenBalances({address:t,chain:n});if(o.success&&o.data?.result?.length){let a=o.data.result.find(i=>(i.symbol??"").toLowerCase()===r);if(a)return{address:a.token_address,symbol:a.symbol,name:a.name}}let s=await this.service.searchTokensByKey({key:e,chain:n});if(s.success&&s.data?.length){let i=s.data.find(l=>(l.symbol??"").toLowerCase()===r)??s.data[0];if(i?.token_address)return{address:i.token_address,symbol:i.symbol,name:i.name}}}buildCounterparties(e){let t=new Map,n=new Map;for(let o of e){let s=o.direction==="send"?t:n,a=o.counterparty.toLowerCase(),i=parseFloat(o.amount_formatted)||0,l=s.get(a);l?(l.total+=i,l.count+=1,!l.label&&o.counterparty_label&&(l.label=o.counterparty_label),!l.entity&&o.counterparty_entity&&(l.entity=o.counterparty_entity),o.block_timestamp<l.first&&(l.first=o.block_timestamp),o.block_timestamp>l.last&&(l.last=o.block_timestamp)):s.set(a,{label:o.counterparty_label,entity:o.counterparty_entity,total:i,count:1,first:o.block_timestamp,last:o.block_timestamp})}let r=o=>Array.from(o.entries()).sort((s,a)=>a[1].count-s[1].count).map(([s,a])=>({address:s,label:a.label,entity:a.entity,total_amount:a.total.toFixed(6).replace(/\.?0+$/,""),tx_count:a.count,first_seen:a.first,last_seen:a.last}));return{sent:r(t),received:r(n)}}parseBlock(e){if(typeof e=="number")return Number.isFinite(e)?e:void 0;if(typeof e=="string"&&e){let t=Number(e);return Number.isFinite(t)?t:void 0}}};var tt=class extends v{name="get-wallet-nft-transfers";description=`Get all NFT transfers for a wallet from the dedicated Moralis NFT transfers endpoint. Each transfer includes direction (send/receive), the exact counterparty address, token ID, collection, contract type (ERC721/ERC1155), and optional last sale price. The response includes a 'counterparties' section aggregating unique senders/recipients with token IDs and collections. Use this tool for questions like: "Which NFTs did I sell and to whom?" (direction=send), "Who sent me NFTs from collection 0x\u2026?" (contractAddresses=[0x\u2026], direction=receive), "Show all transfers for my NFT collection 0x\u2026" (contractAddresses=[0x\u2026]), "What NFTs did I mint?" (direction=receive), "Show NFT sales with prices" (direction=send, includePrices=true). Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. Returns paginated results \u2014 pass cursor to get the next page.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea . ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"contractAddresses",type:"array",description:"Filter by one or more NFT contract addresses (0x\u2026). Use this to scope queries to a specific collection. Omit to return all NFT transfers.",required:!1,items:{type:"string"}},{name:"direction",type:"string",description:'Client-side direction filter: "send" (wallet sent the NFT), "receive" (wallet received it), "all" (default).',required:!1,default:"all"},{name:"limit",type:"number",description:"Page size (1-100, default 25).",required:!1,default:25},{name:"fromDate",type:"string",description:'Inclusive start date (ISO-8601 or "YYYY-MM-DD").',required:!1},{name:"toDate",type:"string",description:'Inclusive end date (ISO-8601 or "YYYY-MM-DD").',required:!1},{name:"fromBlock",type:"number",description:"Minimum block number.",required:!1},{name:"toBlock",type:"number",description:"Maximum block number.",required:!1},{name:"cursor",type:"string",description:"Pagination cursor from a previous response.",required:!1},{name:"order",type:"string",description:'"DESC" newest first (default) or "ASC" oldest first.',required:!1,default:"DESC"},{name:"includePrices",type:"boolean",description:"If true, include last_sale price data (buyer, seller, price, USD value, payment token) on each transfer. Useful for questions about NFT sale prices.",required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=typeof e.limit=="number"?e.limit:Number(e.limit),s=Number.isFinite(o)&&o>0?Math.min(100,Math.floor(o)):25,a=typeof e.fromDate=="string"&&e.fromDate?e.fromDate:void 0,i=typeof e.toDate=="string"&&e.toDate?e.toDate:void 0,l=this.parseBlock(e.fromBlock),u=this.parseBlock(e.toBlock),d=typeof e.cursor=="string"&&e.cursor?e.cursor:void 0,p=(typeof e.order=="string"?e.order.toUpperCase():"")==="ASC"?"ASC":"DESC",h=typeof e.includePrices=="boolean"?e.includePrices:void 0,g=typeof e.direction=="string"?e.direction.trim().toLowerCase():"all",f=g==="send"?"send":g==="receive"?"receive":"all",y=Array.isArray(e.contractAddresses)?e.contractAddresses.filter(C=>typeof C=="string"&&!!C).map(C=>C.trim()):void 0,k=await this.service.getWalletNftTransfers({address:n,chain:r,contractAddresses:y,limit:s,fromDate:a,toDate:i,fromBlock:l,toBlock:u,cursor:d,order:p,includePrices:h});if(!k.success)return{error:k.error||"Failed to fetch NFT transfers"};let w=n.toLowerCase(),T=(k.data?.result||[]).map(C=>{let L=C.from_address.toLowerCase()===w,x=L?"send":"receive",D=L?C.to_address:C.from_address,A=L?C.to_address_label??void 0:C.from_address_label??void 0,H=L?C.to_address_entity??void 0:C.from_address_entity??void 0;return{...C,direction:x,counterparty:D,counterparty_label:A,counterparty_entity:H}}),P=f==="all"?T:T.filter(C=>C.direction===f),S=this.buildCounterparties(P);return{walletAddress:n,chain:r||"default",filters:{contractAddresses:y||null,direction:f,limit:s,order:p,fromDate:a||null,toDate:i||null,fromBlock:l??null,toBlock:u??null,includePrices:h??null},pagination:{cursor:k.data?.cursor??null,pageSize:k.data?.page_size??s,page:k.data?.page??null,hasMore:!!k.data?.cursor},transferCount:P.length,transfers:P,counterparties:S}}buildCounterparties(e){let t=new Map,n=new Map;for(let o of e){let s=o.direction==="send"?t:n,a=o.counterparty.toLowerCase(),i=o.token_name??o.token_address,l=s.get(a);l?(l.tokenIds.add(o.token_id),l.collections.add(i),l.count+=1,!l.label&&o.counterparty_label&&(l.label=o.counterparty_label),!l.entity&&o.counterparty_entity&&(l.entity=o.counterparty_entity),o.block_timestamp<l.first&&(l.first=o.block_timestamp),o.block_timestamp>l.last&&(l.last=o.block_timestamp)):s.set(a,{label:o.counterparty_label,entity:o.counterparty_entity,tokenIds:new Set([o.token_id]),collections:new Set([i]),count:1,first:o.block_timestamp,last:o.block_timestamp})}let r=o=>Array.from(o.entries()).sort((s,a)=>a[1].count-s[1].count).map(([s,a])=>({address:s,label:a.label,entity:a.entity,token_ids:Array.from(a.tokenIds),collections:Array.from(a.collections),tx_count:a.count,first_seen:a.first,last_seen:a.last}));return{sent:r(t),received:r(n)}}parseBlock(e){if(typeof e=="number")return Number.isFinite(e)?e:void 0;if(typeof e=="string"&&e){let t=Number(e);return Number.isFinite(t)?t:void 0}}};var kn=class extends v{name="get-wallet-net-worth";description=`Get a wallet's total net worth in USD, with a per-chain breakdown. Returns: total_networth_usd (grand total across all queried chains), chains[] (each with chain, native_balance_formatted, native_balance_usd, token_balance_usd, networth_usd), and optional unsupported_chain_ids / unavailable_chains lists. Use this tool for questions like: "How much is my wallet worth?", "What is my total portfolio value?", "What is my net worth on Ethereum?", "Portfolio value across all chains?". Pass chains=["0x1","0x2105"] to query multiple chains at once; defaults to the connected chain. Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. Do NOT use for: individual token balances \u2192 get-wallet-token-balances; realized profit/loss \u2192 get-wallet-pnl-summary.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chains",type:"array",description:'One or more hex chain IDs to aggregate. Values: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea If omitted, defaults to the connected chain.',required:!1,items:{type:"string"}},{name:"excludeSpam",type:"boolean",description:"Exclude tokens flagged as spam. Default true for cleaner totals.",required:!1,default:!0},{name:"excludeUnverifiedContracts",type:"boolean",description:"Exclude unverified token contracts. Default false.",required:!1,default:!1},{name:"maxTokenInactivity",type:"number",description:"Exclude tokens that have been inactive for more than N days.",required:!1},{name:"minPairSideLiquidityUsd",type:"number",description:"Exclude tokens with pair-side liquidity below this USD threshold.",required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=e.address||t?.walletAddress||void 0;if(!n)return{error:'No wallet address available. Please connect a wallet or pass "address".'};let r=Array.isArray(e.chains)?e.chains.filter(p=>typeof p=="string"&&!!p).map(p=>p.trim()):void 0,o=t?.chain,s=r&&r.length>0?r:o?[o]:void 0,a=typeof e.excludeSpam=="boolean"?e.excludeSpam:!0,i=typeof e.excludeUnverifiedContracts=="boolean"?e.excludeUnverifiedContracts:void 0,l=typeof e.maxTokenInactivity=="number"&&Number.isFinite(e.maxTokenInactivity)?e.maxTokenInactivity:void 0,u=typeof e.minPairSideLiquidityUsd=="number"&&Number.isFinite(e.minPairSideLiquidityUsd)?e.minPairSideLiquidityUsd:void 0,d=await this.service.getWalletNetWorth({address:n,chains:s,excludeSpam:a,excludeUnverifiedContracts:i,maxTokenInactivity:l,minPairSideLiquidityUsd:u});if(!d.success)return{error:d.error||"Failed to fetch wallet net worth"};let m=d.data;return{walletAddress:n,chainsQueried:s??["default"],filters:{excludeSpam:a,excludeUnverifiedContracts:i??null,maxTokenInactivity:l??null,minPairSideLiquidityUsd:u??null},totalNetWorthUsd:m.total_networth_usd,chains:m.chains,unsupportedChainIds:m.unsupported_chain_ids??[],unavailableChains:m.unavailable_chains??[]}}};var jr=["all","7","30","60","90"],nt=class extends v{name="get-wallet-pnl-summary";description=`Get a wallet's aggregate realized profit-and-loss summary across all tokens it has traded. Returns: total_count_of_trades, total_trade_volume (USD), total_realized_profit_usd, total_realized_profit_percentage, total_buys, total_sells, total_sold_volume_usd, total_bought_volume_usd. Use this tool for questions like: "How much profit have I made trading?", "What is my realized PnL?", "How many trades have I done this month?" (days=30), "Am I up or down overall?". IMPORTANT \u2014 this endpoint only supports mainnet: Ethereum ("0x1"), Base ("0x2105"), Polygon ("0x89"). Use days="all" (default), "7", "30", "60", or "90" to scope the time window. Do NOT use for: per-token breakdown \u2192 get-wallet-pnl; current portfolio value \u2192 get-wallet-token-balance; transfer history \u2192 get-wallet-history.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea . ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"days",type:"string",description:'Time window for the summary. Values: "all" (default, lifetime), "7", "30", "60", "90". Pass "30" when the user asks about the last month, "7" for the last week, etc.',required:!1,default:"all"}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=typeof e.days=="string"?e.days.trim().toLowerCase():"",s=jr.includes(o)?o:void 0,a=await this.service.getWalletPnlSummary({address:n,chain:r,days:s});if(!a.success)return{error:a.error||"Failed to fetch wallet PnL summary"};let i=a.data;return{walletAddress:n,chain:r||"default",days:s??"all",summary:{totalCountOfTrades:i.total_count_of_trades,totalTradeVolume:i.total_trade_volume,totalRealizedProfitUsd:i.total_realized_profit_usd,totalRealizedProfitPercentage:i.total_realized_profit_percentage,totalBuys:i.total_buys,totalSells:i.total_sells,totalBoughtVolumeUsd:i.total_bought_volume_usd,totalSoldVolumeUsd:i.total_sold_volume_usd}}}};var zr=["all","7","30","60","90"],Tn=25,ot=class extends v{name="get-wallet-pnl";description=`Get a wallet's realized profit-and-loss broken down per ERC-20 token. Each entry includes: token_address, name, symbol, decimals, logo, avg_buy_price_usd, avg_sell_price_usd, total_usd_invested, total_tokens_bought, total_tokens_sold, total_sold_usd, avg_cost_of_quantity_sold, count_of_trades, realized_profit_usd, realized_profit_percentage, total_buys, total_sells, possible_spam. Use this tool for questions like: "Which tokens made me the most money?", "What are my best/worst trades?", "How much profit did I make on USDC?" (tokenSymbols=["USDC"]), "PnL for PEPE and DEGEN this month" (tokenSymbols=["PEPE","DEGEN"], days=30), "PnL breakdown for each token I traded this month" (days=30). IMPORTANT \u2014 this endpoint ONLY supports mainnet: Ethereum ("0x1"), Polygon ("0x89"), Base ("0x2105"). Use days="all" (default), "7", "30", "60", or "90" for the time window. Pass tokenSymbols (by ticker, auto-resolved) and/or tokenAddresses (raw 0x\u2026) to restrict to specific tokens \u2014 combined total capped at ${Tn}. Do NOT use for: aggregate summary \u2192 get-wallet-pnl-summary; current balances \u2192 get-wallet-token-balances; transfer history \u2192 get-wallet-token-transfers.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"days",type:"string",description:'Time window for the breakdown. Values: "all" (default, lifetime), "7", "30", "60", "90".',required:!1,default:"all"},{name:"tokenSymbols",type:"array",description:`Optional list of token symbols (e.g. ["USDC", "PEPE"]). Auto-resolved to contract addresses via the connected wallet's balances first, then Pantograph search. Symbols that can't be resolved are skipped. Merged with tokenAddresses; combined total capped at ${Tn}.`,required:!1,items:{type:"string"}},{name:"tokenAddresses",type:"array",description:`Optional list of raw ERC-20 contract addresses (0x\u2026). Use when the exact addresses are already known. Merged with tokenSymbols; combined total capped at ${Tn}.`,required:!1,items:{type:"string"}}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=typeof e.days=="string"?e.days.trim().toLowerCase():"",s=zr.includes(o)?o:void 0,a=Array.isArray(e.tokenSymbols)?e.tokenSymbols.filter(g=>typeof g=="string"&&!!g.trim()).map(g=>g.trim()):[],i=Array.isArray(e.tokenAddresses)?e.tokenAddresses.filter(g=>typeof g=="string"&&!!g.trim()).map(g=>g.trim()):[],l=[],u=[];a.length>0&&(await Promise.all(a.map(f=>this.resolveContractAddress(f,r,n)))).forEach((f,y)=>{f?l.push({symbol:a[y],address:f.address}):u.push(a[y])});let d=Qr([...l.map(g=>g.address),...i]).slice(0,Tn),m=d.length>0?d:void 0,p=await this.service.getWalletPnl({address:n,chain:r,days:s,tokenAddresses:m});if(!p.success)return{error:p.error||"Failed to fetch wallet PnL"};let h=p.data?.result??[];return{walletAddress:n,chain:r||"default",days:s??"all",filters:{tokenAddresses:m??null,resolvedSymbols:l.length>0?l:null,unresolvedSymbols:u.length>0?u:null},tokenCount:h.length,tokens:h}}async resolveContractAddress(e,t,n){let r=e.toLowerCase();if(n){let s=await this.service.getWalletTokenBalances({address:n,chain:t});if(s.success&&s.data?.result?.length){let a=s.data.result.find(i=>(i.symbol??"").toLowerCase()===r);if(a)return{address:a.token_address,symbol:a.symbol,name:a.name}}}let o=await this.service.searchTokensByKey({key:e,chain:t});if(o.success&&o.data?.length){let a=o.data.find(i=>(i.symbol??"").toLowerCase()===r)??o.data[0];if(a?.token_address)return{address:a.token_address,symbol:a.symbol,name:a.name}}}};function Qr(c){let e=new Set,t=[];for(let n of c){let r=n.toLowerCase();e.has(r)||(e.add(r),t.push(n))}return t}var Xr=BigInt(2)**BigInt(255),rt=class extends v{name="get-wallet-approvals";description=`List every active ERC-20 token approval granted by a wallet \u2014 i.e. which contracts can still spend the wallet's tokens. For each approval, returns: the token (address, name, symbol, logo, current balance, USD price, USD at risk, possible_spam, verified_contract), the spender (address, label, entity \u2014 e.g. "Uniswap V3 Router", "Permit2"), the approved amount (value / value_formatted / isUnlimited flag), and when the approval was granted (block number, timestamp, transaction hash). Also returns aggregates: total approvals, unlimited-approval count, total USD at risk, and approvals flagged as risky (spam tokens, unverified contracts, or unlimited allowance to unlabeled spenders). Use for questions like: "What approvals do I have?", "Show my token approvals", "Am I exposed to any risky approvals?", "Which contracts can drain my wallet?", "Do I have any unlimited approvals?", "Revoke approvals / token allowances". Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea (EVM mainnets only). Paginated \u2014 pass cursor to fetch the next page.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"limit",type:"number",description:"Page size (1-100, default 100).",required:!1,default:100},{name:"cursor",type:"string",description:"Pagination cursor from a previous response.",required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=typeof e.limit=="number"?e.limit:Number(e.limit),s=Number.isFinite(o)&&o>0?Math.min(100,Math.floor(o)):100,a=typeof e.cursor=="string"&&e.cursor?e.cursor:void 0,i=await this.service.getWalletApprovals({address:n,chain:r,limit:s,cursor:a});if(!i.success)return{error:i.error||"Failed to fetch wallet approvals"};let l=i.data,d=(l.result||[]).map(g=>Jr(g)),m=0,p=0,h=[];for(let g of d){g.isUnlimited&&(p+=1);let f=parseFloat(g.token.usdAtRisk??"");Number.isFinite(f)&&(m+=f);let y=g.token.possibleSpam||g.token.verifiedContract===!1,k=!g.spender.label&&!g.spender.entity;(y||g.isUnlimited&&k)&&h.push(g)}return{walletAddress:n,chain:r||"default",filters:{limit:s,cursor:a??null},pagination:{cursor:l.cursor??null,pageSize:l.page_size??s,page:l.page??null,hasMore:!!l.cursor},summary:{totalApprovals:d.length,unlimitedApprovals:p,totalUsdAtRisk:m,riskyApprovalCount:h.length},approvals:d,riskyApprovals:h}}};function Jr(c){let e=Zr(c.value);return{blockNumber:c.block_number,blockTimestamp:c.block_timestamp??null,transactionHash:c.transaction_hash??null,value:c.value,valueFormatted:c.value_formatted??null,isUnlimited:e,token:{address:c.token.address,addressLabel:c.token.address_label??null,name:c.token.name??null,symbol:c.token.symbol??null,logo:c.token.logo??null,possibleSpam:!!c.token.possible_spam,verifiedContract:c.token.verified_contract??null,currentBalance:c.token.current_balance??null,currentBalanceFormatted:c.token.current_balance_formatted??null,usdPrice:c.token.usd_price??null,usdAtRisk:c.token.usd_at_risk??null},spender:{address:c.spender.address,label:c.spender.address_label??null,entity:c.spender.entity??null,entityLogo:c.spender.entity_logo??null}}}function Zr(c){if(!c)return!1;try{return BigInt(c)>=Xr}catch{return!1}}var st=class extends v{name="get-wallet-defi-summary";description=`Get a wallet's DeFi protocols summary: which protocols the wallet is using, total USD value locked across all protocols, total unclaimed rewards/fees, number of active protocols, and total number of positions. Returns a per-protocol breakdown (protocol name, logo, url, positions count, usd value, unclaimed). Use for questions like: "Which DeFi protocols am I using?", "What's my total DeFi value?", "How much do I have in DeFi?", "Show my DeFi portfolio overview", "Unclaimed rewards across protocols". Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea (EVM mainnets only). Do NOT use for: detailed per-position data \u2192 get-wallet-defi-positions; positions inside a single protocol \u2192 get-wallet-defi-protocol-positions.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=await this.service.getWalletDefiSummary({address:n,chain:r});if(!o.success)return{error:o.error||"Failed to fetch wallet DeFi summary"};let s=o.data;return{walletAddress:n,chain:r||"default",activeProtocols:s.active_protocols,totalPositions:s.total_positions,totalUsdValue:s.total_usd_value,totalUnclaimedUsdValue:s.total_unclaimed_usd_value,protocols:(s.protocols||[]).map(a=>({protocolName:a.protocol_name,protocolId:a.protocol_id,protocolUrl:a.protocol_url,protocolLogo:a.protocol_logo,positions:a.positions,totalUsdValue:a.total_usd_value,totalUnclaimedUsdValue:a.total_unclaimed_usd_value,accountHealthFactor:a.account_health_factor??null}))}}};var at=class extends v{name="get-wallet-defi-positions";description='Get every DeFi position a wallet holds across all supported protocols, with full detail: protocol identity, position label (e.g. "Liquidity Provision", "Supply", "Borrow", "Staking"), tokens involved (with balances and USD values), balance_usd, total_unclaimed_usd_value, and position_details (fee tier, liquidity, APY, price range, health factor, etc.). Use for questions like: "Show my DeFi positions", "What LP positions do I have?", "What am I staking?", "Do I have any borrows?", "List all my DeFi holdings with details". Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. Do NOT use for: aggregate totals \u2192 get-wallet-defi-summary; positions filtered to a single protocol \u2192 get-wallet-defi-protocol-positions.';category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=await this.service.getWalletDefiPositions({address:n,chain:r});if(!o.success)return{error:o.error||"Failed to fetch wallet DeFi positions"};let s=o.data||[];return{walletAddress:n,chain:r||"default",positionCount:s.length,positions:s.map(a=>es(a))}}};function es(c){return{protocolName:c.protocol_name,protocolId:c.protocol_id,protocolUrl:c.protocol_url,protocolLogo:c.protocol_logo,accountHealthFactor:c.account_data?.health_factor??null,position:ts(c.position)}}function ts(c){return{label:c.label,address:c.address,balanceUsd:c.balance_usd,totalUnclaimedUsdValue:c.total_unclaimed_usd_value,tokens:(c.tokens||[]).map(e=>({tokenType:e.token_type,name:e.name,symbol:e.symbol,contractAddress:e.contract_address,decimals:e.decimals,logo:e.logo,thumbnail:e.thumbnail,balance:e.balance,balanceFormatted:e.balance_formatted,usdPrice:e.usd_price,usdValue:e.usd_value})),details:c.position_details??null}}var it=class extends v{name="get-wallet-defi-protocol-positions";description='Get every position a wallet holds inside a specific DeFi protocol, with full detail. Returns the protocol identity, totals (total_usd_value, total_unclaimed_usd_value), and an array of positions (label, tokens, balance_usd, unclaimed, fee tier, APY, health factor, etc.). Use when the user names a specific protocol, e.g. "my Uniswap v3 positions", "what do I have on Aave v3", "show my Lido staking", "my Curve pools", "Pendle positions". The "protocol" argument is the Moralis protocol id (kebab-case), e.g. uniswap-v2, uniswap-v3, pancakeswap-v2, pancakeswap-v3, quickswap-v2, quickswap-v3, sushiswap-v2, aave-v2, aave-v3, aave-lido, fraxswap-v1, fraxswap-v2, lido, makerdao, eigenlayer, pendle, etherfi, rocketpool, sparkfi, takara-lend, neverland, kintsu. Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea (EVM mainnets only). Do NOT use for: cross-protocol view \u2192 get-wallet-defi-positions; totals only \u2192 get-wallet-defi-summary.';category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"protocol",type:"string",description:'Moralis protocol identifier in kebab-case. Examples: "uniswap-v2", "uniswap-v3", "pancakeswap-v2", "pancakeswap-v3", "quickswap-v2", "quickswap-v3", "sushiswap-v2", "aave-v2", "aave-v3", "aave-lido", "fraxswap-v1", "fraxswap-v2", "lido", "makerdao", "eigenlayer", "pendle", "etherfi", "rocketpool", "sparkfi", "takara-lend", "neverland", "kintsu"Use get-wallet-defi-summary to discover which protocols a wallet uses.',required:!0},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=e.protocol?.trim();if(!n)return{error:'Protocol identifier is required (e.g. "uniswap-v3", "aave-v3").'};let r=Y(e.address,t),o=R(e.chain,t),s=await this.service.getWalletDefiProtocolPositions({address:r,protocol:n,chain:o});if(!s.success)return{error:s.error||"Failed to fetch wallet DeFi protocol positions"};let a=s.data;return a?{walletAddress:r,chain:o||"default",protocolName:a.protocol_name,protocolId:a.protocol_id,protocolUrl:a.protocol_url,protocolLogo:a.protocol_logo,totalUsdValue:a.total_usd_value,totalUnclaimedUsdValue:a.total_unclaimed_usd_value,accountHealthFactor:a.account_data?.health_factor??null,positionCount:(a.positions||[]).length,positions:(a.positions||[]).map(ns)}:{error:"No data returned for this protocol"}}};function ns(c){return{label:c.label,address:c.address,balanceUsd:c.balance_usd,totalUnclaimedUsdValue:c.total_unclaimed_usd_value,tokens:(c.tokens||[]).map(e=>({tokenType:e.token_type,name:e.name,symbol:e.symbol,contractAddress:e.contract_address,decimals:e.decimals,logo:e.logo,thumbnail:e.thumbnail,balance:e.balance,balanceFormatted:e.balance_formatted,usdPrice:e.usd_price,usdValue:e.usd_value})),details:c.position_details??null}}function os(c){try{return(Number(BigInt(c))/1e18).toFixed(10).replace(/\.?0+$/,"")||"0"}catch{return c}}var lt=class extends v{name="get-transaction-by-hash";description='Get full decoded details of a single EVM transaction by its hash. Returns: status (success/failed), timestamp, from/to addresses with labels and entity names, native value transferred (ETH), transaction fee, gas used, decoded function call with params, and decoded event logs (ERC-20 transfers, swaps, approvals, etc.). Use this when the user asks: "what did this transaction do?", "explain tx 0x\u2026", "was this transaction successful?", "who sent/received in this tx?", "what function was called?". Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea.';category="blockchain-data";parameters=[{name:"transactionHash",type:"string",description:"The transaction hash to look up (0x\u2026).",required:!0},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=e.transactionHash;if(!n)return{error:"Transaction hash is required."};let r=R(e.chain,t),o=await this.service.getTransactionByHash({transactionHash:n,chain:r});if(!o.success||!o.data)return{error:o.error||"Failed to fetch transaction"};let s=o.data,a=(s.logs??[]).filter(l=>!!l.decoded_event).map(l=>({contract:l.address,signature:l.decoded_event.signature,label:l.decoded_event.label,params:l.decoded_event.params})),i=s.logs.map(l=>({address:l.address,decodedEvent:l.decoded_event?{signature:l.decoded_event.signature,label:l.decoded_event.label,params:l.decoded_event.params}:null}));return{hash:s.hash,status:s.receipt_status==="1"?"success":s.receipt_status==="0"?"failed":"unknown",timestamp:s.block_timestamp,blockNumber:s.block_number,from:{address:s.from_address,label:s.from_address_label||null,entity:s.from_address_entity||null},to:s.to_address?{address:s.to_address,label:s.to_address_label||null,entity:s.to_address_entity||null}:null,valueEth:os(s.value||"0"),fee:s.transaction_fee,gasUsed:s.receipt_gas_used,gasPriceGwei:s.gas_price?(Number(s.gas_price)/1e9).toFixed(4):null,decodedCall:s.decoded_call?{signature:s.decoded_call.signature,label:s.decoded_call.label,params:s.decoded_call.params}:null,decodedEvents:a,contractCreated:s.receipt_contract_address||null,logs:i}}};var fe=class extends v{kind="data";category="nft";noSuggestions=!0;parameters=[];linkPhrase="this website";url;constructor(e){super();let t=e?.url?.trim();this.url=t||void 0}async run(){let e=this.url?`[${this.linkPhrase}](${this.url})`:this.linkPhrase,t=this.template.replace("{link}",e);return{message:t,_instructions:`This is a fixed notice. Output it to the user EXACTLY as written below \u2014 in English, without translating, rephrasing, summarising, or adding/removing any words. Preserve the Markdown link verbatim (do not change, wrap, or drop the URL or the linked words). Do not mention tools. Reply with only this message:
|
|
15
|
+
Format numbers human-readably: price as $0.65 / $0.016 (more decimals for sub-cent), market cap & volume compact ($12.8M, $6,474), price change signed with one or two decimals (+5.67%, -1.6%). Reply in the user's language and use the human-readable chain name. Do NOT mention tool names, UI, or forms.`,chain:n?I(n):"all",timeFrame:o??null,count:l.length,tokens:l}}};var Je=class extends v{name="get-wallet-token-balances";description='Get all ERC-20 token balances for a wallet address, including USD prices and 24h changes. Use this when the user asks about: "my tokens", "my balances", "what do I hold", "portfolio", "how much ETH/USDC/\u2026 do I have", or any wallet balance question. Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. ';category="blockchain-data";parameters=[{name:"address",type:"string",description:"Wallet address to query (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}truncateUsd(e){if(!Number.isFinite(e))return"0.00";let t=e<0,[n,r=""]=Math.abs(e).toFixed(8).split(".");return`${t?"-":""}${n}.${(r+"00").slice(0,2)}`}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=await this.service.getWalletTokenBalances({address:n,chain:r,excludeSpam:!1,excludeUnverifiedContracts:!1});if(!o.success)return{error:o.error||"Failed to fetch token balances"};let s=o.data?.result||[],a=s.map(l=>{let u=l.name||l.symbol||"Unknown",d=l.balance_formatted??"0",m=l.symbol||"",p=typeof l.usd_value=="number"?`$${this.truncateUsd(l.usd_value)}`:"$-";return`- ${u}: ${d} ${m} (${p})`.replace(/\s+/g," ").trim()}),i=s.reduce((l,u)=>l+(u.usd_value||0),0);return{_instructions:"Open with one short, natural sentence in the user's language stating the wallet's total value (totalUsdValue), e.g. \"Your wallet is worth about $0.04.\" (plain text \u2014 do NOT bold it). Then output the token lines EXACTLY as provided in `tokens` \u2014 one Markdown bullet each, in order, nothing added or removed. Keep every amount and USD value verbatim: never shorten, round, reformat, or bold them. Keep it conversational and clean \u2014 no table, no extra headings, no bold, no tool names.",walletAddress:n,chain:r||"default",totalUsdValue:`$${this.truncateUsd(i)}`,tokens:a}}};var Ze=class extends v{name="get-wallet-history";description=`Get a wallet's decoded on-chain transaction history. Always fetches the latest 100 transactions. Each transaction includes: category, summary, from_address, to_address, and nested arrays: native_transfers (each has direction="send"|"receive", from_address, to_address, value_formatted, token_symbol), erc20_transfers (each has direction, token_symbol, value_formatted), nft_transfers. To find ETH sends/receives, inspect native_transfers[].direction \u2014 ETH moves appear across many categories (e.g. "token swap", "send", "receive"), not just category="send". Use this tool for: native coin transfers, swaps, airdrops, deposits, withdrawals, contract interactions, mixed history. Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. Returns paginated results \u2014 pass cursor to get the next page. Do NOT use for: specific ERC-20 tokens \u2192 get-wallet-token-transfers; NFT transfers \u2192 get-wallet-nft-transfers; balances \u2192 get-wallet-token-balances.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea . ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"fromDate",type:"string",description:'Inclusive start date (ISO-8601 or "YYYY-MM-DD").',required:!1},{name:"toDate",type:"string",description:'Inclusive end date (ISO-8601 or "YYYY-MM-DD").',required:!1},{name:"fromBlock",type:"number",description:"Minimum block number.",required:!1},{name:"toBlock",type:"number",description:"Maximum block number.",required:!1},{name:"cursor",type:"string",description:"Pagination cursor from a previous response.",required:!1},{name:"order",type:"string",description:'"DESC" newest first (default) or "ASC" oldest first.',required:!1,default:"DESC"},{name:"includeInternalTransactions",type:"boolean",description:"Include decoded internal transactions on each item.",required:!1},{name:"nftMetadata",type:"boolean",description:"Include NFT normalized metadata in nft_transfers.",required:!1},{name:"limit",type:"number",description:"Number of transactions to return per page. Defaults to 10.",required:!1,default:10}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=typeof e.fromDate=="string"&&e.fromDate?e.fromDate:void 0,s=typeof e.toDate=="string"&&e.toDate?e.toDate:void 0,a=typeof e.fromBlock=="number"?e.fromBlock:typeof e.fromBlock=="string"&&e.fromBlock?Number(e.fromBlock):void 0,i=typeof e.toBlock=="number"?e.toBlock:typeof e.toBlock=="string"&&e.toBlock?Number(e.toBlock):void 0,l=Number.isFinite(a)?a:void 0,u=Number.isFinite(i)?i:void 0,d=typeof e.cursor=="string"&&e.cursor?e.cursor:void 0,p=(typeof e.order=="string"?e.order.toUpperCase():void 0)==="ASC"?"ASC":"DESC",h=typeof e.includeInternalTransactions=="boolean"?e.includeInternalTransactions:void 0,g=typeof e.nftMetadata=="boolean"?e.nftMetadata:void 0,f=typeof e.limit=="number"?e.limit:typeof e.limit=="string"?Number(e.limit):void 0,y=Number.isFinite(f)&&f>0?f:10,k=await this.service.getWalletHistory({address:n,chain:r,limit:y,fromDate:o,toDate:s,fromBlock:l,toBlock:u,cursor:d,order:p,includeInternalTransactions:h,nftMetadata:g});if(!k.success)return{error:k.error||"Failed to fetch wallet history"};let w=k.data?.result||[];return{walletAddress:n,chain:r||"default",pagination:{cursor:k.data?.cursor??null,hasMore:!!k.data?.cursor},transactionCount:w.length,transactions:w}}};function Kr(c){if(c.value_decimal)return c.value_decimal;let e=parseInt(c.token_decimals??"18",10);if(isNaN(e)||e===0)return c.value;try{let t=BigInt(c.value),n=BigInt(10)**BigInt(e),r=t/n,s=(t%n).toString().padStart(e,"0").replace(/0+$/,"");return s?`${r}.${s}`:`${r}`}catch{return c.value}}var et=class extends v{name="get-wallet-token-transfers";description=`Get all ERC-20 token transfers for a wallet from the dedicated Moralis transfers endpoint. Each transfer includes direction (send/receive), human-readable amount, and the exact counterparty address with its label/entity. The response includes a "counterparties" section that aggregates unique sender/recipient addresses with totals. Use tokenSymbol (e.g. "USDC") to filter by token name \u2014 the tool automatically resolves the contract address by checking the wallet's token balances first, then falling back to token search. Use contractAddresses when you already have the exact contract address. Use this tool for questions like: "When did I last send USDC and to whom?" (tokenSymbol=USDC, direction=send, limit=1), "Who have I sent token 0x\u2026 to?" (contractAddresses=[0x\u2026], direction=send), "Who sent me USDT?" (tokenSymbol=USDT, direction=receive), "Show all USDC transfers" (tokenSymbol=USDC), "What tokens did I receive this month?" (fromDate=..., direction=receive). Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. Returns paginated results \u2014 pass cursor to get the next page. IMPORTANT \u2014 this tool covers ERC-20 tokens ONLY. Do NOT use it for native coins (ETH, BNB, MATIC, AVAX, etc.) \u2014 native coin transfers are not ERC-20 and will not appear here. For native coin transfer history use get-wallet-history instead.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea . ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"tokenSymbol",type:"string",description:'Filter by token symbol (e.g. "USDC", "USDT", "WETH"). The tool resolves the contract address automatically: first checks wallet balances, then searches by symbol on the chain. Use this when the user mentions a token by name/symbol. Takes precedence over contractAddresses when both are given.',required:!1},{name:"contractAddresses",type:"array",description:"Filter by one or more ERC-20 token contract addresses (0x\u2026). Use when the exact contract address is already known. Ignored if tokenSymbol is provided.",required:!1,items:{type:"string"}},{name:"direction",type:"string",description:'Client-side direction filter: "send" (wallet is sender), "receive" (wallet is recipient), "all" (default).',required:!1,default:"all"},{name:"limit",type:"number",description:'Page size (1-100, default 25). Use limit=1 ONLY when the user asks for the single most recent transfer (e.g. "L\u1EA7n cu\u1ED1i c\xF9ng t\xF4i g\u1EEDi USDC l\xE0 khi n\xE0o?"). For "show recent history" or "list my transfers" questions use the default (25). Use 100 for bulk counterparty analysis.',required:!1,default:25},{name:"fromDate",type:"string",description:'Inclusive start date (ISO-8601 or "YYYY-MM-DD").',required:!1},{name:"toDate",type:"string",description:'Inclusive end date (ISO-8601 or "YYYY-MM-DD").',required:!1},{name:"fromBlock",type:"number",description:"Minimum block number.",required:!1},{name:"toBlock",type:"number",description:"Maximum block number.",required:!1},{name:"cursor",type:"string",description:"Pagination cursor from a previous response.",required:!1},{name:"order",type:"string",description:'"DESC" newest first (default) or "ASC" oldest first.',required:!1,default:"DESC"}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=typeof e.limit=="number"?e.limit:Number(e.limit),s=Number.isFinite(o)&&o>0?Math.min(100,Math.floor(o)):25,a=typeof e.fromDate=="string"&&e.fromDate?e.fromDate:void 0,i=typeof e.toDate=="string"&&e.toDate?e.toDate:void 0,l=this.parseBlock(e.fromBlock),u=this.parseBlock(e.toBlock),d=typeof e.cursor=="string"&&e.cursor?e.cursor:void 0,p=(typeof e.order=="string"?e.order.toUpperCase():"")==="ASC"?"ASC":"DESC",h=typeof e.direction=="string"?e.direction.trim().toLowerCase():"all",g=h==="send"?"send":h==="receive"?"receive":"all",f=typeof e.tokenSymbol=="string"&&e.tokenSymbol?e.tokenSymbol.trim():void 0,y=Array.isArray(e.contractAddresses)?e.contractAddresses.filter(x=>typeof x=="string"&&!!x).map(x=>x.trim()):void 0,k,w;if(f){let x=await this.resolveContractAddressBySymbol(f,n,r);x&&(y=[x.address],k=x.symbol,w=x.name)}let b=await this.service.getWalletTokenTransfers({address:n,chain:r,contractAddresses:y,limit:s,fromDate:a,toDate:i,fromBlock:l,toBlock:u,cursor:d,order:p});if(!b.success)return{error:b.error||"Failed to fetch token transfers"};let T=n.toLowerCase(),S=(b.data?.result||[]).map(x=>{let D=x.from_address.toLowerCase()===T,A=D?"send":"receive",H=D?x.to_address:x.from_address,Pe=D?x.to_address_label??void 0:x.from_address_label??void 0,ce=D?x.to_address_entity??void 0:x.from_address_entity??void 0;return{...x,direction:A,amount_formatted:Kr(x),counterparty:H,counterparty_label:Pe,counterparty_entity:ce}}),C=g==="all"?S:S.filter(x=>x.direction===g);if(f&&!y){let x=f.toLowerCase();C=C.filter(D=>(D.token_symbol??"").toLowerCase()===x)}let L=this.buildCounterparties(C);return{walletAddress:n,chain:r||"default",resolvedToken:k?{symbol:k,name:w,contractAddress:y?.[0]}:null,filters:{tokenSymbol:f||null,contractAddresses:y||null,direction:g,limit:s,order:p,fromDate:a||null,toDate:i||null,fromBlock:l??null,toBlock:u??null},pagination:{cursor:b.data?.cursor??null,pageSize:b.data?.page_size??s,page:b.data?.page??null,hasMore:!!b.data?.cursor},transferCount:C.length,transfers:C,counterparties:L}}async resolveContractAddressBySymbol(e,t,n){let r=e.toLowerCase(),o=await this.service.getWalletTokenBalances({address:t,chain:n});if(o.success&&o.data?.result?.length){let a=o.data.result.find(i=>(i.symbol??"").toLowerCase()===r);if(a)return{address:a.token_address,symbol:a.symbol,name:a.name}}let s=await this.service.searchTokensByKey({key:e,chain:n});if(s.success&&s.data?.length){let i=s.data.find(l=>(l.symbol??"").toLowerCase()===r)??s.data[0];if(i?.token_address)return{address:i.token_address,symbol:i.symbol,name:i.name}}}buildCounterparties(e){let t=new Map,n=new Map;for(let o of e){let s=o.direction==="send"?t:n,a=o.counterparty.toLowerCase(),i=parseFloat(o.amount_formatted)||0,l=s.get(a);l?(l.total+=i,l.count+=1,!l.label&&o.counterparty_label&&(l.label=o.counterparty_label),!l.entity&&o.counterparty_entity&&(l.entity=o.counterparty_entity),o.block_timestamp<l.first&&(l.first=o.block_timestamp),o.block_timestamp>l.last&&(l.last=o.block_timestamp)):s.set(a,{label:o.counterparty_label,entity:o.counterparty_entity,total:i,count:1,first:o.block_timestamp,last:o.block_timestamp})}let r=o=>Array.from(o.entries()).sort((s,a)=>a[1].count-s[1].count).map(([s,a])=>({address:s,label:a.label,entity:a.entity,total_amount:a.total.toFixed(6).replace(/\.?0+$/,""),tx_count:a.count,first_seen:a.first,last_seen:a.last}));return{sent:r(t),received:r(n)}}parseBlock(e){if(typeof e=="number")return Number.isFinite(e)?e:void 0;if(typeof e=="string"&&e){let t=Number(e);return Number.isFinite(t)?t:void 0}}};var tt=class extends v{name="get-wallet-nft-transfers";description=`Get all NFT transfers for a wallet from the dedicated Moralis NFT transfers endpoint. Each transfer includes direction (send/receive), the exact counterparty address, token ID, collection, contract type (ERC721/ERC1155), and optional last sale price. The response includes a 'counterparties' section aggregating unique senders/recipients with token IDs and collections. Use this tool for questions like: "Which NFTs did I sell and to whom?" (direction=send), "Who sent me NFTs from collection 0x\u2026?" (contractAddresses=[0x\u2026], direction=receive), "Show all transfers for my NFT collection 0x\u2026" (contractAddresses=[0x\u2026]), "What NFTs did I mint?" (direction=receive), "Show NFT sales with prices" (direction=send, includePrices=true). Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. Returns paginated results \u2014 pass cursor to get the next page.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea . ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"contractAddresses",type:"array",description:"Filter by one or more NFT contract addresses (0x\u2026). Use this to scope queries to a specific collection. Omit to return all NFT transfers.",required:!1,items:{type:"string"}},{name:"direction",type:"string",description:'Client-side direction filter: "send" (wallet sent the NFT), "receive" (wallet received it), "all" (default).',required:!1,default:"all"},{name:"limit",type:"number",description:"Page size (1-100, default 25).",required:!1,default:25},{name:"fromDate",type:"string",description:'Inclusive start date (ISO-8601 or "YYYY-MM-DD").',required:!1},{name:"toDate",type:"string",description:'Inclusive end date (ISO-8601 or "YYYY-MM-DD").',required:!1},{name:"fromBlock",type:"number",description:"Minimum block number.",required:!1},{name:"toBlock",type:"number",description:"Maximum block number.",required:!1},{name:"cursor",type:"string",description:"Pagination cursor from a previous response.",required:!1},{name:"order",type:"string",description:'"DESC" newest first (default) or "ASC" oldest first.',required:!1,default:"DESC"},{name:"includePrices",type:"boolean",description:"If true, include last_sale price data (buyer, seller, price, USD value, payment token) on each transfer. Useful for questions about NFT sale prices.",required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=typeof e.limit=="number"?e.limit:Number(e.limit),s=Number.isFinite(o)&&o>0?Math.min(100,Math.floor(o)):25,a=typeof e.fromDate=="string"&&e.fromDate?e.fromDate:void 0,i=typeof e.toDate=="string"&&e.toDate?e.toDate:void 0,l=this.parseBlock(e.fromBlock),u=this.parseBlock(e.toBlock),d=typeof e.cursor=="string"&&e.cursor?e.cursor:void 0,p=(typeof e.order=="string"?e.order.toUpperCase():"")==="ASC"?"ASC":"DESC",h=typeof e.includePrices=="boolean"?e.includePrices:void 0,g=typeof e.direction=="string"?e.direction.trim().toLowerCase():"all",f=g==="send"?"send":g==="receive"?"receive":"all",y=Array.isArray(e.contractAddresses)?e.contractAddresses.filter(C=>typeof C=="string"&&!!C).map(C=>C.trim()):void 0,k=await this.service.getWalletNftTransfers({address:n,chain:r,contractAddresses:y,limit:s,fromDate:a,toDate:i,fromBlock:l,toBlock:u,cursor:d,order:p,includePrices:h});if(!k.success)return{error:k.error||"Failed to fetch NFT transfers"};let w=n.toLowerCase(),T=(k.data?.result||[]).map(C=>{let L=C.from_address.toLowerCase()===w,x=L?"send":"receive",D=L?C.to_address:C.from_address,A=L?C.to_address_label??void 0:C.from_address_label??void 0,H=L?C.to_address_entity??void 0:C.from_address_entity??void 0;return{...C,direction:x,counterparty:D,counterparty_label:A,counterparty_entity:H}}),P=f==="all"?T:T.filter(C=>C.direction===f),S=this.buildCounterparties(P);return{walletAddress:n,chain:r||"default",filters:{contractAddresses:y||null,direction:f,limit:s,order:p,fromDate:a||null,toDate:i||null,fromBlock:l??null,toBlock:u??null,includePrices:h??null},pagination:{cursor:k.data?.cursor??null,pageSize:k.data?.page_size??s,page:k.data?.page??null,hasMore:!!k.data?.cursor},transferCount:P.length,transfers:P,counterparties:S}}buildCounterparties(e){let t=new Map,n=new Map;for(let o of e){let s=o.direction==="send"?t:n,a=o.counterparty.toLowerCase(),i=o.token_name??o.token_address,l=s.get(a);l?(l.tokenIds.add(o.token_id),l.collections.add(i),l.count+=1,!l.label&&o.counterparty_label&&(l.label=o.counterparty_label),!l.entity&&o.counterparty_entity&&(l.entity=o.counterparty_entity),o.block_timestamp<l.first&&(l.first=o.block_timestamp),o.block_timestamp>l.last&&(l.last=o.block_timestamp)):s.set(a,{label:o.counterparty_label,entity:o.counterparty_entity,tokenIds:new Set([o.token_id]),collections:new Set([i]),count:1,first:o.block_timestamp,last:o.block_timestamp})}let r=o=>Array.from(o.entries()).sort((s,a)=>a[1].count-s[1].count).map(([s,a])=>({address:s,label:a.label,entity:a.entity,token_ids:Array.from(a.tokenIds),collections:Array.from(a.collections),tx_count:a.count,first_seen:a.first,last_seen:a.last}));return{sent:r(t),received:r(n)}}parseBlock(e){if(typeof e=="number")return Number.isFinite(e)?e:void 0;if(typeof e=="string"&&e){let t=Number(e);return Number.isFinite(t)?t:void 0}}};var kn=class extends v{name="get-wallet-net-worth";description=`Get a wallet's total net worth in USD, with a per-chain breakdown. Returns: total_networth_usd (grand total across all queried chains), chains[] (each with chain, native_balance_formatted, native_balance_usd, token_balance_usd, networth_usd), and optional unsupported_chain_ids / unavailable_chains lists. Use this tool for questions like: "How much is my wallet worth?", "What is my total portfolio value?", "What is my net worth on Ethereum?", "Portfolio value across all chains?". Pass chains=["0x1","0x2105"] to query multiple chains at once; defaults to the connected chain. Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. Do NOT use for: individual token balances \u2192 get-wallet-token-balances; realized profit/loss \u2192 get-wallet-pnl-summary.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chains",type:"array",description:'One or more hex chain IDs to aggregate. Values: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea If omitted, defaults to the connected chain.',required:!1,items:{type:"string"}},{name:"excludeSpam",type:"boolean",description:"Exclude tokens flagged as spam. Default true for cleaner totals.",required:!1,default:!0},{name:"excludeUnverifiedContracts",type:"boolean",description:"Exclude unverified token contracts. Default false.",required:!1,default:!1},{name:"maxTokenInactivity",type:"number",description:"Exclude tokens that have been inactive for more than N days.",required:!1},{name:"minPairSideLiquidityUsd",type:"number",description:"Exclude tokens with pair-side liquidity below this USD threshold.",required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=e.address||t?.walletAddress||void 0;if(!n)return{error:'No wallet address available. Please connect a wallet or pass "address".'};let r=Array.isArray(e.chains)?e.chains.filter(p=>typeof p=="string"&&!!p).map(p=>p.trim()):void 0,o=t?.chain,s=r&&r.length>0?r:o?[o]:void 0,a=typeof e.excludeSpam=="boolean"?e.excludeSpam:!0,i=typeof e.excludeUnverifiedContracts=="boolean"?e.excludeUnverifiedContracts:void 0,l=typeof e.maxTokenInactivity=="number"&&Number.isFinite(e.maxTokenInactivity)?e.maxTokenInactivity:void 0,u=typeof e.minPairSideLiquidityUsd=="number"&&Number.isFinite(e.minPairSideLiquidityUsd)?e.minPairSideLiquidityUsd:void 0,d=await this.service.getWalletNetWorth({address:n,chains:s,excludeSpam:a,excludeUnverifiedContracts:i,maxTokenInactivity:l,minPairSideLiquidityUsd:u});if(!d.success)return{error:d.error||"Failed to fetch wallet net worth"};let m=d.data;return{walletAddress:n,chainsQueried:s??["default"],filters:{excludeSpam:a,excludeUnverifiedContracts:i??null,maxTokenInactivity:l??null,minPairSideLiquidityUsd:u??null},totalNetWorthUsd:m.total_networth_usd,chains:m.chains,unsupportedChainIds:m.unsupported_chain_ids??[],unavailableChains:m.unavailable_chains??[]}}};var jr=["all","7","30","60","90"],nt=class extends v{name="get-wallet-pnl-summary";description=`Get a wallet's aggregate realized profit-and-loss summary across all tokens it has traded. Returns: total_count_of_trades, total_trade_volume (USD), total_realized_profit_usd, total_realized_profit_percentage, total_buys, total_sells, total_sold_volume_usd, total_bought_volume_usd. Use this tool for questions like: "How much profit have I made trading?", "What is my realized PnL?", "How many trades have I done this month?" (days=30), "Am I up or down overall?". IMPORTANT \u2014 this endpoint only supports mainnet: Ethereum ("0x1"), Base ("0x2105"), Polygon ("0x89"). Use days="all" (default), "7", "30", "60", or "90" to scope the time window. Do NOT use for: per-token breakdown \u2192 get-wallet-pnl; current portfolio value \u2192 get-wallet-token-balance; transfer history \u2192 get-wallet-history.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea . ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"days",type:"string",description:'Time window for the summary. Values: "all" (default, lifetime), "7", "30", "60", "90". Pass "30" when the user asks about the last month, "7" for the last week, etc.',required:!1,default:"all"}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=typeof e.days=="string"?e.days.trim().toLowerCase():"",s=jr.includes(o)?o:void 0,a=await this.service.getWalletPnlSummary({address:n,chain:r,days:s});if(!a.success)return{error:a.error||"Failed to fetch wallet PnL summary"};let i=a.data;return{walletAddress:n,chain:r||"default",days:s??"all",summary:{totalCountOfTrades:i.total_count_of_trades,totalTradeVolume:i.total_trade_volume,totalRealizedProfitUsd:i.total_realized_profit_usd,totalRealizedProfitPercentage:i.total_realized_profit_percentage,totalBuys:i.total_buys,totalSells:i.total_sells,totalBoughtVolumeUsd:i.total_bought_volume_usd,totalSoldVolumeUsd:i.total_sold_volume_usd}}}};var zr=["all","7","30","60","90"],Tn=25,ot=class extends v{name="get-wallet-pnl";description=`Get a wallet's realized profit-and-loss broken down per ERC-20 token. Each entry includes: token_address, name, symbol, decimals, logo, avg_buy_price_usd, avg_sell_price_usd, total_usd_invested, total_tokens_bought, total_tokens_sold, total_sold_usd, avg_cost_of_quantity_sold, count_of_trades, realized_profit_usd, realized_profit_percentage, total_buys, total_sells, possible_spam. Use this tool for questions like: "Which tokens made me the most money?", "What are my best/worst trades?", "How much profit did I make on USDC?" (tokenSymbols=["USDC"]), "PnL for PEPE and DEGEN this month" (tokenSymbols=["PEPE","DEGEN"], days=30), "PnL breakdown for each token I traded this month" (days=30). IMPORTANT \u2014 this endpoint ONLY supports mainnet: Ethereum ("0x1"), Polygon ("0x89"), Base ("0x2105"). Use days="all" (default), "7", "30", "60", or "90" for the time window. Pass tokenSymbols (by ticker, auto-resolved) and/or tokenAddresses (raw 0x\u2026) to restrict to specific tokens \u2014 combined total capped at ${Tn}. Do NOT use for: aggregate summary \u2192 get-wallet-pnl-summary; current balances \u2192 get-wallet-token-balances; transfer history \u2192 get-wallet-token-transfers.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"days",type:"string",description:'Time window for the breakdown. Values: "all" (default, lifetime), "7", "30", "60", "90".',required:!1,default:"all"},{name:"tokenSymbols",type:"array",description:`Optional list of token symbols (e.g. ["USDC", "PEPE"]). Auto-resolved to contract addresses via the connected wallet's balances first, then Pantograph search. Symbols that can't be resolved are skipped. Merged with tokenAddresses; combined total capped at ${Tn}.`,required:!1,items:{type:"string"}},{name:"tokenAddresses",type:"array",description:`Optional list of raw ERC-20 contract addresses (0x\u2026). Use when the exact addresses are already known. Merged with tokenSymbols; combined total capped at ${Tn}.`,required:!1,items:{type:"string"}}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=typeof e.days=="string"?e.days.trim().toLowerCase():"",s=zr.includes(o)?o:void 0,a=Array.isArray(e.tokenSymbols)?e.tokenSymbols.filter(g=>typeof g=="string"&&!!g.trim()).map(g=>g.trim()):[],i=Array.isArray(e.tokenAddresses)?e.tokenAddresses.filter(g=>typeof g=="string"&&!!g.trim()).map(g=>g.trim()):[],l=[],u=[];a.length>0&&(await Promise.all(a.map(f=>this.resolveContractAddress(f,r,n)))).forEach((f,y)=>{f?l.push({symbol:a[y],address:f.address}):u.push(a[y])});let d=Qr([...l.map(g=>g.address),...i]).slice(0,Tn),m=d.length>0?d:void 0,p=await this.service.getWalletPnl({address:n,chain:r,days:s,tokenAddresses:m});if(!p.success)return{error:p.error||"Failed to fetch wallet PnL"};let h=p.data?.result??[];return{walletAddress:n,chain:r||"default",days:s??"all",filters:{tokenAddresses:m??null,resolvedSymbols:l.length>0?l:null,unresolvedSymbols:u.length>0?u:null},tokenCount:h.length,tokens:h}}async resolveContractAddress(e,t,n){let r=e.toLowerCase();if(n){let s=await this.service.getWalletTokenBalances({address:n,chain:t});if(s.success&&s.data?.result?.length){let a=s.data.result.find(i=>(i.symbol??"").toLowerCase()===r);if(a)return{address:a.token_address,symbol:a.symbol,name:a.name}}}let o=await this.service.searchTokensByKey({key:e,chain:t});if(o.success&&o.data?.length){let a=o.data.find(i=>(i.symbol??"").toLowerCase()===r)??o.data[0];if(a?.token_address)return{address:a.token_address,symbol:a.symbol,name:a.name}}}};function Qr(c){let e=new Set,t=[];for(let n of c){let r=n.toLowerCase();e.has(r)||(e.add(r),t.push(n))}return t}var Xr=BigInt(2)**BigInt(255),rt=class extends v{name="get-wallet-approvals";description=`List every active ERC-20 token approval granted by a wallet \u2014 i.e. which contracts can still spend the wallet's tokens. For each approval, returns: the token (address, name, symbol, logo, current balance, USD price, USD at risk, possible_spam, verified_contract), the spender (address, label, entity \u2014 e.g. "Uniswap V3 Router", "Permit2"), the approved amount (value / value_formatted / isUnlimited flag), and when the approval was granted (block number, timestamp, transaction hash). Also returns aggregates: total approvals, unlimited-approval count, total USD at risk, and approvals flagged as risky (spam tokens, unverified contracts, or unlimited allowance to unlabeled spenders). Use for questions like: "What approvals do I have?", "Show my token approvals", "Am I exposed to any risky approvals?", "Which contracts can drain my wallet?", "Do I have any unlimited approvals?", "Revoke approvals / token allowances". Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea (EVM mainnets only). Paginated \u2014 pass cursor to fetch the next page.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1},{name:"limit",type:"number",description:"Page size (1-100, default 100).",required:!1,default:100},{name:"cursor",type:"string",description:"Pagination cursor from a previous response.",required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=typeof e.limit=="number"?e.limit:Number(e.limit),s=Number.isFinite(o)&&o>0?Math.min(100,Math.floor(o)):100,a=typeof e.cursor=="string"&&e.cursor?e.cursor:void 0,i=await this.service.getWalletApprovals({address:n,chain:r,limit:s,cursor:a});if(!i.success)return{error:i.error||"Failed to fetch wallet approvals"};let l=i.data,d=(l.result||[]).map(g=>Jr(g)),m=0,p=0,h=[];for(let g of d){g.isUnlimited&&(p+=1);let f=parseFloat(g.token.usdAtRisk??"");Number.isFinite(f)&&(m+=f);let y=g.token.possibleSpam||g.token.verifiedContract===!1,k=!g.spender.label&&!g.spender.entity;(y||g.isUnlimited&&k)&&h.push(g)}return{walletAddress:n,chain:r||"default",filters:{limit:s,cursor:a??null},pagination:{cursor:l.cursor??null,pageSize:l.page_size??s,page:l.page??null,hasMore:!!l.cursor},summary:{totalApprovals:d.length,unlimitedApprovals:p,totalUsdAtRisk:m,riskyApprovalCount:h.length},approvals:d,riskyApprovals:h}}};function Jr(c){let e=Zr(c.value);return{blockNumber:c.block_number,blockTimestamp:c.block_timestamp??null,transactionHash:c.transaction_hash??null,value:c.value,valueFormatted:c.value_formatted??null,isUnlimited:e,token:{address:c.token.address,addressLabel:c.token.address_label??null,name:c.token.name??null,symbol:c.token.symbol??null,logo:c.token.logo??null,possibleSpam:!!c.token.possible_spam,verifiedContract:c.token.verified_contract??null,currentBalance:c.token.current_balance??null,currentBalanceFormatted:c.token.current_balance_formatted??null,usdPrice:c.token.usd_price??null,usdAtRisk:c.token.usd_at_risk??null},spender:{address:c.spender.address,label:c.spender.address_label??null,entity:c.spender.entity??null,entityLogo:c.spender.entity_logo??null}}}function Zr(c){if(!c)return!1;try{return BigInt(c)>=Xr}catch{return!1}}var st=class extends v{name="get-wallet-defi-summary";description=`Get a wallet's DeFi protocols summary: which protocols the wallet is using, total USD value locked across all protocols, total unclaimed rewards/fees, number of active protocols, and total number of positions. Returns a per-protocol breakdown (protocol name, logo, url, positions count, usd value, unclaimed). Use for questions like: "Which DeFi protocols am I using?", "What's my total DeFi value?", "How much do I have in DeFi?", "Show my DeFi portfolio overview", "Unclaimed rewards across protocols". Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea (EVM mainnets only). Do NOT use for: detailed per-position data \u2192 get-wallet-defi-positions; positions inside a single protocol \u2192 get-wallet-defi-protocol-positions.`;category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=await this.service.getWalletDefiSummary({address:n,chain:r});if(!o.success)return{error:o.error||"Failed to fetch wallet DeFi summary"};let s=o.data;return{walletAddress:n,chain:r||"default",activeProtocols:s.active_protocols,totalPositions:s.total_positions,totalUsdValue:s.total_usd_value,totalUnclaimedUsdValue:s.total_unclaimed_usd_value,protocols:(s.protocols||[]).map(a=>({protocolName:a.protocol_name,protocolId:a.protocol_id,protocolUrl:a.protocol_url,protocolLogo:a.protocol_logo,positions:a.positions,totalUsdValue:a.total_usd_value,totalUnclaimedUsdValue:a.total_unclaimed_usd_value,accountHealthFactor:a.account_health_factor??null}))}}};var at=class extends v{name="get-wallet-defi-positions";description='Get every DeFi position a wallet holds across all supported protocols, with full detail: protocol identity, position label (e.g. "Liquidity Provision", "Supply", "Borrow", "Staking"), tokens involved (with balances and USD values), balance_usd, total_unclaimed_usd_value, and position_details (fee tier, liquidity, APY, price range, health factor, etc.). Use for questions like: "Show my DeFi positions", "What LP positions do I have?", "What am I staking?", "Do I have any borrows?", "List all my DeFi holdings with details". Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea. Do NOT use for: aggregate totals \u2192 get-wallet-defi-summary; positions filtered to a single protocol \u2192 get-wallet-defi-protocol-positions.';category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=Y(e.address,t),r=R(e.chain,t),o=await this.service.getWalletDefiPositions({address:n,chain:r});if(!o.success)return{error:o.error||"Failed to fetch wallet DeFi positions"};let s=o.data||[];return{walletAddress:n,chain:r||"default",positionCount:s.length,positions:s.map(a=>es(a))}}};function es(c){return{protocolName:c.protocol_name,protocolId:c.protocol_id,protocolUrl:c.protocol_url,protocolLogo:c.protocol_logo,accountHealthFactor:c.account_data?.health_factor??null,position:ts(c.position)}}function ts(c){return{label:c.label,address:c.address,balanceUsd:c.balance_usd,totalUnclaimedUsdValue:c.total_unclaimed_usd_value,tokens:(c.tokens||[]).map(e=>({tokenType:e.token_type,name:e.name,symbol:e.symbol,contractAddress:e.contract_address,decimals:e.decimals,logo:e.logo,thumbnail:e.thumbnail,balance:e.balance,balanceFormatted:e.balance_formatted,usdPrice:e.usd_price,usdValue:e.usd_value})),details:c.position_details??null}}var it=class extends v{name="get-wallet-defi-protocol-positions";description='Get every position a wallet holds inside a specific DeFi protocol, with full detail. Returns the protocol identity, totals (total_usd_value, total_unclaimed_usd_value), and an array of positions (label, tokens, balance_usd, unclaimed, fee tier, APY, health factor, etc.). Use when the user names a specific protocol, e.g. "my Uniswap v3 positions", "what do I have on Aave v3", "show my Lido staking", "my Curve pools", "Pendle positions". The "protocol" argument is the Moralis protocol id (kebab-case), e.g. uniswap-v2, uniswap-v3, pancakeswap-v2, pancakeswap-v3, quickswap-v2, quickswap-v3, sushiswap-v2, aave-v2, aave-v3, aave-lido, fraxswap-v1, fraxswap-v2, lido, makerdao, eigenlayer, pendle, etherfi, rocketpool, sparkfi, takara-lend, neverland, kintsu. Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea (EVM mainnets only). Do NOT use for: cross-protocol view \u2192 get-wallet-defi-positions; totals only \u2192 get-wallet-defi-summary.';category="blockchain-data";parameters=[{name:"address",type:"string",description:"EVM wallet address (0x\u2026). If omitted, uses the connected wallet from user context.",required:!1},{name:"protocol",type:"string",description:'Moralis protocol identifier in kebab-case. Examples: "uniswap-v2", "uniswap-v3", "pancakeswap-v2", "pancakeswap-v3", "quickswap-v2", "quickswap-v3", "sushiswap-v2", "aave-v2", "aave-v3", "aave-lido", "fraxswap-v1", "fraxswap-v2", "lido", "makerdao", "eigenlayer", "pendle", "etherfi", "rocketpool", "sparkfi", "takara-lend", "neverland", "kintsu"Use get-wallet-defi-summary to discover which protocols a wallet uses.',required:!0},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=e.protocol?.trim();if(!n)return{error:'Protocol identifier is required (e.g. "uniswap-v3", "aave-v3").'};let r=Y(e.address,t),o=R(e.chain,t),s=await this.service.getWalletDefiProtocolPositions({address:r,protocol:n,chain:o});if(!s.success)return{error:s.error||"Failed to fetch wallet DeFi protocol positions"};let a=s.data;return a?{walletAddress:r,chain:o||"default",protocolName:a.protocol_name,protocolId:a.protocol_id,protocolUrl:a.protocol_url,protocolLogo:a.protocol_logo,totalUsdValue:a.total_usd_value,totalUnclaimedUsdValue:a.total_unclaimed_usd_value,accountHealthFactor:a.account_data?.health_factor??null,positionCount:(a.positions||[]).length,positions:(a.positions||[]).map(ns)}:{error:"No data returned for this protocol"}}};function ns(c){return{label:c.label,address:c.address,balanceUsd:c.balance_usd,totalUnclaimedUsdValue:c.total_unclaimed_usd_value,tokens:(c.tokens||[]).map(e=>({tokenType:e.token_type,name:e.name,symbol:e.symbol,contractAddress:e.contract_address,decimals:e.decimals,logo:e.logo,thumbnail:e.thumbnail,balance:e.balance,balanceFormatted:e.balance_formatted,usdPrice:e.usd_price,usdValue:e.usd_value})),details:c.position_details??null}}function os(c){try{return(Number(BigInt(c))/1e18).toFixed(10).replace(/\.?0+$/,"")||"0"}catch{return c}}var lt=class extends v{name="get-transaction-by-hash";description='Get full decoded details of a single EVM transaction by its hash. Returns: status (success/failed), timestamp, from/to addresses with labels and entity names, native value transferred (ETH), transaction fee, gas used, decoded function call with params, and decoded event logs (ERC-20 transfers, swaps, approvals, etc.). Use this when the user asks: "what did this transaction do?", "explain tx 0x\u2026", "was this transaction successful?", "who sent/received in this tx?", "what function was called?". Supports: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Linea.';category="blockchain-data";parameters=[{name:"transactionHash",type:"string",description:"The transaction hash to look up (0x\u2026).",required:!0},{name:"chain",type:"string",description:'Hex chain ID: "0x1" Ethereum, "0xa" Optimism, "0x38" BSC, "0x89" Polygon, "0x2105" Base, "0xa4b1" Arbitrum, "0xa86a" Avalanche, "0xe708" Linea. ONLY set this when the user EXPLICITLY names a chain; otherwise OMIT it so the connected wallet chain is used.',required:!1}];service;constructor(e){super(),this.service=new E(e)}async run(e,t){let n=e.transactionHash;if(!n)return{error:"Transaction hash is required."};let r=R(e.chain,t),o=await this.service.getTransactionByHash({transactionHash:n,chain:r});if(!o.success||!o.data)return{error:o.error||"Failed to fetch transaction"};let s=o.data,a=(s.logs??[]).filter(l=>!!l.decoded_event).map(l=>({contract:l.address,signature:l.decoded_event.signature,label:l.decoded_event.label,params:l.decoded_event.params})),i=s.logs.map(l=>({address:l.address,decodedEvent:l.decoded_event?{signature:l.decoded_event.signature,label:l.decoded_event.label,params:l.decoded_event.params}:null}));return{hash:s.hash,status:s.receipt_status==="1"?"success":s.receipt_status==="0"?"failed":"unknown",timestamp:s.block_timestamp,blockNumber:s.block_number,from:{address:s.from_address,label:s.from_address_label||null,entity:s.from_address_entity||null},to:s.to_address?{address:s.to_address,label:s.to_address_label||null,entity:s.to_address_entity||null}:null,valueEth:os(s.value||"0"),fee:s.transaction_fee,gasUsed:s.receipt_gas_used,gasPriceGwei:s.gas_price?(Number(s.gas_price)/1e9).toFixed(4):null,decodedCall:s.decoded_call?{signature:s.decoded_call.signature,label:s.decoded_call.label,params:s.decoded_call.params}:null,decodedEvents:a,contractCreated:s.receipt_contract_address||null,logs:i}}};var fe=class extends v{kind="data";category="nft";noSuggestions=!0;parameters=[];linkPhrase="this website";url;constructor(e){super();let t=e?.url?.trim();this.url=t||void 0}async run(){let e=this.url?`[${this.linkPhrase}](${this.url})`:this.linkPhrase,t=this.template.replace("{link}",e);return{message:t,_instructions:`This is a fixed notice. Output it to the user EXACTLY as written below \u2014 in English, without translating, rephrasing, summarising, or adding/removing any words. Preserve the Markdown link verbatim (do not change, wrap, or drop the URL or the linked words). Do not mention tools. Reply with only this message:
|
|
16
16
|
|
|
17
17
|
`+t}}};var ct=class extends fe{name="get-wallet-nfts";description='Use when the user wants to view their NFTs / NFT collection / holdings ("my NFTs", "show my NFTs", "what NFTs do I own", "NFT collection"). Returns a fixed notice directing them to the NFT website. Takes no arguments.';template="Please view your NFT collection on {link} for more details"};var ut=class extends fe{name="get-nft-contract-info";description="Use when the user asks about an NFT collection / contract (name, symbol, type, floor, socials). Returns a fixed notice directing them to the NFT website. Takes no arguments.";template="Please view your NFT collection on {link} for more details"};var dt=class extends fe{name="get-nft-metadata";description='Use when the user asks about a specific NFT \u2014 its details, traits, image, or floor price ("show NFT #1234 of collection X", "traits of this NFT", "floor price of this NFT"). Returns a fixed notice directing them to the NFT website. Takes no arguments.';template="Please view your NFT collection on {link} for more details"};var mt=class extends v{name="gemini-search-ai";description="Ask a search-grounded Gemini model for blockchain / crypto insights that no dedicated tool can answer. Use this as a LAST-RESORT fallback when the specialised data tools are insufficient. Backed by live Google Search grounding \u2014 good for: market analysis, category/theme queries (meme, AI, gaming, L2, RWA), DeFi protocol explanations, cross-chain comparisons, trend / sentiment, recent news or announcements, gas insights, NFT collection lore, and any open-ended crypto reasoning question. Chain-agnostic \u2014 write the chain (Ethereum, BSC, Base, \u2026) and any addresses, time range, or token symbols directly into the prompt. Do NOT use this for: token balances \u2192 get-wallet-token-balances; token prices/metadata \u2192 get-token-info; NFT holdings \u2192 get-wallet-nfts; NFT contract info \u2192 get-nft-contract-info; transaction details \u2192 get-transaction-by-hash; wallet history \u2192 get-wallet-history; token transfers \u2192 get-wallet-token-transfers; NFT transfers \u2192 get-wallet-nft-transfers; token holders \u2192 get-token-holders; wallet PnL \u2192 get-wallet-pnl or get-wallet-pnl-summary; pool / liquidity data \u2192 pool-agent tools.";category="blockchain-ai";parameters=[{name:"prompt",type:"string",description:'A clear, self-contained English question for the AI. Must include every detail needed to answer without the conversation context: chain (Ethereum / BSC / Base / \u2026), wallet or contract addresses, token symbols, time range, what to compare or rank. Instruct the model to use up-to-date web sources when relevant. Example: "List the top 10 meme-category tokens on Ethereum right now, ranked by 24h trading volume, using up-to-date market data."',required:!0}];llm;constructor(e){super(),this.llm=new se(e??{})}async run(e,t){let n=typeof e.prompt=="string"?e.prompt.trim():"";if(!n)return{error:"Missing required parameter: prompt"};let r=[];t?.walletAddress&&r.push(`- Connected wallet address: ${t.walletAddress}`),t?.chain&&r.push(`- Current chain: ${t.chain}`),r.push("Use this context only when relevant to the question. Do not invent on-chain values.");let o=Date.now(),s=[{role:"system",content:`[USER CONTEXT]
|
|
18
18
|
${r.join(`
|
|
@@ -874,9 +874,9 @@ ${i.join(`
|
|
|
874
874
|
${e}${l}
|
|
875
875
|
|
|
876
876
|
Return JSON only.`,timestamp:Date.now()}],m=[{role:"system",content:Pa,timestamp:0},{role:"user",content:e,timestamp:Date.now()}],[p,h]=await Promise.allSettled([this.llm.chat(d),this.llm.chat(m)]),g={};if(p.status==="fulfilled")try{g=this.parseJSON(p.value.text)}catch(k){this.debug&&console.log(`[QueryRewriter] rewrite parse fail: ${k}`)}else this.debug&&console.log(`[QueryRewriter] rewrite call fail: ${p.reason}`);let f="";if(h.status==="fulfilled")try{let k=this.parseJSON(h.value.text);typeof k.language=="string"&&(f=k.language.trim().toLowerCase())}catch(k){this.debug&&console.log(`[QueryRewriter] detect parse fail: ${k}`)}else this.debug&&console.log(`[QueryRewriter] detect call fail: ${h.reason}`);let y={isFollowUp:r&&typeof g.isFollowUp=="boolean"?g.isFollowUp:!1,rewrittenQuery:typeof g.rewrittenQuery=="string"&&g.rewrittenQuery.trim()?g.rewrittenQuery.trim():e,topicChanged:r&&typeof g.topicChanged=="boolean"?g.topicChanged:!1,reasoning:typeof g.reasoning=="string"?g.reasoning:"",language:f,mentionedChain:typeof g.mentionedChain=="string"?g.mentionedChain.trim():"",needsWebSearch:g.needsWebSearch===!0};if(this.debug){let k=Date.now()-u,w=y.rewrittenQuery!==e;console.log(`
|
|
877
|
-
[QueryRewriter] (${k}ms)`),console.log(` original : "${e}"`),console.log(` rewritten : "${y.rewrittenQuery}"${w?"":" (unchanged)"}`),console.log(` followUp : ${y.isFollowUp} topicChanged: ${y.topicChanged}`),y.reasoning&&console.log(` reasoning : ${y.reasoning}`),console.log(` language : ${y.language}`),console.log(` webSearch : ${y.needsWebSearch}`)}return y}parseJSON(e){let t=e.trim();t.startsWith("```")&&(t=t.replace(/^```(?:json)?\s*/,"").replace(/```\s*$/,""));let n=t.match(/\{[\s\S]*\}/);return n&&(t=n[0]),JSON.parse(t)}};var M=require("@langchain/langgraph");var re=c=>({reducer:(e,t)=>t,default:c}),_a=M.Annotation.Root({userMessage:(0,M.Annotation)(),doSuggest:(0,M.Annotation)(re(()=>!0)),overrideLang:(0,M.Annotation)(re(()=>"")),conversationMessages:(0,M.Annotation)(re(()=>[])),lastSubagents:(0,M.Annotation)(re(()=>[])),messageId:(0,M.Annotation)(re(()=>"")),rewrite:(0,M.Annotation)(re(()=>null)),effectiveQuery:(0,M.Annotation)(re(()=>"")),turnLanguage:(0,M.Annotation)(re(()=>"")),kbContext:(0,M.Annotation)(re(()=>"")),decision:(0,M.Annotation)(re(()=>null)),assignment:(0,M.Annotation)(re(()=>null)),assignmentIndex:(0,M.Annotation)(re(()=>0)),subResults:(0,M.Annotation)({reducer:(c,e)=>c.concat(e),default:()=>[]}),response:(0,M.Annotation)(re(()=>null))});function sr(c){let e=async d=>{c.addUserMessage(d.userMessage),c.needsSummary()&&await c.compactHistory();let m=c.conversationForTurn(),p=c.lastAssistantSubagents(m);return c.debug&&p.length>0&&console.log(`[AgentCore] previous turn handled by: ${p.join(", ")}`),{conversationMessages:m,lastSubagents:p,messageId:c.generateMessageId()}},t=async d=>{let m=await c.rewrite(d.userMessage,d.conversationMessages,d.lastSubagents),p=d.overrideLang||m.language||"";return{rewrite:m,effectiveQuery:m.rewrittenQuery,turnLanguage:p}},n=async d=>{let m=d.rewrite,p=m.isFollowUp?d.effectiveQuery:d.userMessage,h=await c.searchKB(p),g=c.formatKBContext(h),f=await c.tryAnswerFromKB(d.userMessage,h,g,d.messageId);return f?{kbContext:g,response:{...f,messageId:d.messageId,rewrite:m}}:{kbContext:g}},r=async d=>({decision:await c.route(d.effectiveQuery,d.conversationMessages,c.subagentCards(),d.lastSubagents)}),o=async d=>({response:{...await c.answerDirectly(d.effectiveQuery,d.conversationMessages,d.kbContext,d.doSuggest,d.messageId,d.rewrite?.needsWebSearch??!1),messageId:d.messageId,routerDecision:d.decision,rewrite:d.rewrite}}),s=async d=>{let m=await c.runSubagent(d.assignment,d.conversationMessages,d.turnLanguage);return{subResults:[{i:d.assignmentIndex,result:m}]}},a=async d=>{let m=d.subResults.slice().sort((b,T)=>b.i-T.i).map(b=>b.result);c.persistToolMessages(m);let p=c.mergeTrace(m),h=await c.synthesise(d.userMessage,p,c.synthesiserHistory(),d.turnLanguage||void 0),g=m.map(b=>b.subagentName),f=c.collectUiActions(m,d.turnLanguage||null),y=c.collectActionButtons(m,d.turnLanguage||null),k=c.subResultsTriggerNoSuggestions(m);return{response:{...await c.finaliseAnswer({userMessage:d.userMessage,answer:h,subagents:g,uiActions:f,actionButtons:y,messageId:d.messageId},{generateSuggestions:d.doSuggest&&!k&&y.length===0}),messageId:d.messageId,trace:p,routerDecision:d.decision,subagentResults:m,rewrite:d.rewrite,...f.length>0?{uiActions:f}:{},...y.length>0?{actionButtons:y}:{}}}},i=async d=>{let m=(d.rewrite?.mentionedChain||String(c.connectedChain()??"")).trim();return{response:{...await c.answerUnsupportedChain(m,d.turnLanguage,d.messageId),messageId:d.messageId,routerDecision:d.decision,rewrite:d.rewrite}}},l=d=>d.response?M.END:"route",u=d=>{let m=d.decision?.assignments??[];if(m.length===0)return"direct";let p=m.some(g=>g.subagent!=="ai-agent"),h=(d.rewrite?.mentionedChain||c.connectedChain()||"").trim();return p&&h!==""&&!bn(h)?"unsupportedChain":m.map((g,f)=>new M.Send("subagent",{...d,assignment:g,assignmentIndex:f}))};return new M.StateGraph(_a).addNode("setup",e).addNode("contextualize",t).addNode("kb",n).addNode("route",r).addNode("direct",o).addNode("subagent",s).addNode("synthesize",a).addNode("unsupportedChain",i).addEdge(M.START,"setup").addEdge("setup","contextualize").addEdge("contextualize","kb").addConditionalEdges("kb",l,["route",M.END]).addConditionalEdges("route",u,["direct","subagent","unsupportedChain"]).addEdge("unsupportedChain",M.END).addEdge("direct",M.END).addEdge("subagent","synthesize").addEdge("synthesize",M.END).compile()}var ar=require("js-sha3");function Vn(){let c=Date.now().toString(16),e=Math.floor(Math.random()*65535).toString(16).padStart(4,"0");return(c+e).slice(-8)}var Ca="You are a helpful AI assistant. Answer the user accurately and concisely. Respond in the same language as the user.",Hn=class{llm;registry;history;summarizer;router;rewriter;subagents;synthesizer;chatGraph;systemPrompt;debug;secretKey;licenseChecked=!1;userContext={};storage;storageKey;persistHistoryEnabled;kb;kbEntries;vectorKB=null;vectorKBAutoIngested=!1;vectorKBAutoIngestPromise=null;autoIngestEnabled=!1;kbAnswerThreshold;suggestionsEnabled;historyLoaded=!1;historyLoadingPromise=null;historyReady;constructor(e){this.secretKey=e.secretKey,ro(e.rpcUrls),yn(e.excludeChains),this.llm=new se(e.llm),this.registry=new Fe,this.history=new Yt(e.maxHistoryMessages??50),this.summarizer=new Kt(this.llm),this.synthesizer=new Qt(this.llm),this.systemPrompt=e.systemPrompt??Ca,this.debug=e.debug??!1,this.suggestionsEnabled=e.generateSuggestions??!0,this.storage=e.storage??null,this.storageKey=e.storageKey??"keyring-agent-history",this.persistHistoryEnabled=e.persistHistory??!1,this.kbEntries=new jt(e.knowledgeBase),this.kbEntries.setLLM(this.llm);let t=e.vectorKB;t?.enabled?(t.provider?this.kb=t.provider:(this.vectorKB=new Re({url:t.url,token:t.token,namespace:t.namespace,minScore:t.minScore,defaultTopK:t.defaultTopK,debug:this.debug}),this.kb=this.vectorKB,this.autoIngestEnabled=t.autoIngest===!0),this.debug&&console.log(`[AgentCore] vector KB enabled (${t.provider?"custom provider":"Upstash"}`+(t.namespace?`, ns=${t.namespace}`:"")+")")):this.kb=this.kbEntries;let n=e.kbAnswerThreshold;if(typeof n=="number"?this.kbAnswerThreshold=n:t?.enabled&&!t.provider?this.kbAnswerThreshold=t.minScore??1.3:this.kbAnswerThreshold=.8,this.debug&&console.log(`[AgentCore] kbAnswerThreshold = ${this.kbAnswerThreshold}`),e.moralis!==!1){let u=typeof e.moralis=="object"?e.moralis:void 0;this.registry.register(new Je(u)),this.registry.register(new Ye(u)),this.registry.register(new Ze(u)),this.registry.register(new et(u)),this.registry.register(new tt(u)),this.registry.register(new Ke(u)),this.registry.register(new nt(u)),this.registry.register(new ot(u)),this.registry.register(new lt(u)),this.registry.register(new st(u)),this.registry.register(new at(u)),this.registry.register(new it(u)),this.registry.register(new rt(u)),this.registry.register(new Qe(u)),this.registry.register(new Xe(u)),this.registry.register(new je(u)),this.registry.register(new ze(u))}let r=e.nftLink;this.registry.register(new ct({url:r})),this.registry.register(new ut({url:r})),this.registry.register(new dt({url:r})),this.registry.register(new mt(e.llm));let o=e.subagents?.["pool-subgraph"]===!0;if((o?e.subagents?.pool===!0:e.subagents?.pool!==!1)&&e.uniswap!==!1){let u=typeof e.uniswap=="object"?e.uniswap:void 0;this.registry.register(new ht(u)),this.registry.register(new gt(u)),this.registry.register(new ft(u)),this.registry.register(new yt(u)),this.registry.register(new _t(u));let d=u?{isProduction:u.isProduction}:void 0;this.registry.register(new At({baseUrl:u?.baseUrl,pool:d,minProvideUsd:u?.minProvideUsd})),this.registry.register(new Pt({pool:d}))}if(o&&e.subgraph!==!1){let u=typeof e.subgraph=="object"?e.subgraph:void 0;this.registry.register(new Ct(u)),this.registry.register(new Ut(u)),this.registry.register(new Rt(u)),this.registry.register(new Et(u)),this.registry.register(new Nt(u)),this.registry.register(new It(u)),this.registry.register(new Dt(u)),this.registry.register(new pt(e.llm))}if(e.subagents?.["wallet-action"]!==!1){let u=e.moralis===!1?void 0:typeof e.moralis=="object"?e.moralis:{};this.registry.register(new Bt(u)),this.registry.register(new Ot(u)),this.registry.register(new Gt(u,{url:r})),this.registry.register(new qt(u)),this.registry.register(new Vt(u,{debug:this.debug})),this.registry.register(new Ht(u,{debug:this.debug}))}this.router=new zt(this.llm,{debug:this.debug}),this.rewriter=new Wn(this.llm,{debug:this.debug});let i=typeof e.subgraph=="object"?e.subgraph:void 0,l=$n(this.llm,this.registry,{maxToolCalls:e.maxIterations??5,debug:this.debug,linkAddLiquidity:i?.linkAddLiquidity},e.subagents);this.subagents=new Map(l.map(u=>[u.name,u])),this.chatGraph=sr(this.createGraphHost()),this.historyReady=this.loadHistory()}registerTool(e){this.registry.register(e)}registerTools(e){for(let t of e)this.registry.register(t)}unregisterTool(e){return this.registry.unregister(e)}listTools(){return this.registry.listNames()}async invokeTool(e,t,n){if(this.assertLicense(),await this.loadHistory(),!this.registry.get(e))return{answer:`Unknown tool: "${e}".`,messageId:Vn()};this.debug&&console.log(`[AgentCore] invokeTool ${e} ${JSON.stringify(t)}`);let o=n?.userMessage??`[invoke ${e}]`;this.history.add({role:"user",content:o,timestamp:Date.now()});let s=await this.registry.execute(e,t,this.userContext),a=s.data,i=s.success?a?.summary??"Done.":`Action failed: ${s.error??"unknown error"}`,l=Vn(),u=s.success&&s.ui?[this.stampLanguage(s.ui,null)]:[],d={role:"assistant",content:i,timestamp:Date.now(),subagents:["direct-invoke"],messageId:l};return u.length>0&&(d.uiActions=u),this.history.add(d),await this.persistHistory(),{answer:i,messageId:l,...u.length>0?{uiActions:u}:{}}}registerSubagent(e){this.subagents.set(e.name,e)}unregisterSubagent(e){return this.subagents.delete(e)}listSubagents(){return Array.from(this.subagents.keys())}setKnowledgeBase(e){this.kbEntries.setEntries(e),this.vectorKBAutoIngested=!1}addKnowledgeBase(e){this.kbEntries.addEntries(e),this.vectorKBAutoIngested=!1}async ingestKnowledgeBase(){if(!this.vectorKB)return{count:0};let e=this.kbEntries.getEntries();if(e.length===0)return{count:0};let t=await this.vectorKB.upsert(e);return this.vectorKBAutoIngested=!0,t}async maybeAutoIngest(e){if(!(!e||!this.vectorKB||this.vectorKBAutoIngested)){if(this.vectorKBAutoIngestPromise)return this.vectorKBAutoIngestPromise;this.vectorKBAutoIngestPromise=(async()=>{try{let{count:t}=await this.ingestKnowledgeBase();this.debug&&t>0&&console.log(`[AgentCore] auto-ingested ${t} KB entr${t===1?"y":"ies"} to vector store`)}catch(t){this.debug&&console.warn("[AgentCore] auto-ingest failed:",t)}finally{this.vectorKBAutoIngestPromise=null}})(),await this.vectorKBAutoIngestPromise}}setUserContext(e){this.userContext={...e}}getUserContext(){return{...this.userContext}}async loadHistory(){if(!this.historyLoaded){if(this.historyLoadingPromise)return this.historyLoadingPromise;this.historyLoadingPromise=this._doLoadHistory(),await this.historyLoadingPromise}}async _doLoadHistory(){if(!this.storage){this.debug&&console.log("[AgentCore] loadHistory: no storage configured"),this.historyLoaded=!0;return}if(!this.persistHistoryEnabled){this.debug&&console.log("[AgentCore] loadHistory: persistHistory disabled \u2014 starting fresh session");try{await this.storage.removeItem(this.storageKey)}catch(e){this.debug&&console.warn("[AgentCore] failed to clear stale history:",e)}this.historyLoaded=!0;return}try{let e=await this.storage.getItem(this.storageKey);if(this.debug&&console.log(`[AgentCore] loadHistory: storage key "${this.storageKey}" ${e?`has ${e.length} chars`:"is empty"}`),e){let t=JSON.parse(e);this.history.restore(t),this.debug&&console.log(`[AgentCore] Restored ${this.history.length} messages from storage`)}}catch(e){this.debug&&console.warn("[AgentCore] Failed to load history from storage:",e)}finally{this.historyLoaded=!0}}async persistHistory(){if(this.storage&&this.persistHistoryEnabled)try{let e=JSON.stringify(this.history.serialise());await this.storage.setItem(this.storageKey,e)}catch(e){this.debug&&console.warn("[AgentCore] Failed to persist history to storage:",e)}}assertLicense(){if(this.licenseChecked)return;let e="d00d67291d3c660a5034b01c0b2afbc8d4ac5552099a04f28a92d75fdb44c188";if(e&&(!this.secretKey||(0,ar.sha3_256)(this.secretKey)!==e))throw new Error("AgentCore: invalid or missing secretKey.");this.licenseChecked=!0}async chat(e,t){this.assertLicense();let n=t?.generateSuggestions??this.suggestionsEnabled,r=typeof t?.language=="string"&&t.language.trim()?t.language.trim():"";await this.loadHistory(),await this.maybeAutoIngest(this.autoIngestEnabled);let o=Date.now();this.debug&&(console.log(`
|
|
878
|
-
${"\u2500".repeat(60)}`),console.log(`[AgentCore] query: "${e}"`));let s=
|
|
879
|
-
`)),
|
|
877
|
+
[QueryRewriter] (${k}ms)`),console.log(` original : "${e}"`),console.log(` rewritten : "${y.rewrittenQuery}"${w?"":" (unchanged)"}`),console.log(` followUp : ${y.isFollowUp} topicChanged: ${y.topicChanged}`),y.reasoning&&console.log(` reasoning : ${y.reasoning}`),console.log(` language : ${y.language}`),console.log(` webSearch : ${y.needsWebSearch}`)}return y}parseJSON(e){let t=e.trim();t.startsWith("```")&&(t=t.replace(/^```(?:json)?\s*/,"").replace(/```\s*$/,""));let n=t.match(/\{[\s\S]*\}/);return n&&(t=n[0]),JSON.parse(t)}};var M=require("@langchain/langgraph");var re=c=>({reducer:(e,t)=>t,default:c}),_a=M.Annotation.Root({userMessage:(0,M.Annotation)(),doSuggest:(0,M.Annotation)(re(()=>!0)),overrideLang:(0,M.Annotation)(re(()=>"")),conversationMessages:(0,M.Annotation)(re(()=>[])),lastSubagents:(0,M.Annotation)(re(()=>[])),messageId:(0,M.Annotation)(re(()=>"")),rewrite:(0,M.Annotation)(re(()=>null)),effectiveQuery:(0,M.Annotation)(re(()=>"")),turnLanguage:(0,M.Annotation)(re(()=>"")),kbContext:(0,M.Annotation)(re(()=>"")),decision:(0,M.Annotation)(re(()=>null)),assignment:(0,M.Annotation)(re(()=>null)),assignmentIndex:(0,M.Annotation)(re(()=>0)),subResults:(0,M.Annotation)({reducer:(c,e)=>c.concat(e),default:()=>[]}),response:(0,M.Annotation)(re(()=>null))});function sr(c){let e=async d=>{c.addUserMessage(d.userMessage),c.needsSummary()&&await c.compactHistory();let m=c.conversationForTurn(),p=c.lastAssistantSubagents(m);return c.debug&&p.length>0&&console.log(`[AgentCore] previous turn handled by: ${p.join(", ")}`),{conversationMessages:m,lastSubagents:p,messageId:c.generateMessageId()}},t=async d=>{let m=await c.rewrite(d.userMessage,d.conversationMessages,d.lastSubagents),p=d.overrideLang||m.language||"";return{rewrite:m,effectiveQuery:m.rewrittenQuery,turnLanguage:p}},n=async d=>{let m=d.rewrite,p=m.isFollowUp?d.effectiveQuery:d.userMessage,h=await c.searchKB(p),g=c.formatKBContext(h),f=await c.tryAnswerFromKB(d.userMessage,h,g,d.messageId);return f?{kbContext:g,response:{...f,messageId:d.messageId,rewrite:m}}:{kbContext:g}},r=async d=>({decision:await c.route(d.effectiveQuery,d.conversationMessages,c.subagentCards(),d.lastSubagents)}),o=async d=>({response:{...await c.answerDirectly(d.effectiveQuery,d.conversationMessages,d.kbContext,d.doSuggest,d.messageId,d.rewrite?.needsWebSearch??!1),messageId:d.messageId,routerDecision:d.decision,rewrite:d.rewrite}}),s=async d=>{let m=await c.runSubagent(d.assignment,d.conversationMessages,d.turnLanguage);return{subResults:[{i:d.assignmentIndex,result:m}]}},a=async d=>{let m=d.subResults.slice().sort((b,T)=>b.i-T.i).map(b=>b.result);c.persistToolMessages(m);let p=c.mergeTrace(m),h=await c.synthesise(d.userMessage,p,c.synthesiserHistory(),d.turnLanguage||void 0),g=m.map(b=>b.subagentName),f=c.collectUiActions(m,d.turnLanguage||null),y=c.collectActionButtons(m,d.turnLanguage||null),k=c.subResultsTriggerNoSuggestions(m);return{response:{...await c.finaliseAnswer({userMessage:d.userMessage,answer:h,subagents:g,uiActions:f,actionButtons:y,messageId:d.messageId},{generateSuggestions:d.doSuggest&&!k&&y.length===0}),messageId:d.messageId,trace:p,routerDecision:d.decision,subagentResults:m,rewrite:d.rewrite,...f.length>0?{uiActions:f}:{},...y.length>0?{actionButtons:y}:{}}}},i=async d=>{let m=(d.rewrite?.mentionedChain||String(c.connectedChain()??"")).trim();return{response:{...await c.answerUnsupportedChain(m,d.turnLanguage,d.messageId),messageId:d.messageId,routerDecision:d.decision,rewrite:d.rewrite}}},l=d=>d.response?M.END:"route",u=d=>{let m=d.decision?.assignments??[];if(m.length===0)return"direct";let p=m.some(g=>g.subagent!=="ai-agent"),h=(d.rewrite?.mentionedChain||c.connectedChain()||"").trim();return p&&h!==""&&!bn(h)?"unsupportedChain":m.map((g,f)=>new M.Send("subagent",{...d,assignment:g,assignmentIndex:f}))};return new M.StateGraph(_a).addNode("setup",e).addNode("contextualize",t).addNode("kb",n).addNode("route",r).addNode("direct",o).addNode("subagent",s).addNode("synthesize",a).addNode("unsupportedChain",i).addEdge(M.START,"setup").addEdge("setup","contextualize").addEdge("contextualize","kb").addConditionalEdges("kb",l,["route",M.END]).addConditionalEdges("route",u,["direct","subagent","unsupportedChain"]).addEdge("unsupportedChain",M.END).addEdge("direct",M.END).addEdge("subagent","synthesize").addEdge("synthesize",M.END).compile()}var ar=require("js-sha3");function Vn(){let c=Date.now().toString(16),e=Math.floor(Math.random()*65535).toString(16).padStart(4,"0");return(c+e).slice(-8)}var Ca="You are a helpful AI assistant. Answer the user accurately and concisely. Respond in the same language as the user.",Hn=class{llm;registry;history;summarizer;router;rewriter;subagents;synthesizer;chatGraph;systemPrompt;debug;secretKey;licenseChecked=!1;userContext={};storage;storageKey;persistHistoryEnabled;kb;kbEntries;vectorKB=null;vectorKBAutoIngested=!1;vectorKBAutoIngestPromise=null;autoIngestEnabled=!1;kbAnswerThreshold;suggestionsEnabled;historyLoaded=!1;historyLoadingPromise=null;inFlightTurn=null;historyReady;constructor(e){this.secretKey=e.secretKey,ro(e.rpcUrls),yn(e.excludeChains),this.llm=new se(e.llm),this.registry=new Fe,this.history=new Yt(e.maxHistoryMessages??50),this.summarizer=new Kt(this.llm),this.synthesizer=new Qt(this.llm),this.systemPrompt=e.systemPrompt??Ca,this.debug=e.debug??!1,this.suggestionsEnabled=e.generateSuggestions??!0,this.storage=e.storage??null,this.storageKey=e.storageKey??"keyring-agent-history",this.persistHistoryEnabled=e.persistHistory??!1,this.kbEntries=new jt(e.knowledgeBase),this.kbEntries.setLLM(this.llm);let t=e.vectorKB;t?.enabled?(t.provider?this.kb=t.provider:(this.vectorKB=new Re({url:t.url,token:t.token,namespace:t.namespace,minScore:t.minScore,defaultTopK:t.defaultTopK,debug:this.debug}),this.kb=this.vectorKB,this.autoIngestEnabled=t.autoIngest===!0),this.debug&&console.log(`[AgentCore] vector KB enabled (${t.provider?"custom provider":"Upstash"}`+(t.namespace?`, ns=${t.namespace}`:"")+")")):this.kb=this.kbEntries;let n=e.kbAnswerThreshold;if(typeof n=="number"?this.kbAnswerThreshold=n:t?.enabled&&!t.provider?this.kbAnswerThreshold=t.minScore??1.3:this.kbAnswerThreshold=.8,this.debug&&console.log(`[AgentCore] kbAnswerThreshold = ${this.kbAnswerThreshold}`),e.moralis!==!1){let u=typeof e.moralis=="object"?e.moralis:void 0;this.registry.register(new Je(u)),this.registry.register(new Ye(u)),this.registry.register(new Ze(u)),this.registry.register(new et(u)),this.registry.register(new tt(u)),this.registry.register(new Ke(u)),this.registry.register(new nt(u)),this.registry.register(new ot(u)),this.registry.register(new lt(u)),this.registry.register(new st(u)),this.registry.register(new at(u)),this.registry.register(new it(u)),this.registry.register(new rt(u)),this.registry.register(new Qe(u)),this.registry.register(new Xe(u)),this.registry.register(new je(u)),this.registry.register(new ze(u))}let r=e.nftLink;this.registry.register(new ct({url:r})),this.registry.register(new ut({url:r})),this.registry.register(new dt({url:r})),this.registry.register(new mt(e.llm));let o=e.subagents?.["pool-subgraph"]===!0;if((o?e.subagents?.pool===!0:e.subagents?.pool!==!1)&&e.uniswap!==!1){let u=typeof e.uniswap=="object"?e.uniswap:void 0;this.registry.register(new ht(u)),this.registry.register(new gt(u)),this.registry.register(new ft(u)),this.registry.register(new yt(u)),this.registry.register(new _t(u));let d=u?{isProduction:u.isProduction}:void 0;this.registry.register(new At({baseUrl:u?.baseUrl,pool:d,minProvideUsd:u?.minProvideUsd})),this.registry.register(new Pt({pool:d}))}if(o&&e.subgraph!==!1){let u=typeof e.subgraph=="object"?e.subgraph:void 0;this.registry.register(new Ct(u)),this.registry.register(new Ut(u)),this.registry.register(new Rt(u)),this.registry.register(new Et(u)),this.registry.register(new Nt(u)),this.registry.register(new It(u)),this.registry.register(new Dt(u)),this.registry.register(new pt(e.llm))}if(e.subagents?.["wallet-action"]!==!1){let u=e.moralis===!1?void 0:typeof e.moralis=="object"?e.moralis:{};this.registry.register(new Bt(u)),this.registry.register(new Ot(u)),this.registry.register(new Gt(u,{url:r})),this.registry.register(new qt(u)),this.registry.register(new Vt(u,{debug:this.debug})),this.registry.register(new Ht(u,{debug:this.debug}))}this.router=new zt(this.llm,{debug:this.debug}),this.rewriter=new Wn(this.llm,{debug:this.debug});let i=typeof e.subgraph=="object"?e.subgraph:void 0,l=$n(this.llm,this.registry,{maxToolCalls:e.maxIterations??5,debug:this.debug,linkAddLiquidity:i?.linkAddLiquidity},e.subagents);this.subagents=new Map(l.map(u=>[u.name,u])),this.chatGraph=sr(this.createGraphHost()),this.historyReady=this.loadHistory()}registerTool(e){this.registry.register(e)}registerTools(e){for(let t of e)this.registry.register(t)}unregisterTool(e){return this.registry.unregister(e)}listTools(){return this.registry.listNames()}async invokeTool(e,t,n){if(this.assertLicense(),await this.loadHistory(),!this.registry.get(e))return{answer:`Unknown tool: "${e}".`,messageId:Vn()};this.debug&&console.log(`[AgentCore] invokeTool ${e} ${JSON.stringify(t)}`);let o=n?.userMessage??`[invoke ${e}]`;this.history.add({role:"user",content:o,timestamp:Date.now()});let s=await this.registry.execute(e,t,this.userContext),a=s.data,i=s.success?a?.summary??"Done.":`Action failed: ${s.error??"unknown error"}`,l=Vn(),u=s.success&&s.ui?[this.stampLanguage(s.ui,null)]:[],d={role:"assistant",content:i,timestamp:Date.now(),subagents:["direct-invoke"],messageId:l};return u.length>0&&(d.uiActions=u),this.history.add(d),await this.persistHistory(),{answer:i,messageId:l,...u.length>0?{uiActions:u}:{}}}registerSubagent(e){this.subagents.set(e.name,e)}unregisterSubagent(e){return this.subagents.delete(e)}listSubagents(){return Array.from(this.subagents.keys())}setKnowledgeBase(e){this.kbEntries.setEntries(e),this.vectorKBAutoIngested=!1}addKnowledgeBase(e){this.kbEntries.addEntries(e),this.vectorKBAutoIngested=!1}async ingestKnowledgeBase(){if(!this.vectorKB)return{count:0};let e=this.kbEntries.getEntries();if(e.length===0)return{count:0};let t=await this.vectorKB.upsert(e);return this.vectorKBAutoIngested=!0,t}async maybeAutoIngest(e){if(!(!e||!this.vectorKB||this.vectorKBAutoIngested)){if(this.vectorKBAutoIngestPromise)return this.vectorKBAutoIngestPromise;this.vectorKBAutoIngestPromise=(async()=>{try{let{count:t}=await this.ingestKnowledgeBase();this.debug&&t>0&&console.log(`[AgentCore] auto-ingested ${t} KB entr${t===1?"y":"ies"} to vector store`)}catch(t){this.debug&&console.warn("[AgentCore] auto-ingest failed:",t)}finally{this.vectorKBAutoIngestPromise=null}})(),await this.vectorKBAutoIngestPromise}}setUserContext(e){this.userContext={...e}}getUserContext(){return{...this.userContext}}async loadHistory(){if(!this.historyLoaded){if(this.historyLoadingPromise)return this.historyLoadingPromise;this.historyLoadingPromise=this._doLoadHistory(),await this.historyLoadingPromise}}async _doLoadHistory(){if(!this.storage){this.debug&&console.log("[AgentCore] loadHistory: no storage configured"),this.historyLoaded=!0;return}if(!this.persistHistoryEnabled){this.debug&&console.log("[AgentCore] loadHistory: persistHistory disabled \u2014 starting fresh session");try{await this.storage.removeItem(this.storageKey)}catch(e){this.debug&&console.warn("[AgentCore] failed to clear stale history:",e)}this.historyLoaded=!0;return}try{let e=await this.storage.getItem(this.storageKey);if(this.debug&&console.log(`[AgentCore] loadHistory: storage key "${this.storageKey}" ${e?`has ${e.length} chars`:"is empty"}`),e){let t=JSON.parse(e);this.history.restore(t),this.debug&&console.log(`[AgentCore] Restored ${this.history.length} messages from storage`)}}catch(e){this.debug&&console.warn("[AgentCore] Failed to load history from storage:",e)}finally{this.historyLoaded=!0}}async persistHistory(){if(this.storage&&this.persistHistoryEnabled)try{let e=JSON.stringify(this.history.serialise());await this.storage.setItem(this.storageKey,e)}catch(e){this.debug&&console.warn("[AgentCore] Failed to persist history to storage:",e)}}assertLicense(){if(this.licenseChecked)return;let e="d00d67291d3c660a5034b01c0b2afbc8d4ac5552099a04f28a92d75fdb44c188";if(e&&(!this.secretKey||(0,ar.sha3_256)(this.secretKey)!==e))throw new Error("AgentCore: invalid or missing secretKey.");this.licenseChecked=!0}async chat(e,t){this.assertLicense();let n=t?.generateSuggestions??this.suggestionsEnabled,r=typeof t?.language=="string"&&t.language.trim()?t.language.trim():"";await this.loadHistory(),await this.maybeAutoIngest(this.autoIngestEnabled);let o=Date.now();this.debug&&(console.log(`
|
|
878
|
+
${"\u2500".repeat(60)}`),console.log(`[AgentCore] query: "${e}"`));let s=this.chatGraph.invoke({userMessage:e,doSuggest:n,overrideLang:r});this.inFlightTurn=s;let a;try{a=await s}finally{this.inFlightTurn===s&&(this.inFlightTurn=null)}return this.debug&&(console.log(`[AgentCore] turn done in ${Date.now()-o}ms total`),console.log(`${"\u2500".repeat(60)}
|
|
879
|
+
`)),a.response??{answer:"",messageId:Vn()}}createGraphHost(){return{debug:this.debug,addUserMessage:e=>this.addUserMessage(e),needsSummary:()=>this.history.needsSummary(),compactHistory:()=>this.compactHistory(),conversationForTurn:()=>{let e=this.history.getConversation();return e.length>0&&e[e.length-1].role==="user"?e.slice(0,-1):e},lastAssistantSubagents:e=>tr(e),generateMessageId:()=>Vn(),rewrite:(e,t,n)=>this.rewriter.rewrite(e,t,n),searchKB:e=>this.searchKB(e),formatKBContext:e=>this.formatKBContext(e),tryAnswerFromKB:(e,t,n,r)=>this.tryAnswerFromKB(e,t,n,r),subagentCards:()=>Array.from(this.subagents.values()).map(e=>e.getCard()),route:(e,t,n,r)=>this.router.route(e,t,n,this.userContext,r),connectedChain:()=>this.userContext.chain,answerUnsupportedChain:(e,t,n)=>this.answerUnsupportedChain(e,t,n),answerDirectly:(e,t,n,r,o,s)=>this.answerDirectly(e,t,n,r,o,s),runSubagent:async(e,t,n)=>{let r=this.subagents.get(e.subagent);if(!r)return this.debug&&console.log(`[AgentCore] WARN: subagent "${e.subagent}" not registered`),{subagentName:e.subagent,steps:[],finalAnswer:`Subagent "${e.subagent}" is not registered.`,toolResults:[],toolMessages:[]};let o=Date.now(),s=await r.run({query:e.query,reasoning:e.reasoning,language:n},t,this.userContext);if(this.debug){let a=s.toolResults.map(i=>i.toolName).join(", ")||"\u2014";console.log(`[AgentCore] ${e.subagent} done in ${Date.now()-o}ms | tools: ${a}`)}return s},persistToolMessages:e=>this.persistToolMessages(e),synthesiserHistory:()=>{let e=this.history.getConversation(),t=e.length>0&&e[e.length-1].role==="user"?e.slice(0,-1):e;return we(t)},mergeTrace:e=>this.mergeTrace(e),synthesise:(e,t,n,r)=>this.synthesizer.synthesise(e,t,n,r),collectUiActions:(e,t)=>this.collectUiActions(e,t),collectActionButtons:(e,t)=>this.collectActionButtons(e,t),subResultsTriggerNoSuggestions:e=>this.subResultsTriggerNoSuggestions(e),finaliseAnswer:(e,t)=>this.finaliseAnswer(e,t)}}subResultsTriggerNoSuggestions(e){for(let t of e)for(let n of t.toolResults){if(!n.success)continue;if(this.registry.get(n.toolName)?.noSuggestions===!0)return!0}return!1}capitalizeFirst(e){if(!e)return e;let t=Array.from(e);return t[0]=t[0].toLocaleUpperCase(),t.join("")}collectActionButtons(e,t){let n=new Map,r=[];for(let o of e)for(let s of o.toolResults)if(!(!s.success||!Array.isArray(s.actionButtons)))for(let a of s.actionButtons){if(!a||typeof a!="object"||typeof a.label!="string"||!a.label.trim()||typeof a.prompt!="string"||!a.prompt.trim())continue;let i=this.capitalizeFirst(a.prompt),l={label:a.label,prompt:i,...t?{language:t}:{}},u=n.get(i);u?l.label.length>u.label.length&&n.set(i,l):(n.set(i,l),r.push(i))}return r.map(o=>n.get(o))}collectUiActions(e,t){let n=[];for(let r of e)for(let o of r.toolResults)o.success&&o.ui&&typeof o.ui=="object"&&typeof o.ui.component=="string"&&n.push(this.stampLanguage(o.ui,t));if(this.debug&&n.length>0){let r=n.map(o=>`${o.component}=${o.language}`).join(", ");console.log(`[AgentCore] uiActions stamped (rewrite.language="${t??""}"): ${r}`)}return n}stampLanguage(e,t){return!t||e.language?e:{...e,language:t}}addUserMessage(e){this.history.add({role:"user",content:e,timestamp:Date.now()})}async searchKB(e){let t=await this.kb.search(e);if(this.debug)if(t.length===0)console.log(`[AgentCore] KB no hits for "${e}"`);else{let n=t.slice(0,3).map(r=>`${r.score.toFixed(3)} ${this.snippet(r.entry.question,60)}`).join(" | ");console.log(`[AgentCore] KB hits (${t.length}): ${n}`)}return t}snippet(e,t){return e.length<=t?e:e.slice(0,t-1)+"\u2026"}formatKBContext(e){return e.length===0?"":e.map((t,n)=>`[Reference ${n+1}]
|
|
880
880
|
Q: ${t.entry.question}
|
|
881
881
|
A: ${t.entry.answer}`).join(`
|
|
882
882
|
|
|
@@ -936,4 +936,4 @@ RULES:
|
|
|
936
936
|
- Suggestions must be diverse \u2014 do not repeat the same intent in different words.
|
|
937
937
|
- Use the same language as the user.
|
|
938
938
|
- Good example (pool): ["Add liquidity to USDC/WETH 0.05%", "Estimate yield for $1000 here", "Compare with 0.3% fee tier"]
|
|
939
|
-
- Bad example: ["What is a pool?", "How do pools work?", "Tell me more"] (generic, no action, no specifics)`,timestamp:0}])).text.match(/\[[\s\S]*\]/);return a?JSON.parse(a[0]).filter(l=>typeof l=="string"&&l.length>0).slice(0,3):[]}catch{return[]}}getHistory(){return this.history.getAllFull()}getDisplayHistory(){return this.history.getAllFull().filter(e=>!(e.role!=="user"&&e.role!=="assistant"||e._intermediate||e.role==="assistant"&&!e.content?.trim()))}getLastSuggestions(){let e=this.getDisplayHistory();for(let t=e.length-1;t>=0;t--){let n=e[t];if(n.role==="assistant")return n.suggestedPrompts??[]}return[]}async clearHistory(){this.history.clear(),this.historyLoaded=!0,this.historyLoadingPromise=null,await this.persistHistory()}restoreHistory(e){this.history.restore(e)}serialiseHistory(){return this.history.serialise()}async compactHistory(){this.debug&&console.log("[AgentCore] Summarizing conversation history\u2026");let e=this.history.getAll(),t=6,n=0,r=e.length;for(let m=e.length-1;m>=0;m--)if(e[m].role==="user"&&(n++,n>=t)){r=m;break}let o=e.slice(r),s=er(o,o.length),a=e.length-s.length,i=we(e.slice(0,a)),l=this.history.getSummary(),u=[];l&&u.push({role:"user",content:`[Previous context summary]: ${l}`,timestamp:0}),u.push(...i);let d=await this.summarizer.summarize(u);this.history.compactWith(d,s)}persistToolMessages(e){for(let t of e)t.toolMessages.length>0&&(this.history.addMany(t.toolMessages),this.history.add({role:"assistant",content:t.finalAnswer,_intermediate:!0,timestamp:Date.now()}),this.debug&&console.log(`[AgentCore] stored ${t.toolMessages.length} tool message(s) + finalAnswer from ${t.subagentName}`))}getLLMProvider(){return this.llm}getToolRegistry(){return this.registry}};var Ua=c=>{let e=JSON.parse(c),t=Array.isArray(e)?e:e?.entries;if(!Array.isArray(t))throw new Error("JSON must be an array or { entries: [...] }");return t.map((n,r)=>{if(!n||typeof n.question!="string"||typeof n.answer!="string")throw new Error(`Entry #${r} is missing "question" or "answer"`);return n})};async function ir(c,e){let t=c.entries??(c.json?Ua(c.json):[]);return t.length===0?{count:0}:new Re(e).upsert(t)}0&&(module.exports={AI_AGENT_TOOL_NAMES,AgentCore,ApproveTokenTool,BaseNftMessageTool,BaseSwapService,BaseTool,BaseWalletActionTool,BuyTokenTool,ChatHistory,DEFAULT_CHAIN,DEFAULT_PROVIDER,DEFAULT_RPC_BY_CHAIN,DebridgeAdapter,EstimatePoolYieldTool,GeminiProvider,GeminiSearchAiTool,HEX_TO_PANTOGRAPH,KnowledgeBase,MoralisService,NFTContractInfoTool,NFTMetadataTool,NFT_AGENT_TOOL_NAMES,OpenAddLiquidityFormTool,POOL_AGENT_TOOL_NAMES,PantographService,PoolByAddressTool,PoolDetailTool,PoolFallbackAiTool,PoolSearchTool,PoolService,PreviewAddLiquidityTool,RelayAdapter,Router,SUPPORTED_CHAINS,SUPPORTED_CHAINS_LABEL,SWAP_PROVIDER_CONFIG,SendNativeTool,SendNftTool,SendTokenTool,Subagent,SubgraphAddPoolTool,SubgraphCoinPoolPairsTool,SubgraphPoolByAddressTool,SubgraphPoolByPositionIdTool,SubgraphPoolSearchTool,SubgraphPositionDetailTool,SubgraphTrendingPoolsTool,Summarizer,SwapServiceFactory,SwapTokenTool,Synthesizer,TOKEN_AGENT_TOOL_NAMES,TRANSFER_TOPIC,TRENDING_DEFAULT_BY_HEX_CHAIN,TokenAnalyticsTool,TokenHoldersTool,TokenInfoTool,TokenScoreTool,ToolRegistry,TopGainersTool,TopPoolsTool,TransactionByHashTool,TrendingTokensTool,UNISWAP_CHAIN_SLUG,UpstashKnowledgeBase,WALLET_ACTION_AGENT_TOOL_NAMES,WALLET_AGENT_TOOL_NAMES,WalletApprovalsTool,WalletDefiPositionsTool,WalletDefiProtocolPositionsTool,WalletDefiSummaryTool,WalletHistoryTool,WalletNFTsTool,WalletNetWorthTool,WalletNftTransfersTool,WalletPnlSummaryTool,WalletPnlTool,WalletTokenBalancesTool,WalletTokenTransfersTool,ZERO_ADDRESS,buildRangePresets,buildUniswapPoolUrl,clampTick,configureSupportedChains,createAiAgent,createDefaultSubagents,createNftAgent,createPoolAgent,createTokenAgent,createWalletActionAgent,createWalletAgent,ethCallAt,ethCallByChain,getAffiliateFee,getChainMeta,getDefaultRpcUrl,getGatewayAddress,getNativeTokenInfo,getPositionManagerAddress,getProviderByChain,ingestKnowledgeBase,priceToTick,resolveRpcUrl,roundTickToSpacing,rpcCall,setRpcOverrides,swapServiceFactory,tickToPrice,toPantographChain});
|
|
939
|
+
- Bad example: ["What is a pool?", "How do pools work?", "Tell me more"] (generic, no action, no specifics)`,timestamp:0}])).text.match(/\[[\s\S]*\]/);return a?JSON.parse(a[0]).filter(l=>typeof l=="string"&&l.length>0).slice(0,3):[]}catch{return[]}}getHistory(){return this.history.getAllFull()}getDisplayHistory(){return this.history.getAllFull().filter(e=>!(e.role!=="user"&&e.role!=="assistant"||e._intermediate||e.role==="assistant"&&!e.content?.trim()))}getLastSuggestions(){let e=this.getDisplayHistory();for(let t=e.length-1;t>=0;t--){let n=e[t];if(n.role==="assistant")return n.suggestedPrompts??[]}return[]}async clearHistory(){if(this.historyLoadingPromise)try{await this.historyLoadingPromise}catch{}if(this.inFlightTurn)try{await this.inFlightTurn}catch{}this.history.clear(),this.historyLoaded=!0,this.historyLoadingPromise=null,await this.persistHistory()}restoreHistory(e){this.history.restore(e)}serialiseHistory(){return this.history.serialise()}async compactHistory(){this.debug&&console.log("[AgentCore] Summarizing conversation history\u2026");let e=this.history.getAll(),t=6,n=0,r=e.length;for(let m=e.length-1;m>=0;m--)if(e[m].role==="user"&&(n++,n>=t)){r=m;break}let o=e.slice(r),s=er(o,o.length),a=e.length-s.length,i=we(e.slice(0,a)),l=this.history.getSummary(),u=[];l&&u.push({role:"user",content:`[Previous context summary]: ${l}`,timestamp:0}),u.push(...i);let d=await this.summarizer.summarize(u);this.history.compactWith(d,s)}persistToolMessages(e){for(let t of e)t.toolMessages.length>0&&(this.history.addMany(t.toolMessages),this.history.add({role:"assistant",content:t.finalAnswer,_intermediate:!0,timestamp:Date.now()}),this.debug&&console.log(`[AgentCore] stored ${t.toolMessages.length} tool message(s) + finalAnswer from ${t.subagentName}`))}getLLMProvider(){return this.llm}getToolRegistry(){return this.registry}};var Ua=c=>{let e=JSON.parse(c),t=Array.isArray(e)?e:e?.entries;if(!Array.isArray(t))throw new Error("JSON must be an array or { entries: [...] }");return t.map((n,r)=>{if(!n||typeof n.question!="string"||typeof n.answer!="string")throw new Error(`Entry #${r} is missing "question" or "answer"`);return n})};async function ir(c,e){let t=c.entries??(c.json?Ua(c.json):[]);return t.length===0?{count:0}:new Re(e).upsert(t)}0&&(module.exports={AI_AGENT_TOOL_NAMES,AgentCore,ApproveTokenTool,BaseNftMessageTool,BaseSwapService,BaseTool,BaseWalletActionTool,BuyTokenTool,ChatHistory,DEFAULT_CHAIN,DEFAULT_PROVIDER,DEFAULT_RPC_BY_CHAIN,DebridgeAdapter,EstimatePoolYieldTool,GeminiProvider,GeminiSearchAiTool,HEX_TO_PANTOGRAPH,KnowledgeBase,MoralisService,NFTContractInfoTool,NFTMetadataTool,NFT_AGENT_TOOL_NAMES,OpenAddLiquidityFormTool,POOL_AGENT_TOOL_NAMES,PantographService,PoolByAddressTool,PoolDetailTool,PoolFallbackAiTool,PoolSearchTool,PoolService,PreviewAddLiquidityTool,RelayAdapter,Router,SUPPORTED_CHAINS,SUPPORTED_CHAINS_LABEL,SWAP_PROVIDER_CONFIG,SendNativeTool,SendNftTool,SendTokenTool,Subagent,SubgraphAddPoolTool,SubgraphCoinPoolPairsTool,SubgraphPoolByAddressTool,SubgraphPoolByPositionIdTool,SubgraphPoolSearchTool,SubgraphPositionDetailTool,SubgraphTrendingPoolsTool,Summarizer,SwapServiceFactory,SwapTokenTool,Synthesizer,TOKEN_AGENT_TOOL_NAMES,TRANSFER_TOPIC,TRENDING_DEFAULT_BY_HEX_CHAIN,TokenAnalyticsTool,TokenHoldersTool,TokenInfoTool,TokenScoreTool,ToolRegistry,TopGainersTool,TopPoolsTool,TransactionByHashTool,TrendingTokensTool,UNISWAP_CHAIN_SLUG,UpstashKnowledgeBase,WALLET_ACTION_AGENT_TOOL_NAMES,WALLET_AGENT_TOOL_NAMES,WalletApprovalsTool,WalletDefiPositionsTool,WalletDefiProtocolPositionsTool,WalletDefiSummaryTool,WalletHistoryTool,WalletNFTsTool,WalletNetWorthTool,WalletNftTransfersTool,WalletPnlSummaryTool,WalletPnlTool,WalletTokenBalancesTool,WalletTokenTransfersTool,ZERO_ADDRESS,buildRangePresets,buildUniswapPoolUrl,clampTick,configureSupportedChains,createAiAgent,createDefaultSubagents,createNftAgent,createPoolAgent,createTokenAgent,createWalletActionAgent,createWalletAgent,ethCallAt,ethCallByChain,getAffiliateFee,getChainMeta,getDefaultRpcUrl,getGatewayAddress,getNativeTokenInfo,getPositionManagerAddress,getProviderByChain,ingestKnowledgeBase,priceToTick,resolveRpcUrl,roundTickToSpacing,rpcCall,setRpcOverrides,swapServiceFactory,tickToPrice,toPantographChain});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keyring-agent-core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"description": "Core AI chat agent with multi-agent architecture, ReAct pattern, and modular tool system powered by Gemini",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"react-native": "dist/index.js",
|