@@ -52,11 +52,20 @@ export function assertUnreachableEvent(event: never): never {
5252/** Event names supported by {@link ExecutionEventBus}. */
5353export type ExecutionEventName = 'event' | 'finished' ;
5454
55+ /** Listener for `'event'` notifications, invoked with the published event. */
56+ export type EventListener = ( event : AgentExecutionEvent ) => void ;
57+
58+ /** Listener for `'finished'` notifications, invoked with no arguments. */
59+ export type FinishedListener = ( ) => void ;
60+
5561export interface ExecutionEventBus {
5662 publish ( event : AgentExecutionEvent ) : void ;
57- on ( eventName : ExecutionEventName , listener : ( event : AgentExecutionEvent ) => void ) : this;
58- off ( eventName : ExecutionEventName , listener : ( event : AgentExecutionEvent ) => void ) : this;
59- once ( eventName : ExecutionEventName , listener : ( event : AgentExecutionEvent ) => void ) : this;
63+ on ( eventName : 'event' , listener : EventListener ) : this;
64+ on ( eventName : 'finished' , listener : FinishedListener ) : this;
65+ off ( eventName : 'event' , listener : EventListener ) : this;
66+ off ( eventName : 'finished' , listener : FinishedListener ) : this;
67+ once ( eventName : 'event' , listener : EventListener ) : this;
68+ once ( eventName : 'finished' , listener : FinishedListener ) : this;
6069 removeAllListeners ( eventName ?: ExecutionEventName ) : this;
6170 finished ( ) : void ;
6271}
@@ -74,7 +83,6 @@ const CustomEventImpl: typeof CustomEvent =
7483 }
7584 } as typeof CustomEvent ) ;
7685
77- type Listener = ( event : AgentExecutionEvent ) => void ;
7886type WrappedListener = ( e : Event ) => void ;
7987
8088// Should always pass for 'event' type events since we control the dispatch
@@ -92,11 +100,11 @@ function isAgentExecutionCustomEvent(e: Event): e is CustomEvent<AgentExecutionE
92100 * `listenerCount`, `rawListeners`, etc. are not available.
93101 */
94102export class DefaultExecutionEventBus extends EventTarget implements ExecutionEventBus {
95- // Separate storage for each event type — both use the interface's
96- // Listener type but are invoked differently (with event payload vs. no
97- // arguments) .
98- private readonly eventListeners : Map < Listener , WrappedListener [ ] > = new Map ( ) ;
99- private readonly finishedListeners : Map < Listener , WrappedListener [ ] > = new Map ( ) ;
103+ // Separate storage so each event type can hold listeners of its own
104+ // signature: 'event' listeners receive a payload, 'finished' listeners
105+ // are invoked with no arguments.
106+ private readonly eventListeners : Map < EventListener , WrappedListener [ ] > = new Map ( ) ;
107+ private readonly finishedListeners : Map < FinishedListener , WrappedListener [ ] > = new Map ( ) ;
100108
101109 publish ( event : AgentExecutionEvent ) : void {
102110 this . dispatchEvent ( new CustomEventImpl ( 'event' , { detail : event } ) ) ;
@@ -106,29 +114,35 @@ export class DefaultExecutionEventBus extends EventTarget implements ExecutionEv
106114 this . dispatchEvent ( new Event ( 'finished' ) ) ;
107115 }
108116
109- on ( eventName : ExecutionEventName , listener : ( event : AgentExecutionEvent ) => void ) : this {
117+ on ( eventName : 'event' , listener : EventListener ) : this;
118+ on ( eventName : 'finished' , listener : FinishedListener ) : this;
119+ on ( eventName : ExecutionEventName , listener : EventListener | FinishedListener ) : this {
110120 if ( eventName === 'event' ) {
111- this . addEventListenerInternal ( listener ) ;
121+ this . addEventListenerInternal ( listener as EventListener ) ;
112122 } else {
113- this . addFinishedListenerInternal ( listener ) ;
123+ this . addFinishedListenerInternal ( listener as FinishedListener ) ;
114124 }
115125 return this ;
116126 }
117127
118- off ( eventName : ExecutionEventName , listener : ( event : AgentExecutionEvent ) => void ) : this {
128+ off ( eventName : 'event' , listener : EventListener ) : this;
129+ off ( eventName : 'finished' , listener : FinishedListener ) : this;
130+ off ( eventName : ExecutionEventName , listener : EventListener | FinishedListener ) : this {
119131 if ( eventName === 'event' ) {
120- this . removeEventListenerInternal ( listener ) ;
132+ this . removeEventListenerInternal ( listener as EventListener ) ;
121133 } else {
122- this . removeFinishedListenerInternal ( listener ) ;
134+ this . removeFinishedListenerInternal ( listener as FinishedListener ) ;
123135 }
124136 return this ;
125137 }
126138
127- once ( eventName : ExecutionEventName , listener : ( event : AgentExecutionEvent ) => void ) : this {
139+ once ( eventName : 'event' , listener : EventListener ) : this;
140+ once ( eventName : 'finished' , listener : FinishedListener ) : this;
141+ once ( eventName : ExecutionEventName , listener : EventListener | FinishedListener ) : this {
128142 if ( eventName === 'event' ) {
129- this . addEventListenerOnceInternal ( listener ) ;
143+ this . addEventListenerOnceInternal ( listener as EventListener ) ;
130144 } else {
131- this . addFinishedListenerOnceInternal ( listener ) ;
145+ this . addFinishedListenerOnceInternal ( listener as FinishedListener ) ;
132146 }
133147 return this ;
134148 }
@@ -157,9 +171,9 @@ export class DefaultExecutionEventBus extends EventTarget implements ExecutionEv
157171
158172 // Listener tracking helpers.
159173
160- private trackListener (
161- listenerMap : Map < Listener , WrappedListener [ ] > ,
162- listener : Listener ,
174+ private trackListener < L > (
175+ listenerMap : Map < L , WrappedListener [ ] > ,
176+ listener : L ,
163177 wrapped : WrappedListener
164178 ) : void {
165179 const existing = listenerMap . get ( listener ) ;
@@ -170,9 +184,9 @@ export class DefaultExecutionEventBus extends EventTarget implements ExecutionEv
170184 }
171185 }
172186
173- private untrackWrappedListener (
174- listenerMap : Map < Listener , WrappedListener [ ] > ,
175- listener : Listener ,
187+ private untrackWrappedListener < L > (
188+ listenerMap : Map < L , WrappedListener [ ] > ,
189+ listener : L ,
176190 wrapped : WrappedListener
177191 ) : void {
178192 const wrappedList = listenerMap . get ( listener ) ;
@@ -189,7 +203,7 @@ export class DefaultExecutionEventBus extends EventTarget implements ExecutionEv
189203
190204 // 'event' listeners.
191205
192- private addEventListenerInternal ( listener : Listener ) : void {
206+ private addEventListenerInternal ( listener : EventListener ) : void {
193207 const wrapped : WrappedListener = ( e : Event ) => {
194208 if ( ! isAgentExecutionCustomEvent ( e ) ) {
195209 throw new Error ( 'Internal error: expected CustomEvent for "event" type' ) ;
@@ -201,7 +215,7 @@ export class DefaultExecutionEventBus extends EventTarget implements ExecutionEv
201215 this . addEventListener ( 'event' , wrapped ) ;
202216 }
203217
204- private removeEventListenerInternal ( listener : Listener ) : void {
218+ private removeEventListenerInternal ( listener : EventListener ) : void {
205219 const wrappedList = this . eventListeners . get ( listener ) ;
206220 if ( wrappedList && wrappedList . length > 0 ) {
207221 const wrapped = wrappedList . pop ( ) ! ;
@@ -212,7 +226,7 @@ export class DefaultExecutionEventBus extends EventTarget implements ExecutionEv
212226 }
213227 }
214228
215- private addEventListenerOnceInternal ( listener : Listener ) : void {
229+ private addEventListenerOnceInternal ( listener : EventListener ) : void {
216230 const wrapped : WrappedListener = ( e : Event ) => {
217231 if ( ! isAgentExecutionCustomEvent ( e ) ) {
218232 throw new Error ( 'Internal error: expected CustomEvent for "event" type' ) ;
@@ -225,11 +239,10 @@ export class DefaultExecutionEventBus extends EventTarget implements ExecutionEv
225239 this . addEventListener ( 'event' , wrapped , { once : true } ) ;
226240 }
227241
228- // 'finished' listeners. The interface declares listeners as taking an
229- // `AgentExecutionEvent`, but for 'finished' they're invoked with no
230- // arguments (matching EventEmitter behaviour).
242+ // 'finished' listeners. Invoked with no arguments; the interface
243+ // declares them as `FinishedListener` so callers get a precise type.
231244
232- private addFinishedListenerInternal ( listener : Listener ) : void {
245+ private addFinishedListenerInternal ( listener : FinishedListener ) : void {
233246 const wrapped : WrappedListener = ( ) => {
234247 listener . call ( this ) ;
235248 } ;
@@ -238,7 +251,7 @@ export class DefaultExecutionEventBus extends EventTarget implements ExecutionEv
238251 this . addEventListener ( 'finished' , wrapped ) ;
239252 }
240253
241- private removeFinishedListenerInternal ( listener : Listener ) : void {
254+ private removeFinishedListenerInternal ( listener : FinishedListener ) : void {
242255 const wrappedList = this . finishedListeners . get ( listener ) ;
243256 if ( wrappedList && wrappedList . length > 0 ) {
244257 const wrapped = wrappedList . pop ( ) ! ;
@@ -249,7 +262,7 @@ export class DefaultExecutionEventBus extends EventTarget implements ExecutionEv
249262 }
250263 }
251264
252- private addFinishedListenerOnceInternal ( listener : Listener ) : void {
265+ private addFinishedListenerOnceInternal ( listener : FinishedListener ) : void {
253266 const wrapped : WrappedListener = ( ) => {
254267 this . untrackWrappedListener ( this . finishedListeners , listener , wrapped ) ;
255268 listener . call ( this ) ;
0 commit comments