@novu/framework 2.11.0 → 2.11.2-alpha.0

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.
Files changed (85) hide show
  1. package/README.md +114 -9
  2. package/ai-sdk/package.json +4 -0
  3. package/cards/package.json +4 -0
  4. package/dist/{esm/index-dylq0Kmx.d.ts → cjs/agent.types-DdgaVUb7.d.cts} +356 -192
  5. package/dist/cjs/ai-sdk/index.cjs +1 -0
  6. package/dist/cjs/ai-sdk/index.d.cts +39 -0
  7. package/dist/cjs/cards.cjs +57 -0
  8. package/dist/cjs/cards.d.cts +2 -0
  9. package/dist/cjs/{health-check.types-uaDLF5bo.d.cts → health-check.types-CkUmYLNG.d.cts} +34 -140
  10. package/dist/cjs/index-BCp3U0UG.d.cts +189 -0
  11. package/dist/cjs/index.cjs +138 -135
  12. package/dist/cjs/index.d.cts +5 -3
  13. package/dist/cjs/internal/index.cjs +1 -1
  14. package/dist/cjs/internal/index.d.cts +96 -4
  15. package/dist/cjs/jsx-dev-runtime.cjs +1 -1
  16. package/dist/cjs/jsx-runtime.cjs +1 -1
  17. package/dist/cjs/langchain/index.cjs +1 -0
  18. package/dist/cjs/langchain/index.d.cts +105 -0
  19. package/dist/cjs/servers/express.cjs +137 -134
  20. package/dist/cjs/servers/express.d.cts +6 -4
  21. package/dist/cjs/servers/h3.cjs +136 -133
  22. package/dist/cjs/servers/h3.d.cts +6 -4
  23. package/dist/cjs/servers/lambda.cjs +138 -135
  24. package/dist/cjs/servers/lambda.d.cts +6 -5
  25. package/dist/cjs/servers/nest.cjs +136 -133
  26. package/dist/cjs/servers/nest.d.cts +21 -7
  27. package/dist/cjs/servers/next.cjs +138 -135
  28. package/dist/cjs/servers/next.d.cts +6 -4
  29. package/dist/cjs/servers/nuxt.cjs +136 -133
  30. package/dist/cjs/servers/nuxt.d.cts +6 -4
  31. package/dist/cjs/servers/remix.cjs +138 -135
  32. package/dist/cjs/servers/remix.d.cts +6 -4
  33. package/dist/cjs/servers/sveltekit.cjs +136 -133
  34. package/dist/cjs/servers/sveltekit.d.cts +6 -4
  35. package/dist/cjs/step-resolver.d.cts +3 -2
  36. package/dist/cjs/{subscriber.types-PRaHFLJu.d.cts → subscriber.types-DxMMRBIi.d.cts} +2 -78
  37. package/dist/cjs/util.types-DaFfsxgy.d.cts +78 -0
  38. package/dist/{cjs/index-D-SLxj--.d.cts → esm/agent.types-Bu3DhlVb.d.ts} +356 -192
  39. package/dist/esm/ai-sdk/index.d.ts +39 -0
  40. package/dist/esm/ai-sdk/index.js +1 -0
  41. package/dist/esm/cards.d.ts +2 -0
  42. package/dist/esm/cards.js +1 -0
  43. package/dist/esm/{chunk-K7PM3FEJ.js → chunk-3XT6S7TZ.js} +14 -14
  44. package/dist/esm/chunk-3ZWME5KT.js +0 -0
  45. package/dist/esm/chunk-C3P3ZH2I.js +36 -0
  46. package/dist/esm/chunk-FHYMHX3T.js +1 -0
  47. package/dist/esm/chunk-KLIOXJR3.js +1 -0
  48. package/dist/esm/chunk-W6DIBD4Z.js +1 -0
  49. package/dist/esm/chunk-YF62BBGH.js +98 -0
  50. package/dist/esm/{health-check.types-XZwesagD.d.ts → health-check.types-nDCnGlmX.d.ts} +34 -140
  51. package/dist/esm/index-DEehllqa.d.ts +189 -0
  52. package/dist/esm/index.d.ts +5 -3
  53. package/dist/esm/index.js +1 -1
  54. package/dist/esm/internal/index.d.ts +96 -4
  55. package/dist/esm/internal/index.js +1 -1
  56. package/dist/esm/jsx-dev-runtime.js +1 -1
  57. package/dist/esm/jsx-runtime-7EPQR56T.js +1 -0
  58. package/dist/esm/jsx-runtime.js +1 -1
  59. package/dist/esm/langchain/index.d.ts +105 -0
  60. package/dist/esm/langchain/index.js +1 -0
  61. package/dist/esm/servers/express.d.ts +6 -4
  62. package/dist/esm/servers/express.js +1 -1
  63. package/dist/esm/servers/h3.d.ts +6 -4
  64. package/dist/esm/servers/h3.js +1 -1
  65. package/dist/esm/servers/lambda.d.ts +6 -5
  66. package/dist/esm/servers/lambda.js +1 -1
  67. package/dist/esm/servers/nest.d.ts +21 -7
  68. package/dist/esm/servers/nest.js +1 -1
  69. package/dist/esm/servers/next.d.ts +6 -4
  70. package/dist/esm/servers/next.js +1 -1
  71. package/dist/esm/servers/nuxt.d.ts +6 -4
  72. package/dist/esm/servers/nuxt.js +1 -1
  73. package/dist/esm/servers/remix.d.ts +6 -4
  74. package/dist/esm/servers/remix.js +1 -1
  75. package/dist/esm/servers/sveltekit.d.ts +6 -4
  76. package/dist/esm/servers/sveltekit.js +1 -1
  77. package/dist/esm/step-resolver.d.ts +3 -2
  78. package/dist/esm/step-resolver.js +1 -1
  79. package/dist/esm/{subscriber.types-CC7F0JO_.d.ts → subscriber.types-BbyO_Cz6.d.ts} +2 -78
  80. package/dist/esm/util.types-DaFfsxgy.d.ts +78 -0
  81. package/dist/esm/validators.js +1 -1
  82. package/package.json +55 -7
  83. package/dist/esm/chunk-52LSX2V5.js +0 -1
  84. package/dist/esm/chunk-LJUUDK2J.js +0 -130
  85. package/dist/esm/chunk-N4PZBM53.js +0 -1
