Skip to content

Commit 9da2cb9

Browse files
committed
fix(core): add generic type support for custom event handlers
Allow plugins to use typed custom events by extending EventPayload.
1 parent 3c099c2 commit 9da2cb9

File tree

3 files changed

+74
-5
lines changed

3 files changed

+74
-5
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { describe, it, expect, beforeEach } from 'bun:test';
2+
import { AgentRuntime } from '../runtime';
3+
import type { Character, EventPayload } from '../types';
4+
import { stringToUuid } from '../utils';
5+
6+
interface CustomEventPayload extends EventPayload {
7+
customField: string;
8+
count: number;
9+
}
10+
11+
describe('registerEvent', () => {
12+
let runtime: AgentRuntime;
13+
14+
const mockCharacter: Character = {
15+
id: stringToUuid('test-character'),
16+
name: 'TestBot',
17+
bio: 'A test bot',
18+
};
19+
20+
beforeEach(() => {
21+
runtime = new AgentRuntime({
22+
character: mockCharacter,
23+
});
24+
});
25+
26+
it('should register and emit custom typed events', async () => {
27+
const receivedPayloads: CustomEventPayload[] = [];
28+
29+
runtime.registerEvent<CustomEventPayload>('CUSTOM_EVENT', async (params) => {
30+
receivedPayloads.push(params);
31+
});
32+
33+
await runtime.emitEvent('CUSTOM_EVENT', {
34+
customField: 'test-value',
35+
count: 42,
36+
});
37+
38+
expect(receivedPayloads).toHaveLength(1);
39+
expect(receivedPayloads[0].customField).toBe('test-value');
40+
expect(receivedPayloads[0].count).toBe(42);
41+
// emitEvent injects runtime and source
42+
expect(receivedPayloads[0].runtime).toBeDefined();
43+
expect(receivedPayloads[0].source).toBeDefined();
44+
});
45+
46+
it('should support multiple handlers for same event', async () => {
47+
let handler1Called = false;
48+
let handler2Called = false;
49+
50+
runtime.registerEvent<CustomEventPayload>('MULTI_HANDLER_EVENT', async () => {
51+
handler1Called = true;
52+
});
53+
54+
runtime.registerEvent<CustomEventPayload>('MULTI_HANDLER_EVENT', async () => {
55+
handler2Called = true;
56+
});
57+
58+
await runtime.emitEvent('MULTI_HANDLER_EVENT', {
59+
customField: 'test',
60+
count: 1,
61+
});
62+
63+
expect(handler1Called).toBe(true);
64+
expect(handler2Called).toBe(true);
65+
});
66+
});

packages/core/src/runtime.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2466,11 +2466,11 @@ export class AgentRuntime implements IAgentRuntime {
24662466
}
24672467

24682468
registerEvent<T extends keyof EventPayloadMap>(event: T, handler: EventHandler<T>): void;
2469-
registerEvent(event: string, handler: (params: EventPayload) => Promise<void>): void;
2470-
registerEvent(
2469+
registerEvent<P extends EventPayload = EventPayload>(
24712470
event: string,
2472-
handler: ((params: EventPayload) => Promise<void>) | ((params: unknown) => Promise<void>)
2473-
): void {
2471+
handler: (params: P) => Promise<void>
2472+
): void;
2473+
registerEvent(event: string, handler: (params: EventPayload) => Promise<void>): void {
24742474
if (!this.events[event]) {
24752475
this.events[event] = [];
24762476
}

packages/core/src/types/runtime.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,10 @@ export interface IAgentRuntime extends IDatabaseAdapter {
187187
): ((runtime: IAgentRuntime, params: Record<string, unknown>) => Promise<unknown>) | undefined;
188188

189189
registerEvent<T extends keyof EventPayloadMap>(event: T, handler: EventHandler<T>): void;
190-
registerEvent(event: string, handler: (params: EventPayload) => Promise<void>): void;
190+
registerEvent<P extends EventPayload = EventPayload>(
191+
event: string,
192+
handler: (params: P) => Promise<void>
193+
): void;
191194

192195
getEvent<T extends keyof EventPayloadMap>(event: T): EventHandler<T>[] | undefined;
193196
getEvent(event: string): ((params: EventPayload) => Promise<void>)[] | undefined;

0 commit comments

Comments
 (0)