kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
Merge pull request #14 from transitive-bullshit/novu
commit
979c129b8e
|
@ -0,0 +1,86 @@
|
|||
<h1 align="center">Novu Agentic Service</h1>
|
||||
|
||||
## Intro
|
||||
|
||||
[Novu][novu] provides open-source notification infrastructure for all communication channels in one place: Email, SMS, Direct, and Push. It integrates with almost all major email providers (Mailgun, Sendgrid, Postmark, etc.), SMS providers (e.g., Twilio or Plivo), and a large selection of push and chat providers (such as OneSignal or Slack) while providing a unified API for sending notifications.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
Ensure the following environment variable is set:
|
||||
|
||||
- `NOVU_API_KEY` - Novu API key.
|
||||
|
||||
Otherwise, you can pass it in as an argument to the `Novu` constructor.
|
||||
|
||||
### How to Retrieve API Key on Novu.co
|
||||
|
||||
1. Open https://web.novu.co and sign in with your existing Novu account credentials (create a new account with your email address and a password or sign in with GitHub if you don't have an account yet)
|
||||
|
||||
2. Navigate to "Settings"
|
||||
|
||||

|
||||
|
||||
3. Click "API Keys"
|
||||
|
||||

|
||||
|
||||
4. Click here to copy your API key to your clipboard
|
||||
|
||||

|
||||
|
||||
### Create a Notification Template
|
||||
|
||||
For each notification type you want to send, you need to create a template in Novu. This is a one-time setup step that you can do on the Novu web interface.
|
||||
|
||||
It is possible to customize the notification content at each invocation via handlebars-style placeholders. For example, you can create a template for an email notification that looks like this:
|
||||
|
||||
```
|
||||
Hello {{name}},
|
||||
{{content}}
|
||||
```
|
||||
|
||||
The placeholders will be replaced with the actual values of the `payload` object you pass to the `send` method.
|
||||
|
||||
To create a template, follow these steps:
|
||||
|
||||
1. Open https://web.novu.co and sign in with your Novu account credentials
|
||||
|
||||
2. Click "Notifications"
|
||||
|
||||

|
||||
|
||||
3. Click "Create Workflow" on the top-right
|
||||
|
||||

|
||||
|
||||
4. Double-click the "notification name" field and enter the name of the template. For this example, we choose the name `send-sms`. This is the event name with which the respective notification may be triggered from the API.
|
||||
|
||||

|
||||
|
||||
5. To create, for example, a SMS notification template, click and hold "SMS" and drag it to the left underneath the trigger.
|
||||
|
||||

|
||||
|
||||
6. Click inside the "SMS message content" text field on the right and enter the content of your SMS, e.g. a handlebars placeholder such as `{{content}}`.
|
||||
|
||||