@@ -1,8 +1,156 @@
1
1
  import { ChatElement, Emoji, CardElement } from 'chat';
2
- import { T as TriggerRecipientsPayload, C as ClientOptions, W as Workflow, H as HealthCheck, e as DiscoverOutput, i as Event, n as ExecuteOutput, d as CodeResult, j as EventTriggerParams, m as Execute, t as WorkflowOptions } from './health-check.types-uaDLF5bo.cjs';
3
- import { g as Awaitable } from './subscriber.types-PRaHFLJu.cjs';
4
- import { S as Schema, a as FromSchema, F as FromSchemaUnvalidated } from './base.schema.types-BApIn9jr.cjs';
5
- import './step-resolver.cjs';
2
+ import { A as Awaitable } from './util.types-DaFfsxgy.js';
3
+
4
+ declare enum ChannelTypeEnum {
5
+ IN_APP = "in_app",
6
+ EMAIL = "email",
7
+ SMS = "sms",
8
+ CHAT = "chat",
9
+ PUSH = "push"
10
+ }
11
+ interface IAttachmentOptions {
12
+ mime: string;
13
+ file: Buffer;
14
+ name?: string;
15
+ channels?: ChannelTypeEnum[];
16
+ cid?: string;
17
+ disposition?: string;
18
+ }
19
+ interface ITriggerPayload {
20
+ attachments?: IAttachmentOptions[];
21
+ [key: string]: string | string[] | boolean | number | undefined | IAttachmentOptions | IAttachmentOptions[] | Record<string, unknown>;
22
+ }
23
+ interface ISubscriberPayload {
24
+ subscriberId: string;
25
+ firstName?: string;
26
+ lastName?: string;
27
+ email?: string;
28
+ phone?: string;
29
+ avatar?: string;
30
+ locale?: string;
31
+ data?: Record<string, unknown>;
32
+ channels?: ISubscriberChannel[];
33
+ }
34
+ interface ISubscriberChannel {
35
+ providerId: ChatProviderIdEnum | PushProviderIdEnum;
36
+ integrationIdentifier?: string;
37
+ credentials: IChannelCredentials;
38
+ }
39
+ interface IChannelCredentials {
40
+ webhookUrl?: string;
41
+ deviceTokens?: string[];
42
+ }
43
+ interface ITopic {
44
+ type: 'Topic';
45
+ topicKey: string;
46
+ exclude?: string[];
47
+ }
48
+ type TriggerRecipientsPayload = string | ISubscriberPayload | ITopic | ISubscriberPayload[] | ITopic[];
49
+ declare enum TriggerEventStatusEnum {
50
+ ERROR = "error",
51
+ NOT_ACTIVE = "trigger_not_active",
52
+ NO_WORKFLOW_ACTIVE_STEPS = "no_workflow_active_steps_defined",
53
+ NO_WORKFLOW_STEPS = "no_workflow_steps_defined",
54
+ PROCESSED = "processed",
55
+ SUBSCRIBER_MISSING = "subscriber_id_missing",
56
+ TENANT_MISSING = "no_tenant_found"
57
+ }
58
+ declare enum ChatProviderIdEnum {
59
+ Slack = "slack",
60
+ Discord = "discord",
61
+ MsTeams = "msteams",
62
+ Mattermost = "mattermost",
63
+ Ryver = "ryver",
64
+ Zulip = "zulip",
65
+ GrafanaOnCall = "grafana-on-call",
66
+ GetStream = "getstream",
67
+ RocketChat = "rocket-chat",
68
+ WhatsAppBusiness = "whatsapp-business",
69
+ ChatWebhook = "chat-webhook",
70
+ Telegram = "telegram"
71
+ }
72
+ declare enum PushProviderIdEnum {
73
+ FCM = "fcm",
74
+ APNS = "apns",
75
+ EXPO = "expo",
76
+ OneSignal = "one-signal",
77
+ Pushpad = "pushpad",
78
+ PushWebhook = "push-webhook",
79
+ PusherBeams = "pusher-beams",
80
+ AppIO = "appio"
81
+ }
82
+ /**
83
+ * A preference for a notification delivery workflow.
84
+ *
85
+ * This provides a shortcut to setting all channels to the same preference.
86
+ */
87
+ type WorkflowPreference = {
88
+ /**
89
+ * A flag specifying if notification delivery is enabled for the workflow.
90
+ *
91
+ * If `true`, notification delivery is enabled by default for all channels.
92
+ *
93
+ * This setting can be overridden by the channel preferences.
94
+ *
95
+ * @default true
96
+ */
97
+ enabled: boolean;
98
+ /**
99
+ * A flag specifying if the preference is read-only.
100
+ *
101
+ * If `true`, the preference cannot be changed by the Subscriber.
102
+ *
103
+ * @default false
104
+ */
105
+ readOnly: boolean;
106
+ };
107
+ /** A preference for a notification delivery channel. */
108
+ type ChannelPreference = {
109
+ /**
110
+ * A flag specifying if notification delivery is enabled for the channel.
111
+ *
112
+ * If `true`, notification delivery is enabled.
113
+ *
114
+ * @default true
115
+ */
116
+ enabled: boolean;
117
+ };
118
+ type WorkflowPreferences = {
119
+ /**
120
+ * A preference for the workflow.
121
+ *
122
+ * The values specified here will be used if no preference is specified for a channel.
123
+ */
124
+ all: WorkflowPreference;
125
+ /**
126
+ * A preference for each notification delivery channel.
127
+ *
128
+ * If no preference is specified for a channel, the `all` preference will be used.
129
+ */
130
+ channels: Record<ChannelTypeEnum, ChannelPreference>;
131
+ };
132
+ /**
133
+ * Recursively make all properties of type `T` optional.
134
+ */
135
+ type DeepPartial<T> = T extends object ? {
136
+ [P in keyof T]?: DeepPartial<T[P]>;
137
+ } : T;
138
+ /** A partial set of workflow preferences. */
139
+ type WorkflowPreferencesPartial = DeepPartial<WorkflowPreferences>;
140
+
141
+ type Verdict = 'approve' | 'deny';
142
+ interface ToolApprovalRequestPayload {
143
+ approvalId: string;
144
+ toolCallId: string;
145
+ name: string;
146
+ input?: Record<string, unknown>;
147
+ }
148
+ interface ParsedApprovalAction {
149
+ approved: boolean;
150
+ approvalId: string;
151
+ }
152
+ declare function buildApprovalActionId(verdict: Verdict, approvalId: string): string;
153
+ declare function parseApprovalActionId(id: string | undefined): ParsedApprovalAction | null;
6
154
 
