@@ -131,106 +131,152 @@ export default function ConfigPage() {
131131 loadChains ( )
132132 } , [ ] )
133133
134+ // Prefill from persisted store config (Polkadot) when available
135+ useEffect ( ( ) => {
136+ if ( config ) {
137+ setAgentConfig ( ( prev ) => ( {
138+ ...prev ,
139+ privateKey : config . privateKey || prev . privateKey ,
140+ keyType : ( config . keyType as string ) || prev . keyType ,
141+ chains : ( config . chains as string [ ] ) || prev . chains ,
142+ } ) )
143+ }
144+ } , [ config ] )
145+
146+ // Prefill LLM config from localStorage when available
147+ useEffect ( ( ) => {
148+ try {
149+ const saved = localStorage . getItem ( "llm_config" )
150+ if ( saved ) {
151+ const { provider, model, apiKey } = JSON . parse ( saved )
152+ setAgentConfig ( ( prev ) => ( {
153+ ...prev ,
154+ llmProvider : provider || prev . llmProvider ,
155+ llmModel : model || prev . llmModel ,
156+ apiKey : apiKey || prev . apiKey ,
157+ } ) )
158+ }
159+ } catch ( e ) {
160+ // ignore
161+ }
162+ } , [ ] )
163+
134164 const handleConfigureAgent = async ( ) => {
135165 const needsApiKey = agentConfig . llmProvider === "openai"
136- if ( ! agentConfig . llmProvider ) {
137- alert ( "Please select an LLM provider" )
138- return
166+
167+ // Determine what changed vs persisted values
168+ const prevLlmRaw = typeof window !== 'undefined' ? localStorage . getItem ( "llm_config" ) : null
169+ const prevLlm = prevLlmRaw ? JSON . parse ( prevLlmRaw ) : null
170+ const prevAgent = config
171+
172+ const llmChanged = ( ( ) => {
173+ const prevProvider = prevLlm ?. provider || ""
174+ const prevModel = prevLlm ?. model || ""
175+ const prevApiKey = prevLlm ?. apiKey || ""
176+ return (
177+ prevProvider !== agentConfig . llmProvider ||
178+ prevModel !== agentConfig . llmModel ||
179+ ( needsApiKey && ( prevApiKey || "" ) !== ( agentConfig . apiKey || "" ) )
180+ )
181+ } ) ( )
182+
183+ const chainsEqual = ( a : string [ ] = [ ] , b : string [ ] = [ ] ) => {
184+ if ( a . length !== b . length ) return false
185+ for ( let i = 0 ; i < a . length ; i ++ ) if ( a [ i ] !== b [ i ] ) return false
186+ return true
139187 }
140-
141- // For OpenAI, check if API key is provided or use environment variable
142- if ( needsApiKey ) {
143- const apiKey = agentConfig . apiKey || process . env . NEXT_PUBLIC_OPENAI_KEY
144- if ( ! apiKey ) {
145- alert ( "API key is required for OpenAI. Please provide it in the input field or set NEXT_PUBLIC_OPENAI_KEY environment variable." )
188+ const polkadotChanged = ( ( ) => {
189+ if ( ! prevAgent ) return true
190+ return (
191+ prevAgent . privateKey !== agentConfig . privateKey ||
192+ prevAgent . keyType !== ( agentConfig . keyType as any ) ||
193+ ! chainsEqual ( prevAgent . chains as any , agentConfig . chains )
194+ )
195+ } ) ( )
196+
197+ // Validate only the parts that changed
198+ if ( llmChanged ) {
199+ if ( ! agentConfig . llmProvider ) {
200+ alert ( "Please select an LLM provider" )
146201 return
147202 }
148- // Update the config with the API key (either from input or env)
149- agentConfig . apiKey = apiKey
150- }
151- if ( ! agentConfig . privateKey ) {
152- alert ( "Private key is required" )
153- return
154- }
155- if ( ! agentConfig . keyType ) {
156- alert ( "Please select a key type" )
157- return
203+ if ( needsApiKey ) {
204+ const apiKey = agentConfig . apiKey || process . env . NEXT_PUBLIC_OPENAI_KEY
205+ if ( ! apiKey ) {
206+ alert ( "API key is required for OpenAI. Provide it or set NEXT_PUBLIC_OPENAI_KEY." )
207+ return
208+ }
209+ agentConfig . apiKey = apiKey
210+ }
158211 }
159- if ( ! agentConfig . chains || agentConfig . chains . length === 0 ) {
160- alert ( "Please select at least one chain" )
161- return
212+
213+ if ( polkadotChanged ) {
214+ if ( ! agentConfig . privateKey ) {
215+ alert ( "Private key is required" )
216+ return
217+ }
218+ if ( ! agentConfig . keyType ) {
219+ alert ( "Please select a key type" )
220+ return
221+ }
222+ if ( ! agentConfig . chains || agentConfig . chains . length === 0 ) {
223+ alert ( "Please select at least one chain" )
224+ return
225+ }
162226 }
163227
164228 setInitializing ( true )
165229 setLlmConnected ( "idle" )
166230
167231 try {
168- // Save API key temporarily in localStorage (client-side only)
169- if ( needsApiKey ) {
170- localStorage . setItem ( "llm_api_key" , agentConfig . apiKey )
171- } else {
172- localStorage . removeItem ( "llm_api_key" )
173- }
232+ // If LLM changed, persist LLM config and (optionally) validate
233+ if ( llmChanged ) {
234+ localStorage . setItem ( "llm_config" , JSON . stringify ( {
235+ provider : agentConfig . llmProvider ,
236+ model : agentConfig . llmModel ,
237+ apiKey : agentConfig . llmProvider === "openai" ? agentConfig . apiKey : null
238+ } ) )
174239
175- // Save LLM config to localStorage
176- localStorage . setItem ( "llm_config" , JSON . stringify ( {
177- provider : agentConfig . llmProvider ,
178- model : agentConfig . llmModel ,
179- apiKey : agentConfig . apiKey
180- } ) )
181-
182- // Create config for Zustand store
183- const storeConfig = {
184- privateKey : agentConfig . privateKey ,
185- keyType : agentConfig . keyType as "Sr25519" | "Ed25519" ,
186- chains : agentConfig . chains ,
187- isConfigured : true
188- }
189-
190-
191- try {
192- setConfig ( storeConfig )
193-
194- // Check store state after setConfig
195- setTimeout ( ( ) => {
196- console . log ( '[ConfigPage] Store state after setConfig:' , { config, isConfigured } )
197- } , 100 )
198- } catch ( error ) {
199- console . error ( '[ConfigPage] Error calling setConfig:' , error )
240+ if ( agentConfig . llmProvider === "ollama" ) {
241+ const controller = new AbortController ( )
242+ const timeout = setTimeout ( ( ) => controller . abort ( ) , 2500 )
243+ try {
244+ const res = await fetch ( "http://127.0.0.1:11434/api/tags" , { signal : controller . signal } )
245+ setLlmConnected ( res . ok ? "ok" : "error" )
246+ } catch ( _ ) {
247+ setLlmConnected ( "error" )
248+ } finally {
249+ clearTimeout ( timeout )
250+ }
251+ } else if ( agentConfig . llmProvider === "openai" ) {
252+ try {
253+ const validation = await validateOpenAIKey ( agentConfig . apiKey )
254+ setLlmConnected ( validation . isValid ? "ok" : "error" )
255+ if ( ! validation . isValid ) {
256+ console . warn ( "OpenAI validation failed:" , validation . error )
257+ alert ( `OpenAI validation failed: ${ validation . error } ` )
258+ }
259+ } catch ( e : any ) {
260+ console . warn ( "OpenAI validation error:" , e ?. message || e )
261+ setLlmConnected ( "error" )
262+ }
263+ }
200264 }
201265
202- // Initialize agent using Zustand store
203- await initializeAgent ( )
204-
205- // Check LLM connectivity
206- if ( agentConfig . llmProvider === "ollama" ) {
207- // Try ping local Ollama
208- const controller = new AbortController ( )
209- const timeout = setTimeout ( ( ) => controller . abort ( ) , 2500 )
210- try {
211- const res = await fetch ( "http://127.0.0.1:11434/api/tags" , { signal : controller . signal } )
212- setLlmConnected ( res . ok ? "ok" : "error" )
213- } catch ( _ ) {
214- setLlmConnected ( "error" )
215- } finally {
216- clearTimeout ( timeout )
266+ // If Polkadot config changed, update store and (re)initialize agent
267+ if ( polkadotChanged ) {
268+ const storeConfig = {
269+ privateKey : agentConfig . privateKey ,
270+ keyType : agentConfig . keyType as "Sr25519" | "Ed25519" ,
271+ chains : agentConfig . chains ,
272+ isConfigured : true
217273 }
218- } else if ( agentConfig . llmProvider === "openai" ) {
219- // Validate OpenAI API key and check gpt-4o-mini availability
220- // Note: OpenAI may block browser requests (CORS). Treat failures as non-fatal
221- // for agent initialization so the Polkadot Agent can still be used.
222274 try {
223- const validation = await validateOpenAIKey ( agentConfig . apiKey )
224- setLlmConnected ( validation . isValid ? "ok" : "error" )
225- if ( ! validation . isValid ) {
226- console . warn ( "OpenAI validation failed:" , validation . error )
227- alert ( `OpenAI validation failed: ${ validation . error } ` )
228- }
229- } catch ( e : any ) {
230- console . warn ( "OpenAI validation error:" , e ?. message || e )
231- setLlmConnected ( "error" )
232- // continue without throwing to keep agent initialized
275+ setConfig ( storeConfig )
276+ } catch ( error ) {
277+ console . error ( '[ConfigPage] Error calling setConfig:' , error )
233278 }
279+ await initializeAgent ( )
234280 }
235281
236282 const updatedConfig = { ...agentConfig , isConfigured : true }
@@ -420,11 +466,7 @@ export default function ConfigPage() {
420466 < Button
421467 onClick = { handleConfigureAgent }
422468 disabled = {
423- isInitializing ||
424- ! agentConfig . llmProvider ||
425- ! agentConfig . privateKey ||
426- agentConfig . chains . length === 0 ||
427- ( agentConfig . llmProvider === "openai" && ! agentConfig . apiKey && ! process . env . NEXT_PUBLIC_OPENAI_KEY )
469+ isInitializing
428470 }
429471 className = "mt-6 sm:mt-8 px-6 sm:px-8 h-10 sm:h-12 text-sm sm:text-base font-medium modern-button-primary w-full sm:w-auto"
430472 >
0 commit comments