|
||||
|
||||
7. When you're done, click "Update" on the top-right. You are now ready to send SMS notifications via the API. For example, to manually trigger a notification via the Agentic Novu Service client:
|
||||
|
||||
```ts
|
||||
import { NovuClient } from '@agentic/core'
|
||||
|
||||
const client = new NovuClient()
|
||||
|
||||
client.triggerEvent('send-sms', { content: 'Hello World!' }, [{
|
||||
subscriberId: '1',
|
||||
name: 'Jane Doe',
|
||||
email: 'jane.doe-123@hotmail.com'
|
||||
phone: '+11234567890'
|
||||
}])
|
||||
```
|
||||
|
||||
The `subscriberId` is a required field with the ID of the subscriber in Novu. If a subscriber with a provided `subscriberId` does not exist yet in Novu, a new subscriber will be created before the trigger will be executed synchronously. You can find more information about subscribers [in the official Novu documentation][novu-subscribers].
|
||||
|
||||
[novu]: https://novu.co/
|
||||
[novu-subscribers]: https://docs.novu.co/platform/subscribers
|
|
@ -6,4 +6,6 @@ export * from './human-feedback'
|
|||
|
||||
export * from './services/metaphor'
|
||||
export * from './services/serpapi'
|
||||
export * from './services/novu'
|
||||
export * from './tools/metaphor'
|
||||
export * from './tools/novu'
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import ky from 'ky'
|
||||
|
||||
export type NovuSubscriber = {
|
||||
subscriberId: string
|
||||
email?: string
|
||||
firstName?: string
|
||||
lastName?: string
|
||||
phone?: string
|
||||
}
|
||||
|
||||
export type NovuTriggerEventResponse = {
|
||||
data: {
|
||||
acknowledged?: boolean
|
||||
status?: string
|
||||
transactionId?: string
|
||||
}
|
||||
}
|
||||
|
||||
export class NovuClient {
|
||||
apiKey: string
|
||||
baseUrl: string
|
||||
|
||||
constructor({
|
||||
apiKey = process.env.NOVU_API_KEY,
|
||||
baseUrl = 'https://api.novu.co/v1'
|
||||
}: {
|
||||
apiKey?: string
|
||||
baseUrl?: string
|
||||
} = {}) {
|
||||
if (!apiKey) {
|
||||
throw new Error(`Error NovuClient missing required "apiKey"`)
|
||||
}
|
||||
this.apiKey = apiKey
|
||||
this.baseUrl = baseUrl
|
||||
}
|
||||
|
||||
async triggerEvent({
|
||||
name,
|
||||
payload,
|
||||
to
|
||||
}: {
|
||||
name: string
|
||||
payload: Record<string, unknown>
|
||||
to: NovuSubscriber[]
|
||||
}) {
|
||||
const url = `${this.baseUrl}/events/trigger`
|
||||
const headers = {
|
||||
Authorization: `ApiKey ${this.apiKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
const response = await ky.post(url, {
|
||||
headers,
|
||||
json: {
|
||||
name,
|
||||
payload,
|
||||
to
|
||||
}
|
||||
})
|
||||
return response.json<NovuTriggerEventResponse>()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
import { z } from 'zod'
|
||||
|
||||
import * as types from '../types'
|
||||
import { Agentic } from '../agentic'
|
||||
import { NovuClient } from '../services/novu'
|
||||
import { BaseTask } from '../task'
|
||||
|
||||
export const NovuNotificationToolInputSchema = z.object({
|
||||
name: z.string(),
|
||||
payload: z.record(z.unknown()),
|
||||
to: z.array(
|
||||
z.object({
|
||||
subscriberId: z.string(),
|
||||
email: z.string().optional(),
|
||||
firstName: z.string().optional(),
|
||||
lastName: z.string().optional(),
|
||||
phone: z.string().optional()
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
export type NovuNotificationToolInput = z.infer<
|
||||
typeof NovuNotificationToolInputSchema
|
||||
>
|
||||
|
||||
export const NovuNotificationToolOutputSchema = z.object({
|
||||
data: z.object({
|
||||
acknowledged: z.boolean().optional(),
|
||||
status: z.string().optional(),
|
||||
transactionId: z.string().optional()
|
||||
})
|
||||
})
|
||||
|
||||
export type NovuNotificationToolOutput = z.infer<
|
||||
typeof NovuNotificationToolOutputSchema
|
||||
>
|
||||
|
||||
export class NovuNotificationTool extends BaseTask<
|
||||
typeof NovuNotificationToolInputSchema,
|
||||
typeof NovuNotificationToolOutputSchema
|
||||
> {
|
||||
_novuClient: NovuClient
|
||||
|
||||
constructor({
|
||||
agentic,
|
||||
novuClient = new NovuClient()
|
||||
}: {
|
||||
agentic: Agentic
|
||||
novuClient?: NovuClient
|
||||
}) {
|
||||
super({
|
||||
agentic
|
||||
})
|
||||
|
||||
this._novuClient = novuClient
|
||||
}
|
||||
|
||||
public override get inputSchema() {
|
||||
return NovuNotificationToolInputSchema
|
||||
}
|
||||
|
||||
public override get outputSchema() {
|
||||
return NovuNotificationToolOutputSchema
|
||||
}
|
||||
|
||||
protected override async _call(
|
||||
input: NovuNotificationToolInput
|
||||
): Promise<types.TaskResponse<typeof NovuNotificationToolOutputSchema>> {
|
||||
// TODO: handle errors gracefully
|
||||
input = this.inputSchema.parse(input)
|
||||
|
||||
const result = await this._novuClient.triggerEvent(input)
|
||||
return {
|
||||
result,
|
||||
metadata: {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import test from 'ava'
|
||||
|
||||
import { NovuClient } from '../src/services/novu'
|
||||
import './_utils'
|
||||
|
||||
test('NovuClient.triggerEvent', async (t) => {
|
||||
if (!process.env.NOVU_API_KEY) {
|
||||
return t.pass()
|
||||
}
|
||||
|
||||
t.timeout(2 * 60 * 1000)
|
||||
const client = new NovuClient()
|
||||
|
||||
const result = await client.triggerEvent({
|
||||
name: 'send-email',
|
||||
payload: {
|
||||
content: 'Hello World!'
|
||||
},
|
||||
to: [
|
||||
{
|
||||
subscriberId: '123456',
|
||||
email: 'pburckhardt@outlook.com'
|
||||
}
|
||||
]
|
||||
})
|
||||
t.truthy(result)
|
||||
})
|
Ładowanie…
Reference in New Issue