7
155
  declare enum AgentEventEnum {
8
156
  ON_MESSAGE = "onMessage",
@@ -64,6 +212,24 @@ interface AgentSubscriber {
64
212
  /** Arbitrary custom data attached to the subscriber in Novu. */
65
213
  data?: Record<string, unknown>;
66
214
  }
215
+ /**
216
+ * Tool-call details on a tool-related history entry. Which fields are set depends on the
217
+ * entry's `type` (`tool_approval_request`, `tool_approval_decision`, or `tool_result`).
218
+ */
219
+ interface AgentToolData {
220
+ /** Id of the tool call. */
221
+ toolCallId?: string;
222
+ /** Name of the tool. */
223
+ toolName?: string;
224
+ /** Id linking an approval request to its decision. */
225
+ approvalId?: string;
226
+ /** Arguments the tool was called with. */
227
+ input?: Record<string, unknown>;
228
+ /** Whether the tool call was approved or denied. */
229
+ approved?: boolean;
230
+ /** What the tool returned (or the `execution-denied` marker for a denied call). */
231
+ output?: unknown;
232
+ }
67
233
  /**
68
234
  * A single entry in the conversation history.
69
235
  * `ctx.history` is an ordered array of these entries — map them to your LLM's
@@ -72,17 +238,22 @@ interface AgentSubscriber {
72
238
  interface AgentHistoryEntry {
73
239
  /** Message role: `'user'`, `'assistant'`, or `'system'`. */
74
240
  role: string;
75
- /** Content type: `'text'`, `'card'`, etc. */
241
+ /**
242
+ * The kind of entry: `'message'`, `'edit'`, `'signal'`, or a tool-lifecycle event
243
+ * (`'tool_approval_request'`, `'tool_approval_decision'`, `'tool_result'`).
244
+ */
76
245
  type: string;
77
246
  /** Plain-text representation of the message content. */
78
247
  content: string;
79
248
  richContent?: Record<string, unknown>;
80
249
  senderName?: string;
81
- /** Present on system entries that carry a Novu signal (e.g. metadata updates). */
250
+ /** Structured data for `signal` entries (e.g. metadata updates). */
82
251
  signalData?: {
83
252
  type: string;
84
253
  payload?: Record<string, unknown>;
85
254
  };
255
+ /** Tool-call details — set on tool-lifecycle entries (`tool_*`). */
256
+ toolData?: AgentToolData;
86
257
  createdAt: string;
87
258
  }
