@knocklabs/agent-toolkit 0.1.13 → 0.1.14

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.
@@ -1,8 +1,9 @@
1
1
  import { ToolSet, Tool } from 'ai';
2
- import { a as DeferredToolCall, b as DeferredToolCallConfig, K as KnockOutboundWebhookEvent, D as DeferredToolCallInteractionResult } from '../types-CrTRlRnE.js';
2
+ import { a as DeferredToolCall, b as DeferredToolCallConfig, K as KnockOutboundWebhookEvent, D as DeferredToolCallInteractionResult } from '../types-D6xiNyB2.js';
3
3
  import { ToolkitConfig, ToolCategory } from '../types.js';
4
4
  import { ToolInvocation } from '@ai-sdk/ui-utils';
5
5
  import '@knocklabs/node/dist/src/resources/messages/interfaces';
6
+ import '@knocklabs/node/dist/src/resources/workflows/interfaces';
6
7
 
7
8
  /**
8
9
  * Convert a deferred tool call to a tool invocation. Useful when building an assistant
@@ -2,7 +2,7 @@ import {
2
2
  handleMessageInteraction,
3
3
  triggerHumanInTheLoopWorkflow,
4
4
  wrapToolDescription
5
- } from "../chunk-6O7VMHBN.js";
5
+ } from "../chunk-IGJSMDBC.js";
6
6
  import {
7
7
  createKnockClient
8
8
  } from "../chunk-TRLABEB7.js";
@@ -106,6 +106,7 @@ var createKnockToolkit = async (config) => {
106
106
  description: wrapToolDescription(toolToWrap.description ?? ""),
107
107
  execute: async (input, options) => {
108
108
  const toolExecution = {
109
+ id: options.toolCallId,
109
110
  method,
110
111
  args: input,
111
112
  extra: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ai-sdk/tool-converter.ts","../../src/ai-sdk/helpers.ts","../../src/ai-sdk/index.ts"],"sourcesContent":["import type { Tool } from \"ai\";\nimport { tool } from \"ai\";\nimport { z } from \"zod\";\n\nimport { KnockClient } from \"../lib/knock-client.js\";\nimport { KnockTool } from \"../lib/knock-tool.js\";\nimport { Config } from \"../types.js\";\n\n/**\n * Convert a KnockTool to an AI Tool, ready to pass to the AI SDK.\n */\nconst knockToolToAiTool = (\n knockClient: KnockClient,\n config: Config,\n knockTool: KnockTool\n): Tool => {\n return tool({\n description: knockTool.description,\n parameters: knockTool.parameters ?? z.object({}),\n execute: knockTool.bindExecute(knockClient, config),\n });\n};\n\n/**\n * Convert a list of KnockTools to an AI ToolSet, ready to pass to the AI SDK.\n */\nconst knockToolsToToolSet = (\n knockClient: KnockClient,\n config: Config,\n knockTools: KnockTool[]\n) => {\n return knockTools.reduce(\n (acc, tool) => {\n acc[tool.method] = knockToolToAiTool(knockClient, config, tool);\n return acc;\n },\n {} as Record<string, Tool>\n );\n};\n\nexport { knockToolToAiTool, knockToolsToToolSet };\n","import { ToolInvocation } from \"@ai-sdk/ui-utils\";\n\nimport { DeferredToolCall } from \"@/lib/human-in-the-loop/types\";\n\n/**\n * Convert a deferred tool call to a tool invocation. Useful when building an assistant\n * response from a deferred tool call.\n *\n * @param deferredToolCall - The deferred tool call to convert.\n * @param result - The result of the tool call.\n * @returns The tool invocation.\n */\nfunction deferredToolCallToToolInvocation(\n deferredToolCall: DeferredToolCall,\n result: unknown\n): ToolInvocation {\n return {\n args: deferredToolCall.args,\n toolName: deferredToolCall.method,\n toolCallId: deferredToolCall.extra?.toolCallId as string,\n state: \"result\",\n step: 0,\n result,\n };\n}\n\nexport { deferredToolCallToToolInvocation };\n","import { Tool, ToolExecutionOptions, ToolSet } from \"ai\";\n\nimport {\n handleMessageInteraction,\n triggerHumanInTheLoopWorkflow,\n wrapToolDescription,\n} from \"../lib/human-in-the-loop/index.js\";\nimport {\n DeferredToolCall,\n DeferredToolCallConfig,\n KnockOutboundWebhookEvent,\n DeferredToolCallInteractionResult,\n} from \"../lib/human-in-the-loop/types.js\";\nimport { createKnockClient } from \"../lib/knock-client.js\";\nimport { getToolMap, getToolsByPermissionsInCategories } from \"../lib/utils.js\";\nimport { ToolCategory, ToolkitConfig } from \"../types.js\";\n\nimport { knockToolsToToolSet, knockToolToAiTool } from \"./tool-converter.js\";\n\ntype KnockToolkit = {\n getAllTools: () => ToolSet;\n getTools: (category: ToolCategory) => ToolSet;\n getToolMap: () => Record<string, Tool>;\n requireHumanInput: (\n toolsToWrap: ToolSet,\n inputConfig: DeferredToolCallConfig\n ) => ToolSet;\n resumeToolExecution: (toolInteraction: DeferredToolCall) => Promise<unknown>;\n wrappedToolsRequiringInput: () => Map<string, Tool>;\n handleMessageInteraction: (\n event: KnockOutboundWebhookEvent\n ) => DeferredToolCallInteractionResult | null;\n};\n\n/**\n * Creates a Knock toolkit for use with the AI SDK.\n *\n * You can filter the set of tools that are available by setting the `config.permissions` property.\n *\n * When the `config.permissions.workflows.trigger` is set, then workflow triggers for\n * the specified workflows will be included in the returned tools.\n *\n * You can also specify a list of workflow keys to include in the returned tools, should you wish to\n * limit the set of workflows that are available.\n *\n * @example\n * ```ts\n * const toolkit = await createKnockToolkit({\n * permissions: {\n * workflows: { read: true },\n * },\n * });\n * ```\n *\n * @param config - The configuration to use for the toolkit\n * @returns A toolkit for use with the AI SDK\n */\nconst createKnockToolkit = async (\n config: ToolkitConfig\n): Promise<KnockToolkit> => {\n const knockClient = createKnockClient(config);\n const allowedToolsByCategory = await getToolsByPermissionsInCategories(\n knockClient,\n config\n );\n const allTools = Object.values(allowedToolsByCategory).flat();\n const toolsByMethod = getToolMap(allTools);\n\n const wrappedToolsRequiringInput = new Map<string, Tool>();\n\n return Promise.resolve({\n /**\n * Get all tools for all categories, including workflow triggers when workflows-as-tools are enabled.\n *\n * @returns A promise that resolves to a set of tools\n */\n getAllTools: (): ToolSet => {\n return knockToolsToToolSet(knockClient, config, allTools);\n },\n\n /**\n * Get all tools for a specific category. When trying to get tools for the `workflows` category and the trigger permission is set,\n * the workflow triggers for the specified workflows will be included in the returned tools.\n *\n * @param category - The category of tools to get\n * @returns An array of tools for the given category\n */\n getTools: (category: ToolCategory): ToolSet => {\n return knockToolsToToolSet(\n knockClient,\n config,\n allowedToolsByCategory[category]\n );\n },\n\n /**\n * Get a map of all tools by method name, including workflow triggers when workflows-as-tools are enabled.\n *\n * @returns A map of all tools by method name\n */\n getToolMap: (): Record<string, Tool> => {\n return Object.entries(toolsByMethod).reduce(\n (acc, [method, tool]) => ({\n ...acc,\n [method]: knockToolToAiTool(knockClient, config, tool),\n }),\n {} as Record<string, Tool>\n );\n },\n\n /**\n * Wraps one or more tools to require human input.\n *\n * @param toolsToWrap - The tools to wrap\n * @param inputConfig - The configuration to use for the HITL request\n */\n requireHumanInput: (\n toolsToWrap: ToolSet,\n inputConfig: DeferredToolCallConfig\n ): ToolSet => {\n const wrappedTools: Record<string, Tool> = {};\n\n for (const [method, toolToWrap] of Object.entries(toolsToWrap)) {\n // Keep a reference to the original tool so we can use it later\n wrappedToolsRequiringInput.set(method, { ...toolToWrap });\n\n const wrappedTool = {\n ...toolToWrap,\n description: wrapToolDescription(toolToWrap.description ?? \"\"),\n execute: async (input: any, options: ToolExecutionOptions) => {\n const toolExecution = {\n method,\n args: input,\n extra: {\n toolCallId: options.toolCallId,\n },\n };\n\n await triggerHumanInTheLoopWorkflow({\n knockClient,\n config,\n toolCall: toolExecution,\n inputConfig,\n });\n\n // TODO: Consider injecting a hook here to allow the AI SDK to react to the tool call being deferred\n return {\n type: \"tool-status\",\n status: \"pending-input\",\n toolCallId: options.toolCallId,\n };\n },\n };\n\n wrappedTools[method] = wrappedTool;\n }\n\n return wrappedTools;\n },\n\n /**\n * Returns any tools that were wrapped with `requireHumanInput`.\n *\n * @returns A map of wrapped tools that require human input\n */\n wrappedToolsRequiringInput: () => wrappedToolsRequiringInput,\n\n /**\n * Resumes the execution of a tool that required human input.\n *\n * @param toolInteraction - The tool interaction to resume\n * @returns A promise that resolves to the result of the tool execution\n */\n resumeToolExecution: async (toolInteraction: DeferredToolCall) => {\n const tool = wrappedToolsRequiringInput.get(toolInteraction.method);\n\n if (!tool) {\n throw new Error(\n `Tool \"${toolInteraction.method}\" not found. Did you forget to wrap the tool with requireHumanInput?`\n );\n }\n\n if (!tool.execute) {\n throw new Error(\n `Tool \"${toolInteraction.method}\" does not have an execute method. Nothing to resume.`\n );\n }\n\n const options = toolInteraction.extra as unknown as ToolExecutionOptions;\n const result = await tool.execute(toolInteraction.args, options);\n\n // Return two message objects to represent the tool call and the call result having\n // finished. Note: this can result in duplicate tool call IDs being present in the message history.\n return {\n type: \"tool-status\",\n status: \"completed\",\n toolCallId: options.toolCallId,\n result,\n };\n },\n\n /**\n * Handles a message interaction event by parsing it into a well-known format.\n *\n * @param event - The message interaction event\n * @returns An deferred tool call, or null if the event is not a message interaction\n */\n handleMessageInteraction,\n });\n};\n\nexport * from \"./helpers.js\";\nexport { createKnockToolkit };\n"],"mappings":"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","names":["tool","tool"]}
