11import { ChatPromptTemplate } from "@langchain/core/prompts" ;
22import type { StructuredToolInterface } from "@langchain/core/tools" ;
3- import { tool } from "@langchain/core/tools" ;
3+ import { DynamicStructuredTool } from "@langchain/core/tools" ;
44import { ChatOllama } from "@langchain/ollama" ;
55import { PolkadotAgentKit } from "@polkadot-agent-kit/sdk" ;
66import { AgentExecutor , createToolCallingAgent } from "langchain/agents" ;
7- import type { BaseChatModel } from "langchain/chat_models/base" ;
87import { z } from "zod" ;
98
109import type { AgentMetadata } from "../../types/agent" ;
@@ -13,202 +12,174 @@ import { logger } from "../../utils/logger";
1312
1413// Wrap PolkadotAgentKit tools as LangChain-compatible tools
1514function wrapBalanceTool ( agentKit : PolkadotAgentKit ) {
16- return tool (
17- async ( { chain } ) => {
15+ return new DynamicStructuredTool ( {
16+ name : "getNativeBalanceTool" ,
17+ description : "Get native token balance for an address on a specific chain" ,
18+ schema : z . object ( {
19+ chain : z . string ( ) . describe ( "The chain to check balance on" )
20+ } ) ,
21+ func : async ( { chain } : { chain : string } ) => {
1822 const tool = agentKit . getNativeBalanceTool ( ) ;
1923 const result = await tool . call ( { chain } ) ;
2024 return JSON . stringify ( result ) ;
21- } ,
22- {
23- name : "getNativeBalanceTool" ,
24- description :
25- "Get native token balance for an address on a specific chain" ,
26- schema : z . object ( {
27- chain : z . string ( ) . describe ( "The chain to check balance on" ) ,
28- } ) ,
29- } ,
30- ) ;
25+ }
26+ } ) ;
3127}
3228
3329function wrapTransferTool ( agentKit : PolkadotAgentKit ) {
34- return tool (
35- async ( { to, amount, chain } ) => {
30+ return new DynamicStructuredTool ( {
31+ name : "transferNativeTool" ,
32+ description : "Transfer native tokens to an address on a specific chain" ,
33+ schema : z . object ( {
34+ to : z . string ( ) ,
35+ amount : z . string ( ) ,
36+ chain : z . string ( )
37+ } ) ,
38+ func : async ( { to, amount, chain } : { to : string , amount : string , chain : string } ) => {
3639 const tool = agentKit . transferNativeTool ( ) ;
3740 const result = await tool . call ( { to, amount, chain } ) ;
3841 return JSON . stringify ( result ) ;
39- } ,
40- {
41- name : "transferNativeTool" ,
42- description : "Transfer native tokens to an address on a specific chain" ,
43- schema : z . object ( {
44- to : z . string ( ) ,
45- amount : z . string ( ) ,
46- chain : z . string ( ) ,
47- } ) ,
48- } ,
49- ) ;
42+ }
43+ } ) ;
5044}
5145
5246function wrapXcmTool ( agentKit : PolkadotAgentKit ) {
53- return tool (
54- async ( { to, amount, sourceChain, destChain } ) => {
47+ return new DynamicStructuredTool ( {
48+ name : "xcmTransferNativeTool" ,
49+ description : "Transfer native tokens across chains using XCM" ,
50+ schema : z . object ( {
51+ to : z . string ( ) ,
52+ amount : z . string ( ) ,
53+ sourceChain : z . string ( ) ,
54+ destChain : z . string ( )
55+ } ) ,
56+ func : async ( { to, amount, sourceChain, destChain } : { to : string , amount : string , sourceChain : string , destChain : string } ) => {
5557 const tool = agentKit . xcmTransferNativeTool ( ) ;
5658 const result = await tool . call ( { to, amount, sourceChain, destChain } ) ;
5759 return JSON . stringify ( result ) ;
58- } ,
59- {
60- name : "xcmTransferNativeTool" ,
61- description : "Transfer native tokens across chains using XCM" ,
62- schema : z . object ( {
63- to : z . string ( ) ,
64- amount : z . string ( ) ,
65- sourceChain : z . string ( ) ,
66- destChain : z . string ( ) ,
67- } ) ,
68- } ,
69- ) ;
60+ }
61+ } ) ;
7062}
7163
7264function wrapInitializeChainApiTool ( agentKit : PolkadotAgentKit ) {
73- return tool (
74- async ( { chain } ) => {
65+ return new DynamicStructuredTool ( {
66+ name : "initializeChainApiTool" ,
67+ description : "Initialize a chain API when it's not available. Use this when other tools fail due to chain not being initialized." ,
68+ schema : z . object ( {
69+ chainId : z . string ( ) . describe ( "The chain ID to initialize (e.g., 'west', 'polkadot', 'hydra')" )
70+ } ) ,
71+ func : async ( { chain } : { chain : string } ) => {
7572 const tool = agentKit . getInitializeChainApiTool ( ) ;
7673 const result = await tool . call ( { chain } ) ;
7774 return JSON . stringify ( result ) ;
78- } ,
79- {
80- name : "initializeChainApiTool" ,
81- description :
82- "Initialize a chain API when it's not available. Use this when other tools fail due to chain not being initialized." ,
83- schema : z . object ( {
84- chain : z
85- . string ( )
86- . describe (
87- "The chain ID to initialize (e.g., 'west', 'polkadot', 'hydra')" ,
88- ) ,
89- } ) ,
90- } ,
91- ) ;
75+ }
76+ } ) ;
9277}
9378
9479function wrapSwapTokensTool ( agentKit : PolkadotAgentKit ) {
95- return tool (
96- async ( { from, to, currencyFrom, currencyTo, amount, receiver } ) => {
80+ return new DynamicStructuredTool ( {
81+ name : "SwapTokensTool" ,
82+ description : "Swap tokens across different chains using the Hydration DEX" ,
83+ schema : z . object ( {
84+ from : z . string ( ) . describe ( "The source chain ID where the swap originates (e.g., 'Polkadot', 'AssetHubPolkadot', 'Hydra', 'Kusama')" ) ,
85+ to : z . string ( ) . describe ( "The destination chain ID where the swap completes (e.g., 'Polkadot', 'AssetHubPolkadot', 'Hydra', 'Kusama')" ) ,
86+ currencyFrom : z . string ( ) . describe ( "The symbol of the token to swap from (e.g., 'DOT', 'KSM', 'HDX')" ) ,
87+ currencyTo : z . string ( ) . describe ( "The symbol of the token to swap to (e.g., 'DOT', 'KSM', 'HDX', 'USDT')" ) ,
88+ amount : z . string ( ) . describe ( "The amount of the source token to swap" ) ,
89+ receiver : z . string ( ) . optional ( ) . describe ( "The receiver address for the swap" )
90+ } ) ,
91+ func : async ( { from, to, currencyFrom, currencyTo, amount, receiver } : { from : string , to : string , currencyFrom : string , currencyTo : string , amount : string , receiver : string | undefined } ) => {
9792 const tool = agentKit . swapTokensTool ( ) ;
98- const result = await tool . call ( {
99- from,
100- to,
101- currencyFrom,
102- currencyTo,
103- amount,
104- receiver,
105- } ) ;
93+ const result = await tool . call ( { from, to, currencyFrom, currencyTo, amount, receiver } ) ;
10694 return JSON . stringify ( result ) ;
107- } ,
108- {
109- name : "SwapTokensTool" ,
110- description :
111- "Swap tokens across different chains using the Hydration DEX" ,
112- schema : z . object ( {
113- from : z
114- . string ( )
115- . describe (
116- "The source chain ID where the swap originates (e.g., 'Polkadot', 'AssetHubPolkadot', 'Hydra', 'Kusama')" ,
117- ) ,
118- to : z
119- . string ( )
120- . describe (
121- "The destination chain ID where the swap completes (e.g., 'Polkadot', 'AssetHubPolkadot', 'Hydra', 'Kusama')" ,
122- ) ,
123- currencyFrom : z
124- . string ( )
125- . describe (
126- "The symbol of the token to swap from (e.g., 'DOT', 'KSM', 'HDX')" ,
127- ) ,
128- currencyTo : z
129- . string ( )
130- . describe (
131- "The symbol of the token to swap to (e.g., 'DOT', 'KSM', 'HDX', 'USDT')" ,
132- ) ,
133- amount : z . string ( ) . describe ( "The amount of the source token to swap" ) ,
134- receiver : z
135- . string ( )
136- . optional ( )
137- . describe ( "The receiver address for the swap" ) ,
138- } ) ,
139- } ,
140- ) ;
95+ }
96+ } ) ;
14197}
14298
14399function wrapJoinPoolTool ( agentKit : PolkadotAgentKit ) {
144- return tool (
145- async ( { amount, chain } ) => {
100+ return new DynamicStructuredTool ( {
101+ name : "joinPoolTool" ,
102+ description : "Join a nomination pool for staking" ,
103+ schema : z . object ( {
104+ amount : z . string ( ) . describe ( "The amount of tokens to join the pool" ) ,
105+ chain : z . string ( ) . describe ( "The chain to join the pool on" )
106+ } ) ,
107+ func : async ( { amount, chain } : { amount : string , chain : string } ) => {
146108 const tool = agentKit . joinPoolTool ( ) ;
147109 const result = await tool . call ( { amount, chain } ) ;
148110 return JSON . stringify ( result ) ;
149- } ,
150- {
151- name : "joinPoolTool" ,
152- description : "Join a nomination pool for staking" ,
153- schema : z . object ( {
154- amount : z . string ( ) . describe ( "The amount of tokens to join the pool" ) ,
155- chain : z . string ( ) . describe ( "The chain to join the pool on" ) ,
111+ }
112+ } ) ;
113+ }
114+
115+ function wrapBondExtraTool ( agentKit : PolkadotAgentKit ) {
116+ return new DynamicStructuredTool ( {
117+ name : "bondExtraTool" ,
118+ description : "Bond extra tokens to a nomination pool. Use 'FreeBalance' to bond a specific amount from your wallet, or 'Rewards' to re-stake your earned rewards." ,
119+ schema : z . discriminatedUnion ( "type" , [
120+ z . object ( {
121+ type : z . literal ( "FreeBalance" ) ,
122+ amount : z . string ( ) . describe ( "The amount of tokens to bond from your free balance." ) ,
123+ chain : z . string ( ) . describe ( "The chain to bond extra tokens on." ) ,
124+ } ) ,
125+ z . object ( {
126+ type : z . literal ( "Rewards" ) ,
127+ chain : z . string ( ) . describe ( "The chain to bond rewards on." ) ,
156128 } ) ,
157- } ,
158- ) ;
129+ ] ) ,
130+ func : async ( input ) => {
131+ const tool = agentKit . bondExtraTool ( ) ;
132+ const result = await tool . call ( input ) ;
133+ return JSON . stringify ( result ) ;
134+ }
135+ } ) ;
159136}
160137
161138function wrapUnbondTool ( agentKit : PolkadotAgentKit ) {
162- return tool (
163- async ( { amount, chain } ) => {
139+ return new DynamicStructuredTool ( {
140+ name : "unbondTool" ,
141+ description : "Unbond tokens from a nomination pool" ,
142+ schema : z . object ( {
143+ amount : z . string ( ) . describe ( "The amount of tokens to unbond" ) ,
144+ chain : z . string ( ) . describe ( "The chain to unbond tokens on" )
145+ } ) ,
146+ func : async ( { amount, chain } : { amount : string , chain : string } ) => {
164147 const tool = agentKit . unbondTool ( ) ;
165148 const result = await tool . call ( { amount, chain } ) ;
166149 return JSON . stringify ( result ) ;
167- } ,
168- {
169- name : "unbondTool" ,
170- description : "Unbond tokens from a nomination pool" ,
171- schema : z . object ( {
172- amount : z . string ( ) . describe ( "The amount of tokens to unbond" ) ,
173- chain : z . string ( ) . describe ( "The chain to unbond tokens on" ) ,
174- } ) ,
175- } ,
176- ) ;
150+ }
151+ } ) ;
177152}
178153
179154function wrapWithdrawUnbondedTool ( agentKit : PolkadotAgentKit ) {
180- return tool (
181- async ( { slashingSpans, chain } ) => {
155+ return new DynamicStructuredTool ( {
156+ name : "withdrawUnbondedTool" ,
157+ description : "Withdraw unbonded tokens from a nomination pool" ,
158+ schema : z . object ( {
159+ slashingSpans : z . string ( ) . describe ( "The number of slashing spans" ) ,
160+ chain : z . string ( ) . describe ( "The chain to withdraw unbonded tokens on" )
161+ } ) ,
162+ func : async ( { slashingSpans, chain } : { slashingSpans : string , chain : string } ) => {
182163 const tool = agentKit . withdrawUnbondedTool ( ) ;
183164 const result = await tool . call ( { slashingSpans, chain } ) ;
184165 return JSON . stringify ( result ) ;
185- } ,
186- {
187- name : "withdrawUnbondedTool" ,
188- description : "Withdraw unbonded tokens from a nomination pool" ,
189- schema : z . object ( {
190- slashingSpans : z . string ( ) . describe ( "The number of slashing spans" ) ,
191- chain : z . string ( ) . describe ( "The chain to withdraw unbonded tokens on" ) ,
192- } ) ,
193- } ,
194- ) ;
166+ }
167+ } ) ;
195168}
196169
197170function wrapClaimRewardsTool ( agentKit : PolkadotAgentKit ) {
198- return tool (
199- async ( { chain } ) => {
171+ return new DynamicStructuredTool ( {
172+ name : "claimRewardsTool" ,
173+ description : "Claim rewards from a nomination pool" ,
174+ schema : z . object ( {
175+ chain : z . string ( ) . describe ( "The chain to claim rewards on" )
176+ } ) ,
177+ func : async ( { chain } : { chain : string } ) => {
200178 const tool = agentKit . claimRewardsTool ( ) ;
201179 const result = await tool . call ( { chain } ) ;
202180 return JSON . stringify ( result ) ;
203- } ,
204- {
205- name : "claimRewardsTool" ,
206- description : "Claim rewards from a nomination pool" ,
207- schema : z . object ( {
208- chain : z . string ( ) . describe ( "The chain to claim rewards on" ) ,
209- } ) ,
210- } ,
211- ) ;
181+ }
182+ } ) ;
212183}
213184
214185export class PolkadotCLIAgent {
@@ -255,6 +226,7 @@ export class PolkadotCLIAgent {
255226
256227 if ( this . agent . tools . includes ( "staking" ) ) {
257228 tools . push ( wrapJoinPoolTool ( this . agentKit ) ) ;
229+ tools . push ( wrapBondExtraTool ( this . agentKit ) ) ;
258230 tools . push ( wrapUnbondTool ( this . agentKit ) ) ;
259231 tools . push ( wrapWithdrawUnbondedTool ( this . agentKit ) ) ;
260232 tools . push ( wrapClaimRewardsTool ( this . agentKit ) ) ;
@@ -269,7 +241,8 @@ export class PolkadotCLIAgent {
269241
270242 // Create the agent with system prompt
271243 const agentPrompt = createToolCallingAgent ( {
272- llm : llm as unknown as BaseChatModel ,
244+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
245+ llm : llm as any ,
273246
274247 tools : tools as any ,
275248
@@ -288,6 +261,8 @@ export class PolkadotCLIAgent {
288261 verbose : true ,
289262 } ) ;
290263
264+ logger . info ( "This agent executor:" , this . agentExecutor ) ;
265+
291266 this . initialized = true ;
292267 } catch ( error ) {
293268 logger . error (
0 commit comments