@slashfi/agents-sdk 0.25.1 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/events.ts CHANGED
@@ -10,26 +10,48 @@
10
10
  * Filtering happens in the callback, not the API.
11
11
  */
12
12
 
13
+ import type { CallAgentRequest, CallAgentResponse } from "./types.js";
13
14
  // =============================================================================
14
15
  // Event Types
15
16
  // =============================================================================
16
17
 
17
18
  /**
18
- * All supported event types.
19
+ * Built-in system event types managed by the runtime.
19
20
  */
20
- export type EventType =
21
+ export type SystemEventType =
21
22
  | "tool/call"
22
23
  | "tool/result"
23
24
  | "tool/error"
24
25
  | "step"
25
- | "invoke";
26
+ | "invoke"
27
+ | "call";
28
+
29
+ /**
30
+ * Augmentable map for custom event types. Consumers extend this
31
+ * via declaration merging to register their own events:
32
+ *
33
+ * ```ts
34
+ * declare module '@slashfi/agents-sdk' {
35
+ * interface CustomEventMap {
36
+ * 'callback/resolve': MyCallbackResolveEvent;
37
+ * }
38
+ * }
39
+ * ```
40
+ */
41
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
42
+ export interface CustomEventMap {}
43
+
44
+ /**
45
+ * All event types — system + consumer-defined custom events.
46
+ */
47
+ export type EventType = SystemEventType | Extract<keyof CustomEventMap, string>;
26
48
 
27
49
  /**
28
50
  * Base event shape — every event has these fields.
29
51
  */
