kernl 0.1.1
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/.turbo/turbo-build.log +5 -0
- package/CHANGELOG.md +53 -0
- package/LICENSE +201 -0
- package/dist/agent.d.ts +43 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +130 -0
- package/dist/context.d.ts +70 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +111 -0
- package/dist/env.d.ts +45 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +31 -0
- package/dist/error.d.ts +1 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +1 -0
- package/dist/guardrail.d.ts +178 -0
- package/dist/guardrail.d.ts.map +1 -0
- package/dist/guardrail.js +34 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/kernel.d.ts +7 -0
- package/dist/kernel.d.ts.map +1 -0
- package/dist/kernel.js +7 -0
- package/dist/kernl.d.ts +18 -0
- package/dist/kernl.d.ts.map +1 -0
- package/dist/kernl.js +16 -0
- package/dist/lib/env.d.ts +43 -0
- package/dist/lib/env.d.ts.map +1 -0
- package/dist/lib/env.js +29 -0
- package/dist/lib/error.d.ts +88 -0
- package/dist/lib/error.d.ts.map +1 -0
- package/dist/lib/error.js +117 -0
- package/dist/lib/logger.d.ts +36 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +43 -0
- package/dist/lib/serde/__tests__/codec.test.d.ts +2 -0
- package/dist/lib/serde/__tests__/codec.test.d.ts.map +1 -0
- package/dist/lib/serde/__tests__/codec.test.js +75 -0
- package/dist/lib/serde/codec.d.ts +12 -0
- package/dist/lib/serde/codec.d.ts.map +1 -0
- package/dist/lib/serde/codec.js +54 -0
- package/dist/lib/serde/json.d.ts +8 -0
- package/dist/lib/serde/json.d.ts.map +1 -0
- package/dist/lib/serde/json.js +13 -0
- package/dist/lib/serde/thread.d.ts +1 -0
- package/dist/lib/serde/thread.d.ts.map +1 -0
- package/dist/lib/serde/thread.js +172 -0
- package/dist/lib/serde/tool.d.ts +36 -0
- package/dist/lib/serde/tool.d.ts.map +1 -0
- package/dist/lib/serde/tool.js +1 -0
- package/dist/lib/utils.d.ts +19 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +41 -0
- package/dist/lifecycle.d.ts +133 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +29 -0
- package/dist/logger.d.ts +36 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +43 -0
- package/dist/mcp/__tests__/base.test.d.ts +2 -0
- package/dist/mcp/__tests__/base.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/base.test.js +268 -0
- package/dist/mcp/__tests__/fixtures/echo-server.d.ts +3 -0
- package/dist/mcp/__tests__/fixtures/echo-server.d.ts.map +1 -0
- package/dist/mcp/__tests__/fixtures/echo-server.js +92 -0
- package/dist/mcp/__tests__/fixtures/math-server.d.ts +3 -0
- package/dist/mcp/__tests__/fixtures/math-server.d.ts.map +1 -0
- package/dist/mcp/__tests__/fixtures/math-server.js +98 -0
- package/dist/mcp/__tests__/fixtures/server.d.ts +3 -0
- package/dist/mcp/__tests__/fixtures/server.d.ts.map +1 -0
- package/dist/mcp/__tests__/fixtures/server.js +162 -0
- package/dist/mcp/__tests__/fixtures/test-server.d.ts +3 -0
- package/dist/mcp/__tests__/fixtures/test-server.d.ts.map +1 -0
- package/dist/mcp/__tests__/fixtures/test-server.js +163 -0
- package/dist/mcp/__tests__/fixtures/utils.d.ts +17 -0
- package/dist/mcp/__tests__/fixtures/utils.d.ts.map +1 -0
- package/dist/mcp/__tests__/fixtures/utils.js +42 -0
- package/dist/mcp/__tests__/integration.test.d.ts +2 -0
- package/dist/mcp/__tests__/integration.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/integration.test.js +360 -0
- package/dist/mcp/__tests__/stdio.test.d.ts +2 -0
- package/dist/mcp/__tests__/stdio.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/stdio.test.js +180 -0
- package/dist/mcp/__tests__/test-utils.d.ts +17 -0
- package/dist/mcp/__tests__/test-utils.d.ts.map +1 -0
- package/dist/mcp/__tests__/test-utils.js +42 -0
- package/dist/mcp/__tests__/utils.test.d.ts +2 -0
- package/dist/mcp/__tests__/utils.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/utils.test.js +300 -0
- package/dist/mcp/base.d.ts +88 -0
- package/dist/mcp/base.d.ts.map +1 -0
- package/dist/mcp/base.js +68 -0
- package/dist/mcp/http.d.ts +34 -0
- package/dist/mcp/http.d.ts.map +1 -0
- package/dist/mcp/http.js +100 -0
- package/dist/mcp/node.d.ts +60 -0
- package/dist/mcp/node.d.ts.map +1 -0
- package/dist/mcp/node.js +297 -0
- package/dist/mcp/sse.d.ts +34 -0
- package/dist/mcp/sse.d.ts.map +1 -0
- package/dist/mcp/sse.js +97 -0
- package/dist/mcp/stdio.d.ts +32 -0
- package/dist/mcp/stdio.d.ts.map +1 -0
- package/dist/mcp/stdio.js +96 -0
- package/dist/mcp/types.d.ts +172 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +16 -0
- package/dist/mcp/utils.d.ts +23 -0
- package/dist/mcp/utils.d.ts.map +1 -0
- package/dist/mcp/utils.js +44 -0
- package/dist/model.d.ts +175 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +1 -0
- package/dist/providers/ai.d.ts +1 -0
- package/dist/providers/ai.d.ts.map +1 -0
- package/dist/providers/ai.js +1 -0
- package/dist/providers/default.d.ts +16 -0
- package/dist/providers/default.d.ts.map +1 -0
- package/dist/providers/default.js +17 -0
- package/dist/providers/registry.d.ts +1 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +1 -0
- package/dist/sched/scheduler.d.ts +20 -0
- package/dist/sched/scheduler.d.ts.map +1 -0
- package/dist/sched/scheduler.js +1 -0
- package/dist/sched/task.d.ts +92 -0
- package/dist/sched/task.d.ts.map +1 -0
- package/dist/sched/task.js +102 -0
- package/dist/serde/__tests__/codec.test.d.ts +2 -0
- package/dist/serde/__tests__/codec.test.d.ts.map +1 -0
- package/dist/serde/__tests__/codec.test.js +75 -0
- package/dist/serde/codec.d.ts +12 -0
- package/dist/serde/codec.d.ts.map +1 -0
- package/dist/serde/codec.js +54 -0
- package/dist/serde/json.d.ts +8 -0
- package/dist/serde/json.d.ts.map +1 -0
- package/dist/serde/json.js +13 -0
- package/dist/serde/thread.d.ts +687 -0
- package/dist/serde/thread.d.ts.map +1 -0
- package/dist/serde/thread.js +158 -0
- package/dist/serde/tool.d.ts +36 -0
- package/dist/serde/tool.d.ts.map +1 -0
- package/dist/serde/tool.js +1 -0
- package/dist/session.d.ts +1 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +1 -0
- package/dist/task.d.ts +87 -0
- package/dist/task.d.ts.map +1 -0
- package/dist/task.js +97 -0
- package/dist/thread/__tests__/mock.d.ts +28 -0
- package/dist/thread/__tests__/mock.d.ts.map +1 -0
- package/dist/thread/__tests__/mock.js +74 -0
- package/dist/thread/__tests__/thread.test.d.ts +2 -0
- package/dist/thread/__tests__/thread.test.d.ts.map +1 -0
- package/dist/thread/__tests__/thread.test.js +1412 -0
- package/dist/thread/index.d.ts +2 -0
- package/dist/thread/index.d.ts.map +1 -0
- package/dist/thread/index.js +1 -0
- package/dist/thread/thread.d.ts +66 -0
- package/dist/thread/thread.d.ts.map +1 -0
- package/dist/thread/thread.js +472 -0
- package/dist/thread/utils.d.ts +19 -0
- package/dist/thread/utils.d.ts.map +1 -0
- package/dist/thread/utils.js +50 -0
- package/dist/tool/__tests__/fixtures.d.ts +45 -0
- package/dist/tool/__tests__/fixtures.d.ts.map +1 -0
- package/dist/tool/__tests__/fixtures.js +97 -0
- package/dist/tool/__tests__/tool.test.d.ts +2 -0
- package/dist/tool/__tests__/tool.test.d.ts.map +1 -0
- package/dist/tool/__tests__/tool.test.js +172 -0
- package/dist/tool/__tests__/toolkit.test.d.ts +2 -0
- package/dist/tool/__tests__/toolkit.test.d.ts.map +1 -0
- package/dist/tool/__tests__/toolkit.test.js +134 -0
- package/dist/tool/index.d.ts +4 -0
- package/dist/tool/index.d.ts.map +1 -0
- package/dist/tool/index.js +2 -0
- package/dist/tool/mcp.d.ts +75 -0
- package/dist/tool/mcp.d.ts.map +1 -0
- package/dist/tool/mcp.js +111 -0
- package/dist/tool/tool.d.ts +95 -0
- package/dist/tool/tool.d.ts.map +1 -0
- package/dist/tool/tool.js +176 -0
- package/dist/tool/toolkit.d.ts +121 -0
- package/dist/tool/toolkit.d.ts.map +1 -0
- package/dist/tool/toolkit.js +180 -0
- package/dist/tool/types.d.ts +187 -0
- package/dist/tool/types.d.ts.map +1 -0
- package/dist/tool/types.js +1 -0
- package/dist/tools.d.ts +362 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +220 -0
- package/dist/trace/processor.d.ts +1 -0
- package/dist/trace/processor.d.ts.map +1 -0
- package/dist/trace/processor.js +1 -0
- package/dist/trace/traces.d.ts +1 -0
- package/dist/trace/traces.d.ts.map +1 -0
- package/dist/trace/traces.js +73 -0
- package/dist/trace/utils.d.ts +22 -0
- package/dist/trace/utils.d.ts.map +1 -0
- package/dist/trace/utils.js +30 -0
- package/dist/types/agent.d.ts +91 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +1 -0
- package/dist/types/proto.d.ts +1551 -0
- package/dist/types/proto.d.ts.map +1 -0
- package/dist/types/proto.js +531 -0
- package/dist/types/thread.d.ts +71 -0
- package/dist/types/thread.d.ts.map +1 -0
- package/dist/types/thread.js +5 -0
- package/dist/usage.d.ts +43 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +61 -0
- package/package.json +52 -0
- package/src/agent.ts +203 -0
- package/src/context.ts +265 -0
- package/src/guardrail.ts +277 -0
- package/src/index.ts +3 -0
- package/src/kernl.ts +22 -0
- package/src/lib/env.ts +36 -0
- package/src/lib/error.ts +158 -0
- package/src/lib/logger.ts +78 -0
- package/src/lib/serde/json.ts +18 -0
- package/src/lib/serde/thread.ts +188 -0
- package/src/lifecycle.ts +181 -0
- package/src/mcp/__tests__/base.test.ts +344 -0
- package/src/mcp/__tests__/fixtures/server.ts +179 -0
- package/src/mcp/__tests__/fixtures/utils.ts +58 -0
- package/src/mcp/__tests__/integration.test.ts +447 -0
- package/src/mcp/__tests__/stdio.test.ts +236 -0
- package/src/mcp/__tests__/utils.test.ts +360 -0
- package/src/mcp/base.ts +162 -0
- package/src/mcp/http.ts +147 -0
- package/src/mcp/sse.ts +137 -0
- package/src/mcp/stdio.ts +136 -0
- package/src/mcp/types.ts +202 -0
- package/src/mcp/utils.ts +62 -0
- package/src/task.ts +119 -0
- package/src/thread/__tests__/mock.ts +95 -0
- package/src/thread/__tests__/thread.test.ts +1574 -0
- package/src/thread/index.ts +1 -0
- package/src/thread/thread.ts +611 -0
- package/src/thread/utils.ts +67 -0
- package/src/tool/__tests__/fixtures.ts +106 -0
- package/src/tool/__tests__/tool.test.ts +235 -0
- package/src/tool/__tests__/toolkit.test.ts +174 -0
- package/src/tool/index.ts +10 -0
- package/src/tool/tool.ts +264 -0
- package/src/tool/toolkit.ts +234 -0
- package/src/tool/types.ts +243 -0
- package/src/trace/processor.ts +0 -0
- package/src/trace/traces.ts +86 -0
- package/src/trace/utils.ts +38 -0
- package/src/types/agent.ts +145 -0
- package/src/types/thread.ts +86 -0
- package/tsconfig.json +13 -0
- package/vitest.config.ts +14 -0
package/src/tool/tool.ts
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { Context, UnknownContext } from "@/context";
|
|
2
|
+
|
|
3
|
+
import { ModelBehaviorError } from "@/lib/error";
|
|
4
|
+
import { logger } from "@/lib/logger";
|
|
5
|
+
import { json } from "@kernl/shared/lib";
|
|
6
|
+
import { FAILED, COMPLETED, INTERRUPTIBLE } from "@kernl/protocol";
|
|
7
|
+
import type { LanguageModelTool } from "@kernl/protocol";
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
ToolType,
|
|
11
|
+
ToolConfig,
|
|
12
|
+
ToolApprovalFunction,
|
|
13
|
+
ToolEnabledFunction,
|
|
14
|
+
ToolEnabledPredicate,
|
|
15
|
+
ToolErrorFunction,
|
|
16
|
+
ToolExecuteArgument,
|
|
17
|
+
ToolExecuteFunction,
|
|
18
|
+
ToolInputParameters,
|
|
19
|
+
ToolResult,
|
|
20
|
+
} from "./types";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Exposes a function to the agent as a tool to be called
|
|
24
|
+
*
|
|
25
|
+
* @param config The options for the tool
|
|
26
|
+
* @returns A new tool instance
|
|
27
|
+
*/
|
|
28
|
+
export function tool<
|
|
29
|
+
TContext = UnknownContext,
|
|
30
|
+
TParameters extends ToolInputParameters = undefined,
|
|
31
|
+
TResult = string,
|
|
32
|
+
>(
|
|
33
|
+
config: ToolConfig<TContext, TParameters, TResult>,
|
|
34
|
+
): FunctionTool<TContext, TParameters, TResult> {
|
|
35
|
+
return new FunctionTool(config);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Base class for all tools (function and hosted)
|
|
40
|
+
*/
|
|
41
|
+
export abstract class BaseTool<TContext = UnknownContext> {
|
|
42
|
+
abstract readonly type: "function" | "hosted-tool";
|
|
43
|
+
abstract readonly id: string;
|
|
44
|
+
abstract readonly name?: string;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The function to invoke when an error occurs while running the tool.
|
|
48
|
+
*/
|
|
49
|
+
abstract errorfn: ToolErrorFunction | null;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Whether the tool requires human approval before it can be called.
|
|
53
|
+
*/
|
|
54
|
+
abstract requiresApproval: ToolApprovalFunction<any>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Determines whether the tool should be exposed to the model for the current run.
|
|
58
|
+
*/
|
|
59
|
+
abstract isEnabled(context: Context<TContext>, agent: any): Promise<boolean>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Serialize this tool for sending to the model
|
|
63
|
+
*/
|
|
64
|
+
abstract serialize(): LanguageModelTool;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* A function tool that can be used by agents.
|
|
69
|
+
*/
|
|
70
|
+
export class FunctionTool<
|
|
71
|
+
TContext = UnknownContext,
|
|
72
|
+
TParameters extends ToolInputParameters = undefined,
|
|
73
|
+
TResult = unknown,
|
|
74
|
+
> extends BaseTool<TContext> {
|
|
75
|
+
readonly type = "function" as const;
|
|
76
|
+
readonly id: string;
|
|
77
|
+
readonly name?: string;
|
|
78
|
+
readonly description: string;
|
|
79
|
+
readonly parameters?: TParameters;
|
|
80
|
+
readonly mode: "blocking" | "async";
|
|
81
|
+
private execute: ToolExecuteFunction<TContext, TParameters, TResult>;
|
|
82
|
+
|
|
83
|
+
errorfn: ToolErrorFunction | null;
|
|
84
|
+
requiresApproval: ToolApprovalFunction<TParameters>;
|
|
85
|
+
isEnabled: ToolEnabledFunction<TContext>;
|
|
86
|
+
|
|
87
|
+
constructor(config: ToolConfig<TContext, TParameters, TResult>) {
|
|
88
|
+
super();
|
|
89
|
+
this.id = config.id;
|
|
90
|
+
this.name = config.name;
|
|
91
|
+
this.description = config.description;
|
|
92
|
+
this.parameters = config.parameters;
|
|
93
|
+
this.mode = config.mode ?? "blocking";
|
|
94
|
+
this.execute = config.execute;
|
|
95
|
+
|
|
96
|
+
// setup error function
|
|
97
|
+
this.errorfn =
|
|
98
|
+
typeof config.errorfn === "undefined"
|
|
99
|
+
? defaultToolErrorFunction
|
|
100
|
+
: config.errorfn;
|
|
101
|
+
|
|
102
|
+
// setup approval function
|
|
103
|
+
this.requiresApproval =
|
|
104
|
+
typeof config.requiresApproval === "function"
|
|
105
|
+
? config.requiresApproval
|
|
106
|
+
: async () =>
|
|
107
|
+
typeof config.requiresApproval === "boolean"
|
|
108
|
+
? config.requiresApproval
|
|
109
|
+
: false;
|
|
110
|
+
|
|
111
|
+
// setup enabled function
|
|
112
|
+
this.isEnabled =
|
|
113
|
+
typeof config.isEnabled === "function"
|
|
114
|
+
? async (context, agent) => {
|
|
115
|
+
const predicate =
|
|
116
|
+
config.isEnabled as ToolEnabledPredicate<TContext>;
|
|
117
|
+
const result = await predicate({ context, agent });
|
|
118
|
+
return Boolean(result);
|
|
119
|
+
}
|
|
120
|
+
: async () =>
|
|
121
|
+
typeof config.isEnabled === "boolean" ? config.isEnabled : true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Main invocation method -
|
|
126
|
+
*
|
|
127
|
+
* Wraps execute with parsing, approval, and error handling
|
|
128
|
+
*/
|
|
129
|
+
async invoke(
|
|
130
|
+
context: Context<TContext>,
|
|
131
|
+
args: string,
|
|
132
|
+
callId?: string,
|
|
133
|
+
): Promise<ToolResult<TResult>> {
|
|
134
|
+
return this._invoke(context, args, callId).catch((error) => {
|
|
135
|
+
const msg = this.errorfn
|
|
136
|
+
? this.errorfn(context, error)
|
|
137
|
+
: error instanceof Error
|
|
138
|
+
? error.message
|
|
139
|
+
: String(error);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
state: FAILED,
|
|
143
|
+
result: undefined,
|
|
144
|
+
error: msg,
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Executes the tool with the provided execute() function
|
|
151
|
+
*/
|
|
152
|
+
private async _invoke(
|
|
153
|
+
context: Context<TContext>,
|
|
154
|
+
args: string,
|
|
155
|
+
callId?: string,
|
|
156
|
+
): Promise<ToolResult<TResult>> {
|
|
157
|
+
let parsed = args as ToolExecuteArgument<TParameters>;
|
|
158
|
+
|
|
159
|
+
if (this.parameters) {
|
|
160
|
+
try {
|
|
161
|
+
parsed = json(this.parameters).decode(
|
|
162
|
+
args,
|
|
163
|
+
) as ToolExecuteArgument<TParameters>;
|
|
164
|
+
} catch (error) {
|
|
165
|
+
logger.debug(`Invalid JSON input for tool ${this.id}: ${args}`);
|
|
166
|
+
throw new ModelBehaviorError("Invalid JSON input for tool");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Check if approval is required
|
|
171
|
+
const needsApproval = await this.requiresApproval(context, parsed, callId);
|
|
172
|
+
const approvalStatus = callId ? context.approvals.get(callId) : undefined;
|
|
173
|
+
|
|
174
|
+
if (needsApproval && approvalStatus !== "approved") {
|
|
175
|
+
return {
|
|
176
|
+
state: INTERRUPTIBLE,
|
|
177
|
+
result: undefined,
|
|
178
|
+
error: null,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const result = await this.execute(context, parsed);
|
|
183
|
+
return {
|
|
184
|
+
state: COMPLETED,
|
|
185
|
+
result: result,
|
|
186
|
+
error: null,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Serialize this function tool for sending to the model
|
|
192
|
+
*/
|
|
193
|
+
serialize(): LanguageModelTool {
|
|
194
|
+
return {
|
|
195
|
+
kind: "function",
|
|
196
|
+
name: this.id,
|
|
197
|
+
description: this.description,
|
|
198
|
+
parameters: this.parameters as any, // TODO: convert Zod to JSON Schema
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Hosted tool executed server-side by the model provider
|
|
205
|
+
*/
|
|
206
|
+
export class HostedTool extends BaseTool {
|
|
207
|
+
readonly type = "hosted-tool" as const;
|
|
208
|
+
readonly id: string;
|
|
209
|
+
readonly name?: string;
|
|
210
|
+
readonly providerData?: Record<string, any>;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Hosted tools use the default error function
|
|
214
|
+
*/
|
|
215
|
+
errorfn: ToolErrorFunction | null = defaultToolErrorFunction;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Hosted tools do not require approval by default
|
|
219
|
+
*/
|
|
220
|
+
requiresApproval: ToolApprovalFunction<any> = async () => false;
|
|
221
|
+
|
|
222
|
+
constructor(config: {
|
|
223
|
+
id: string;
|
|
224
|
+
name?: string;
|
|
225
|
+
providerData?: Record<string, any>;
|
|
226
|
+
}) {
|
|
227
|
+
super();
|
|
228
|
+
this.id = config.id;
|
|
229
|
+
this.name = config.name;
|
|
230
|
+
this.providerData = config.providerData;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Hosted tools are always enabled
|
|
235
|
+
*/
|
|
236
|
+
async isEnabled(): Promise<boolean> {
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Serialize this hosted tool for sending to the model
|
|
242
|
+
*/
|
|
243
|
+
serialize(): LanguageModelTool {
|
|
244
|
+
return {
|
|
245
|
+
kind: "provider-defined",
|
|
246
|
+
id: this.id as `${string}.${string}`,
|
|
247
|
+
name: this.name || this.id,
|
|
248
|
+
args: this.providerData || {},
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* The default function to invoke when an error occurs while running the tool.
|
|
255
|
+
*
|
|
256
|
+
* Always returns `An error occurred while running the tool. Please try again. Error: <error details>`
|
|
257
|
+
*
|
|
258
|
+
* @param context - An instance of the current Context
|
|
259
|
+
* @param error - The error that occurred
|
|
260
|
+
*/
|
|
261
|
+
function defaultToolErrorFunction(context: Context, error: Error | unknown) {
|
|
262
|
+
const details = error instanceof Error ? error.toString() : String(error);
|
|
263
|
+
return `An error occurred while running the tool. Please try again. Error: ${details}`;
|
|
264
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import type { Agent } from "@/agent";
|
|
2
|
+
import type { Context, UnknownContext } from "@/context";
|
|
3
|
+
|
|
4
|
+
import { MCPServer } from "@/mcp/base";
|
|
5
|
+
import { mcpToFunctionTool } from "@/mcp/utils";
|
|
6
|
+
import { filter } from "@kernl/shared/lib";
|
|
7
|
+
|
|
8
|
+
import type { Tool } from ".";
|
|
9
|
+
import type {
|
|
10
|
+
FunctionToolkitConfig,
|
|
11
|
+
MCPToolkitConfig,
|
|
12
|
+
ToolkitFilter,
|
|
13
|
+
} from "./types";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A toolkit is a collection of related tools that can be used by an agent.
|
|
17
|
+
*
|
|
18
|
+
* Toolkits can be static (FunctionToolkit) or dynamic (MCPToolkit), and provide
|
|
19
|
+
* a unified interface for tool discovery and management.
|
|
20
|
+
*/
|
|
21
|
+
export abstract class Toolkit<TContext = UnknownContext> {
|
|
22
|
+
/**
|
|
23
|
+
* Unique identifier for this toolkit
|
|
24
|
+
*/
|
|
25
|
+
abstract readonly id: string;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The agent this toolkit is bound to (if any)
|
|
29
|
+
*/
|
|
30
|
+
protected agent?: Agent<TContext, any>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Bind this toolkit to an agent.
|
|
34
|
+
* Called by Agent constructor.
|
|
35
|
+
*/
|
|
36
|
+
bind(agent: Agent<TContext, any>): void {
|
|
37
|
+
this.agent = agent;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get a specific tool by its ID.
|
|
42
|
+
*
|
|
43
|
+
* @param id The tool ID to look up
|
|
44
|
+
* @returns The tool if found, undefined otherwise
|
|
45
|
+
*/
|
|
46
|
+
abstract get(id: string): Tool<TContext> | undefined;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* List all tools available for the given context.
|
|
50
|
+
* If no context provided, returns all tools without filtering.
|
|
51
|
+
*
|
|
52
|
+
* @param context Optional context for filtering tools
|
|
53
|
+
* @returns Array of tools available in this toolkit
|
|
54
|
+
*/
|
|
55
|
+
abstract list(context?: Context<TContext>): Promise<Tool<TContext>[]>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Cleanup resources held by this toolkit.
|
|
59
|
+
* Override if your toolkit needs cleanup (e.g., closing connections).
|
|
60
|
+
* Default implementation does nothing.
|
|
61
|
+
*/
|
|
62
|
+
async destroy(): Promise<void> {
|
|
63
|
+
// Default: no-op
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* A toolkit containing static function tools.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* const fs = new FunctionToolkit({
|
|
73
|
+
* id: "fs",
|
|
74
|
+
* tools: [readFile, writeFile, listDir, ...]
|
|
75
|
+
* });
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export class FunctionToolkit<
|
|
79
|
+
TContext = UnknownContext,
|
|
80
|
+
> extends Toolkit<TContext> {
|
|
81
|
+
readonly id: string;
|
|
82
|
+
private tools: Map<string, Tool<TContext>>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Create a new function toolkit.
|
|
86
|
+
*
|
|
87
|
+
* @param config Toolkit configuration with id and tools array
|
|
88
|
+
*/
|
|
89
|
+
constructor(config: FunctionToolkitConfig<TContext>) {
|
|
90
|
+
super();
|
|
91
|
+
this.id = config.id;
|
|
92
|
+
this.tools = new Map(config.tools.map((t) => [t.id, t]));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get a specific tool by ID.
|
|
97
|
+
*
|
|
98
|
+
* @param id The tool ID to look up
|
|
99
|
+
* @returns The tool if found, undefined otherwise
|
|
100
|
+
*/
|
|
101
|
+
get(id: string): Tool<TContext> | undefined {
|
|
102
|
+
return this.tools.get(id);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* List all tools in this toolkit.
|
|
107
|
+
*
|
|
108
|
+
* @param context Optional context for filtering tools (currently unused)
|
|
109
|
+
* @returns Array of all tools in this toolkit
|
|
110
|
+
*/
|
|
111
|
+
async list(context?: Context<TContext>): Promise<Tool<TContext>[]> {
|
|
112
|
+
return Array.from(this.tools.values());
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/*
|
|
117
|
+
* A toolkit that wraps an MCP server and provides tools from it.
|
|
118
|
+
*
|
|
119
|
+
* Handles connection lifecycle automatically - connects lazily on first tool request
|
|
120
|
+
* and provides cleanup via destroy().
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* const server = new MCPServerStdio({
|
|
125
|
+
* id: "github",
|
|
126
|
+
* command: "npx",
|
|
127
|
+
* args: ["-y", "@modelcontextprotocol/server-github"],
|
|
128
|
+
* env: {
|
|
129
|
+
* GITHUB_TOKEN: process.env.GITHUB_TOKEN,
|
|
130
|
+
* },
|
|
131
|
+
* });
|
|
132
|
+
*
|
|
133
|
+
* const github = new MCPToolkit({
|
|
134
|
+
* id: "github",
|
|
135
|
+
* server,
|
|
136
|
+
* filter: async (ctx, tool) => {
|
|
137
|
+
* // Only allow certain tools
|
|
138
|
+
* return !tool.id.startsWith("dangerous_");
|
|
139
|
+
* },
|
|
140
|
+
* });
|
|
141
|
+
*
|
|
142
|
+
* const agent = new Agent({
|
|
143
|
+
* toolkits: [github],
|
|
144
|
+
* });
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export class MCPToolkit<TContext = UnknownContext> extends Toolkit<TContext> {
|
|
148
|
+
readonly id: string;
|
|
149
|
+
private server: MCPServer;
|
|
150
|
+
private cache: Map<string, Tool<TContext>>;
|
|
151
|
+
private filter: ToolkitFilter<TContext>;
|
|
152
|
+
|
|
153
|
+
private connected = false;
|
|
154
|
+
private cached = false;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Create a new MCP toolkit.
|
|
158
|
+
*
|
|
159
|
+
* @param config Toolkit configuration with id and server instance
|
|
160
|
+
*/
|
|
161
|
+
constructor(config: MCPToolkitConfig<TContext>) {
|
|
162
|
+
super();
|
|
163
|
+
this.id = config.id;
|
|
164
|
+
this.server = config.server;
|
|
165
|
+
this.filter = config.filter ?? (() => true);
|
|
166
|
+
this.cache = new Map();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Get a specific tool by ID.
|
|
171
|
+
*
|
|
172
|
+
* Returns the tool from the local cache. The cache is populated on the first
|
|
173
|
+
* call to list(). Returns undefined if list() hasn't been called yet.
|
|
174
|
+
*
|
|
175
|
+
* @param id The tool ID to look up
|
|
176
|
+
* @returns The tool if found in cache, undefined otherwise
|
|
177
|
+
*/
|
|
178
|
+
get(id: string): Tool<TContext> | undefined {
|
|
179
|
+
return this.cache.get(id);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* List all tools available from the MCP server.
|
|
184
|
+
*
|
|
185
|
+
* Connects to the server lazily on first call. Tools are cached locally after
|
|
186
|
+
* the first fetch. The MCP server itself also handles caching via the
|
|
187
|
+
* cacheToolsList option, so the network call is only made once.
|
|
188
|
+
*
|
|
189
|
+
* @param context Optional context for filtering tools
|
|
190
|
+
* @returns Array of tools from the MCP server
|
|
191
|
+
*/
|
|
192
|
+
async list(context?: Context<TContext>): Promise<Tool<TContext>[]> {
|
|
193
|
+
if (!this.connected) {
|
|
194
|
+
await this.server.connect();
|
|
195
|
+
this.connected = true;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// lazy cache population
|
|
199
|
+
if (!this.cached) {
|
|
200
|
+
const mcpTools = await this.server.listTools();
|
|
201
|
+
|
|
202
|
+
for (const mcpTool of mcpTools) {
|
|
203
|
+
const tool = mcpToFunctionTool(this.server, mcpTool);
|
|
204
|
+
this.cache.set(tool.id, tool);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this.cached = true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const tools = Array.from(this.cache.values());
|
|
211
|
+
|
|
212
|
+
// apply filter
|
|
213
|
+
if (context && this.agent) {
|
|
214
|
+
const ctx = { context, agent: this.agent, toolkitId: this.id };
|
|
215
|
+
return filter(tools, async (tool) => {
|
|
216
|
+
return await this.filter(ctx, tool);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return tools;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Cleanup resources and close the MCP server connection.
|
|
225
|
+
*/
|
|
226
|
+
async destroy(): Promise<void> {
|
|
227
|
+
if (this.connected) {
|
|
228
|
+
await this.server.close();
|
|
229
|
+
this.connected = false;
|
|
230
|
+
this.cache.clear();
|
|
231
|
+
this.cached = false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|