@knocklabs/agent-toolkit 0.1.9 → 0.1.11

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.
@@ -248,98 +248,48 @@ var createOrUpdateMessageType = KnockTool({
248
248
  method: "create_or_update_message_type",
249
249
  name: "Create or update message type",
250
250
  description: `
251
- Create or update a message type. A message type is a schema that defines fields available to an editor within Knock. Message types always have at least one variant, that MUST be named "default".
252
-
253
- Use this tool when you need to create a new message type, or update an existing message type. You must pass the FULL message type to this tool if you're going to update an existing message type.
251
+ Create or update a message type. A message type is a schema that defines fields available to an editor within Knock. Message types always have at least one variant, that MUST be named "default". Use this tool when you need to create a new message type, or update an existing message type.
252
+
253
+ ## Schema and fields
254
+
255
+ The schema defines the fields available to an editor within Knock. A variant should have at least one field. Fields can be of different types, including: text, markdown, select, multi-select, image, and button.
254
256
 
255
- The preview is a string of HTML that will be rendered in the Knock UI as a representation of the message type. It is shared across all variants. It supports liquid, where the field name is available as a variable, so a field named "text" will be rendered as {{ text }}.
257
+ Each field must have a key, label, and type. Some fields like \`select\` and \`multi_select\` have additional settings that can be used to configure the field.
256
258
 
257
259
  <example>
258
- <description>
259
- Create a new message type for a banner component that has a text and an action URL.
260
- </description>
261
- <input>
262
- {
263
- "messageTypeKey": "banner",
264
- "name": "Banner",
265
- "description": "A banner component that has a text and an action URL.",
266
- "preview": "<div>{{ text }}</div>",
267
- "variants": [
268
- {
269
- "key": "default",
270
- "name": "Default",
271
- "fields": [
272
- {
273
- "key": "text",
274
- "type": "text",
275
- "label": "Text",
276
- "settings": {
277
- "max_length": 100,
278
- },
279
- },
280
- {
281
- "key": "action_url",
282
- "type": "text",
283
- "label": "Action URL",
284
- "settings": {
285
- "placeholder": "https://example.com",
286
- },
287
- }
288
- ]
289
- }
290
- ]
291
- }
292
- </input>
260
+ {
261
+ "key": "text",
262
+ "label": "Text",
263
+ "type": "text",
293
264
  </example>
265
+
294
266
  <example>
295
- <description>
296
- Create a message type for a card component that has an icon type, title, body, and a single action button.
297
- </description>
298
- <input>
299
- {
300
- "messageTypeKey": "card",
301
- "name": "Card",
302
- "description": "A single-action card component.",
303
- "preview": "
304
- <div>
305
- <h2>{{ title }}</h2>
306
- <p>{{ body }}</p>
307
- <button>Action</button>
308
- </div>
309
- ",
310
- "variants": [
267
+ {
268
+ "key": "select",
269
+ "label": "Select",
270
+ "type": "select",
271
+ "settings": {
272
+ "options": [
311
273
  {
312
- "key": "default",
313
- "name": "Default",
314
- "fields": [
315
- {
316
- "key": "icon_type",
317
- "type": "select",
318
- "label": "Icon type",
319
- "settings": {
320
- "options": [
321
- {
322
- "value": "warning",
323
- "label": "Warning",
324
- },
325
- ]
326
- },
327
- },
328
- {
329
- "key": "description",
330
- "type": "markdown",
331
- "label": "Description",
332
- },
333
- {
334
- "key": "action_button",
335
- "type": "button",
336
- "label": "Action button",
337
- },
338
- ]
339
- }
340
- ]
341
- }
342
- </input>
274
+ "value": "option1",
275
+ "label": "Option 1",
276
+ },
277
+ ],
278
+ },
279
+ }
280
+ </example>
281
+
282
+ ## Preview templates
283
+
284
+ The preview is a string of HTML that will be rendered in the Knock UI as a representation of the message type. It is shared across all variants. It supports liquid, where the field name is available as a variable, so a field named "text" will be rendered as {{ text }}. All fields should be included in the preview.
285
+
286
+ You can make an educated guess as to what the preview template should look like based on the name of the message type and the fields. You can use plain CSS to style the preview by supplying a style tag in the preview. Use simple selectors like .class-name to style elements.
287
+
288
+ <example>
289
+ {
290
+ "preview": "<style>div { color: red; }</style>
291
+ <div>Hello there, {{ text }}</div>"
292
+ }
343
293
  </example>
344
294
  `,
345
295
  parameters: z5.object({
@@ -578,11 +528,77 @@ var listPartials = KnockTool({
578
528
  return allPartials;
579
529
  }
580
530
  });
531
+ var getPartial = KnockTool({
532
+ method: "get_partial",
533
+ name: "Get partial",
534
+ description: `
535
+ Get a partial by its key. Use this tool when you need to know if a specific partial exists by key.
536
+ `,
537
+ parameters: z8.object({
538
+ environment: z8.string().optional().describe(
539
+ "(string): The environment to get the partial for. Defaults to `development`."
540
+ ),
541
+ key: z8.string().describe("(string): The key of the partial to get.")
542
+ }),
543
+ execute: (knockClient, config) => async (params) => {
544
+ const partial = await knockClient.partials.retrieve(params.key, {
545
+ environment: params.environment ?? config.environment ?? "development"
546
+ });
547
+ return serializePartial(partial);
548
+ }
549
+ });
550
+ var createOrUpdatePartial = KnockTool({
551
+ method: "upsert_partial",
552
+ name: "Upsert partial",
553
+ description: `
554
+ Create or update a partial. A partial is a reusable piece of content that can be used in a template. Use this tool when you need to create a new partial or update an existing one.
555
+
556
+ When working with a partial you must chose the type of the partial. The type determines the format of the content. If you're working with an email template, you should use the "html" or "markdown" type.
557
+
558
+ If you need to work with dynamic content in your partial you can use liquid syntax. Liquid is a templating language that is supported in Knock. You can supply a variable like {{ some_variable }} in the content and it will be replaced with the actual value when the partial is used in a template.
559
+
560
+ <example>
561
+ {
562
+ "name": "Greeting",
563
+ "key": "greeting",
564
+ "type": "html",
565
+ "content": "<div>Hello, {{ recipient_name }}</div>"
566
+ }
567
+ </example>
568
+
569
+ Changes to a partial MUST be committed before they can be used in a template.
570
+ `,
571
+ parameters: z8.object({
572
+ environment: z8.string().optional().describe(
573
+ "(string): The environment to upsert the partial for. Defaults to `development`."
574
+ ),
575
+ key: z8.string().describe("(string): The key of the partial to upsert."),
576
+ name: z8.string().describe("(string): The name of the partial."),
577
+ description: z8.string().optional().describe("(string): The description of the partial."),
578
+ content: z8.string().describe("(string): The content of the partial."),
579
+ type: z8.enum(["html", "text", "json", "markdown"]).describe("(string): The type of the partial.")
580
+ }),
581
+ execute: (knockClient, config) => async (params) => {
582
+ const partial = await knockClient.partials.upsert(params.key, {
583
+ environment: params.environment ?? config.environment ?? "development",
584
+ partial: {
585
+ name: params.name,
586
+ description: params.description,
587
+ content: params.content,
588
+ type: params.type
589
+ }
590
+ });
591
+ return serializePartial(partial.partial);
592
+ }
593
+ });
581
594
  var partials = {
582
- listPartials
595
+ getPartial,
596
+ listPartials,
597
+ createOrUpdatePartial
583
598
  };
584
599
  var permissions9 = {
585
- read: ["listPartials"]
600
+ read: ["getPartial", "listPartials"],
601
+ manage: ["createOrUpdatePartial"]
586
602
  };
587
603
 
588
604
  // src/lib/tools/tenants.ts
@@ -1015,7 +1031,488 @@ var permissions11 = {
1015
1031
  };
1016
1032
 
1017
1033
  // src/lib/tools/workflows.ts
1034
+ import { z as z14 } from "zod";
1035
+
1036
+ // src/lib/tools/workflow-steps.ts
1018
1037
  import { z as z13 } from "zod";
1038
+ function generateStepRef(stepType) {
1039
+ const randomString = Math.random().toString(36).substring(2, 7).toUpperCase();
1040
+ return `${stepType}_${randomString}`;
1041
+ }
1042
+ async function updateWorkflowWithStep(knockClient, workflow2, step, environment) {
1043
+ const workflowParams = {
1044
+ environment,
1045
+ workflow: {
1046
+ ...workflow2,
1047
+ steps: [...workflow2.steps, step]
1048
+ }
1049
+ };
1050
+ const result = await knockClient.workflows.upsert(
1051
+ workflow2.key,
1052
+ workflowParams
1053
+ );
1054
+ return serializeWorkflowResponse(result.workflow);
1055
+ }
1056
+ var SHARED_PROMPTS = {
1057
+ workflow: `
1058
+ To use this tool, you MUST first create a workflow using the \`createWorkflow\` tool, or get an existing workflow using the \`getWorkflow\` tool. You ONLY need to pass the workflow key to this tool and the sms step will be added to the end of the workflow's steps array.
1059
+ `,
1060
+ liquid: `
1061
+ ## Personalization
1062
+
1063
+ If you need to include personalization, you can use liquid to include dynamic content in the email and the subject line.
1064
+ The following variables are always available to use in liquid:
1065
+
1066
+ - \`recipient.id\`: The ID of the recipient.
1067
+ - \`recipient.name\`: The name of the recipient.
1068
+ - \`recipient.email\`: The email of the recipient.
1069
+ - \`recipient.phone_number\`: The phone number of the recipient.
1070
+
1071
+ You can supply **any** other dynamic variables you think are needed by referencing them under the \`data\` key. You add those like \`{{ data.variable_name }}\`.
1072
+
1073
+ <example>
1074
+ # Hello, {{ recipient.name }}
1075
+
1076
+ This is a dynamic message:
1077
+
1078
+ > {{ data.message }}
1079
+ </example>
1080
+
1081
+ ## Liquid helpers
1082
+
1083
+ You have access to a full suite of liquid helpers to help you perform common templating tasks. The full list of helper is available here: https://docs.knock.app/designing-workflows/template-editor/reference-liquid-helpers.
1084
+
1085
+ <example>
1086
+ Hello, {{ recipient.name | split: " " | first | default: "there" }}
1087
+ </example>
1088
+ `
1089
+ };
1090
+ var createEmailStepInWorkflow = KnockTool({
1091
+ method: "create_email_step_in_workflow",
1092
+ name: "Create email step in workflow",
1093
+ description: `
1094
+ Creates an email step in a workflow. Use this tool when you're asked to create an email notification and you need to specify the content of the email.
1095
+
1096
+ ${SHARED_PROMPTS.workflow}
1097
+
1098
+ ## Blocks
1099
+
1100
+ The content of the email is supplied as an array of "blocks". The simplest block is a "markdown" block, which supports content in a markdown format. That should always be your default block type.
1101
+
1102
+ The following block types are supported:
1103
+
1104
+ - \`markdown\`: A block that supports markdown content.
1105
+ - \`html\`: A block that supports markdown content.
1106
+ - \`image\`: A block that supports an image.
1107
+ - \`button_set\`: A block that adds one or more buttons.
1108
+ - \`divider\`: A block that supports a divider.
1109
+ - \`partial\`: A block that supports rendering a shared content partial.
1110
+
1111
+ <example>
1112
+ {
1113
+ "blocks": [
1114
+ {
1115
+ "type": "markdown",
1116
+ "content": "# Greetings from Knock!
1117
+ Hello, {{ recipient.name }}."
1118
+ },
1119
+ {
1120
+ "type": "divider"
1121
+ },
1122
+ {
1123
+ "type": "button_set",
1124
+ "buttons": [
1125
+ {
1126
+ "label": "Approve",
1127
+ "action": "{{ data.primary_action_url }}",
1128
+ "variant": "solid"
1129
+ }
1130
+ ]
1131
+ }
1132
+ ]
1133
+ }
1134
+ </example>
1135
+
1136
+ ### Markdown
1137
+
1138
+ When using the \`markdown\` block, you must supply a \`content\` key. The \`content\` key supports markdown.
1139
+
1140
+ <example>
1141
+ {
1142
+ "type": "markdown",
1143
+ "content": "Hello, world!"
1144
+ }
1145
+ </example>
1146
+
1147
+ ### HTML
1148
+
1149
+ The \`html\` block supports raw HTML content. This should be used sparingly, and only when you need to include custom HTML content that markdown doesn't support. When using the \`html\` block, you must supply a \`content\` key. HTML content can include liquid personalization.
1150
+
1151
+ ### Button sets
1152
+
1153
+ Button sets are a special type of block that allows you to add one or more buttons to the email. They're useful for directing users to take specific actions. Button sets support one or more buttons. You must always include at least one button in a button set.
1154
+
1155
+ Buttons are specified in a button set under the \`buttons\` key. Each button requires a \`label\`, \`action\`, and \`variant\`. The ONLY valid variants are \`solid\` and \`outline\`. The label and action can allowed be dynamic variables using liquid.
1156
+
1157
+ <example>
1158
+ {
1159
+ "type": "button_set",
1160
+ "buttons": [
1161
+ {
1162
+ "label": "Approve",
1163
+ "action": "https://example.com",
1164
+ "variant": "solid"
1165
+ }
1166
+ ]
1167
+ }
1168
+ </example>
1169
+
1170
+ ### Image
1171
+
1172
+ Images are a special type of block that allows you to add an image to the email. When using the \`image\` block, you must supply a \`url\` key. The \`url\` key supports a URL to an image.
1173
+
1174
+ <example>
1175
+ {
1176
+ "type": "image",
1177
+ "url": "https://example.com/image.png"
1178
+ }
1179
+ </example>
1180
+
1181
+ ${SHARED_PROMPTS.liquid}
1182
+
1183
+ ## Partials
1184
+
1185
+ If you need to reuse content across multiple emails, you can create or reference an existing partial and reference it in the email. You should only use partials if you're instructed to do so.
1186
+
1187
+ When you do need to use a partial in an email, you can use the \`partial\` block and then set the \`key\` to the key of the partial you want to use. If the partial requires any variables, you pass those in the \`attrs\` key.
1188
+
1189
+ ## Writing style
1190
+
1191
+ Unless asked otherwise, you should write content for the email in a concise and formal writing style. Do NOT use complex language or try to over explain. Keep the subject line to 8 words or less.
1192
+ `,
1193
+ parameters: z13.object({
1194
+ workflowKey: z13.string().describe("(string): The key of the workflow to add the step to."),
1195
+ blocks: z13.array(z13.any()).describe("(array): The blocks for the email step."),
1196
+ subject: z13.string().describe("(string): The subject of the email step.")
1197
+ }),
1198
+ execute: (knockClient, config) => async (params) => {
1199
+ const workflow2 = await knockClient.workflows.retrieve(params.workflowKey, {
1200
+ environment: config.environment ?? "development"
1201
+ });
1202
+ const emailChannelsPage = await knockClient.channels.list();
1203
+ const emailChannels = emailChannelsPage.entries.filter(
1204
+ (channel) => channel.type === "email"
1205
+ );
1206
+ if (emailChannels.length === 0) {
1207
+ throw new Error("No email channels found");
1208
+ }
1209
+ return await updateWorkflowWithStep(
1210
+ knockClient,
1211
+ workflow2,
1212
+ // @ts-expect-error
1213
+ {
1214
+ type: "channel",
1215
+ channel_key: emailChannels[0].key,
1216
+ template: {
1217
+ settings: {
1218
+ layout_key: "default"
1219
+ },
1220
+ subject: params.subject,
1221
+ visual_blocks: params.blocks
1222
+ },
1223
+ ref: generateStepRef("email")
1224
+ },
1225
+ config.environment ?? "development"
1226
+ );
1227
+ }
1228
+ });
1229
+ var createSmsStepInWorkflow = KnockTool({
1230
+ method: "create_sms_step_in_workflow",
1231
+ name: "Create sms step in workflow",
1232
+ description: `
1233
+ Creates an SMS step in a workflow. Use this tool when you're asked to create an SMS notification and you need to specify the content of the SMS.
1234
+
1235
+ ${SHARED_PROMPTS.workflow}
1236
+
1237
+ ${SHARED_PROMPTS.liquid}
1238
+ `,
1239
+ parameters: z13.object({
1240
+ workflowKey: z13.string().describe("(string): The key of the workflow to add the step to."),
1241
+ content: z13.string().describe("(string): The content of the SMS.")
1242
+ }),
1243
+ execute: (knockClient, config) => async (params) => {
1244
+ const workflow2 = await knockClient.workflows.retrieve(params.workflowKey, {
1245
+ environment: config.environment ?? "development"
1246
+ });
1247
+ const smsChannelsPage = await knockClient.channels.list();
1248
+ const smsChannels = smsChannelsPage.entries.filter(
1249
+ (channel) => channel.type === "sms"
1250
+ );
1251
+ if (smsChannels.length === 0) {
1252
+ throw new Error("No SMS channels found");
1253
+ }
1254
+ return await updateWorkflowWithStep(
1255
+ knockClient,
1256
+ workflow2,
1257
+ // @ts-expect-error
1258
+ {
1259
+ type: "channel",
1260
+ channel_key: smsChannels[0].key,
1261
+ template: {
1262
+ text_body: params.content
1263
+ },
1264
+ ref: generateStepRef("sms")
1265
+ },
1266
+ config.environment ?? "development"
1267
+ );
1268
+ }
1269
+ });
1270
+ var createPushStepInWorkflow = KnockTool({
1271
+ method: "create_push_step_in_workflow",
1272
+ name: "Create push step in workflow",
1273
+ description: `
1274
+ Creates a push step in a workflow. Use this tool when you're asked to create a push notification and you need to specify the content of the push notification.
1275
+
1276
+ ${SHARED_PROMPTS.workflow}
1277
+
1278
+ ${SHARED_PROMPTS.liquid}
1279
+
1280
+ Be terse in your writing as this is a push notification and should be direct and to the point.
1281
+ `,
1282
+ parameters: z13.object({
1283
+ workflowKey: z13.string().describe("(string): The key of the workflow to add the step to."),
1284
+ title: z13.string().describe("(string): The title of the push notification."),
1285
+ content: z13.string().describe("(string): The content (body) of the push notification.")
1286
+ }),
1287
+ execute: (knockClient, config) => async (params) => {
1288
+ const workflow2 = await knockClient.workflows.retrieve(params.workflowKey, {
1289
+ environment: config.environment ?? "development"
1290
+ });
1291
+ const pushChannelsPage = await knockClient.channels.list();
1292
+ const pushChannels = pushChannelsPage.entries.filter(
1293
+ (channel) => channel.type === "push"
1294
+ );
1295
+ if (pushChannels.length === 0) {
1296
+ throw new Error("No push channels found");
1297
+ }
1298
+ return await updateWorkflowWithStep(
1299
+ knockClient,
1300
+ workflow2,
1301
+ // @ts-expect-error
1302
+ {
1303
+ type: "channel",
1304
+ channel_key: pushChannels[0].key,
1305
+ template: {
1306
+ title: params.title,
1307
+ text_body: params.content
1308
+ },
1309
+ ref: generateStepRef("push")
1310
+ },
1311
+ config.environment ?? "development"
1312
+ );
1313
+ }
1314
+ });
1315
+ var createInAppFeedStepInWorkflow = KnockTool({
1316
+ method: "create_in_app_feed_step_in_workflow",
1317
+ name: "Create in app feed step in workflow",
1318
+ description: `
1319
+ Creates an in app feed step in a workflow. Use this tool when you're asked to create an in app feed notification and you need to specify the content of the in app feed notification.
1320
+
1321
+ ${SHARED_PROMPTS.workflow}
1322
+
1323
+ ${SHARED_PROMPTS.liquid}
1324
+ `,
1325
+ parameters: z13.object({
1326
+ workflowKey: z13.string().describe("(string): The key of the workflow to add the step to."),
1327
+ actionUrl: z13.string().describe(
1328
+ "(string): The URL to navigate to when the in app feed is tapped."
1329
+ ),
1330
+ body: z13.string().describe("(string): The markdown content of the in app feed.")
1331
+ }),
1332
+ execute: (knockClient, config) => async (params) => {
1333
+ const workflow2 = await knockClient.workflows.retrieve(params.workflowKey, {
1334
+ environment: config.environment ?? "development"
1335
+ });
1336
+ const inAppChannelsPage = await knockClient.channels.list();
1337
+ const inAppChannels = inAppChannelsPage.entries.filter(
1338
+ (channel) => channel.type === "in_app_feed"
1339
+ );
1340
+ if (inAppChannels.length === 0) {
1341
+ throw new Error("No in app channels found");
1342
+ }
1343
+ return await updateWorkflowWithStep(
1344
+ knockClient,
1345
+ workflow2,
1346
+ // @ts-expect-error
1347
+ {
1348
+ type: "channel",
1349
+ channel_key: inAppChannels[0].key,
1350
+ template: {
1351
+ action_url: params.actionUrl,
1352
+ markdown_body: params.body
1353
+ },
1354
+ ref: generateStepRef("in_app_feed")
1355
+ },
1356
+ config.environment ?? "development"
1357
+ );
1358
+ }
1359
+ });
1360
+ var createChatStepInWorkflow = KnockTool({
1361
+ method: "create_chat_step_in_workflow",
1362
+ name: "Create chat step in workflow",
1363
+ description: `
1364
+ Creates a chat step in a workflow. Use this tool when you're asked to create a chat, Slack, Discord, or Microsoft Teams notification and you need to specify the content of the chat notification.
1365
+
1366
+ ${SHARED_PROMPTS.workflow}
1367
+
1368
+ ${SHARED_PROMPTS.liquid}
1369
+ `,
1370
+ parameters: z13.object({
1371
+ workflowKey: z13.string().describe("(string): The key of the workflow to add the step to."),
1372
+ body: z13.string().describe("(string): The markdown content of the notification.")
1373
+ }),
1374
+ execute: (knockClient, config) => async (params) => {
1375
+ const workflow2 = await knockClient.workflows.retrieve(params.workflowKey, {
1376
+ environment: config.environment ?? "development"
1377
+ });
1378
+ const chatChannelsPage = await knockClient.channels.list();
1379
+ const chatChannels = chatChannelsPage.entries.filter(
1380
+ (channel) => channel.type === "chat"
1381
+ );
1382
+ if (chatChannels.length === 0) {
1383
+ throw new Error("No chat channels found");
1384
+ }
1385
+ return await updateWorkflowWithStep(
1386
+ knockClient,
1387
+ workflow2,
1388
+ // @ts-expect-error
1389
+ {
1390
+ type: "channel",
1391
+ channel_key: chatChannels[0].key,
1392
+ template: {
1393
+ markdown_body: params.body
1394
+ },
1395
+ ref: generateStepRef("chat")
1396
+ },
1397
+ config.environment ?? "development"
1398
+ );
1399
+ }
1400
+ });
1401
+ var createDelayStepInWorkflow = KnockTool({
1402
+ method: "create_delay_step_in_workflow",
1403
+ name: "Create delay step in workflow",
1404
+ description: `
1405
+ Creates a delay step in a workflow. Use this tool when you're asked to add a delay to the workflow that pauses, or waits for a period of time before continuing.
1406
+
1407
+ ${SHARED_PROMPTS.workflow}
1408
+
1409
+ Delays are specified in "unit" and "value" pairs. The only valid units are "seconds", "minutes", "hours", and "days".
1410
+
1411
+ <example>
1412
+ {
1413
+ "delayValue": 5,
1414
+ "delayUnit": "minutes"
1415
+ }
1416
+ </example>
1417
+ `,
1418
+ parameters: z13.object({
1419
+ workflowKey: z13.string().describe("(string): The key of the workflow to add the step to."),
1420
+ delayValue: z13.number().describe("(number): The value of the delay."),
1421
+ delayUnit: z13.enum(["seconds", "minutes", "hours", "days"]).describe("(enum): The unit of the delay.")
1422
+ }),
1423
+ execute: (knockClient, config) => async (params) => {
1424
+ const workflow2 = await knockClient.workflows.retrieve(params.workflowKey, {
1425
+ environment: config.environment ?? "development"
1426
+ });
1427
+ const workflowParams = {
1428
+ environment: config.environment ?? "development",
1429
+ workflow: {
1430
+ ...workflow2,
1431
+ steps: [
1432
+ // @ts-expect-error
1433
+ ...workflow2.steps,
1434
+ // @ts-expect-error
1435
+ {
1436
+ type: "delay",
1437
+ settings: {
1438
+ delay_for: {
1439
+ value: params.delayValue,
1440
+ unit: params.delayUnit
1441
+ }
1442
+ },
1443
+ ref: generateStepRef("delay")
1444
+ }
1445
+ ]
1446
+ }
1447
+ };
1448
+ const result = await knockClient.workflows.upsert(
1449
+ params.workflowKey,
1450
+ workflowParams
1451
+ );
1452
+ return serializeWorkflowResponse(result.workflow);
1453
+ }
1454
+ });
1455
+ var createBatchStepInWorkflow = KnockTool({
1456
+ method: "create_batch_step_in_workflow",
1457
+ name: "Create batch step in workflow",
1458
+ description: `
1459
+ Creates a batch step in a workflow. Use this tool when you're asked to create a batch step or asked to add digesting behavior to a workflow. The batch step collects multiple workflow triggers for a single recipient over a period of time and then flushes the content to the next step.
1460
+
1461
+ ${SHARED_PROMPTS.workflow}
1462
+
1463
+ Batch windows are specified in "unit" and "value" pairs. The only valid units are "seconds", "minutes", "hours", and "days".
1464
+
1465
+ <example>
1466
+ {
1467
+ "batchWindow": {
1468
+ "value": 5,
1469
+ "unit": "minutes"
1470
+ }
1471
+ }
1472
+ </example>
1473
+ `,
1474
+ parameters: z13.object({
1475
+ workflowKey: z13.string().describe("(string): The key of the workflow to add the step to."),
1476
+ batchWindow: z13.object({
1477
+ value: z13.number().describe("(number): The value of the batch window."),
1478
+ unit: z13.enum(["seconds", "minutes", "hours", "days"]).describe("(enum): The unit of the batch window.")
1479
+ })
1480
+ }),
1481
+ execute: (knockClient, config) => async (params) => {
1482
+ const workflow2 = await knockClient.workflows.retrieve(params.workflowKey, {
1483
+ environment: config.environment ?? "development"
1484
+ });
1485
+ return await updateWorkflowWithStep(
1486
+ knockClient,
1487
+ workflow2,
1488
+ // @ts-expect-error
1489
+ {
1490
+ type: "batch",
1491
+ settings: {
1492
+ batch_window: {
1493
+ value: params.batchWindow.value,
1494
+ unit: params.batchWindow.unit
1495
+ }
1496
+ },
1497
+ ref: generateStepRef("batch")
1498
+ },
1499
+ config.environment ?? "development"
1500
+ );
1501
+ }
1502
+ });
1503
+ var workflowStepTools = {
1504
+ // Channel steps
1505
+ createEmailStepInWorkflow,
1506
+ createSmsStepInWorkflow,
1507
+ createPushStepInWorkflow,
1508
+ createInAppFeedStepInWorkflow,
1509
+ createChatStepInWorkflow,
1510
+ // Function steps
1511
+ createDelayStepInWorkflow,
1512
+ createBatchStepInWorkflow
1513
+ };
1514
+
1515
+ // src/lib/tools/workflows.ts
1019
1516
  function serializeWorkflowResponse(workflow2) {
1020
1517
  return {
1021
1518
  key: workflow2.key,
@@ -1033,8 +1530,8 @@ var listWorkflows = KnockTool({
1033
1530
 
1034
1531
  Use this tool when you need to understand which workflows are available to be called.
1035
1532
  `,
1036
- parameters: z13.object({
1037
- environment: z13.string().optional().describe(
1533
+ parameters: z14.object({
1534
+ environment: z14.string().optional().describe(
1038
1535
  "(string): The environment to list workflows for. Defaults to `development`."
1039
1536
  )
1040
1537
  }),
@@ -1055,11 +1552,11 @@ var getWorkflow = KnockTool({
1055
1552
  description: `
1056
1553
  Get a workflow by key. Returns structural information about the workflow, including the key, name, description, and categories.
1057
1554
  `,
1058
- parameters: z13.object({
1059
- environment: z13.string().optional().describe(
1555
+ parameters: z14.object({
1556
+ environment: z14.string().optional().describe(
1060
1557
  "(string): The environment to get the workflow for. Defaults to `development`."
1061
1558
  ),
1062
- workflowKey: z13.string().describe("(string): The key of the workflow to get.")
1559
+ workflowKey: z14.string().describe("(string): The key of the workflow to get.")
1063
1560
  }),
1064
1561
  execute: (knockClient, config) => async (params) => {
1065
1562
  const workflow2 = await knockClient.workflows.retrieve(params.workflowKey, {
@@ -1080,16 +1577,16 @@ var triggerWorkflow = KnockTool({
1080
1577
 
1081
1578
  Returns the workflow run ID, which can be used to lookup messages produced by the workflow.
1082
1579
  `,
1083
- parameters: z13.object({
1084
- environment: z13.string().optional().describe(
1580
+ parameters: z14.object({
1581
+ environment: z14.string().optional().describe(
1085
1582
  "(string): The environment to trigger the workflow in. Defaults to `development`."
1086
1583
  ),
1087
- workflowKey: z13.string().describe("(string): The key of the workflow to trigger."),
1088
- recipients: z13.array(z13.string()).optional().describe(
1584
+ workflowKey: z14.string().describe("(string): The key of the workflow to trigger."),
1585
+ recipients: z14.array(z14.string()).optional().describe(
1089
1586
  "(array): The recipients to trigger the workflow for. This is an array of user IDs."
1090
1587
  ),
1091
- data: z13.record(z13.string(), z13.any()).optional().describe("(object): Data to pass to the workflow."),
1092
- tenant: z13.record(z13.string(), z13.any()).optional().describe(
1588
+ data: z14.record(z14.string(), z14.any()).optional().describe("(object): Data to pass to the workflow."),
1589
+ tenant: z14.record(z14.string(), z14.any()).optional().describe(
1093
1590
  "(object): The tenant to trigger the workflow for. Must contain an id if being sent."
1094
1591
  )
1095
1592
  }),
@@ -1103,80 +1600,30 @@ var triggerWorkflow = KnockTool({
1103
1600
  return result.workflow_run_id;
1104
1601
  }
1105
1602
  });
1106
- var createEmailWorkflow = KnockTool({
1107
- method: "create_email_workflow",
1108
- name: "Create email workflow",
1603
+ var createWorkflow = KnockTool({
1604
+ method: "create_workflow",
1605
+ name: "Create workflow",
1109
1606
  description: `
1110
- Creates a simple email workflow with a single step that sends an email to the recipient. Use this tool when you need to need to create an email notification, and you don't need to specify any additional steps. You can only create workflows in the development environment.
1111
-
1112
- The content of the email you supply should ONLY ever be in markdown format for simplicity. You can supply dynamic variables to the subject and body of the email using the liquid template language.
1113
-
1114
- When writing markdown, be sure to use headings (##) to separate sections of the email. Use an informal writing style, and avoid using complex language.
1115
-
1116
- The following variables are available to use in the email subject and body:
1117
-
1118
- - \`recipient.name\`: The name of the recipient.
1119
- - \`recipient.email\`: The email of the recipient.
1120
- - \`recipient.phone_number\`: The phone number of the recipient.
1121
- - \`tenant.id\`: The id of the tenant.
1122
- - \`tenant.name\`: The name of the tenant.
1123
-
1124
- You can supply any other dynamic variables by referencing them under the \`data\` key in the \`data\` parameter when triggering the workflow. You add those like \`{{ data.variable_name }}\`.
1125
-
1126
- You can also supply a list of categories to the workflow. These are used to categorize workflows for notification preferences. Categories should be supplied as lowercase strings in kebab case.
1127
-
1128
- Once you've created the workflow, you should ask if you should commit the changes to the environment.
1607
+ 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.
1129
1608
  `,
1130
- parameters: z13.object({
1131
- environment: z13.string().optional().describe(
1609
+ parameters: z14.object({
1610
+ environment: z14.string().optional().describe(
1132
1611
  "(string): The environment to create the workflow in. Defaults to `development`."
1133
1612
  ),
1134
- workflowKey: z13.string().describe("(string): The key of the workflow."),
1135
- name: z13.string().describe("(string): The name of the workflow."),
1136
- categories: z13.array(z13.string()).optional().describe("(array): The categories to add to the workflow."),
1137
- subject: z13.string().describe("(string): The subject of the email."),
1138
- body: z13.string().describe("(string): The body of the email.")
1613
+ name: z14.string().describe("(string): The name of the workflow."),
1614
+ description: z14.string().describe("(string): The description of the workflow."),
1615
+ categories: z14.array(z14.string()).describe("(array): The categories to add to the workflow.")
1139
1616
  }),
1140
1617
  execute: (knockClient, config) => async (params) => {
1141
- const emailChannelsPage = await knockClient.channels.list();
1142
- const emailChannels = emailChannelsPage.entries.filter(
1143
- (channel) => channel.type === "email"
1144
- );
1145
- if (emailChannels.length === 0) {
1146
- throw new Error("No email channels found");
1147
- }
1148
- const workflowParams = {
1149
- environment: params.environment ?? config.environment ?? "development",
1618
+ const result = await knockClient.workflows.upsert(params.workflowKey, {
1619
+ environment: config.environment ?? "development",
1150
1620
  workflow: {
1151
1621
  name: params.name,
1622
+ description: params.description,
1152
1623
  categories: params.categories ?? [],
1153
- steps: [
1154
- {
1155
- type: "channel",
1156
- channel_key: emailChannels[0].key,
1157
- template: {
1158
- settings: {
1159
- layout_key: "default"
1160
- },
1161
- subject: params.subject,
1162
- visual_blocks: [
1163
- // @ts-ignore
1164
- {
1165
- type: "markdown",
1166
- content: params.body
1167
- }
1168
- ]
1169
- },
1170
- name: "Email",
1171
- ref: "email_1"
1172
- }
1173
- ]
1624
+ steps: []
1174
1625
  }
1175
- };
1176
- const result = await knockClient.workflows.upsert(
1177
- params.workflowKey,
1178
- workflowParams
1179
- );
1626
+ });
1180
1627
  return serializeWorkflowResponse(result.workflow);
1181
1628
  }
1182
1629
  });
@@ -1194,18 +1641,18 @@ var createOneOffWorkflowSchedule = KnockTool({
1194
1641
  - In one hour, send a password reset email to a user
1195
1642
  - In two weeks, send a survey to a user
1196
1643
  `,
1197
- parameters: z13.object({
1198
- environment: z13.string().optional().describe(
1644
+ parameters: z14.object({
1645
+ environment: z14.string().optional().describe(
1199
1646
  "(string): The environment to create the workflow in. Defaults to `development`."
1200
1647
  ),
1201
- workflowKey: z13.string().describe("(string): The key of the workflow to schedule."),
1202
- userId: z13.string().describe(
1648
+ workflowKey: z14.string().describe("(string): The key of the workflow to schedule."),
1649
+ userId: z14.string().describe(
1203
1650
  "(string): The userId of the user to schedule the workflow for."
1204
1651
  ),
1205
- scheduledAt: z13.string().describe(
1652
+ scheduledAt: z14.string().describe(
1206
1653
  "(string): The date and time to schedule the workflow for. Must be in ISO 8601 format."
1207
1654
  ),
1208
- data: z13.record(z13.string(), z13.any()).optional().describe("(object): Data to pass to the workflow.")
1655
+ data: z14.record(z14.string(), z14.any()).optional().describe("(object): Data to pass to the workflow.")
1209
1656
  }),
1210
1657
  execute: (knockClient, config) => async (params) => {
1211
1658
  const publicClient = await knockClient.publicApi(params.environment);
@@ -1220,12 +1667,15 @@ var workflows = {
1220
1667
  listWorkflows,
1221
1668
  getWorkflow,
1222
1669
  triggerWorkflow,
1223
- createEmailWorkflow,
1670
+ createWorkflow,
1671
+ ...workflowStepTools,
1224
1672
  createOneOffWorkflowSchedule
1225
1673
  };
1226
1674
  var permissions12 = {
1227
1675
  read: ["listWorkflows", "getWorkflow"],
1228
- manage: ["createEmailWorkflow", "createOneOffWorkflowSchedule"],
1676
+ manage: ["createWorkflow", "createOneOffWorkflowSchedule"].concat(
1677
+ ...Object.keys(workflowStepTools)
1678
+ ),
1229
1679
  run: ["triggerWorkflow"]
1230
1680
  };
1231
1681
 
@@ -1281,4 +1731,4 @@ export {
1281
1731
  getToolsByPermissionsInCategories,
1282
1732
  getToolMap
1283
1733
  };
1284
- //# sourceMappingURL=chunk-6UHXLKAV.js.map
1734
+ //# sourceMappingURL=chunk-URQB3FDZ.js.map