Skip to content

Commit c22b3ac

Browse files
committed
Add receive decorator
1 parent 162da15 commit c22b3ac

File tree

6 files changed

+91
-11
lines changed

6 files changed

+91
-11
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pompeii-labs/magma",
3-
"version": "1.8.3",
3+
"version": "1.9.0",
44
"description": "The Typescript framework to build AI agents quickly and easily",
55
"keywords": [
66
"Agents",

src/agent.ts

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ import {
2323
MagmaToolCallBlock,
2424
MagmaToolCall,
2525
MagmaSendFunction,
26+
MagmaReceive,
2627
} from './types';
2728
import { Provider } from './providers';
2829
import {
2930
loadHooks,
3031
loadJobs,
3132
loadMiddleware,
33+
loadReceivers,
3234
loadTools,
3335
parseErrorToError,
3436
parseErrorToString,
@@ -106,11 +108,6 @@ export class MagmaAgent {
106108
*/
107109
public async receive?(message: any, send: MagmaSendFunction): Promise<void> {}
108110

109-
/**
110-
* Sends data to the connected client depending on the medium (ws, SSE, etc)
111-
* @param message any data object to be sent to the client
112-
*/
113-
114111
public async onWsClose(code: number, reason?: string): Promise<void> {}
115112

116113
public async cleanup(): Promise<void> {
@@ -148,6 +145,15 @@ export class MagmaAgent {
148145
* @throws Will rethrow the error if no `onError` handler is defined
149146
*/
150147
public async main(args: {
148+
config?: MagmaProviderConfig;
149+
send: MagmaSendFunction;
150+
userMessage: MagmaUserMessage;
151+
onTrace?: (trace: TraceEvent[]) => void;
152+
}) {
153+
return await this._main(args);
154+
}
155+
156+
private async _main(args: {
151157
config?: MagmaProviderConfig;
152158
send: MagmaSendFunction;
153159
userMessage: MagmaUserMessage;
@@ -290,7 +296,7 @@ export class MagmaAgent {
290296

291297
// Trigger another completion with the error message as context
292298
return resolve(
293-
await this.main({
299+
await this._main({
294300
config,
295301
send,
296302
messages: localMessages,
@@ -335,7 +341,7 @@ export class MagmaAgent {
335341
);
336342

337343
return resolve(
338-
await this.main({
344+
await this._main({
339345
config,
340346
send,
341347
messages: localMessages,
@@ -376,7 +382,7 @@ export class MagmaAgent {
376382

377383
// Trigger another completion with the tool result because last message was a tool call
378384
return resolve(
379-
await this.main({
385+
await this._main({
380386
config,
381387
send,
382388
messages: localMessages,
@@ -410,7 +416,7 @@ export class MagmaAgent {
410416
);
411417

412418
return resolve(
413-
await this.main({
419+
await this._main({
414420
config,
415421
send,
416422
messages: localMessages,
@@ -1283,6 +1289,10 @@ export class MagmaAgent {
12831289
return [];
12841290
}
12851291

1292+
public getReceivers(): MagmaReceive[] {
1293+
return [];
1294+
}
1295+
12861296
public get tools(): MagmaTool[] {
12871297
const agentTools = loadTools(this);
12881298
const loadedTools = this.getTools();
@@ -1314,6 +1324,13 @@ export class MagmaAgent {
13141324
return agentJobs.concat(loadedJobs).concat(utilityJobs);
13151325
}
13161326

1327+
public get receivers(): MagmaReceive[] {
1328+
const agentReceivers = loadReceivers(this);
1329+
const loadedReceivers = this.getReceivers();
1330+
const utilityReceivers = this.utilities.flatMap((u) => u.receivers.filter(Boolean));
1331+
return agentReceivers.concat(loadedReceivers).concat(utilityReceivers);
1332+
}
1333+
13171334
/* EVENT HANDLERS */
13181335

13191336
getSystemPrompts(): MagmaSystemMessageType[] {

src/decorators.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,21 @@ export function job(cron: string, options: { timezone?: string } = {}) {
205205
descriptor.value._options = options;
206206
};
207207
}
208+
209+
export function receive(messageType: string) {
210+
return function <R extends void>(
211+
target: object,
212+
propertyKey: string,
213+
descriptor: TypedPropertyDescriptor<
214+
((data: unknown, send: MagmaSendFunction, agent: MagmaAgent) => R) & {
215+
_messageType?: string;
216+
}
217+
>
218+
) {
219+
if (!descriptor.value) {
220+
throw new Error('Receive decorator must be used on a function');
221+
}
222+
223+
descriptor.value._messageType = messageType;
224+
};
225+
}

src/helpers/utilities.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
MagmaHook,
33
MagmaJob,
44
MagmaMiddleware,
5+
MagmaReceive,
56
MagmaTool,
67
MagmaToolParam,
78
MagmaUtilities,
@@ -44,8 +45,9 @@ export function loadUtilities(target: any): MagmaUtilities {
4445
const hooks = loadHooks(target);
4546
const jobs = loadJobs(target);
4647
const middleware = loadMiddleware(target);
48+
const receivers = loadReceivers(target);
4749

48-
return { tools, hooks, jobs, middleware };
50+
return { tools, hooks, jobs, middleware, receivers };
4951
}
5052

5153
/**
@@ -156,3 +158,27 @@ export function loadMiddleware(target: any): MagmaMiddleware[] {
156158

157159
return middleware;
158160
}
161+
162+
/**
163+
* Helper function to load middleware from a class or instance of a class
164+
* If the target is an instance, it will load both the static and instance middleware
165+
* @param target class or instance of a class to load middleware from
166+
* @returns array of MagmaMiddleware objects
167+
*/
168+
export function loadReceivers(target: any): MagmaReceive[] {
169+
const receivers: MagmaReceive[] = [];
170+
171+
const { staticMethods, instanceMethods } = getMethodsFromClassOrInstance(target);
172+
const methods = [...staticMethods, ...instanceMethods];
173+
174+
for (const method of methods) {
175+
if (typeof method === 'function' && '_messageType' in method) {
176+
receivers.push({
177+
handler: method.bind(target),
178+
messageType: (method as any)['_messageType'],
179+
});
180+
}
181+
}
182+
183+
return receivers;
184+
}

src/types/utilities/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import { MagmaHook } from './hooks';
22
import { MagmaJob } from './jobs';
33
import { MagmaMiddleware } from './middleware';
4+
import { MagmaReceive } from './receive';
45
import { MagmaTool } from './tools';
56

67
export * from './hooks';
78
export * from './jobs';
89
export * from './middleware';
910
export * from './tools';
11+
export * from './receive';
1012

1113
export type MagmaUtilities = {
1214
tools: MagmaTool[];
1315
middleware: MagmaMiddleware[];
1416
hooks: MagmaHook[];
1517
jobs: MagmaJob[];
18+
receivers: MagmaReceive[];
1619
};

src/types/utilities/receive.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { MagmaAgent } from '../../agent';
2+
import { MagmaSendFunction } from '../agent';
3+
4+
export type MagmaWSMessage = {
5+
type: string;
6+
data: unknown;
7+
};
8+
9+
export type MagmaReceive = {
10+
handler: (
11+
wsMessage: MagmaWSMessage,
12+
send: MagmaSendFunction,
13+
agent: MagmaAgent
14+
) => Promise<void> | void;
15+
messageType: string;
16+
};

0 commit comments

Comments
 (0)