|
| 1 | +--- |
| 2 | +title: "Concepts" |
| 3 | +description: 'Entities, lifecycle, and handler building blocks for a custom code agent with Novu.' |
| 4 | +icon: "brain" |
| 5 | +--- |
| 6 | + |
| 7 | + |
| 8 | +These are the ideas behind Novu for Agents (Agent Communication Infrastructure, or ACI). You write handler code; Novu handles providers, delivery, and conversation state. |
| 9 | + |
| 10 | +## Inbound flow |
| 11 | + |
| 12 | +Users can message your agent, and your agent can message back. When someone interacts on a connected platform, Novu resolves identity and conversation state, forwards a context object to your server, then delivers your reply to the right thread. |
| 13 | + |
| 14 | + |
| 15 | + |
| 16 | +| Step | What Novu does | |
| 17 | +| --- | --- | |
| 18 | +| **Receive and identify** | Normalizes the platform webhook. Maps the platform user (for example a Slack user ID) to a Novu subscriber when possible. Known users get full profiles; unknown users stay anonymous until resolved. | |
| 19 | +| **Load conversation** | Creates or loads the conversation for that thread. Assembles message history, metadata, and subscriber data into one context object. | |
| 20 | +| **Your handler** | Calls your code with message, history, subscriber, and platform details. You run your LLM or business logic and call `ctx.reply()`. | |
| 21 | +| **Deliver and persist** | Sends the reply to the provider thread, stores it in history, and logs activity in the dashboard. | |
| 22 | + |
| 23 | +Your server never calls Slack, Teams, or email APIs directly. It gets a context object and returns a reply; Novu handles the rest. |
| 24 | + |
| 25 | +## Key entities |
| 26 | + |
| 27 | +### Agent |
| 28 | + |
| 29 | +The dashboard object that connects your code to one or more chat providers. Each agent has a name, identifier, and event handlers. |
| 30 | + |
| 31 | +It does not define your model, prompts, tools, or business rules. It is the bridge to the app where that logic lives. The provider is where the user chats; the agent is how your app responds. |
| 32 | + |
| 33 | +### Provider connection |
| 34 | + |
| 35 | +Credentials and config that link an agent to a platform (Slack, Teams, WhatsApp, email, and others). |
| 36 | + |
| 37 | +Setup and capabilities differ per provider (reactions, typing indicators, attachments, cards, message edits, and so on). Novu normalizes inbound events before your handler runs, so you work with one interface instead of provider-specific webhooks. Your handler code stays provider-agnostic; Novu translates outbound replies per platform. |
| 38 | + |
| 39 | +### Conversation |
| 40 | + |
| 41 | +The stateful thread for a chat. Novu creates or loads it when a message arrives. It holds history, metadata, participants, status, and platform context. |
| 42 | + |
| 43 | +The agent is a participant, not the conversation itself (relevant when you read threads in the dashboard). A Slack thread, email thread, or similar maps to one Novu conversation. |
| 44 | + |
| 45 | +**Lifecycle:** **Active** from the first message until resolved. **Resolved** when the agent emits the resolve signal (`onResolve` runs; optional summary stored). **Reopened** automatically if the user messages again after resolution. |
| 46 | + |
| 47 | +### Participants and identity |
| 48 | + |
| 49 | +Novu maps platform users to subscribers when it can: |
| 50 | + |
| 51 | +- **Match found:** handler gets subscriber ID, name, email, and related fields. |
| 52 | +- **No match:** user is tracked as a platform user; write handlers that tolerate missing subscriber data. |
| 53 | + |
| 54 | +Later resolution upgrades them to a full subscriber. Identity is provider-aware (Slack user ID vs email sender, and so on) but can resolve to one subscriber record. Use it for personalization, account lookup, and escalation rules. |
| 55 | + |
| 56 | +## Bridge surface |
| 57 | + |
| 58 | +The same handler API applies no matter which provider sent the event or which model you use. |
| 59 | + |
| 60 | +### Event handlers |
| 61 | + |
| 62 | +| Handler | When it runs | Typical use | |
| 63 | +| --- | --- | --- | |
| 64 | +| `onMessage` | User sends a message | Process text and reply | |
| 65 | +| `onAction` | User clicks a button or selects from a card | Forms, buttons, dropdowns | |
| 66 | +| `onReaction` | User adds or removes a reaction | Feedback, follow-ups | |
| 67 | +| `onResolve` | Conversation marked resolved | Cleanup, analytics, summary | |
| 68 | + |
| 69 | +Handlers connect Novu's delivery layer to your app. An `onMessage` handler might pass context to an LLM and return a reply through Novu. |
| 70 | + |
| 71 | +### Context object |
| 72 | + |
| 73 | +Each handler receives a context with some or all of: |
| 74 | + |
| 75 | +- Incoming message |
| 76 | +- Conversation state and metadata |
| 77 | +- Resolved subscriber (when available) |
| 78 | +- Recent history |
| 79 | +- Provider and platform details (thread, channel IDs) |
| 80 | +- Methods to reply, set metadata, trigger workflows, or resolve |
| 81 | + |
| 82 | +That object is the only interface your code needs. You do not integrate Slack, Teams, WhatsApp, or email separately in the handler. |
| 83 | + |
| 84 | +### Replies vs signals |
| 85 | + |
| 86 | +**Replies** are user-visible messages: plain text, markdown with files, or interactive cards (buttons, dropdowns, links, inputs). Card interactions fire `onAction` with `actionId` and value. |
| 87 | + |
| 88 | +**Signals** update state without necessarily sending another chat message: |
| 89 | + |
| 90 | +| Signal | What it does | |
| 91 | +| --- | --- | |
| 92 | +| Metadata | Key-value data on the conversation, persists across turns | |
| 93 | +| Trigger | Starts a Novu workflow from the thread | |
| 94 | +| Resolve | Marks the conversation resolved, optional summary | |
| 95 | + |
| 96 | +Replies talk to the user; signals update the system around the conversation. One handler turn can reply, set metadata, trigger a workflow, and resolve. |
| 97 | + |
| 98 | +Signals queue in memory and batch with your next `ctx.reply()` in one request. If the handler exits without calling `ctx.reply()`, pending signals still send. |
| 99 | + |
| 100 | +## Conversations and workflows |
| 101 | + |
| 102 | +Conversations and Novu workflows share the same account: |
| 103 | + |
| 104 | +- **Conversation to workflow:** User asks in Slack for a report by email; handler calls `ctx.trigger()` and an existing workflow sends the email. |
| 105 | +- **Workflow to conversation:** User replies to a digest email; that reply opens a new agent conversation. |
| 106 | + |
| 107 | +ACI extends Novu's workflow system; it does not replace it. Transactional workflows and open-ended chat work together on one platform. |
| 108 | + |
| 109 | +## Full flow (example: Slack) |
| 110 | + |
| 111 | +1. User messages the agent in Slack. |
| 112 | +2. Novu receives the event via the provider connection. |
| 113 | +3. Novu maps the thread to a conversation and resolves the subscriber when possible. |
| 114 | +4. Novu calls `onMessage` with the context object. |
| 115 | +5. Your handler passes message and history to your agent logic. |
| 116 | +6. Your logic decides the next action. |
| 117 | +7. Handler sends a reply, signals, or both. |
| 118 | +8. Novu posts the reply to the Slack thread. |
| 119 | +9. Novu records messages, participants, metadata, signals, and status. |
| 120 | + |
| 121 | +The same handler code works on every connected provider; adding a provider does not require changing agent logic. |
| 122 | + |
| 123 | +## Next steps |
| 124 | + |
| 125 | +<Columns cols={2}> |
| 126 | + <Card icon="house" href="/agents/custom-code-agent/quickstart" title="Quickstart"> |
| 127 | + Create an agent, connect Slack, and get a reply in-thread. |
| 128 | + </Card> |
| 129 | + <Card icon="brain" href="/agents/custom-code-agent/connect-your-first-agent" title="Connect your first agent"> |
| 130 | + Walk through a full support-bot handler file. |
| 131 | + </Card> |
| 132 | +</Columns> |
0 commit comments