diff --git a/packages/framework/src/resources/agent/agent.test.ts b/packages/framework/src/resources/agent/agent.test.ts index cfd1ebcc001..e01c4624501 100644 --- a/packages/framework/src/resources/agent/agent.test.ts +++ b/packages/framework/src/resources/agent/agent.test.ts @@ -371,10 +371,12 @@ describe('agent dispatch via NovuRequestHandler', () => { it('should provide read-only context properties from bridge payload', async () => { let capturedCtx: any; + let capturedMessage: any; const testBot = agent('test-bot', { - onMessage: async ({ ctx }) => { + onMessage: async ({ message, ctx }) => { capturedCtx = ctx; + capturedMessage = message; await ctx.reply('ok'); }, }); @@ -401,7 +403,7 @@ describe('agent dispatch via NovuRequestHandler', () => { await vi.waitFor(() => expect(capturedCtx).toBeDefined()); expect(capturedCtx.event).toBe('onMessage'); - expect(capturedCtx.message?.text).toBe('Hello bot!'); + expect(capturedMessage.text).toBe('Hello bot!'); expect(capturedCtx.conversation.identifier).toBe('conv-456'); expect(capturedCtx.subscriber?.subscriberId).toBe('sub-001'); expect(capturedCtx.platform).toBe('slack'); @@ -1033,7 +1035,6 @@ describe('agent dispatch via NovuRequestHandler', () => { expect(capturedCtx.event).toBe('onAction'); expect(capturedCtx.action).toEqual({ actionId: 'confirm', value: 'yes', sourceMessageId: 'msg-card-001' }); - expect(capturedCtx.message).toBeNull(); const replyCall = fetchMock.mock.calls.find( (call: any[]) => call[0] === 'https://api.novu.co/v1/agents/test-bot/reply' diff --git a/packages/framework/src/resources/agent/agent.types.ts b/packages/framework/src/resources/agent/agent.types.ts index 976333befb6..dee8277f127 100644 --- a/packages/framework/src/resources/agent/agent.types.ts +++ b/packages/framework/src/resources/agent/agent.types.ts @@ -273,8 +273,6 @@ interface AgentContextBase { /** Context passed to the `onMessage` handler. */ export interface AgentMessageContext extends AgentContextBase { readonly event: 'onMessage'; - /** The incoming message that triggered this handler. */ - readonly message: AgentMessage; } /** Context passed to the `onAction` handler. */ @@ -302,8 +300,8 @@ export type AgentContext = AgentMessageContext | AgentActionContext | AgentReact export interface AgentHandlers { /** * Fires on every text message the user sends. - * `message` is the incoming message. `ctx` provides conversation history, subscriber, - * metadata, and reply/trigger methods. + * `payload.message` is the incoming message. `payload.ctx` provides conversation history, + * subscriber, metadata, and reply/trigger methods. * Return a string or JSX card to reply, or call `ctx.reply()` directly * for more control (e.g. editing a message in place). */ diff --git a/packages/novu/src/commands/init/templates/app-agent/ts/README-template.md b/packages/novu/src/commands/init/templates/app-agent/ts/README-template.md index 88c7f9fcd79..d777bc7200b 100644 --- a/packages/novu/src/commands/init/templates/app-agent/ts/README-template.md +++ b/packages/novu/src/commands/init/templates/app-agent/ts/README-template.md @@ -29,11 +29,12 @@ app/ ## Agent API -Your agent handler receives a context object with: +Your `onMessage` handler receives `{ message, ctx }`: + +- **`message`** — The inbound message (text, author, timestamp) | Method / Property | Description | |---|---| -| `ctx.message` | The inbound message (text, author, timestamp) | | `ctx.conversation` | Current conversation state and metadata | | `ctx.history` | Recent conversation history | | `ctx.subscriber` | Resolved subscriber info | @@ -48,13 +49,13 @@ Your agent handler receives a context object with: Replace the demo handler in `app/novu/agents/support-agent.tsx` with your LLM call: ```typescript -onMessage: async (ctx) => { +onMessage: async ({ message, ctx }) => { const response = await openai.chat.completions.create({ model: 'gpt-4', messages: [ { role: 'system', content: 'You are a helpful support agent.' }, ...ctx.history.map((h) => ({ role: h.role, content: h.content })), - { role: 'user', content: ctx.message?.text ?? '' }, + { role: 'user', content: message.text }, ], });