1
+ {"version":3,"sources":["../../src/ai-sdk/tool-converter.ts","../../src/ai-sdk/helpers.ts","../../src/ai-sdk/index.ts"],"sourcesContent":["import type { Tool } from \"ai\";\nimport { tool } from \"ai\";\nimport { z } from \"zod\";\n\nimport { KnockClient } from \"../lib/knock-client.js\";\nimport { KnockTool } from \"../lib/knock-tool.js\";\nimport { Config } from \"../types.js\";\n\n/**\n * Convert a KnockTool to an AI Tool, ready to pass to the AI SDK.\n */\nconst knockToolToAiTool = (\n knockClient: KnockClient,\n config: Config,\n knockTool: KnockTool\n): Tool => {\n return tool({\n description: knockTool.description,\n parameters: knockTool.parameters ?? z.object({}),\n execute: knockTool.bindExecute(knockClient, config),\n });\n};\n\n/**\n * Convert a list of KnockTools to an AI ToolSet, ready to pass to the AI SDK.\n */\nconst knockToolsToToolSet = (\n knockClient: KnockClient,\n config: Config,\n knockTools: KnockTool[]\n) => {\n return knockTools.reduce(\n (acc, tool) => {\n acc[tool.method] = knockToolToAiTool(knockClient, config, tool);\n return acc;\n },\n {} as Record<string, Tool>\n );\n};\n\nexport { knockToolToAiTool, knockToolsToToolSet };\n","import { ToolInvocation } from \"@ai-sdk/ui-utils\";\n\nimport { DeferredToolCall } from \"@/lib/human-in-the-loop/types\";\n\n/**\n * Convert a deferred tool call to a tool invocation. Useful when building an assistant\n * response from a deferred tool call.\n *\n * @param deferredToolCall - The deferred tool call to convert.\n * @param result - The result of the tool call.\n * @returns The tool invocation.\n */\nfunction deferredToolCallToToolInvocation(\n deferredToolCall: DeferredToolCall,\n result: unknown\n): ToolInvocation {\n return {\n args: deferredToolCall.args,\n toolName: deferredToolCall.method,\n toolCallId: deferredToolCall.extra?.toolCallId as string,\n state: \"result\",\n step: 0,\n result,\n };\n}\n\nexport { deferredToolCallToToolInvocation };\n","import { Tool, ToolExecutionOptions, ToolSet } from \"ai\";\n\nimport {\n handleMessageInteraction,\n triggerHumanInTheLoopWorkflow,\n wrapToolDescription,\n} from \"../lib/human-in-the-loop/index.js\";\nimport {\n DeferredToolCall,\n DeferredToolCallConfig,\n KnockOutboundWebhookEvent,\n DeferredToolCallInteractionResult,\n} from \"../lib/human-in-the-loop/types.js\";\nimport { createKnockClient } from \"../lib/knock-client.js\";\nimport { getToolMap, getToolsByPermissionsInCategories } from \"../lib/utils.js\";\nimport { ToolCategory, ToolkitConfig } from \"../types.js\";\n\nimport { knockToolsToToolSet, knockToolToAiTool } from \"./tool-converter.js\";\n\ntype KnockToolkit = {\n getAllTools: () => ToolSet;\n getTools: (category: ToolCategory) => ToolSet;\n getToolMap: () => Record<string, Tool>;\n requireHumanInput: (\n toolsToWrap: ToolSet,\n inputConfig: DeferredToolCallConfig\n ) => ToolSet;\n resumeToolExecution: (toolInteraction: DeferredToolCall) => Promise<unknown>;\n wrappedToolsRequiringInput: () => Map<string, Tool>;\n handleMessageInteraction: (\n event: KnockOutboundWebhookEvent\n ) => DeferredToolCallInteractionResult | null;\n};\n\n/**\n * Creates a Knock toolkit for use with the AI SDK.\n *\n * You can filter the set of tools that are available by setting the `config.permissions` property.\n *\n * When the `config.permissions.workflows.trigger` is set, then workflow triggers for\n * the specified workflows will be included in the returned tools.\n *\n * You can also specify a list of workflow keys to include in the returned tools, should you wish to\n * limit the set of workflows that are available.\n *\n * @example\n * ```ts\n * const toolkit = await createKnockToolkit({\n * permissions: {\n * workflows: { read: true },\n * },\n * });\n * ```\n *\n * @param config - The configuration to use for the toolkit\n * @returns A toolkit for use with the AI SDK\n */\nconst createKnockToolkit = async (\n config: ToolkitConfig\n): Promise<KnockToolkit> => {\n const knockClient = createKnockClient(config);\n const allowedToolsByCategory = await getToolsByPermissionsInCategories(\n knockClient,\n config\n );\n const allTools = Object.values(allowedToolsByCategory).flat();\n const toolsByMethod = getToolMap(allTools);\n\n const wrappedToolsRequiringInput = new Map<string, Tool>();\n\n return Promise.resolve({\n /**\n * Get all tools for all categories, including workflow triggers when workflows-as-tools are enabled.\n *\n * @returns A promise that resolves to a set of tools\n */\n getAllTools: (): ToolSet => {\n return knockToolsToToolSet(knockClient, config, allTools);\n },\n\n /**\n * Get all tools for a specific category. When trying to get tools for the `workflows` category and the trigger permission is set,\n * the workflow triggers for the specified workflows will be included in the returned tools.\n *\n * @param category - The category of tools to get\n * @returns An array of tools for the given category\n */\n getTools: (category: ToolCategory): ToolSet => {\n return knockToolsToToolSet(\n knockClient,\n config,\n allowedToolsByCategory[category]\n );\n },\n\n /**\n * Get a map of all tools by method name, including workflow triggers when workflows-as-tools are enabled.\n *\n * @returns A map of all tools by method name\n */\n getToolMap: (): Record<string, Tool> => {\n return Object.entries(toolsByMethod).reduce(\n (acc, [method, tool]) => ({\n ...acc,\n [method]: knockToolToAiTool(knockClient, config, tool),\n }),\n {} as Record<string, Tool>\n );\n },\n\n /**\n * Wraps one or more tools to require human input.\n *\n * @param toolsToWrap - The tools to wrap\n * @param inputConfig - The configuration to use for the HITL request\n */\n requireHumanInput: (\n toolsToWrap: ToolSet,\n inputConfig: DeferredToolCallConfig\n ): ToolSet => {\n const wrappedTools: Record<string, Tool> = {};\n\n for (const [method, toolToWrap] of Object.entries(toolsToWrap)) {\n // Keep a reference to the original tool so we can use it later\n wrappedToolsRequiringInput.set(method, { ...toolToWrap });\n\n const wrappedTool = {\n ...toolToWrap,\n description: wrapToolDescription(toolToWrap.description ?? \"\"),\n execute: async (input: any, options: ToolExecutionOptions) => {\n const toolExecution = {\n id: options.toolCallId,\n method,\n args: input,\n extra: {\n toolCallId: options.toolCallId,\n },\n };\n\n await triggerHumanInTheLoopWorkflow({\n knockClient,\n config,\n toolCall: toolExecution,\n inputConfig,\n });\n\n // TODO: Consider injecting a hook here to allow the AI SDK to react to the tool call being deferred\n return {\n type: \"tool-status\",\n status: \"pending-input\",\n toolCallId: options.toolCallId,\n };\n },\n };\n\n wrappedTools[method] = wrappedTool;\n }\n\n return wrappedTools;\n },\n\n /**\n * Returns any tools that were wrapped with `requireHumanInput`.\n *\n * @returns A map of wrapped tools that require human input\n */\n wrappedToolsRequiringInput: () => wrappedToolsRequiringInput,\n\n /**\n * Resumes the execution of a tool that required human input.\n *\n * @param toolInteraction - The tool interaction to resume\n * @returns A promise that resolves to the result of the tool execution\n */\n resumeToolExecution: async (toolInteraction: DeferredToolCall) => {\n const tool = wrappedToolsRequiringInput.get(toolInteraction.method);\n\n if (!tool) {\n throw new Error(\n `Tool \"${toolInteraction.method}\" not found. Did you forget to wrap the tool with requireHumanInput?`\n );\n }\n\n if (!tool.execute) {\n throw new Error(\n `Tool \"${toolInteraction.method}\" does not have an execute method. Nothing to resume.`\n );\n }\n\n const options = toolInteraction.extra as unknown as ToolExecutionOptions;\n const result = await tool.execute(toolInteraction.args, options);\n\n // Return two message objects to represent the tool call and the call result having\n // finished. Note: this can result in duplicate tool call IDs being present in the message history.\n return {\n type: \"tool-status\",\n status: \"completed\",\n toolCallId: options.toolCallId,\n result,\n };\n },\n\n /**\n * Handles a message interaction event by parsing it into a well-known format.\n *\n * @param event - The message interaction event\n * @returns An deferred tool call, or null if the event is not a message interaction\n */\n handleMessageInteraction,\n });\n};\n\nexport * from \"./helpers.js\";\nexport { createKnockToolkit };\n"],"mappings":"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","names":["tool","tool"]}
@@ -8,7 +8,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
8
  import { z } from "zod";
