@@ -73,18 +73,62 @@ export class AgentSession {
7373 private agioProviderConstructor ?: AgioProviderConstructor ;
7474 public sessionInfo ?: SessionInfo ;
7575 private logger : ILogger ;
76+ private storageUnsubscribeMap = new WeakMap < IAgent , ( ) => void > ( ) ;
77+ private pendingEventSaves = new Set < Promise < void > > ( ) ;
78+
79+
80+ constructor (
81+ private server : AgentServer ,
82+ sessionId : string ,
83+ agioProviderImpl ?: AgioProviderConstructor ,
84+ sessionInfo ?: SessionInfo ,
85+ private agentOptions ?: Record < string , any > , // One-time agent initialization options
86+ ) {
87+ this . id = sessionId ;
88+ this . eventBridge = new EventStreamBridge ( ) ;
89+ this . sessionInfo = sessionInfo ;
90+ this . agioProviderConstructor = agioProviderImpl ;
91+ this . logger = getLogger ( 'AgentSession' ) ;
92+
93+ // Agent will be created and initialized in initialize() method
94+ this . agent = null as any ; // Temporary placeholder
95+ }
96+
97+
98+ async initialize ( ) {
99+ // Create and initialize agent with all wrappers
100+ // Event streams are now set up within createAndInitializeAgent before agent.initialize()
101+ this . agent = await this . createAndInitializeAgent ( this . sessionInfo ) ;
102+
103+ // Extract the storage unsubscribe function from our WeakMap
104+ const storageUnsubscribe = this . storageUnsubscribeMap . get ( this . agent ) ;
105+
106+ // Clean up the WeakMap entry
107+ this . storageUnsubscribeMap . delete ( this . agent ) ;
108+
109+ // Notify client that session is ready
110+ this . eventBridge . emit ( 'ready' , { sessionId : this . id } ) ;
111+
112+ return { storageUnsubscribe } ;
113+ }
114+
115+
76116 /**
77117 * Create event handler for storage and AGIO processing
78118 */
79119 private createEventHandler ( ) {
80120 return async ( event : AgentEventStream . Event ) => {
81121 // Save to storage if available and event should be stored
82122 if ( shouldStoreEvent ( event ) ) {
83- try {
84- await this . server . daoFactory . saveEvent ( this . id , event ) ;
85- } catch ( error ) {
86- console . error ( `Failed to save event to storage: ${ error } ` ) ;
87- }
123+ const savePromise = this . server . daoFactory . saveEvent ( this . id , event )
124+ . catch ( error => {
125+ console . error ( `Failed to save event to storage: ${ error } ` ) ;
126+ } )
127+ . finally ( ( ) => {
128+ this . pendingEventSaves . delete ( savePromise ) ;
129+ } ) ;
130+
131+ this . pendingEventSaves . add ( savePromise ) ;
88132 }
89133
90134 // Process AGIO events if collector is configured
@@ -98,23 +142,14 @@ export class AgentSession {
98142 } ;
99143 }
100144
101- /**
102- * Setup event stream connections for storage and client communication
145+ /**
146+ * Wait for all pending event saves to complete
147+ * This ensures that all events emitted during initialization are persisted before querying storage
103148 */
104- private setupEventStreams ( ) {
105- const agentEventStream = this . agent . getEventStream ( ) ;
106- const handleEvent = this . createEventHandler ( ) ;
107-
108- // Subscribe to events for storage and AGIO processing
109- const storageUnsubscribe = agentEventStream . subscribe ( handleEvent ) ;
110-
111- // Connect to event bridge for client communication
112- if ( this . unsubscribe ) {
113- this . unsubscribe ( ) ;
149+ async waitForEventSavesToComplete ( ) : Promise < void > {
150+ if ( this . pendingEventSaves . size > 0 ) {
151+ await Promise . all ( Array . from ( this . pendingEventSaves ) ) ;
114152 }
115- this . unsubscribe = this . eventBridge . connectToAgentEventStream ( agentEventStream ) ;
116-
117- return { storageUnsubscribe } ;
118153 }
119154
120155 /**
@@ -138,7 +173,7 @@ export class AgentSession {
138173 name : this . server . getCurrentAgentName ( ) ,
139174 model : this . resolveModelConfig ( sessionInfo ) ,
140175 sandboxUrl : sessionInfo ?. metadata ?. sandboxUrl ,
141- initialEvents : storedEvents , // 🎯 Pass initial events directly to agent
176+ initialEvents : storedEvents , // Pass initial events directly to agent
142177 } ;
143178
144179 // Apply runtime settings transformation if available
@@ -166,7 +201,23 @@ export class AgentSession {
166201 // Apply snapshot wrapper if enabled
167202 const wrappedAgent = this . createAgentWithSnapshot ( baseAgent , this . id ) ;
168203
204+
205+ // 🎯 Setup event stream connections BEFORE agent initialization
206+ // This ensures that any events emitted during initialize() are properly persisted
207+ const agentEventStream = wrappedAgent . getEventStream ( ) ;
208+ const handleEvent = this . createEventHandler ( ) ;
209+
210+ // Subscribe to events for storage and AGIO processing before initialization
211+ const storageUnsubscribe = agentEventStream . subscribe ( handleEvent ) ;
212+
213+ // Connect to event bridge for client communication before initialization
214+ if ( this . unsubscribe ) {
215+ this . unsubscribe ( ) ;
216+ }
217+ this . unsubscribe = this . eventBridge . connectToAgentEventStream ( agentEventStream ) ;
218+
169219 // Initialize the agent (this will automatically restore events)
220+ // Now any events emitted during initialize() will be properly persisted
170221 await wrappedAgent . initialize ( ) ;
171222
172223 // Initialize AGIO collector if provider URL is configured
@@ -265,22 +316,6 @@ export class AgentSession {
265316 return baseAgent ;
266317 }
267318
268- constructor (
269- private server : AgentServer ,
270- sessionId : string ,
271- agioProviderImpl ?: AgioProviderConstructor ,
272- sessionInfo ?: SessionInfo ,
273- private agentOptions ?: Record < string , any > , // One-time agent initialization options
274- ) {
275- this . id = sessionId ;
276- this . eventBridge = new EventStreamBridge ( ) ;
277- this . sessionInfo = sessionInfo ;
278- this . agioProviderConstructor = agioProviderImpl ;
279- this . logger = getLogger ( 'AgentSession' ) ;
280-
281- // Agent will be created and initialized in initialize() method
282- this . agent = null as any ; // Temporary placeholder
283- }
284319
285320 /**
286321 * Get the current processing status of the agent
@@ -290,19 +325,6 @@ export class AgentSession {
290325 return this . agent . status ( ) === AgentStatus . EXECUTING ;
291326 }
292327
293- async initialize ( ) {
294- // Create and initialize agent with all wrappers
295- this . agent = await this . createAndInitializeAgent ( this . sessionInfo ) ;
296-
297- // Setup event stream connections
298- const { storageUnsubscribe } = this . setupEventStreams ( ) ;
299-
300- // Notify client that session is ready
301- this . eventBridge . emit ( 'ready' , { sessionId : this . id } ) ;
302-
303- return { storageUnsubscribe } ;
304- }
305-
306328 /**
307329 * Run a query and return a strongly-typed response
308330 * This version captures errors and returns structured response objects
@@ -522,9 +544,6 @@ export class AgentSession {
522544
523545 // Create and initialize new agent with updated session info
524546 this . agent = await this . createAndInitializeAgent ( sessionInfo ) ;
525-
526- // Reconnect event streams
527- this . setupEventStreams ( ) ;
528547 } catch ( error ) {
529548 console . error ( 'Failed to recreate agent for session' , { sessionId : this . id , error } ) ;
530549 throw error ;
0 commit comments