-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathworkflows.ts
More file actions
247 lines (222 loc) · 7.69 KB
/
workflows.ts
File metadata and controls
247 lines (222 loc) · 7.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
import { Workflow } from "@knocklabs/mgmt/resources/index.js";
import { z } from "zod";
import { KnockTool } from "../knock-tool.js";
import { workflowStepTools } from "./workflow-steps.js";
/**
* A slimmed down version of the Workflow resource that is easier to work with in the LLM.
*/
export type SerializedWorkflow = {
key: string;
name: string;
description: string | undefined;
categories: string[] | undefined;
schema: Record<string, unknown> | undefined;
};
export function serializeWorkflowResponse(
workflow: Workflow
): SerializedWorkflow {
return {
key: workflow.key,
name: workflow.name,
description: workflow.description,
categories: workflow.categories,
schema: workflow.trigger_data_json_schema,
};
}
const listWorkflows = KnockTool({
method: "list_workflows",
name: "List workflows",
description: `
List all workflows available for the given environment. Returns structural information about the workflows, including the key, name, description, and categories.
Use this tool when you need to understand which workflows are available to be called.
`,
parameters: z.object({
environment: z
.string()
.optional()
.describe(
"(string): The environment to list workflows for. Defaults to `development`."
),
}),
execute: (knockClient, config) => async (params) => {
const allWorkflows: SerializedWorkflow[] = [];
const listParams = {
environment: params.environment ?? config.environment ?? "development",
};
for await (const workflow of knockClient.workflows.list(listParams)) {
allWorkflows.push(serializeWorkflowResponse(workflow));
}
return allWorkflows;
},
});
const getWorkflow = KnockTool({
method: "get_workflow",
name: "Get workflow",
description: `
Get a workflow by key. Returns structural information about the workflow, including the key, name, description, and categories.
`,
parameters: z.object({
environment: z
.string()
.optional()
.describe(
"(string): The environment to get the workflow for. Defaults to `development`."
),
workflowKey: z
.string()
.describe("(string): The key of the workflow to get."),
}),
execute: (knockClient, config) => async (params) => {
const workflow = await knockClient.workflows.retrieve(params.workflowKey, {
environment: params.environment ?? config.environment ?? "development",
});
return serializeWorkflowResponse(workflow);
},
});
const triggerWorkflow = KnockTool({
method: "trigger_workflow",
name: "Trigger workflow",
description: `
Trigger a workflow for one or more recipients, which may produce one or more messages for each recipient depending on the workflow's steps.
Use this tool when you need to trigger a workflow to send a notification across the channels configured for the workflow.
When recipients aren't provided, the workflow will be triggered for the current user specified in the config.
Returns the workflow run ID, which can be used to lookup messages produced by the workflow.
`,
parameters: z.object({
environment: z
.string()
.optional()
.describe(
"(string): The environment to trigger the workflow in. Defaults to `development`."
),
workflowKey: z
.string()
.describe("(string): The key of the workflow to trigger."),
recipients: z
.array(z.string())
.optional()
.describe(
"(array): The recipients to trigger the workflow for. This is an array of user IDs."
),
data: z
.record(z.string(), z.any())
.optional()
.describe("(object): Data to pass to the workflow."),
tenant: z
.record(z.string(), z.any())
.optional()
.describe(
"(object): The tenant to trigger the workflow for. Must contain an id if being sent."
),
}),
execute: (knockClient, config) => async (params) => {
const publicClient = await knockClient.publicApi(params.environment);
const result = await publicClient.workflows.trigger(params.workflowKey, {
recipients: params.recipients ?? [config.userId] ?? [],
data: params.data,
tenant: params.tenant ?? config.tenantId,
});
return result.workflow_run_id;
},
});
const createWorkflow = KnockTool({
method: "create_workflow",
name: "Create workflow",
description: `
Create a new workflow, which is used to control the flow of notifications. Use this tool when you're asked to create a new workflow, or you need to create a new workflow before adding a step to it.
`,
parameters: z.object({
environment: z
.string()
.optional()
.describe(
"(string): The environment to create the workflow in. Defaults to `development`."
),
workflowKey: z
.string()
.describe(
"(string): The key of the workflow to create. Only use a kebab-case string with no spaces or special characters."
),
name: z.string().describe("(string): The name of the workflow."),
description: z
.string()
.describe("(string): The description of the workflow."),
categories: z
.array(z.string())
.describe("(array): The categories to add to the workflow."),
}),
execute: (knockClient, config) => async (params) => {
const result = await knockClient.workflows.upsert(params.workflowKey, {
environment: config.environment ?? "development",
workflow: {
name: params.name,
description: params.description,
categories: params.categories ?? [],
steps: [],
},
});
return serializeWorkflowResponse(result.workflow);
},
});
const createOneOffWorkflowSchedule = KnockTool({
method: "create_one_off_workflow_schedule",
name: "Create one-off workflow schedule",
description: `
Create a one-off workflow schedule for a user. Use this tool when you need to schedule the execution of a workflow for a specific user in the future, like to power a delayed notification.
Schedules can accept a set of data that will be passed to the workflow trigger when it is executed. When the userId is not provided, the schedule will be created for the current user specified in the config.
Examples:
- In three days, send a welcome email to a user
- In one hour, send a password reset email to a user
- In two weeks, send a survey to a user
`,
parameters: z.object({
environment: z
.string()
.optional()
.describe(
"(string): The environment to create the workflow in. Defaults to `development`."
),
workflowKey: z
.string()
.describe("(string): The key of the workflow to schedule."),
userId: z
.string()
.describe(
"(string): The userId of the user to schedule the workflow for."
),
scheduledAt: z
.string()
.describe(
"(string): The date and time to schedule the workflow for. Must be in ISO 8601 format."
),
data: z
.record(z.string(), z.any())
.optional()
.describe("(object): Data to pass to the workflow."),
}),
execute: (knockClient, config) => async (params) => {
const publicClient = await knockClient.publicApi(params.environment);
return await publicClient.workflows.createSchedules(params.workflowKey, {
recipients: [params.userId ?? config.userId],
scheduled_at: params.scheduledAt,
data: params.data,
});
},
});
export const workflows = {
listWorkflows,
getWorkflow,
triggerWorkflow,
createWorkflow,
...workflowStepTools,
createOneOffWorkflowSchedule,
};
export const permissions = {
read: ["listWorkflows", "getWorkflow"],
manage: [
"createWorkflow",
"createOneOffWorkflowSchedule",
"triggerWorkflow",
].concat(...Object.keys(workflowStepTools)),
trigger: [],
};