9
9
  var KnockMcpServer = class extends McpServer {
10
10
  constructor(knockClient, config, tools) {
11
- super({ name: "Knock", version: "0.1.13" });
11
+ super({ name: "Knock", version: "0.1.14" });
12
12
  tools.forEach((tool) => {
13
13
  const toolParams = tool.parameters ?? z.object({});
14
14
  this.tool(
@@ -44,4 +44,4 @@ var createKnockMcpServer = async (params) => {
44
44
  export {
45
45
  createKnockMcpServer
46
46
  };
47
- //# sourceMappingURL=chunk-CCMSCN5A.js.map
47
+ //# sourceMappingURL=chunk-GWRZ4NRX.js.map
@@ -11,6 +11,9 @@ async function triggerHumanInTheLoopWorkflow({
11
11
  inputConfig
12
12
  }) {
13
13
  const knock = await knockClient.publicApi(config.environment);
14
+ if (inputConfig.onBeforeCallKnock) {
15
+ await inputConfig.onBeforeCallKnock(toolCall);
16
+ }
14
17
  const result = await knock.workflows.trigger(inputConfig.workflow, {
15
18
  data: {
16
19
  type: "deferred_tool_call",
@@ -21,6 +24,9 @@ async function triggerHumanInTheLoopWorkflow({
21
24
  tenant: inputConfig.tenant,
22
25
  actor: inputConfig.actor
23
26
  });
27
+ if (inputConfig.onAfterCallKnock) {
28
+ await inputConfig.onAfterCallKnock(toolCall, result);
29
+ }
24
30
  return result;
25
31
  }
26
32
  function handleMessageInteraction(event) {
@@ -36,6 +42,7 @@ function handleMessageInteraction(event) {
36
42
  workflow: message.source.key,
37
43
  interaction: event.event_data,
38
44
  toolCall: {
45
+ id: messageData.tool_call.id,
39
46
  method: messageData.tool_call.method,
40
47
  args: messageData.tool_call.args,
41
48
  extra: messageData.tool_call.extra
@@ -54,4 +61,4 @@ export {
54
61
  triggerHumanInTheLoopWorkflow,
55
62
  handleMessageInteraction
56
63
  };
57
- //# sourceMappingURL=chunk-6O7VMHBN.js.map
64
+ //# sourceMappingURL=chunk-IGJSMDBC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/human-in-the-loop/index.ts"],"sourcesContent":["import { Recipient } from \"@knocklabs/node\";\n\nimport { Config } from \"@/types\";\n\nimport { KnockClient } from \"../knock-client\";\n\nimport {\n DeferredToolCallWorkflowData,\n DeferredToolCallConfig,\n KnockOutboundWebhookEvent,\n DeferredToolCall,\n DeferredToolCallInteractionResult,\n} from \"./types\";\n\nfunction wrapToolDescription(description: string) {\n return `${description}\\n\\nThis tool call is deferred. You will NOT receive a result from this tool but this is NOT an error. Do NOT retry the tool call as the result will be the same. The tool call result will be provided to you in the future.`;\n}\n\n/**\n * Triggers a human in the loop workflow.\n *\n * @param knockClient - The Knock client to use.\n * @param toolCall - The tool call to trigger.\n * @param config - The configuration to use.\n */\nasync function triggerHumanInTheLoopWorkflow({\n knockClient,\n config,\n toolCall,\n inputConfig,\n}: {\n knockClient: KnockClient;\n config: Config;\n toolCall: DeferredToolCall;\n inputConfig: DeferredToolCallConfig;\n}) {\n const knock = await knockClient.publicApi(config.environment);\n\n if (inputConfig.onBeforeCallKnock) {\n await inputConfig.onBeforeCallKnock(toolCall);\n }\n\n const result = await knock.workflows.trigger(inputConfig.workflow, {\n data: {\n type: \"deferred_tool_call\",\n tool_call: toolCall,\n metadata: inputConfig.metadata,\n } as DeferredToolCallWorkflowData,\n recipients: inputConfig.recipients as Recipient[],\n tenant: inputConfig.tenant,\n actor: inputConfig.actor as Recipient,\n });\n\n if (inputConfig.onAfterCallKnock) {\n await inputConfig.onAfterCallKnock(toolCall, result);\n }\n\n return result;\n}\n\n/**\n * Given an outboundwebhook event, this function will parse the event into a normalized format.\n *\n * If the event is not associated with a deferred tool call, this function will return null.\n *\n * @param event - The outbound webhook event\n * @returns A deferred tool call interaction result, or null if the event is not a deferred tool call\n */\nfunction handleMessageInteraction(\n event: KnockOutboundWebhookEvent\n): DeferredToolCallInteractionResult | null {\n const { data: message } = event;\n\n // We only care about message.interacted events\n if (event.type !== \"message.interacted\") {\n return null;\n }\n\n // We only care about messages that contain a tool call\n if (message.data.type !== \"deferred_tool_call\" || !message.data.tool_call) {\n return null;\n }\n\n const messageData = message.data as DeferredToolCallWorkflowData;\n\n return {\n workflow: message.source.key,\n interaction: event.event_data,\n toolCall: {\n id: messageData.tool_call.id,\n method: messageData.tool_call.method,\n args: messageData.tool_call.args,\n extra: messageData.tool_call.extra,\n },\n metadata: messageData.metadata,\n context: {\n messageId: message.id,\n channelId: message.channel_id,\n timestamp: event.created_at,\n },\n };\n}\n\nexport {\n handleMessageInteraction,\n triggerHumanInTheLoopWorkflow,\n wrapToolDescription,\n};\n"],"mappings":";AAcA,SAAS,oBAAoB,aAAqB;AAChD,SAAO,GAAG,WAAW;AAAA;AAAA;AACvB;AASA,eAAe,8BAA8B;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAQ,MAAM,YAAY,UAAU,OAAO,WAAW;AAE5D,MAAI,YAAY,mBAAmB;AACjC,UAAM,YAAY,kBAAkB,QAAQ;AAAA,EAC9C;AAEA,QAAM,SAAS,MAAM,MAAM,UAAU,QAAQ,YAAY,UAAU;AAAA,IACjE,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,WAAW;AAAA,MACX,UAAU,YAAY;AAAA,IACxB;AAAA,IACA,YAAY,YAAY;AAAA,IACxB,QAAQ,YAAY;AAAA,IACpB,OAAO,YAAY;AAAA,EACrB,CAAC;AAED,MAAI,YAAY,kBAAkB;AAChC,UAAM,YAAY,iBAAiB,UAAU,MAAM;AAAA,EACrD;AAEA,SAAO;AACT;AAUA,SAAS,yBACP,OAC0C;AAC1C,QAAM,EAAE,MAAM,QAAQ,IAAI;AAG1B,MAAI,MAAM,SAAS,sBAAsB;AACvC,WAAO;AAAA,EACT;AAGA,MAAI,QAAQ,KAAK,SAAS,wBAAwB,CAAC,QAAQ,KAAK,WAAW;AACzE,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,QAAQ;AAE5B,SAAO;AAAA,IACL,UAAU,QAAQ,OAAO;AAAA,IACzB,aAAa,MAAM;AAAA,IACnB,UAAU;AAAA,MACR,IAAI,YAAY,UAAU;AAAA,MAC1B,QAAQ,YAAY,UAAU;AAAA,MAC9B,MAAM,YAAY,UAAU;AAAA,MAC5B,OAAO,YAAY,UAAU;AAAA,IAC/B;AAAA,IACA,UAAU,YAAY;AAAA,IACtB,SAAS;AAAA,MACP,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ;AAAA,MACnB,WAAW,MAAM;AAAA,IACnB;AAAA,EACF;AACF;","names":[]}
@@ -1,10 +1,11 @@
1
1
  import * as _knocklabs_node from '@knocklabs/node';
2
2
  import { Config } from './types.js';
3
3
  import { K as KnockClient } from './knock-client-BH7Juvis.js';
4
- import { K as KnockOutboundWebhookEvent, D as DeferredToolCallInteractionResult, a as DeferredToolCall, b as DeferredToolCallConfig } from './types-CrTRlRnE.js';
5
- export { c as DeferredToolCallWorkflowData } from './types-CrTRlRnE.js';
4
+ import { K as KnockOutboundWebhookEvent, D as DeferredToolCallInteractionResult, a as DeferredToolCall, b as DeferredToolCallConfig } from './types-D6xiNyB2.js';
5
+ export { c as DeferredToolCallWorkflowData } from './types-D6xiNyB2.js';
6
6
  import '@knocklabs/mgmt';
7
7
  import '@knocklabs/node/dist/src/resources/messages/interfaces';
8
+ import '@knocklabs/node/dist/src/resources/workflows/interfaces';
8
9
 
9
10
  declare function wrapToolDescription(description: string): string;
10
11
  /**
@@ -2,7 +2,7 @@ import {
2
2
  handleMessageInteraction,
3
3
  triggerHumanInTheLoopWorkflow,
4
4
  wrapToolDescription
5
- } from "./chunk-6O7VMHBN.js";
5
+ } from "./chunk-IGJSMDBC.js";
6
6
  import "./chunk-G3PMV62Z.js";
7
7
  export {
8
8
  handleMessageInteraction,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createKnockMcpServer
3
- } from "../chunk-CCMSCN5A.js";
3
+ } from "../chunk-GWRZ4NRX.js";
4
4
  import "../chunk-RMUYOYLN.js";
5
5
  import "../chunk-G3PMV62Z.js";
6
6
  export {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createKnockMcpServer
4
- } from "../chunk-CCMSCN5A.js";
4
+ } from "../chunk-GWRZ4NRX.js";
5
5
  import {
6
6
  createKnockClient
7
7
  } from "../chunk-TRLABEB7.js";
@@ -1,4 +1,5 @@
1
1
  import { Message } from '@knocklabs/node/dist/src/resources/messages/interfaces';
2
+ import { WorkflowRun } from '@knocklabs/node/dist/src/resources/workflows/interfaces';
2
3
 
3
4
  type Metadata = Record<string, unknown> | undefined;
4
5
  interface DeferredToolCallWorkflowData {
@@ -20,7 +21,7 @@ interface DeferredToolCallConfig {
20
21
  /**
21
22
  * The recipients to trigger the workflow for.
22
23
  */
23
- recipients: string[];
24
+ recipients: string[] | Record<string, unknown>[];
24
25
  /**
25
26
  * Any extra data to pass to the workflow as context.
26
27
  */
@@ -32,9 +33,21 @@ interface DeferredToolCallConfig {
32
33
  /**
33
34
  * The actor to trigger the workflow for.
34
35
  */
35
- actor?: string;
36
+ actor?: string | Record<string, unknown>;
37
+ /**
38
+ * A function to call before calling the Knock API.
39
+ */
40
+ onBeforeCallKnock?: (toolCall: DeferredToolCall) => Promise<void>;
41
+ /**
42
+ * A function to call after calling the Knock API.
43
+ */
44
+ onAfterCallKnock?: (toolCall: DeferredToolCall, result: WorkflowRun) => Promise<void>;
36
45
  }
37
46
  type DeferredToolCall = {
47
+ /**
48
+ * The ID of the tool call. Should be automatically generated by the SDK.
49
+ */
50
+ id: string;
38
51
  /**
39
52
  * The method of the tool that was called.
40
53
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knocklabs/agent-toolkit",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "A toolkit for working with Knock in Agent workflows.",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -52,8 +52,8 @@
52
52
  "dist"
53
53
  ],
54
54
  "dependencies": {
55
- "@knocklabs/mgmt": "^0.1.0-rc.0",
56
- "@knocklabs/node": "^0.6.18",
55
+ "@knocklabs/mgmt": "^0.1.0",
56
+ "@knocklabs/node": "^0.6.19",
57
57
  "@modelcontextprotocol/sdk": "^1.7.0",
58
58
  "json-schema-to-zod": "^2.6.1",
59
59
  "uuid": "^11.1.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/human-in-the-loop/index.ts"],"sourcesContent":["import { Config } from \"@/types\";\n\nimport { KnockClient } from \"../knock-client\";\n\nimport {\n DeferredToolCallWorkflowData,\n DeferredToolCallConfig,\n KnockOutboundWebhookEvent,\n DeferredToolCall,\n DeferredToolCallInteractionResult,\n} from \"./types\";\n\nfunction wrapToolDescription(description: string) {\n return `${description}\\n\\nThis tool call is deferred. You will NOT receive a result from this tool but this is NOT an error. Do NOT retry the tool call as the result will be the same. The tool call result will be provided to you in the future.`;\n}\n\n/**\n * Triggers a human in the loop workflow.\n *\n * @param knockClient - The Knock client to use.\n * @param toolCall - The tool call to trigger.\n * @param config - The configuration to use.\n */\nasync function triggerHumanInTheLoopWorkflow({\n knockClient,\n config,\n toolCall,\n inputConfig,\n}: {\n knockClient: KnockClient;\n config: Config;\n toolCall: DeferredToolCall;\n inputConfig: DeferredToolCallConfig;\n}) {\n const knock = await knockClient.publicApi(config.environment);\n\n const result = await knock.workflows.trigger(inputConfig.workflow, {\n data: {\n type: \"deferred_tool_call\",\n tool_call: toolCall,\n metadata: inputConfig.metadata,\n } as DeferredToolCallWorkflowData,\n recipients: inputConfig.recipients,\n tenant: inputConfig.tenant,\n actor: inputConfig.actor,\n });\n\n return result;\n}\n\n/**\n * Given an outboundwebhook event, this function will parse the event into a normalized format.\n *\n * If the event is not associated with a deferred tool call, this function will return null.\n *\n * @param event - The outbound webhook event\n * @returns A deferred tool call interaction result, or null if the event is not a deferred tool call\n */\nfunction handleMessageInteraction(\n event: KnockOutboundWebhookEvent\n): DeferredToolCallInteractionResult | null {\n const { data: message } = event;\n\n // We only care about message.interacted events\n if (event.type !== \"message.interacted\") {\n return null;\n }\n\n // We only care about messages that contain a tool call\n if (message.data.type !== \"deferred_tool_call\" || !message.data.tool_call) {\n return null;\n }\n\n const messageData = message.data as DeferredToolCallWorkflowData;\n\n return {\n workflow: message.source.key,\n interaction: event.event_data,\n toolCall: {\n method: messageData.tool_call.method,\n args: messageData.tool_call.args,\n extra: messageData.tool_call.extra,\n },\n metadata: messageData.metadata,\n context: {\n messageId: message.id,\n channelId: message.channel_id,\n timestamp: event.created_at,\n },\n };\n}\n\nexport {\n handleMessageInteraction,\n triggerHumanInTheLoopWorkflow,\n wrapToolDescription,\n};\n"],"mappings":";AAYA,SAAS,oBAAoB,aAAqB;AAChD,SAAO,GAAG,WAAW;AAAA;AAAA;AACvB;AASA,eAAe,8BAA8B;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAQ,MAAM,YAAY,UAAU,OAAO,WAAW;AAE5D,QAAM,SAAS,MAAM,MAAM,UAAU,QAAQ,YAAY,UAAU;AAAA,IACjE,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,WAAW;AAAA,MACX,UAAU,YAAY;AAAA,IACxB;AAAA,IACA,YAAY,YAAY;AAAA,IACxB,QAAQ,YAAY;AAAA,IACpB,OAAO,YAAY;AAAA,EACrB,CAAC;AAED,SAAO;AACT;AAUA,SAAS,yBACP,OAC0C;AAC1C,QAAM,EAAE,MAAM,QAAQ,IAAI;AAG1B,MAAI,MAAM,SAAS,sBAAsB;AACvC,WAAO;AAAA,EACT;AAGA,MAAI,QAAQ,KAAK,SAAS,wBAAwB,CAAC,QAAQ,KAAK,WAAW;AACzE,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,QAAQ;AAE5B,SAAO;AAAA,IACL,UAAU,QAAQ,OAAO;AAAA,IACzB,aAAa,MAAM;AAAA,IACnB,UAAU;AAAA,MACR,QAAQ,YAAY,UAAU;AAAA,MAC9B,MAAM,YAAY,UAAU;AAAA,MAC5B,OAAO,YAAY,UAAU;AAAA,IAC/B;AAAA,IACA,UAAU,YAAY;AAAA,IACtB,SAAS;AAAA,MACP,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ;AAAA,MACnB,WAAW,MAAM;AAAA,IACnB;AAAA,EACF;AACF;","names":[]}