@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.
- package/README.md +93 -22
- package/dist/ai-sdk/index.d.ts +25 -26
- package/dist/ai-sdk/index.js +106 -8
- package/dist/ai-sdk/index.js.map +1 -1
- package/dist/chunk-6O7VMHBN.js +57 -0
- package/dist/chunk-6O7VMHBN.js.map +1 -0
- package/dist/chunk-G3PMV62Z.js +36 -0
- package/dist/chunk-G3PMV62Z.js.map +1 -0
- package/dist/{chunk-VGU7NXYJ.js → chunk-H3YEJMMF.js} +10 -6
- package/dist/chunk-H3YEJMMF.js.map +1 -0
- package/dist/{chunk-6UHXLKAV.js → chunk-URQB3FDZ.js} +622 -172
- package/dist/chunk-URQB3FDZ.js.map +1 -0
- package/dist/human-in-the-loop.d.ts +33 -0
- package/dist/human-in-the-loop.js +12 -0
- package/dist/human-in-the-loop.js.map +1 -0
- package/dist/knock-client-BH7Juvis.d.ts +10 -0
- package/dist/langchain/index.d.ts +17 -0
- package/dist/langchain/index.js +16055 -0
- package/dist/langchain/index.js.map +1 -0
- package/dist/modelcontextprotocol/index.d.ts +8 -8
- package/dist/modelcontextprotocol/index.js +3 -2
- package/dist/modelcontextprotocol/local-server.js +13 -8
- package/dist/modelcontextprotocol/local-server.js.map +1 -1
- package/dist/openai/index.d.ts +9 -33
- package/dist/openai/index.js +4 -3
- package/dist/openai/index.js.map +1 -1
- package/dist/types-CrTRlRnE.d.ts +105 -0
- package/dist/{types-BJFe1DAl.d.ts → types.d.ts} +2 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/package.json +13 -1
- package/dist/chunk-6UHXLKAV.js.map +0 -1
- package/dist/chunk-VGU7NXYJ.js.map +0 -1
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
- [Model Context Protocol (MCP)](#model-context-protocol-mcp)
|
|
12
12
|
- [AI SDK](#ai-sdk)
|
|
13
13
|
- [OpenAI](#openai)
|
|
14
|
+
- [Langchain](#langchain)
|
|
14
15
|
|
|
15
16
|
## Getting started
|
|
16
17
|
|
|
@@ -23,6 +24,7 @@ Using the Knock agent toolkit allows you to build powerful agent systems that ar
|
|
|
23
24
|
The Knock Agent Toolkit provides three main entry points:
|
|
24
25
|
|
|
25
26
|
- `@knocklabs/agent-toolkit/ai-sdk`: Helpers for integrating with Vercel's AI SDK.
|
|
27
|
+
- `@knocklabs/agent-tookkit/langchain`: Helpers for integrating with [Langchain's JS SDK](https://github.com/langchain-ai/langchainjs).
|
|
26
28
|
- `@knocklabs/agent-toolkit/openai`: Helpers for integrating with the OpenAI SDK.
|
|
27
29
|
- `@knocklabs/agent-toolkit/modelcontextprotocol`: Low level helpers for integrating with the Model Context Protocol (MCP).
|
|
28
30
|
|
|
@@ -66,6 +68,12 @@ npx -y @knocklabs/agent-toolkit -p local-mcp --tools "workflows.*"
|
|
|
66
68
|
npx -y @knocklabs/agent-toolkit -p local-mcp --tools "workflows.triggerWorkflow"
|
|
67
69
|
```
|
|
68
70
|
|
|
71
|
+
If you wish to enable workflows-as-tools within the MCP server, you must set the `--workflows` flag to pass in a list of approved workflow keys to expose. This ensures that you keep the number of tools exposed to your MCP client to a minimum.
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
npx -y @knocklabs/agent-toolkit -p local-mcp --workflows comment-created activate-account
|
|
75
|
+
```
|
|
76
|
+
|
|
69
77
|
It's also possible to pass `environment`, `userId`, and `tenant` to the local MCP server to set default values. Use the `--help` flag to view additional server options.
|
|
70
78
|
|
|
71
79
|
### AI SDK
|
|
@@ -84,7 +92,6 @@ npm install @knocklabs/agent-toolkit
|
|
|
84
92
|
import { createKnockToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
|
|
85
93
|
import { openai } from "@ai-sdk/openai";
|
|
86
94
|
import { streamText } from "ai";
|
|
87
|
-
import { auth } from "@clerk/nextjs/server";
|
|
88
95
|
import { systemPrompt } from "@/lib/ai/prompts";
|
|
89
96
|
|
|
90
97
|
export const maxDuration = 30;
|
|
@@ -132,25 +139,89 @@ import OpenAI from "openai";
|
|
|
132
139
|
|
|
133
140
|
const openai = new OpenAI();
|
|
134
141
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
)
|
|
142
|
+
async function main() {
|
|
143
|
+
const toolkit = await createKnockToolkit({
|
|
144
|
+
serviceToken: "kst_12345",
|
|
145
|
+
permissions: {
|
|
146
|
+
// Set the permissions of the tools to expose
|
|
147
|
+
workflows: { read: true, run: true, manage: true },
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const completion = await openai.chat.completions.create({
|
|
152
|
+
model: "gpt-4o",
|
|
153
|
+
messages,
|
|
154
|
+
// The tools given here are determined by the `permissions`
|
|
155
|
+
// list above in the configuration. For instance, here we're only
|
|
156
|
+
// allowing the workflows
|
|
157
|
+
tools: toolkit.getAllTools(),
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Execute the tool calls
|
|
161
|
+
const toolMessages = await Promise.all(
|
|
162
|
+
message.tool_calls.map((tc) => toolkit.handleToolCall(tc))
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
main();
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Langchain
|
|
170
|
+
|
|
171
|
+
The agent toolkit provides a `createKnockToolkit` under the `/langchain` path for easily integrating into the Lanchain JS SDK and returning tools ready for use.
|
|
172
|
+
|
|
173
|
+
1. Install the package:
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
npm install @knocklabs/agent-toolkit
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
2. Import the `createKnockToolkit` helper, configure it, and use it in your LLM calling:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { createKnockToolkit } from "@knocklabs/agent-toolkit/langchain";
|
|
183
|
+
import { ChatOpenAI } from "@langchain/openai";
|
|
184
|
+
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
|
|
185
|
+
import { LangChainAdapter } from "ai";
|
|
186
|
+
|
|
187
|
+
const systemPrompt = `You are a helpful assistant.`;
|
|
188
|
+
|
|
189
|
+
export const maxDuration = 30;
|
|
190
|
+
|
|
191
|
+
export async function POST(req: Request) {
|
|
192
|
+
const { prompt } = await req.json();
|
|
193
|
+
// Optional - get the auth context from the request
|
|
194
|
+
const authContext = await auth.protect();
|
|
195
|
+
|
|
196
|
+
// Instantiate a new Knock toolkit
|
|
197
|
+
const toolkit = await createKnockToolkit({
|
|
198
|
+
serviceToken: "kst_12345",
|
|
199
|
+
permissions: {
|
|
200
|
+
// (optional but recommended): Set the permissions of the tools to expose
|
|
201
|
+
workflows: { read: true, run: true, manage: true },
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const model = new ChatOpenAI({ model: "gpt-4o", temperature: 0 });
|
|
206
|
+
|
|
207
|
+
const modelWithTools = model.bindTools(toolkit.getAllTools());
|
|
208
|
+
|
|
209
|
+
const messages = [new SystemMessage(systemPrompt), new HumanMessage(prompt)];
|
|
210
|
+
const aiMessage = await modelWithTools.invoke(messages);
|
|
211
|
+
messages.push(aiMessage);
|
|
212
|
+
|
|
213
|
+
for (const toolCall of aiMessage.tool_calls || []) {
|
|
214
|
+
// Call the selected tool by its `name`
|
|
215
|
+
const selectedTool = toolkit.getToolMap()[toolCall.name];
|
|
216
|
+
const toolMessage = await selectedTool.invoke(toolCall);
|
|
217
|
+
|
|
218
|
+
messages.push(toolMessage);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// To simplify the setup, this example uses the ai-sdk langchain adapter
|
|
222
|
+
// to stream the results back to the /langchain page.
|
|
223
|
+
// For more details, see: https://sdk.vercel.ai/providers/adapters/langchain
|
|
224
|
+
const stream = await modelWithTools.stream(messages);
|
|
225
|
+
return LangChainAdapter.toDataStreamResponse(stream);
|
|
226
|
+
}
|
|
156
227
|
```
|
package/dist/ai-sdk/index.d.ts
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import { ToolSet, Tool } from 'ai';
|
|
2
|
-
import {
|
|
2
|
+
import { a as DeferredToolCall, b as DeferredToolCallConfig, K as KnockOutboundWebhookEvent, D as DeferredToolCallInteractionResult } from '../types-CrTRlRnE.js';
|
|
3
|
+
import { ToolkitConfig, ToolCategory } from '../types.js';
|
|
4
|
+
import { ToolInvocation } from '@ai-sdk/ui-utils';
|
|
5
|
+
import '@knocklabs/node/dist/src/resources/messages/interfaces';
|
|
3
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Convert a deferred tool call to a tool invocation. Useful when building an assistant
|
|
9
|
+
* response from a deferred tool call.
|
|
10
|
+
*
|
|
11
|
+
* @param deferredToolCall - The deferred tool call to convert.
|
|
12
|
+
* @param result - The result of the tool call.
|
|
13
|
+
* @returns The tool invocation.
|
|
14
|
+
*/
|
|
15
|
+
declare function deferredToolCallToToolInvocation(deferredToolCall: DeferredToolCall, result: unknown): ToolInvocation;
|
|
16
|
+
|
|
17
|
+
type KnockToolkit = {
|
|
18
|
+
getAllTools: () => ToolSet;
|
|
19
|
+
getTools: (category: ToolCategory) => ToolSet;
|
|
20
|
+
getToolMap: () => Record<string, Tool>;
|
|
21
|
+
requireHumanInput: (toolsToWrap: ToolSet, inputConfig: DeferredToolCallConfig) => ToolSet;
|
|
22
|
+
resumeToolExecution: (toolInteraction: DeferredToolCall) => Promise<unknown>;
|
|
23
|
+
wrappedToolsRequiringInput: () => Map<string, Tool>;
|
|
24
|
+
handleMessageInteraction: (event: KnockOutboundWebhookEvent) => DeferredToolCallInteractionResult | null;
|
|
25
|
+
};
|
|
4
26
|
/**
|
|
5
27
|
* Creates a Knock toolkit for use with the AI SDK.
|
|
6
28
|
*
|
|
@@ -24,29 +46,6 @@ import { T as ToolkitConfig, a as ToolCategory } from '../types-BJFe1DAl.js';
|
|
|
24
46
|
* @param config - The configuration to use for the toolkit
|
|
25
47
|
* @returns A toolkit for use with the AI SDK
|
|
26
48
|
*/
|
|
27
|
-
declare const createKnockToolkit: (config: ToolkitConfig) => Promise<
|
|
28
|
-
/**
|
|
29
|
-
* Get all tools for all categories. When the `config.permissions.workflows.run` is set, then workflow triggers for
|
|
30
|
-
* the specified workflows will be included in the returned tools.
|
|
31
|
-
*
|
|
32
|
-
* @returns A promise that resolves to a set of tools
|
|
33
|
-
*/
|
|
34
|
-
getAllTools: () => Promise<ToolSet>;
|
|
35
|
-
/**
|
|
36
|
-
* Get all tools for a specific category. When trying to get tools for the `workflows` category and the run permission is set,
|
|
37
|
-
* the workflow triggers for the specified workflows will be included in the returned tools.
|
|
38
|
-
*
|
|
39
|
-
* @param category - The category of tools to get
|
|
40
|
-
* @returns An array of tools for the given category
|
|
41
|
-
*/
|
|
42
|
-
getTools: (category: ToolCategory) => Promise<ToolSet>;
|
|
43
|
-
/**
|
|
44
|
-
* Get a map of all tools by method name. When the `config.permissions.workflows.run` is set, then workflow triggers for
|
|
45
|
-
* the specified workflows will be included in the returned tools.
|
|
46
|
-
*
|
|
47
|
-
* @returns A map of all tools by method name
|
|
48
|
-
*/
|
|
49
|
-
getToolMap: () => Promise<Record<string, Tool>>;
|
|
50
|
-
}>;
|
|
49
|
+
declare const createKnockToolkit: (config: ToolkitConfig) => Promise<KnockToolkit>;
|
|
51
50
|
|
|
52
|
-
export { createKnockToolkit };
|
|
51
|
+
export { createKnockToolkit, deferredToolCallToToolInvocation };
|
package/dist/ai-sdk/index.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
handleMessageInteraction,
|
|
3
|
+
triggerHumanInTheLoopWorkflow,
|
|
4
|
+
wrapToolDescription
|
|
5
|
+
} from "../chunk-6O7VMHBN.js";
|
|
1
6
|
import {
|
|
2
7
|
createKnockClient
|
|
3
8
|
} from "../chunk-OMZBTWDH.js";
|
|
4
9
|
import {
|
|
5
10
|
getToolMap,
|
|
6
11
|
getToolsByPermissionsInCategories
|
|
7
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-URQB3FDZ.js";
|
|
13
|
+
import "../chunk-G3PMV62Z.js";
|
|
8
14
|
|
|
9
15
|
// src/ai-sdk/tool-converter.ts
|
|
10
16
|
import { tool } from "ai";
|
|
@@ -26,6 +32,18 @@ var knockToolsToToolSet = (knockClient, config, knockTools) => {
|
|
|
26
32
|
);
|
|
27
33
|
};
|
|
28
34
|
|
|
35
|
+
// src/ai-sdk/helpers.ts
|
|
36
|
+
function deferredToolCallToToolInvocation(deferredToolCall, result) {
|
|
37
|
+
return {
|
|
38
|
+
args: deferredToolCall.args,
|
|
39
|
+
toolName: deferredToolCall.method,
|
|
40
|
+
toolCallId: deferredToolCall.extra?.toolCallId,
|
|
41
|
+
state: "result",
|
|
42
|
+
step: 0,
|
|
43
|
+
result
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
29
47
|
// src/ai-sdk/index.ts
|
|
30
48
|
var createKnockToolkit = async (config) => {
|
|
31
49
|
const knockClient = createKnockClient(config);
|
|
@@ -35,14 +53,15 @@ var createKnockToolkit = async (config) => {
|
|
|
35
53
|
);
|
|
36
54
|
const allTools = Object.values(allowedToolsByCategory).flat();
|
|
37
55
|
const toolsByMethod = getToolMap(allTools);
|
|
38
|
-
|
|
56
|
+
const wrappedToolsRequiringInput = /* @__PURE__ */ new Map();
|
|
57
|
+
return Promise.resolve({
|
|
39
58
|
/**
|
|
40
59
|
* Get all tools for all categories. When the `config.permissions.workflows.run` is set, then workflow triggers for
|
|
41
60
|
* the specified workflows will be included in the returned tools.
|
|
42
61
|
*
|
|
43
62
|
* @returns A promise that resolves to a set of tools
|
|
44
63
|
*/
|
|
45
|
-
getAllTools:
|
|
64
|
+
getAllTools: () => {
|
|
46
65
|
return knockToolsToToolSet(knockClient, config, allTools);
|
|
47
66
|
},
|
|
48
67
|
/**
|
|
@@ -52,7 +71,7 @@ var createKnockToolkit = async (config) => {
|
|
|
52
71
|
* @param category - The category of tools to get
|
|
53
72
|
* @returns An array of tools for the given category
|
|
54
73
|
*/
|
|
55
|
-
getTools:
|
|
74
|
+
getTools: (category) => {
|
|
56
75
|
return knockToolsToToolSet(
|
|
57
76
|
knockClient,
|
|
58
77
|
config,
|
|
@@ -65,7 +84,7 @@ var createKnockToolkit = async (config) => {
|
|
|
65
84
|
*
|
|
66
85
|
* @returns A map of all tools by method name
|
|
67
86
|
*/
|
|
68
|
-
getToolMap:
|
|
87
|
+
getToolMap: () => {
|
|
69
88
|
return Object.entries(toolsByMethod).reduce(
|
|
70
89
|
(acc, [method, tool2]) => ({
|
|
71
90
|
...acc,
|
|
@@ -73,10 +92,89 @@ var createKnockToolkit = async (config) => {
|
|
|
73
92
|
}),
|
|
74
93
|
{}
|
|
75
94
|
);
|
|
76
|
-
}
|
|
77
|
-
|
|
95
|
+
},
|
|
96
|
+
/**
|
|
97
|
+
* Wraps one or more tools to require human input.
|
|
98
|
+
*
|
|
99
|
+
* @param toolsToWrap - The tools to wrap
|
|
100
|
+
* @param inputConfig - The configuration to use for the HITL request
|
|
101
|
+
*/
|
|
102
|
+
requireHumanInput: (toolsToWrap, inputConfig) => {
|
|
103
|
+
const wrappedTools = {};
|
|
104
|
+
for (const [method, toolToWrap] of Object.entries(toolsToWrap)) {
|
|
105
|
+
wrappedToolsRequiringInput.set(method, { ...toolToWrap });
|
|
106
|
+
const wrappedTool = {
|
|
107
|
+
...toolToWrap,
|
|
108
|
+
description: wrapToolDescription(toolToWrap.description ?? ""),
|
|
109
|
+
execute: async (input, options) => {
|
|
110
|
+
const toolExecution = {
|
|
111
|
+
method,
|
|
112
|
+
args: input,
|
|
113
|
+
extra: {
|
|
114
|
+
toolCallId: options.toolCallId
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
await triggerHumanInTheLoopWorkflow({
|
|
118
|
+
knockClient,
|
|
119
|
+
config,
|
|
120
|
+
toolCall: toolExecution,
|
|
121
|
+
inputConfig
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
type: "tool-status",
|
|
125
|
+
status: "pending-input",
|
|
126
|
+
toolCallId: options.toolCallId
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
wrappedTools[method] = wrappedTool;
|
|
131
|
+
}
|
|
132
|
+
return wrappedTools;
|
|
133
|
+
},
|
|
134
|
+
/**
|
|
135
|
+
* Returns any tools that were wrapped with `requireHumanInput`.
|
|
136
|
+
*
|
|
137
|
+
* @returns A map of wrapped tools that require human input
|
|
138
|
+
*/
|
|
139
|
+
wrappedToolsRequiringInput: () => wrappedToolsRequiringInput,
|
|
140
|
+
/**
|
|
141
|
+
* Resumes the execution of a tool that required human input.
|
|
142
|
+
*
|
|
143
|
+
* @param toolInteraction - The tool interaction to resume
|
|
144
|
+
* @returns A promise that resolves to the result of the tool execution
|
|
145
|
+
*/
|
|
146
|
+
resumeToolExecution: async (toolInteraction) => {
|
|
147
|
+
const tool2 = wrappedToolsRequiringInput.get(toolInteraction.method);
|
|
148
|
+
if (!tool2) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`Tool "${toolInteraction.method}" not found. Did you forget to wrap the tool with requireHumanInput?`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
if (!tool2.execute) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
`Tool "${toolInteraction.method}" does not have an execute method. Nothing to resume.`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
const options = toolInteraction.extra;
|
|
159
|
+
const result = await tool2.execute(toolInteraction.args, options);
|
|
160
|
+
return {
|
|
161
|
+
type: "tool-status",
|
|
162
|
+
status: "completed",
|
|
163
|
+
toolCallId: options.toolCallId,
|
|
164
|
+
result
|
|
165
|
+
};
|
|
166
|
+
},
|
|
167
|
+
/**
|
|
168
|
+
* Handles a message interaction event by parsing it into a well-known format.
|
|
169
|
+
*
|
|
170
|
+
* @param event - The message interaction event
|
|
171
|
+
* @returns An deferred tool call, or null if the event is not a message interaction
|
|
172
|
+
*/
|
|
173
|
+
handleMessageInteraction
|
|
174
|
+
});
|
|
78
175
|
};
|
|
79
176
|
export {
|
|
80
|
-
createKnockToolkit
|
|
177
|
+
createKnockToolkit,
|
|
178
|
+
deferredToolCallToToolInvocation
|
|
81
179
|
};
|
|
82
180
|
//# sourceMappingURL=index.js.map
|
package/dist/ai-sdk/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ai-sdk/tool-converter.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 { Tool, ToolSet } from \"ai\";\n\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\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.run` 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 (config: ToolkitConfig) => {\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 return {\n /**\n * Get all tools for all categories. When the `config.permissions.workflows.run` is set, then workflow triggers for\n * the specified workflows will be included in the returned tools.\n *\n * @returns A promise that resolves to a set of tools\n */\n getAllTools: async (): Promise<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 run 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: async (category: ToolCategory): Promise<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. When the `config.permissions.workflows.run` is set, then workflow triggers for\n * the specified workflows will be included in the returned tools.\n *\n * @returns A map of all tools by method name\n */\n getToolMap: async (): Promise<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\nexport { createKnockToolkit };\n"],"mappings":";;;;;;;;;AACA,SAAS,YAAY;AACrB,SAAS,SAAS;AASlB,IAAM,oBAAoB,CACxB,aACA,QACA,cACS;AACT,SAAO,KAAK;AAAA,IACV,aAAa,UAAU;AAAA,IACvB,YAAY,UAAU,cAAc,EAAE,OAAO,CAAC,CAAC;AAAA,IAC/C,SAAS,UAAU,YAAY,aAAa,MAAM;AAAA,EACpD,CAAC;AACH;AAKA,IAAM,sBAAsB,CAC1B,aACA,QACA,eACG;AACH,SAAO,WAAW;AAAA,IAChB,CAAC,KAAKA,UAAS;AACb,UAAIA,MAAK,MAAM,IAAI,kBAAkB,aAAa,QAAQA,KAAI;AAC9D,aAAO;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EACH;AACF;;;ACPA,IAAM,qBAAqB,OAAO,WAA0B;AAC1D,QAAM,cAAc,kBAAkB,MAAM;AAC5C,QAAM,yBAAyB,MAAM;AAAA,IACnC;AAAA,IACA;AAAA,EACF;AACA,QAAM,WAAW,OAAO,OAAO,sBAAsB,EAAE,KAAK;AAC5D,QAAM,gBAAgB,WAAW,QAAQ;AAEzC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOL,aAAa,YAA8B;AACzC,aAAO,oBAAoB,aAAa,QAAQ,QAAQ;AAAA,IAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASA,UAAU,OAAO,aAA6C;AAC5D,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,uBAAuB,QAAQ;AAAA,MACjC;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA,YAAY,YAA2C;AACrD,aAAO,OAAO,QAAQ,aAAa,EAAE;AAAA,QACnC,CAAC,KAAK,CAAC,QAAQC,KAAI,OAAO;AAAA,UACxB,GAAG;AAAA,UACH,CAAC,MAAM,GAAG,kBAAkB,aAAa,QAAQA,KAAI;AAAA,QACvD;AAAA,QACA,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;","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.run` 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. When the `config.permissions.workflows.run` is set, then workflow triggers for\n * the specified workflows will be included in the returned tools.\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 run 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. When the `config.permissions.workflows.run` is set, then workflow triggers for\n * the specified workflows will be included in the returned tools.\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"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// src/lib/human-in-the-loop/index.ts
|
|
2
|
+
function wrapToolDescription(description) {
|
|
3
|
+
return `${description}
|
|
4
|
+
|
|
5
|
+
This 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.`;
|
|
6
|
+
}
|
|
7
|
+
async function triggerHumanInTheLoopWorkflow({
|
|
8
|
+
knockClient,
|
|
9
|
+
config,
|
|
10
|
+
toolCall,
|
|
11
|
+
inputConfig
|
|
12
|
+
}) {
|
|
13
|
+
const knock = await knockClient.publicApi(config.environment);
|
|
14
|
+
const result = await knock.workflows.trigger(inputConfig.workflow, {
|
|
15
|
+
data: {
|
|
16
|
+
type: "deferred_tool_call",
|
|
17
|
+
tool_call: toolCall,
|
|
18
|
+
metadata: inputConfig.metadata
|
|
19
|
+
},
|
|
20
|
+
recipients: inputConfig.recipients,
|
|
21
|
+
tenant: inputConfig.tenant,
|
|
22
|
+
actor: inputConfig.actor
|
|
23
|
+
});
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
function handleMessageInteraction(event) {
|
|
27
|
+
const { data: message } = event;
|
|
28
|
+
if (event.type !== "message.interacted") {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
if (message.data.type !== "deferred_tool_call" || !message.data.tool_call) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const messageData = message.data;
|
|
35
|
+
return {
|
|
36
|
+
workflow: message.source.key,
|
|
37
|
+
interaction: event.event_data,
|
|
38
|
+
toolCall: {
|
|
39
|
+
method: messageData.tool_call.method,
|
|
40
|
+
args: messageData.tool_call.args,
|
|
41
|
+
extra: messageData.tool_call.extra
|
|
42
|
+
},
|
|
43
|
+
metadata: messageData.metadata,
|
|
44
|
+
context: {
|
|
45
|
+
messageId: message.id,
|
|
46
|
+
channelId: message.channel_id,
|
|
47
|
+
timestamp: event.created_at
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
wrapToolDescription,
|
|
54
|
+
triggerHumanInTheLoopWorkflow,
|
|
55
|
+
handleMessageInteraction
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=chunk-6O7VMHBN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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":[]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __export = (target, all) => {
|
|
11
|
+
for (var name in all)
|
|
12
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
+
};
|
|
14
|
+
var __copyProps = (to, from, except, desc) => {
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
+
for (let key of __getOwnPropNames(from))
|
|
17
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
23
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
24
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
25
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
26
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
27
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
28
|
+
mod
|
|
29
|
+
));
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
__commonJS,
|
|
33
|
+
__export,
|
|
34
|
+
__toESM
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=chunk-G3PMV62Z.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
allTools,
|
|
3
3
|
createWorkflowTools
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-URQB3FDZ.js";
|
|
5
5
|
|
|
6
6
|
// src/modelcontextprotocol/adapter.ts
|
|
7
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.
|
|
11
|
+
super({ name: "Knock", version: "0.1.11" });
|
|
12
12
|
tools.forEach((tool) => {
|
|
13
13
|
const toolParams = tool.parameters ?? z.object({});
|
|
14
14
|
this.tool(
|
|
@@ -28,10 +28,14 @@ var KnockMcpServer = class extends McpServer {
|
|
|
28
28
|
|
|
29
29
|
// src/modelcontextprotocol/index.ts
|
|
30
30
|
var createKnockMcpServer = async (params) => {
|
|
31
|
-
const { tools, knockClient, config } = params;
|
|
31
|
+
const { tools, knockClient, config, workflows } = params;
|
|
32
32
|
let baseTools = tools || Object.values(allTools);
|
|
33
|
-
if (
|
|
34
|
-
const workflowTools = await createWorkflowTools(
|
|
33
|
+
if (workflows && Array.isArray(workflows) && workflows.length > 0) {
|
|
34
|
+
const workflowTools = await createWorkflowTools(
|
|
35
|
+
knockClient,
|
|
36
|
+
config,
|
|
37
|
+
workflows
|
|
38
|
+
);
|
|
35
39
|
baseTools = [...baseTools, ...workflowTools];
|
|
36
40
|
}
|
|
37
41
|
return Promise.resolve(new KnockMcpServer(knockClient, config, baseTools));
|
|
@@ -40,4 +44,4 @@ var createKnockMcpServer = async (params) => {
|
|
|
40
44
|
export {
|
|
41
45
|
createKnockMcpServer
|
|
42
46
|
};
|
|
43
|
-
//# sourceMappingURL=chunk-
|
|
47
|
+
//# sourceMappingURL=chunk-H3YEJMMF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/modelcontextprotocol/adapter.ts","../src/modelcontextprotocol/index.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\nimport { KnockClient } from \"../lib/knock-client.js\";\nimport type { KnockTool } from \"../lib/knock-tool.js\";\nimport { Config } from \"../types.js\";\n\nexport class KnockMcpServer extends McpServer {\n constructor(knockClient: KnockClient, config: Config, tools: KnockTool[]) {\n super({ name: \"Knock\", version: PACKAGE_VERSION });\n\n tools.forEach((tool) => {\n const toolParams = tool.parameters ?? z.object({});\n\n this.tool(\n tool.method,\n tool.description,\n toolParams.shape,\n async (arg: unknown) => {\n const res = await tool.bindExecute(knockClient, config)(arg);\n\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(res) }],\n };\n }\n );\n });\n }\n}\n","import { KnockClient } from \"../lib/knock-client.js\";\nimport type { KnockTool } from \"../lib/knock-tool.js\";\nimport { allTools } from \"../lib/tools/index.js\";\nimport { createWorkflowTools } from \"../lib/tools/workflows-as-tools.js\";\nimport { Config } from \"../types.js\";\n\nimport { KnockMcpServer } from \"./adapter.js\";\n\ntype CreateKnockMcpServerParams = {\n /**\n * Array of Knock tools to enable in the server.\n */\n tools?: KnockTool[];\n\n /**\n * A Knock client to use for the server.\n */\n knockClient: KnockClient;\n\n /**\n * The config to use for the server.\n */\n config: Config;\n\n /**\n * The workflows to enable as tools in the MCP server.\n */\n workflows?: string[];\n};\n\n/**\n * Creates a Knock MCP Server with the given parameters.\n */\nexport const createKnockMcpServer = async (\n params: CreateKnockMcpServerParams\n): Promise<KnockMcpServer> => {\n const { tools, knockClient, config, workflows } = params;\n\n let baseTools = tools || Object.values(allTools);\n\n if (workflows && Array.isArray(workflows) && workflows.length > 0) {\n const workflowTools = await createWorkflowTools(\n knockClient,\n config,\n workflows\n );\n\n baseTools = [...baseTools, ...workflowTools];\n }\n\n return Promise.resolve(new KnockMcpServer(knockClient, config, baseTools));\n};\n"],"mappings":";;;;;;AAAA,SAAS,iBAAiB;AAC1B,SAAS,SAAS;AAMX,IAAM,iBAAN,cAA6B,UAAU;AAAA,EAC5C,YAAY,aAA0B,QAAgB,OAAoB;AACxE,UAAM,EAAE,MAAM,SAAS,SAAS,SAAgB,CAAC;AAEjD,UAAM,QAAQ,CAAC,SAAS;AACtB,YAAM,aAAa,KAAK,cAAc,EAAE,OAAO,CAAC,CAAC;AAEjD,WAAK;AAAA,QACH,KAAK;AAAA,QACL,KAAK;AAAA,QACL,WAAW;AAAA,QACX,OAAO,QAAiB;AACtB,gBAAM,MAAM,MAAM,KAAK,YAAY,aAAa,MAAM,EAAE,GAAG;AAE3D,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,GAAG,EAAE,CAAC;AAAA,UAChE;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACKO,IAAM,uBAAuB,OAClC,WAC4B;AAC5B,QAAM,EAAE,OAAO,aAAa,QAAQ,UAAU,IAAI;AAElD,MAAI,YAAY,SAAS,OAAO,OAAO,QAAQ;AAE/C,MAAI,aAAa,MAAM,QAAQ,SAAS,KAAK,UAAU,SAAS,GAAG;AACjE,UAAM,gBAAgB,MAAM;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,gBAAY,CAAC,GAAG,WAAW,GAAG,aAAa;AAAA,EAC7C;AAEA,SAAO,QAAQ,QAAQ,IAAI,eAAe,aAAa,QAAQ,SAAS,CAAC;AAC3E;","names":[]}
|