88
259
  /** Resolved inbound email domain metadata (present when `platform === 'email'`). */
@@ -150,6 +321,7 @@ type MessageContent = string | ChatElement;
150
321
  interface ReplyContent {
151
322
  markdown?: string;
152
323
  card?: CardElement;
324
+ toolApprovalCard?: ToolApprovalCard;
153
325
  files?: FileRef[];
154
326
  }
155
327
  /**
@@ -166,6 +338,89 @@ interface AgentAction {
166
338
  /** Platform-native message ID of the message containing the clicked button/action. */
167
339
  sourceMessageId?: string;
168
340
  }
341
+ /**
342
+ * A tool call that requires user approval before it runs.
343
+ * Pass this to `ctx.toolApproval.request()` when your agent wants to gate a tool.
344
+ */
345
+ interface AgentToolCall {
346
+ id: string;
347
+ name: string;
348
+ input?: Record<string, unknown>;
349
+ }
350
+ /**
351
+ * Presentation descriptor for Novu's built-in tool-approval card. Returned by the
352
+ * injected `approvalCard()` helper. Novu renders it natively on Slack and as a
353
+ * portable fallback elsewhere; Approve/Deny action ids are always supplied by Novu.
354
+ *
355
+ * Channel mapping (self-hosted):
356
+ * - **Slack (native card):** `icon`, `title`, `subtitle`, `body`, `approveLabel`, `denyLabel`
357
+ * - **Other channels (portable card):** `title`, `subtitle`, `approveLabel`, `denyLabel`
358
+ *
359
+ * `icon` and `body` are ignored on non-Slack channels — the portable fallback has no
360
+ * card image or body block. Catalog icons are 32×32; custom `https://` URLs should match.
361
+ */
362
+ interface ToolApprovalCard {
363
+ type: 'tool-approval-card';
364
+ /** Slack only. Catalog id (`'stripe'`), `https://` URL, or omit to auto-match the tool name. Use 32×32 px for custom URLs. */
365
+ icon?: string;
366
+ /** All channels. Card title. Defaults to `Tool approval required`. */
367
+ title?: string;
368
+ /** All channels. Card subtitle; auto-generated from the tool name/input when omitted. */
369
+ subtitle?: string;
370
+ /** Slack only. Optional markdown body (e.g. argument preview). Not shown on portable fallback. */
371
+ body?: string;
372
+ /** All channels. Approve button label. Defaults to `Approve`. */
373
+ approveLabel?: string;
374
+ /** All channels. Deny button label. Defaults to `Deny`. */
375
+ denyLabel?: string;
376
+ }
377
+ /**
378
+ * Returned by `ctx.toolApproval.request()`. Return it from `onMessage` to post
379
+ * an approval card and end the turn until the user approves or denies.
380
+ */
381
+ declare class PendingApproval {
382
+ readonly __novuPendingApproval: true;
383
+ }
384
+ /** Optional customization for tool approval messages. */
385
+ interface ToolApprovalConfig {
386
+ /**
387
+ * Build the approval message shown while waiting for a decision.
388
+ *
389
+ * Return `approvalCard(...)` for Novu's channel-adaptive card (native on Slack,
390
+ * fallback elsewhere), or return a string/`Card` to take full control (portable
391
+ * on every channel). Use the provided `actionIds` on your own buttons.
392
+ */
393
+ renderApproval?: (args: {
394
+ toolCall: AgentToolCall;
395
+ actionIds: {
396
+ approve: string;
397
+ deny: string;
398
+ };
399
+ approvalCard: (overrides?: Omit<ToolApprovalCard, 'type'>) => ToolApprovalCard;
400
+ }) => MessageContent | ToolApprovalCard;
401
+ }
402
+ /** Passed to `onToolApproval` when the user clicks Approve or Deny. */
403
+ interface ToolApprovalDecision {
404
+ /** The tool that was awaiting approval. */
405
+ toolCall: AgentToolCall;
406
+ /** `true` if the user approved, `false` if they denied. */
407
+ approved: boolean;
408
+ /**
409
+ * Handle to the approval message. When you register `onToolApproval`, you own
410
+ * card cleanup — call `edit()` or `delete()` as needed. When the framework
411
+ * handles the approval click, the card is deleted for you.
412
+ */
413
+ approvalMessage: ReplyHandle;
414
+ }
415
+ /** Controls on `ctx.toolApproval` for gating tool calls. */
416
+ interface ToolApprovalControl {
417
+ /**
418
+ * Post an approval message and pause the turn.
419
+ * Return the result (`return ctx.toolApproval.request(...)`) from `onMessage`
420
+ * to end the turn until the user decides.
421
+ */
422
+ request(toolCall: AgentToolCall): Promise<PendingApproval>;
423
+ }
169
424
  /** An emoji reaction added to or removed from a message. */
