@@ -7,6 +7,7 @@ import { Badge } from "@/components/ui/badge"
77import { ScrollArea } from "@/components/ui/scroll-area"
88import { Send , Bot } from "lucide-react"
99import Sidebar from "@/components/sidebar"
10+ import { useAgentStore } from "@/stores/agent-store"
1011
1112
1213interface ChatMessage {
@@ -27,38 +28,20 @@ interface AgentConfig {
2728}
2829
2930export default function ChatPage ( ) {
31+ const { agentKit, isInitialized, config } = useAgentStore ( )
3032 const [ chatInput , setChatInput ] = useState ( "" )
3133 const [ isLoading , setIsLoading ] = useState ( false )
32- const [ agentConfig , setAgentConfig ] = useState < AgentConfig | null > ( null )
3334 const [ isClient , setIsClient ] = useState ( false )
3435
3536 const [ chatMessages , setChatMessages ] = useState < ChatMessage [ ] > ( [ ] )
3637
37- // Initialize client-side state and load config
38+ // Initialize client-side state
3839 useEffect ( ( ) => {
3940 setIsClient ( true )
40-
41-
42- const sync = ( ) => {
43- const savedConfig = localStorage . getItem ( "polkadot-agent-config" )
44- if ( savedConfig ) {
45- setAgentConfig ( JSON . parse ( savedConfig ) )
46- } else {
47- setAgentConfig ( null )
48- }
49- }
50- sync ( )
51- const onStorage = ( e : StorageEvent ) => {
52- if ( e . key === "polkadot-agent-config" ) {
53- sync ( )
54- }
55- }
56- window . addEventListener ( "storage" , onStorage )
57- return ( ) => window . removeEventListener ( "storage" , onStorage )
5841 } , [ ] )
5942
6043 const handleSendMessage = async ( ) => {
61- if ( ! chatInput . trim ( ) || ! agentConfig ?. isConfigured ) return
44+ if ( ! chatInput . trim ( ) || ! isInitialized || ! agentKit ) return
6245
6346 const userMessage : ChatMessage = {
6447 id : `user-${ Date . now ( ) } -${ Math . random ( ) . toString ( 36 ) . substr ( 2 , 9 ) } ` ,
@@ -72,10 +55,46 @@ export default function ChatPage() {
7255 setIsLoading ( true )
7356
7457 try {
75- // Dynamic import to avoid SSR issues
76- const { AgentService } = await import ( "@/services/agent" )
77- const agent = AgentService . getInstance ( )
78- const result = await agent . ask ( userMessage . content )
58+ // Use the shared agentKit from Zustand store to create LangChain agent
59+ const { getLangChainTools } = await import ( "@polkadot-agent-kit/sdk" )
60+ const { AgentExecutor, createToolCallingAgent } = await import ( "langchain/agents" )
61+ const { ChatPromptTemplate } = await import ( "@langchain/core/prompts" )
62+ const { ChatOllama } = await import ( "@langchain/ollama" )
63+
64+ // Get LLM config from localStorage
65+ const llmConfig = localStorage . getItem ( "llm_config" )
66+ if ( ! llmConfig ) throw new Error ( "LLM configuration not found" )
67+
68+ const { provider, model } = JSON . parse ( llmConfig )
69+ if ( provider !== "ollama" ) {
70+ throw new Error ( "Only Ollama is supported in the browser" )
71+ }
72+
73+ const llm = new ChatOllama ( {
74+ model : model || "qwen3:latest" ,
75+ temperature : 0 ,
76+ } )
77+
78+ const tools = getLangChainTools ( agentKit )
79+ const agentPrompt = createToolCallingAgent ( {
80+ llm : llm as any ,
81+ tools : tools as any ,
82+ prompt : ChatPromptTemplate . fromMessages ( [
83+ [ "system" , "You are a helpful Polkadot assistant. Use the available tools to help users with blockchain operations." ] ,
84+ [ "placeholder" , "{chat_history}" ] ,
85+ [ "human" , "{input}" ] ,
86+ [ "placeholder" , "{agent_scratchpad}" ] ,
87+ ] ) as any ,
88+ } )
89+
90+ const agentExecutor = new AgentExecutor ( {
91+ agent : agentPrompt ,
92+ tools : tools as any ,
93+ verbose : true ,
94+ returnIntermediateSteps : true ,
95+ } )
96+
97+ const result = await agentExecutor . invoke ( { input : userMessage . content } )
7998 const outputText = typeof result . output === "string" ? result . output : JSON . stringify ( result . output , null , 2 )
8099 const aiMessage : ChatMessage = {
81100 id : ( Date . now ( ) + 1 ) . toString ( ) ,
@@ -128,12 +147,12 @@ export default function ChatPage() {
128147 </ div >
129148 < div className = "flex items-center gap-3" >
130149 < Badge
131- className = { `px-3 py-1 ${ agentConfig ?. isConfigured ? "modern-badge" : "bg-red-900/30 text-red-400 border-red-700" } ` }
150+ className = { `px-3 py-1 ${ isInitialized ? "modern-badge" : "bg-red-900/30 text-red-400 border-red-700" } ` }
132151 >
133152 < div
134- className = { `w-2 h-2 rounded-full mr-2 ${ agentConfig ?. isConfigured ? "bg-green-400 animate-pulse" : "bg-red-400" } ` }
153+ className = { `w-2 h-2 rounded-full mr-2 ${ isInitialized ? "bg-green-400 animate-pulse" : "bg-red-400" } ` }
135154 />
136- { agentConfig ?. isConfigured ? "Agent Ready" : "Configuration Required" }
155+ { isInitialized ? "Agent Ready" : "Configuration Required" }
137156 </ Badge >
138157 </ div >
139158 </ div >
@@ -196,14 +215,14 @@ export default function ChatPage() {
196215 < div className = "flex gap-4" >
197216 < Textarea
198217 placeholder = {
199- agentConfig ?. isConfigured
218+ isInitialized
200219 ? "Ask me about Polkadot, XCM, Substrate, or any Web3 topic..."
201220 : "Please configure the agent first..."
202221 }
203222 value = { chatInput }
204223 onChange = { ( e ) => setChatInput ( e . target . value ) }
205224 className = "flex-1 min-h-[70px] resize-none modern-input text-base"
206- disabled = { ! agentConfig ?. isConfigured }
225+ disabled = { ! isInitialized }
207226 onKeyDown = { ( e ) => {
208227 const ne = ( e as any ) . nativeEvent
209228 if ( ne ?. isComposing || e . keyCode === 229 ) return
@@ -217,7 +236,7 @@ export default function ChatPage() {
217236 />
218237 < Button
219238 onClick = { handleSendMessage }
220- disabled = { ! chatInput . trim ( ) || isLoading || ! agentConfig ?. isConfigured }
239+ disabled = { ! chatInput . trim ( ) || isLoading || ! isInitialized }
221240 className = "px-8 h-[70px] modern-button-primary text-base font-medium"
222241 >
223242 < Send className = "w-5 h-5" />
0 commit comments