30
52
  export interface BaseEvent {
31
53
  /** Event type */
32
- type: EventType;
54
+ type: string;
33
55
  /** Agent path (e.g., '/agents/atlas-slack') */
34
56
  agentPath: string;
35
57
  /** Timestamp */
@@ -102,31 +124,55 @@ export interface InvokeEvent extends BaseEvent {
102
124
  }
103
125
 
104
126
  /**
105
- * Union of all event types.
127
+ * Event emitted when a call_agent request is received.
128
+ * Call `resolve(response)` to short-circuit the default handler.
129
+ * If no listener resolves, the default call handler runs.
130
+ */
131
+ export interface CallEvent extends BaseEvent {
132
+ type: "call";
133
+ /** The incoming call_agent request */
134
+ request: CallAgentRequest;
135
+ /** Run the default call handler and return its result.
136
+ * Optionally pass a modified request to override the original. */
137
+ next(request?: CallAgentRequest): Promise<CallAgentResponse>;
138
+ /** Short-circuit with a response (skips default handler if next() not called) */
139
+ resolve(response: CallAgentResponse): void;
140
+ }
141
+
142
+ /**
143
+ * Union of all built-in event types.
106
144
  */
107
145
  export type AgentEvent =
108
146
  | ToolCallEvent
109
147
  | ToolResultEvent
110
148
  | ToolErrorEvent
111
149
  | StepEvent
112
- | InvokeEvent;
150
+ | InvokeEvent
151
+ | CallEvent;
113
152
 
114
153
  /**
115
- * Map from event type string to event interface.
154
+ * Map from system event type string to event interface.
116
155
  */
117
- export interface EventMap {
156
+ export interface SystemEventMap {
118
157
  "tool/call": ToolCallEvent;
119
158
  "tool/result": ToolResultEvent;
120
159
  "tool/error": ToolErrorEvent;
121
160
  step: StepEvent;
122
161
  invoke: InvokeEvent;
162
+ call: CallEvent;
123
163
  }
124
164
 
165
+ /**
166
+ * Map from event type string to event interface.
167
+ * Combines system events with custom events.
168
+ */
169
+ export interface EventMap extends SystemEventMap, CustomEventMap {}
170
+
125
171
  /**
126
172
  * Callback for a specific event type.
127
173
  */
128
174
  export type EventCallback<T extends EventType = EventType> = (
129
- event: EventMap[T],
175
+ event: T extends keyof EventMap ? EventMap[T] : BaseEvent,
130
176
  ) => void | Promise<void>;
131
177
 
132
178
  // =============================================================================
@@ -136,7 +182,7 @@ export type EventCallback<T extends EventType = EventType> = (
136
182
  /**
137
183
  * Listener entry — callback + optional scope for agent/tool filtering.
138
184
  */
139
- interface ListenerEntry {
185
+ export interface ListenerEntry {
140
186
  eventType: EventType;
141
187
  callback: EventCallback<EventType>;
142
188
  /** If set, only fire for events matching this agent path */
@@ -161,7 +207,7 @@ export interface EventBus {
161
207
  * Listeners are called in registration order.
162
208
  * Errors in listeners are caught and logged, never propagated.
163
209
  */
164
- emit(event: AgentEvent): Promise<void>;
210
+ emit(event: AgentEvent | (BaseEvent & { type: string })): Promise<void>;
165
211
 
166
212
  /**
167
213
  * Register a scoped listener (used internally by agent.on / tool.on).
@@ -202,7 +248,9 @@ export function createEventBus(): EventBus {
202
248
  });
203
249
  }
204
250
 
205
- async function emit(event: AgentEvent): Promise<void> {
251
+ async function emit(
252
+ event: AgentEvent | (BaseEvent & { type: string }),
253
+ ): Promise<void> {
206
254
  for (const listener of listeners) {
207
255
  // Match event type
208
256
  if (listener.eventType !== event.type) continue;
@@ -222,7 +270,7 @@ export function createEventBus(): EventBus {
222
270
  }
223
271
 
224
272
  try {
225
- await listener.callback(event);
273
+ await listener.callback(event as never);
226
274
  } catch (err) {
227
275
  // Never propagate listener errors — log and continue
228
276
  console.error(
package/src/index.ts CHANGED
@@ -112,14 +112,20 @@ export { createEventBus } from "./events.js";
112
112
  export type {
113
113
  EventBus,
114
114
  EventType,
115
+ SystemEventType,
116
+ CustomEventMap,
115
117
  EventCallback,
116
118
  AgentEvent,
119
+ BaseEvent,
117
120
  ToolCallEvent,
118
121
  ToolResultEvent,
119
122
  ToolErrorEvent,
120
123
  StepEvent,
121
124
  InvokeEvent,
125
+ CallEvent,
122
126
  EventMap,
127
+ SystemEventMap,
128
+ ListenerEntry,
123
129
  } from "./events.js";
124
130
 
125
131
  // Server
package/src/registry.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import { dirname, resolve } from "node:path";
8
- import type { AgentEvent, EventCallback, EventType } from "./events.js";
8
+ import type { AgentEvent, BaseEvent, CustomEventMap, EventCallback, EventType } from "./events.js";
9
9
  import { createEventBus } from "./events.js";
10
10
  import type { SerializedAgentDefinition } from "./serialized.js";
11
11
  import type {
@@ -55,6 +55,7 @@ export interface RegistryMiddleware {
55
55
  registry: AgentRegistry;
56
56
  },
57
57
  ) => Promise<CallAgentLoadResponse>;
58
+
58
59
  }
59
60
 
60
61
  /**
@@ -97,6 +98,21 @@ export interface AgentRegistry {
97
98
 
98
99
  /** Emit an event to all listeners. Used by the runtime to push lifecycle events. */
99
100
  emit(event: AgentEvent): Promise<void>;
101
+
102
+ /**
103
+ * Trigger a custom event. Only accepts custom event types (not system events
104
+ * like tool/call, tool/result, etc. which are managed by the runtime).
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * // After augmenting CustomEventMap:
109
+ * registry.trigger('callback/resolve', { type: 'callback/resolve', ... });
110
+ * ```
111
+ */
112
+ trigger<T extends Extract<keyof CustomEventMap, string>>(
113
+ eventType: T,
114
+ event: CustomEventMap[T] & BaseEvent,
115
+ ): Promise<void>;
100
116
  }
101
117
 
102
118
  // ============================================
@@ -412,7 +428,7 @@ export function createAgentRegistry(
412
428
  };
413
429
  }
414
430
 
415
- const registry: AgentRegistry = {
431
+ const registryObj: AgentRegistry = {
416
432
  register(input: AgentDefinition | SerializedAgentDefinition): void {
417
433
  let agent: AgentDefinition;
418
434
  if (isSerialized(input)) {
@@ -473,7 +489,42 @@ export function createAgentRegistry(
473
489
  await eventBus.emit(event);
474
490
  },
475
491
 
492
+ async trigger<T extends Extract<keyof CustomEventMap, string>>(
493
+ _eventType: T,
494
+ event: CustomEventMap[T] & BaseEvent,
495
+ ): Promise<void> {
496
+ await eventBus.emit(event as never);
497
+ },
498
+
476
499
  async call(request: CallAgentRequest): Promise<CallAgentResponse> {
500
+ // Emit call event — listeners can next()/resolve() to control flow
501
+ let intercepted: CallAgentResponse | undefined;
502
+ let nextCalled = false;
503
+ let nextResult: CallAgentResponse | undefined;
504
+ await eventBus.emit({
505
+ type: "call",
506
+ agentPath: request.path,
507
+ timestamp: Date.now(),
508
+ request,
509
+ async next(overrideRequest?: CallAgentRequest) {
510
+ nextCalled = true;
511
+ nextResult = await callInternal(overrideRequest ?? request);
512
+ return nextResult;
513
+ },
514
+ resolve(response: CallAgentResponse) {
515
+ intercepted = response;
516
+ },
517
+ });
518
+ if (intercepted) return intercepted;
519
+ if (nextCalled) return nextResult!;
520
+ // No listener engaged — run default
521
+ return callInternal(request);
522
+ },
523
+ };
524
+
525
+ return registryObj;
526
+
527
+ async function callInternal(request: CallAgentRequest): Promise<CallAgentResponse> {
477
528
  const agent = agents.get(request.path);
478
529
 
479
530
  if (!agent) {
@@ -673,7 +724,7 @@ export function createAgentRegistry(
673
724
  return options.middleware.load(defaultLoad, {
674
725
  agent,
675
726
  request,
676
- registry,
727
+ registry: registryObj,
677
728
  });
678
729
  }
679
730
  return defaultLoad(agent, request);
@@ -717,8 +768,5 @@ export function createAgentRegistry(
717
768
  } as CallAgentErrorResponse;
718
769
  }
719
770
  }
720
- },
721
- };
722
-
723
- return registry;
724
- }
771
+ }
772
+ }