170
425
  interface AgentReaction {
171
426
  /** Platform-native ID of the message that was reacted to. */
@@ -192,8 +447,10 @@ interface ReplyHandle {
192
447
  edit(content: MessageContent, options?: {
193
448
  files?: FileRef[];
194
449
  }): Promise<ReplyHandle>;
450
+ /** Delete this message from the platform. Removes the rendered message only — history is preserved. */
451
+ delete(): Promise<void>;
195
452
  }
196
- interface AgentContextBase {
453
+ interface AgentHandlerContext {
197
454
  /** Live state of the current conversation, including persisted metadata. */
198
455
  readonly conversation: AgentConversation;
199
456
  /**
@@ -227,6 +484,15 @@ interface AgentContextBase {
227
484
  reply(content: MessageContent, options?: {
228
485
  files?: FileRef[];
229
486
  }): Promise<ReplyHandle>;
487
+ /**
488
+ * Gate tool calls that need user approval before they run.
489
+ *
490
+ * @example
491
+ * if (needsApproval(toolCall)) {
492
+ * return ctx.toolApproval.request(toolCall);
493
+ * }
494
+ */
495
+ readonly toolApproval: ToolApprovalControl;
230
496
  /**
231
497
  * Mark the conversation as resolved. Optionally provide a summary for the resolution record.
232
498
  * Triggers the `onResolve` handler if one is registered.
@@ -285,25 +551,49 @@ interface AgentContextBase {
285
551
  * await ctx.reply('Done!');
286
552
  */
287
553
  addReaction(messageId: string, emojiName: Emoji): void;
554
+ /**
555
+ * Delete a platform message by id. Queued and flushed with the next `ctx.reply()`,
556
+ * or automatically when the handler completes (same batching as `ctx.addReaction()`).
557
+ * Deletes the rendered message only — conversation history is preserved.
558
+ *
559
+ * @example
560
+ * ctx.deleteMessage(ctx.action!.sourceMessageId!);
561
+ * await ctx.reply('Processing…');
562
+ */
563
+ deleteMessage(messageId: string): void;
564
+ /**
565
+ * Control the typing / "Thinking…" status for the current turn.
566
+ * Posts immediately (like `reply()`), updating the indicator Novu already shows on inbound.
567
+ *
568
+ * @example
569
+ * await ctx.typing('Searching the docs…'); // set / replace the status text
570
+ * await ctx.typing(); // reset to the default "Thinking…"
571
+ * await ctx.typing.stop(); // clear it for this turn
572
+ *
573
+ * Behaviour is best-effort per platform: custom text shows on Slack-like platforms,
574
+ * a generic typing bubble on others, and is a no-op where there is no typing channel
575
+ * (e.g. email). A normal turn that ends with `ctx.reply()` clears the status automatically.
576
+ */
577
+ typing: TypingControl;
288
578
  }
289
579
  /** Context passed to the `onMessage` handler. */
290
- interface AgentMessageContext extends AgentContextBase {
580
+ interface AgentMessageContext extends AgentHandlerContext {
291
581
  readonly event: 'onMessage';
292
582
  }
293
583
  /** Context passed to the `onAction` handler. */
294
- interface AgentActionContext extends AgentContextBase {
584
+ interface AgentActionContext extends AgentHandlerContext {
295
585
  readonly event: 'onAction';
296
586
  /** The button click or interactive action that triggered this handler. */
297
587
  readonly action: AgentAction;
298
588
  }
299
589
  /** Context passed to the `onReaction` handler. */
300
- interface AgentReactionContext extends AgentContextBase {
590
+ interface AgentReactionContext extends AgentHandlerContext {
301
591
  readonly event: 'onReaction';
302
592
  /** The emoji reaction that triggered this handler. */
303
593
  readonly reaction: AgentReaction;
304
594
  }
305
595
  /** Context passed to the `onResolve` handler. */
306
- interface AgentResolveContext extends AgentContextBase {
596
+ interface AgentResolveContext extends AgentHandlerContext {
307
597
  readonly event: 'onResolve';
308
598
  }
309
599
  type AgentContext = AgentMessageContext | AgentActionContext | AgentReactionContext | AgentResolveContext;
@@ -346,10 +636,31 @@ interface AgentHandlers {
346
636
  * `ctx.subscriber` and `ctx.conversation`.
347
637
  */
348
638
  onResolve?: (ctx: AgentResolveContext) => Awaitable<MessageContent | void>;
639
+ /**
640
+ * Fires when the user approves or denies a tool call you previously gated with
641
+ * `ctx.toolApproval.request()`.
642
+ *
643
+ * @param decision - The tool, the user's verdict, and a handle to the approval message.
644
+ * @param ctx - Conversation context (history, subscriber, metadata, reply/trigger methods).
645
+ *
646
+ * Run the tool (or skip it), then return a reply or call `ctx.reply()` directly.
647
+ * Register this handler whenever you call `ctx.toolApproval.request()` in `onMessage`.
648
+ */
649
+ onToolApproval?: (decision: ToolApprovalDecision, ctx: AgentActionContext) => Awaitable<MessageContent | void>;
650
+ /**
651
+ * Customize how approval messages look. Omit to use the built-in Approve/Deny card.
652
+ */
653
+ toolApproval?: ToolApprovalConfig;
349
654
  }
350
655
  interface Agent {
351
656
  id: string;
352
657
  handlers: AgentHandlers;
658
+ /**
659
+ * @internal Set by `agent()` / ai-sdk registration. True when the application
660
+ * author registered `onToolApproval` (full manual card cleanup). False when
661
+ * only a framework wrapper handles approval clicks (auto-delete after handler).
662
+ */
663
+ userOnToolApproval?: boolean;
353
664
  }
354
665
  interface AgentBridgeRequest {
355
666
  version: number;
@@ -398,6 +709,17 @@ type TriggerSignal = {
398
709
  payload?: Record<string, unknown>;
399
710
  };
400
711
  type Signal = MetadataSignal | TriggerSignal;
712
+ /** The outcome of a tool call, reported back so it's saved in the conversation history. */
713
+ type ToolResult = {
714
+ /** Id of the tool call this result belongs to. */
715
+ toolCallId: string;
716
+ /** Name of the tool. */
717
+ toolName?: string;
718
+ /** What the tool returned (or the `execution-denied` marker for a denied call). */
719
+ output: unknown;
720
+ /** Optional human-readable summary shown in the conversation timeline. */
721
+ preview?: string;
722
+ };
401
723
  /** In-place edit of a previously posted agent message. Identified by platform message id. */
402
724
  interface EditPayload {
403
725
  messageId: string;
@@ -408,6 +730,24 @@ interface AddReactionPayload {
408
730
  messageId: string;
409
731
  emojiName: Emoji;
410
732
  }
733
+ /** Delete a previously posted platform message. Removes the rendered message only — history is preserved. */
734
+ interface DeleteMessagePayload {
735
+ messageId: string;
736
+ }
737
+ /**
738
+ * Per-turn typing/status control op sent on the reply contract.
739
+ * - `{ status?: string }` — set/replace the status; omit `status` for the default "Thinking…".
740
+ * - `'stop'` — clear the status for this turn.
741
+ */
742
+ type TypingOp = {
743
+ status?: string;
744
+ } | 'stop';
745
+ /**
746
+ * `ctx.typing` surface: a callable that sets/updates the status, plus `.stop()` to clear it.
747
+ */
748
+ type TypingControl = ((status?: string) => Promise<void>) & {
749
+ stop: () => Promise<void>;
750
+ };
411
751
  interface AgentReplyPayload {
412
752
  conversationId: string;
413
753
  integrationIdentifier: string;
@@ -417,7 +757,11 @@ interface AgentReplyPayload {
417
757
  summary?: string;
418
758
  };
419
759
  signals?: Signal[];
760
+ toolResults?: ToolResult[];
761
+ toolApprovalRequest?: ToolApprovalRequestPayload;
420
762
  addReactions?: AddReactionPayload[];
763
+ deleteMessages?: DeleteMessagePayload[];
764
+ typing?: TypingOp;
421
765
  }
422
766
  /** Shape returned by /agents/:id/reply when a reply or edit was delivered. */
423
767
  interface SentMessageInfo {
@@ -425,184 +769,4 @@ interface SentMessageInfo {
425
769
  platformThreadId: string;
426
770
  }
427
771
 
428
- /**
429
- * Thrown by `ctx.reply()` and `handle.edit()` when the upstream message delivery
430
- * fails — e.g. the configured email provider returns 401, Slack rejects the token,
431
- * or Teams rejects the request.
432
- *
433
- * `message` is always a short, human-readable summary.
434
- * `responseBody` preserves the raw upstream body for debugging.
435
- *
436
- * @example
437
- * ```ts
438
- * import { AgentDeliveryError } from '@novu/framework';
439
- *
440
- * try {
441
- * await ctx.reply('Hello!');
442
- * } catch (err) {
443
- * if (err instanceof AgentDeliveryError) {
444
- * console.error('Delivery failed:', err.message);
445
- * return;
446
- * }
447
- * throw err;
448
- * }
449
- * ```
450
- */
451
- declare class AgentDeliveryError extends Error {
452
- readonly statusCode: number;
453
- readonly responseBody: string;
454
- constructor(statusCode: number, responseBody: string);
455
- }
456
-
457
- /**
458
- * Define a new conversational agent.
459
- *
460
- * @param agentId - Unique identifier matching the agent entity created in Novu (e.g. 'wine-bot')
461
- * @param handlers - Handler functions for agent events
462
- */
463
- declare function agent(agentId: string, handlers: AgentHandlers): Agent;
464
-
465
- declare class Client {
466
- private discoveredWorkflows;
467
- private discoverWorkflowPromises;
468
- private registeredAgents;
469
- private templateEngine;
470
- secretKey: string;
471
- apiUrl: string;
472
- version: string;
473
- strictAuthentication: boolean;
474
- verbose: boolean;
475
- constructor(options?: ClientOptions);
476
- private buildOptions;
477
- private log;
478
- /**
479
- * Adds workflows to the client.
480
- *
481
- * A locking mechanism is used to ensure that duplicate workflows are not added.
482
- *
483
- * @param workflows - The workflows to add.
484
- */
485
- addWorkflows(workflows: Array<Workflow>): Promise<void>;
486
- addAgents(agents: Array<Agent>): void;
487
- getAgent(agentId: string): Agent | undefined;
488
- private addWorkflow;
489
- healthCheck(): HealthCheck;
490
- private getWorkflow;
491
- private getStep;
492
- private getRegisteredWorkflows;
493
- discover(): DiscoverOutput;
494
- /**
495
- * Mocks data based on the given schema.
496
- * The `default` value in the schema is used as the base data.
497
- * If no `default` value is provided, the data is generated using JSONSchemaFaker.
498
- *
499
- * @param schema
500
- * @returns mocked data
501
- */
502
- private mock;
503
- private validate;
504
- private throwInvalidProvider;
505
- private throwInvalidStep;
506
- private throwInvalidEvent;
507
- private executeStepFactory;
508
- private shouldSanitize;
509
- private shouldSkip;
510
- executeWorkflow(event: Event): Promise<ExecuteOutput>;
511
- private createExecutionPayload;
512
- private prettyPrintExecute;
513
- private executeProviders;
514
- private previewProvider;
515
- private executeProvider;
516
- private executeStep;
517
- private compileControls;
518
- /**
519
- * Preprocesses standalone translation patterns.
520
- * Transforms {{t.key}} to [T:key] placeholder (not Liquid syntax, passes through unchanged).
521
- */
522
- private preprocessTranslationPatterns;
523
- /**
524
- * Preprocesses translation keys used as filter arguments.
525
- * Transforms 't.key' to '[T:key]' placeholder (not Liquid syntax, passes through unchanged).
526
- * Example: pluralize: 't.apple', 't.apples' → pluralize: '[T:apple]', '[T:apples]'
527
- */
528
- private preprocessFilterTranslationArgs;
529
- /**
530
- * Post-processes placeholders back to translation markers after Liquid render.
531
- * Transforms [T:key] back to {{t.key}} for the translation service.
532
- */
533
- private postprocessTranslationMarkers;
534
- /**
535
- * Create the controls for a step, taking both the event controls and the default controls into account
536
- *
537
- * @param step The step to create the controls for
538
- * @param event The event that triggered the step
539
- * @returns The controls for the step
540
- */
541
- private createStepControls;
542
- private previewStep;
543
- private constructStepForPreview;
544
- private extractMockDataForPreviousSteps;
545
- private previewRequiredStep;
546
- private getStepState;
547
- private getStepCode;
548
- private getWorkflowCode;
549
- getCode(workflowId: string, stepId?: string): CodeResult;
550
- }
551
-
552
- interface ServeHandlerOptions {
553
- client?: Client;
554
- workflows?: Array<Workflow>;
555
- agents?: Array<Agent>;
556
- }
557
- type INovuRequestHandlerOptions<Input extends any[] = any[], Output = any> = ServeHandlerOptions & {
558
- frameworkName: string;
559
- client?: Client;
560
- workflows?: Array<Workflow>;
561
- agents?: Array<Agent>;
562
- handler: Handler<Input, Output>;
563
- };
564
- type Handler<Input extends any[] = any[], Output = any> = (...args: Input) => HandlerResponse<Output>;
565
- type HandlerResponse<Output = any> = {
566
- body: () => Awaitable<any>;
567
- headers: (key: string) => Awaitable<string | null | undefined>;
568
- method: () => Awaitable<string>;
569
- queryString?: (key: string, url: URL) => Awaitable<string | null | undefined>;
570
- url: () => Awaitable<URL>;
571
- transformResponse: (res: IActionResponse<string>) => Output;
572
- waitUntil?: (promise: Promise<unknown>) => void;
573
- };
574
- type IActionResponse<TBody extends string = string> = {
575
- status: number;
576
- headers: Record<string, string>;
577
- body: TBody;
578
- };
579
- declare class NovuRequestHandler<Input extends any[] = any[], Output = any> {
580
- readonly frameworkName: string;
581
- readonly handler: Handler<Input, Output>;
582
- readonly client: Client;
583
- private readonly hmacEnabled;
584
- private readonly http;
585
- private readonly workflows;
586
- private readonly agents;
587
- constructor(options: INovuRequestHandlerOptions<Input, Output>);
588
- createHandler(): (...args: Input) => Promise<Output>;
589
- private getStaticHeaders;
590
- private createResponse;
591
- private createError;
592
- private handleAction;
593
- private getPostActionMap;
594
- triggerAction(triggerEvent: EventTriggerParams): () => Promise<IActionResponse<string>>;
595
- private getGetActionMap;
596
- private handlePostAction;
597
- private handleGetAction;
598
- private runAgentHandler;
599
- private handleError;
600
- private validateHmac;
601
- }
602
-
603
- /**
604
- * Define a new notification workflow.
605
- */
606
- declare function workflow<T_PayloadSchema extends Schema, T_ControlSchema extends Schema, T_EnvSchema extends Schema, T_PayloadValidated extends Record<string, unknown> = FromSchema<T_PayloadSchema>, T_PayloadUnvalidated extends Record<string, unknown> = FromSchemaUnvalidated<T_PayloadSchema>, T_Controls extends Record<string, unknown> = FromSchema<T_ControlSchema>, T_Env extends Record<string, unknown> = FromSchema<T_EnvSchema>>(workflowId: string, execute: Execute<T_PayloadValidated, T_Controls, T_Env>, workflowOptions?: WorkflowOptions<T_PayloadSchema, T_ControlSchema, T_EnvSchema>): Workflow<T_PayloadUnvalidated>;
607
-
608
- export { type Agent as A, Client as C, type EditPayload as E, type FileRef as F, type INovuRequestHandlerOptions as I, type MessageContent as M, NovuRequestHandler as N, type ReplyContent as R, type ServeHandlerOptions as S, type TriggerSignal as T, type AgentAction as a, type AgentActionContext as b, type AgentAttachment as c, type AgentBridgeRequest as d, type AgentContext as e, type AgentConversation as f, AgentDeliveryError as g, AgentEventEnum as h, type AgentHandlers as i, type AgentHistoryEntry as j, type AgentMessage as k, type AgentMessageAuthor as l, type AgentMessageContext as m, type AgentPlatformContext as n, type AgentReaction as o, type AgentReactionContext as p, type AgentReplyPayload as q, type AgentResolveContext as r, type AgentSubscriber as s, type MetadataSignal as t, type ReplyHandle as u, type SentMessageInfo as v, type Signal as w, agent as x, workflow as y };
772
+ export { type Agent as A, type ToolApprovalControl as B, type AgentBridgeRequest as C, type AgentReplyPayload as D, type DeleteMessagePayload as E, type FileRef as F, type EditPayload as G, type MetadataSignal as H, type ITriggerPayload as I, type ReplyContent as J, type Signal as K, type TriggerSignal as L, type MessageContent as M, buildApprovalActionId as N, parseApprovalActionId as O, type ParsedApprovalAction as P, type ReplyHandle as R, type SentMessageInfo as S, type ToolApprovalCard as T, type WorkflowPreferencesPartial as W, type AgentAction as a, type AgentActionContext as b, type AgentAttachment as c, type AgentContext as d, type AgentConversation as e, type AgentHandlerContext as f, type AgentHandlers as g, type AgentHistoryEntry as h, type AgentMessage as i, type AgentMessageAuthor as j, type AgentMessageContext as k, type AgentPlatformContext as l, type AgentReaction as m, type AgentReactionContext as n, type AgentResolveContext as o, type AgentSubscriber as p, type AgentToolCall as q, type ToolApprovalConfig as r, type ToolApprovalDecision as s, type TriggerRecipientsPayload as t, type ISubscriberPayload as u, TriggerEventStatusEnum as v, type ToolResult as w, type ToolApprovalRequestPayload as x, AgentEventEnum as y, type TypingControl as z };