@@ -108,11 +108,13 @@ def __init__(
108
108
# Form state
109
109
self .form_fields : Dict [str , Any ] = {}
110
110
self .collected_data : Dict [str , str ] = {}
111
- self .questions : list [FormQuestion ] = []
111
+ # Pre-initialize questions so conversation can start immediately
112
+ self .questions : list [FormQuestion ] = self ._create_questions_from_analysis ({})
112
113
self .current_question_index = 0
113
114
114
115
# Browser initialization
115
116
self .browser_init_task = None
117
+ self .browser_initializing = False
116
118
117
119
# Enhanced prompt for form filling
118
120
enhanced_prompt = system_prompt + """
@@ -137,6 +139,12 @@ def __init__(
137
139
138
140
async def _initialize_browser (self ):
139
141
"""Initialize browser and extract form fields"""
142
+ # Prevent multiple initializations
143
+ if self .browser_initializing or self .stagehand_filler :
144
+ logger .info ("🔒 Browser already initializing or initialized, skipping" )
145
+ return
146
+
147
+ self .browser_initializing = True
140
148
try :
141
149
logger .info ("🌐 Initializing browser and analyzing form" )
142
150
self .stagehand_filler = StagehandFormFiller (
@@ -159,14 +167,15 @@ async def _initialize_browser(self):
159
167
except Exception as e :
160
168
logger .warning (f"Could not extract form fields: { e } " )
161
169
162
- # Always create questions - don't depend on form extraction
163
- self .questions = self ._create_questions_from_analysis ({})
164
-
165
- logger .info (f"✅ Browser ready with { len (self .questions )} questions" )
170
+ # Questions already initialized in __init__, no need to recreate
171
+ logger .info (f"✅ Browser ready, form can now be filled" )
166
172
167
173
except Exception as e :
168
174
logger .error (f"❌ Failed to initialize browser: { e } " )
175
+ self .browser_initializing = False
169
176
raise
177
+ finally :
178
+ self .browser_initializing = False
170
179
171
180
def _create_questions_from_analysis (self , form_analysis : Dict [str , Any ]) -> list [FormQuestion ]:
172
181
"""Create questions based on form analysis"""
@@ -241,19 +250,12 @@ def _create_questions_from_analysis(self, form_analysis: Dict[str, Any]) -> list
241
250
async def _fill_form_field_async (self , field_name : str , value : str ):
242
251
"""Fill a form field asynchronously in background (non-blocking)"""
243
252
try :
244
- await self ._fill_form_field (field_name , value )
245
- except Exception as e :
246
- logger .error (f"❌ Background form filling error for { field_name } : { e } " )
247
-
248
- async def _fill_form_field (self , field_name : str , value : str ):
249
- """Fill a form field in the browser in real-time"""
250
- if not self .stagehand_filler :
251
- logger .warning ("⚠️ Browser not initialized yet" )
252
- return
253
-
254
- try :
253
+ # Wait for browser initialization if needed
254
+ if self .browser_init_task :
255
+ logger .info (f"⏳ Waiting for browser to initialize before filling { field_name } " )
256
+ await self .browser_init_task
257
+
255
258
logger .info (f"🖊️ Filling field '{ field_name } ' with: { value } in background" )
256
-
257
259
# Use StagehandFormFiller's fill_field method which handles the mapping
258
260
success = await self .stagehand_filler .fill_field (field_name , value )
259
261
@@ -264,10 +266,15 @@ async def _fill_form_field(self, field_name: str, value: str):
264
266
265
267
except Exception as e :
266
268
logger .error (f"Error filling field { field_name } : { e } " )
267
- raise # Re-raise so background task can catch it
268
-
269
+ raise # Re-raise so background task can catch it
270
+
269
271
async def _submit_form (self ):
270
272
"""Submit the completed form"""
273
+ # Wait for browser initialization if needed
274
+ if self .browser_init_task and not self .stagehand_filler :
275
+ logger .info ("⏳ Waiting for browser to initialize before submitting form" )
276
+ await self .browser_init_task
277
+
271
278
if not self .stagehand_filler :
272
279
return False
273
280
@@ -309,12 +316,10 @@ async def process_context(
309
316
AgentResponse: Text responses to the user
310
317
EndCall: Call termination when form is complete
311
318
"""
312
- # Initialize browser on first call
313
- if not self .browser_init_task :
319
+ # Initialize browser on first call (non-blocking)
320
+ if not self .browser_init_task and not self . stagehand_filler :
314
321
self .browser_init_task = asyncio .create_task (self ._initialize_browser ())
315
- # Wait for initialization to complete
316
- await self .browser_init_task
317
- logger .info (f"📝 Initialization complete. Questions loaded: { len (self .questions )} " )
322
+ logger .info ("🚀 Browser initialization started in background" )
318
323
319
324
# Get current question after initialization
320
325
current_question = self .get_current_question ()
@@ -388,7 +393,6 @@ async def process_context(
388
393
Then acknowledge their answer naturally.
389
394
"""
390
395
391
- # Enhanced config
392
396
enhanced_config = gemini_types .GenerateContentConfig (
393
397
system_instruction = self .generation_config .system_instruction + question_context ,
394
398
temperature = self .temperature ,
@@ -427,13 +431,10 @@ async def process_context(
427
431
428
432
# Store data first
429
433
self .collected_data [field_name ] = value
430
-
431
434
# Fill the form field asynchronously in background (non-blocking)
432
435
asyncio .create_task (self ._fill_form_field_async (field_name , value ))
433
-
434
436
# Log the collected data
435
437
logger .info (f"📊 Collected: { field_name } ={ value } " )
436
-
437
438
# Move to next question immediately (don't wait for form filling)
438
439
self .current_question_index += 1
439
440
field_recorded = True
0 commit comments