@kognitivedev/tools 0.2.2

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 ADDED
@@ -0,0 +1,40 @@
1
+ # @kognitivedev/tools
2
+
3
+ > Tool system for Kognitive agents — createTool, ToolRegistry, approval workflows, and AI SDK conversion.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @kognitivedev/tools
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { createTool, ToolRegistry } from "@kognitivedev/tools";
15
+ import { z } from "zod";
16
+ import { streamText } from "ai";
17
+
18
+ const searchTool = createTool({
19
+ id: "search",
20
+ description: "Search documentation",
21
+ inputSchema: z.object({ query: z.string() }),
22
+ execute: async (input) => ({ results: [`Result for: ${input.query}`] }),
23
+ });
24
+
25
+ const registry = new ToolRegistry();
26
+ registry.register(searchTool);
27
+
28
+ const result = await streamText({
29
+ model: openai("gpt-4o"),
30
+ tools: registry.toAISDKTools(),
31
+ messages,
32
+ });
33
+ ```
34
+
35
+ ## Features
36
+
37
+ - **createTool** — typed tool factory with Zod schemas
38
+ - **ToolRegistry** — named collection with `toAISDKTools()` conversion
39
+ - **Approval** — `requireApproval` (boolean or conditional function)
40
+ - **AI SDK native** — converts directly to AI SDK `tool()` format
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const zod_1 = require("zod");
5
+ const index_1 = require("../index");
6
+ const mockContext = {
7
+ abortSignal: new AbortController().signal,
8
+ resourceId: { projectId: "test" },
9
+ emit: vitest_1.vi.fn(),
10
+ };
11
+ (0, vitest_1.describe)("createTool", () => {
12
+ (0, vitest_1.it)("creates a tool with correct properties", () => {
13
+ const tool = (0, index_1.createTool)({
14
+ id: "test-tool",
15
+ description: "A test tool",
16
+ inputSchema: zod_1.z.object({ query: zod_1.z.string() }),
17
+ execute: async (input) => ({ result: input.query }),
18
+ });
19
+ (0, vitest_1.expect)(tool.id).toBe("test-tool");
20
+ (0, vitest_1.expect)(tool.description).toBe("A test tool");
21
+ (0, vitest_1.expect)(tool.inputSchema).toBeDefined();
22
+ (0, vitest_1.expect)(tool.execute).toBeTypeOf("function");
23
+ });
24
+ (0, vitest_1.it)("executes with input and context", async () => {
25
+ const tool = (0, index_1.createTool)({
26
+ id: "echo",
27
+ description: "Echo",
28
+ inputSchema: zod_1.z.object({ msg: zod_1.z.string() }),
29
+ execute: async (input) => input.msg,
30
+ });
31
+ const result = await tool.execute({ msg: "hello" }, mockContext);
32
+ (0, vitest_1.expect)(result).toBe("hello");
33
+ });
34
+ });
35
+ (0, vitest_1.describe)("ToolRegistry", () => {
36
+ (0, vitest_1.it)("registers and retrieves tools", () => {
37
+ const registry = new index_1.ToolRegistry();
38
+ const tool = (0, index_1.createTool)({
39
+ id: "t1",
40
+ description: "Tool 1",
41
+ inputSchema: zod_1.z.object({}),
42
+ execute: async () => "ok",
43
+ });
44
+ registry.register(tool);
45
+ (0, vitest_1.expect)(registry.get("t1")).toBe(tool);
46
+ (0, vitest_1.expect)(registry.has("t1")).toBe(true);
47
+ (0, vitest_1.expect)(registry.size).toBe(1);
48
+ });
49
+ (0, vitest_1.it)("throws on duplicate registration", () => {
50
+ const registry = new index_1.ToolRegistry();
51
+ const tool = (0, index_1.createTool)({
52
+ id: "t1",
53
+ description: "Tool",
54
+ inputSchema: zod_1.z.object({}),
55
+ execute: async () => "ok",
56
+ });
57
+ registry.register(tool);
58
+ (0, vitest_1.expect)(() => registry.register(tool)).toThrow("already registered");
59
+ });
60
+ (0, vitest_1.it)("all returns all tools", () => {
61
+ const registry = new index_1.ToolRegistry();
62
+ const t1 = (0, index_1.createTool)({ id: "t1", description: "1", inputSchema: zod_1.z.object({}), execute: async () => 1 });
63
+ const t2 = (0, index_1.createTool)({ id: "t2", description: "2", inputSchema: zod_1.z.object({}), execute: async () => 2 });
64
+ registry.register(t1);
65
+ registry.register(t2);
66
+ (0, vitest_1.expect)(registry.all()).toHaveLength(2);
67
+ });
68
+ (0, vitest_1.it)("remove deletes tool", () => {
69
+ const registry = new index_1.ToolRegistry();
70
+ const tool = (0, index_1.createTool)({ id: "t1", description: "1", inputSchema: zod_1.z.object({}), execute: async () => 1 });
71
+ registry.register(tool);
72
+ registry.remove("t1");
73
+ (0, vitest_1.expect)(registry.has("t1")).toBe(false);
74
+ });
75
+ (0, vitest_1.it)("toAISDKTools returns record with tool ids as keys", () => {
76
+ const registry = new index_1.ToolRegistry();
77
+ registry.register((0, index_1.createTool)({ id: "search", description: "Search", inputSchema: zod_1.z.object({ q: zod_1.z.string() }), execute: async () => "result" }));
78
+ const sdkTools = registry.toAISDKTools();
79
+ (0, vitest_1.expect)(sdkTools).toHaveProperty("search");
80
+ });
81
+ });
82
+ (0, vitest_1.describe)("needsApproval", () => {
83
+ (0, vitest_1.it)("returns false when no requireApproval", () => {
84
+ const tool = (0, index_1.createTool)({ id: "t", description: "t", inputSchema: zod_1.z.object({}), execute: async () => null });
85
+ (0, vitest_1.expect)((0, index_1.needsApproval)(tool, {})).toBe(false);
86
+ });
87
+ (0, vitest_1.it)("returns true when requireApproval is true", () => {
88
+ const tool = (0, index_1.createTool)({ id: "t", description: "t", inputSchema: zod_1.z.object({}), execute: async () => null, requireApproval: true });
89
+ (0, vitest_1.expect)((0, index_1.needsApproval)(tool, {})).toBe(true);
90
+ });
91
+ (0, vitest_1.it)("evaluates function requireApproval", () => {
92
+ const tool = (0, index_1.createTool)({
93
+ id: "t",
94
+ description: "t",
95
+ inputSchema: zod_1.z.object({ amount: zod_1.z.number() }),
96
+ execute: async () => null,
97
+ requireApproval: (input) => input.amount > 100,
98
+ });
99
+ (0, vitest_1.expect)((0, index_1.needsApproval)(tool, { amount: 50 })).toBe(false);
100
+ (0, vitest_1.expect)((0, index_1.needsApproval)(tool, { amount: 200 })).toBe(true);
101
+ });
102
+ });
103
+ (0, vitest_1.describe)("executeWithApproval", () => {
104
+ (0, vitest_1.it)("executes when no approval needed", async () => {
105
+ const tool = (0, index_1.createTool)({ id: "t", description: "t", inputSchema: zod_1.z.object({}), execute: async () => "done" });
106
+ const result = await (0, index_1.executeWithApproval)(tool, {}, mockContext);
107
+ (0, vitest_1.expect)(result).toBe("done");
108
+ });
109
+ (0, vitest_1.it)("throws when approval needed but no handler", async () => {
110
+ const tool = (0, index_1.createTool)({ id: "t", description: "t", inputSchema: zod_1.z.object({}), execute: async () => "done", requireApproval: true });
111
+ await (0, vitest_1.expect)((0, index_1.executeWithApproval)(tool, {}, mockContext)).rejects.toThrow("Approval denied");
112
+ });
113
+ (0, vitest_1.it)("executes when handler approves", async () => {
114
+ const tool = (0, index_1.createTool)({ id: "t", description: "t", inputSchema: zod_1.z.object({}), execute: async () => "done", requireApproval: true });
115
+ const handler = vitest_1.vi.fn().mockResolvedValue(true);
116
+ const result = await (0, index_1.executeWithApproval)(tool, {}, mockContext, handler);
117
+ (0, vitest_1.expect)(result).toBe("done");
118
+ (0, vitest_1.expect)(handler).toHaveBeenCalled();
119
+ });
120
+ (0, vitest_1.it)("throws when handler denies", async () => {
121
+ const tool = (0, index_1.createTool)({ id: "t", description: "t", inputSchema: zod_1.z.object({}), execute: async () => "done", requireApproval: true });
122
+ const handler = vitest_1.vi.fn().mockResolvedValue(false);
123
+ await (0, vitest_1.expect)((0, index_1.executeWithApproval)(tool, {}, mockContext, handler)).rejects.toThrow("Approval denied");
124
+ });
125
+ });
@@ -0,0 +1,50 @@
1
+ import type { ToolSet } from "ai";
2
+ import type { Tool } from "../types";
3
+ import type { ResourceId } from "@kognitivedev/shared";
4
+ /**
5
+ * Options for converting enhanced tools to AI SDK format.
6
+ */
7
+ export interface AISDKToolOptions {
8
+ /** Resource context to inject into tool execution. */
9
+ resourceId?: ResourceId;
10
+ /** Memory snapshot to inject into tool context. */
11
+ memory?: {
12
+ systemBlock: string | null;
13
+ userContextBlock: string | null;
14
+ };
15
+ /** Abort signal to pass to tool execution. */
16
+ abortSignal?: AbortSignal;
17
+ /** Event handler for tool emissions. */
18
+ onEmit?: (toolId: string, event: string, data: unknown) => void;
19
+ }
20
+ /**
21
+ * Convert a single enhanced Tool to an AI SDK-compatible tool object.
22
+ *
23
+ * Returns a plain object matching the AI SDK Tool interface shape.
24
+ * This can be used directly with streamText, generateText, etc.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * import { streamText } from 'ai';
29
+ *
30
+ * const sdkTool = toAISDKTool(myTool, {
31
+ * resourceId: { projectId: 'proj_1', userId: 'user_1' },
32
+ * });
33
+ * const result = await streamText({
34
+ * model: openai('gpt-4o'),
35
+ * tools: { search: sdkTool },
36
+ * messages,
37
+ * });
38
+ * ```
39
+ */
40
+ export declare function toAISDKTool(tool: Tool<any, any>, options?: AISDKToolOptions): ToolSet[string];
41
+ /**
42
+ * Convert an array of enhanced Tools to an AI SDK ToolSet record.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const tools = toAISDKTools([searchTool, createTool], { resourceId });
47
+ * const result = await streamText({ model, tools, messages });
48
+ * ```
49
+ */
50
+ export declare function toAISDKTools(tools: Tool<any, any>[], options?: AISDKToolOptions): ToolSet;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toAISDKTool = toAISDKTool;
4
+ exports.toAISDKTools = toAISDKTools;
5
+ /**
6
+ * Build a ToolContext from AISDKToolOptions for a specific tool.
7
+ */
8
+ function buildContext(toolId, options) {
9
+ var _a, _b;
10
+ return {
11
+ abortSignal: (_a = options.abortSignal) !== null && _a !== void 0 ? _a : new AbortController().signal,
12
+ resourceId: (_b = options.resourceId) !== null && _b !== void 0 ? _b : { projectId: "default" },
13
+ memory: options.memory,
14
+ emit: (event, data) => {
15
+ var _a;
16
+ (_a = options.onEmit) === null || _a === void 0 ? void 0 : _a.call(options, toolId, event, data);
17
+ },
18
+ };
19
+ }
20
+ /**
21
+ * Convert a single enhanced Tool to an AI SDK-compatible tool object.
22
+ *
23
+ * Returns a plain object matching the AI SDK Tool interface shape.
24
+ * This can be used directly with streamText, generateText, etc.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * import { streamText } from 'ai';
29
+ *
30
+ * const sdkTool = toAISDKTool(myTool, {
31
+ * resourceId: { projectId: 'proj_1', userId: 'user_1' },
32
+ * });
33
+ * const result = await streamText({
34
+ * model: openai('gpt-4o'),
35
+ * tools: { search: sdkTool },
36
+ * messages,
37
+ * });
38
+ * ```
39
+ */
40
+ function toAISDKTool(tool, options = {}) {
41
+ const context = buildContext(tool.id, options);
42
+ // Construct the AI SDK tool object directly.
43
+ // The AI SDK tool() function is a passthrough identity function for type safety.
44
+ // Building the object directly avoids generic type inference issues with `any`.
45
+ // AI SDK v6 uses `inputSchema` (not `parameters`).
46
+ return {
47
+ description: tool.description,
48
+ inputSchema: tool.inputSchema,
49
+ execute: async (input) => {
50
+ const result = await tool.execute(input, context);
51
+ if (tool.toModelOutput) {
52
+ return tool.toModelOutput(result);
53
+ }
54
+ return result;
55
+ },
56
+ };
57
+ }
58
+ /**
59
+ * Convert an array of enhanced Tools to an AI SDK ToolSet record.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * const tools = toAISDKTools([searchTool, createTool], { resourceId });
64
+ * const result = await streamText({ model, tools, messages });
65
+ * ```
66
+ */
67
+ function toAISDKTools(tools, options = {}) {
68
+ const result = {};
69
+ for (const t of tools) {
70
+ result[t.id] = toAISDKTool(t, options);
71
+ }
72
+ return result;
73
+ }
@@ -0,0 +1,15 @@
1
+ import type { Tool, ToolContext, ApprovalRequest } from "./types";
2
+ /**
3
+ * Callback type for handling tool approval requests.
4
+ * Return true to approve, false to deny.
5
+ */
6
+ export type ApprovalHandler = (request: ApprovalRequest) => Promise<boolean>;
7
+ /**
8
+ * Check if a tool requires approval for the given input.
9
+ */
10
+ export declare function needsApproval<TInput>(tool: Tool<TInput, any>, input: TInput): boolean;
11
+ /**
12
+ * Execute a tool with approval check.
13
+ * If the tool requires approval and the handler denies it, throws ApprovalDeniedError.
14
+ */
15
+ export declare function executeWithApproval<TInput, TOutput>(tool: Tool<TInput, TOutput>, input: TInput, context: ToolContext, approvalHandler?: ApprovalHandler): Promise<TOutput>;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.needsApproval = needsApproval;
4
+ exports.executeWithApproval = executeWithApproval;
5
+ const shared_1 = require("@kognitivedev/shared");
6
+ /**
7
+ * Check if a tool requires approval for the given input.
8
+ */
9
+ function needsApproval(tool, input) {
10
+ if (!tool.requireApproval)
11
+ return false;
12
+ if (typeof tool.requireApproval === "function") {
13
+ return tool.requireApproval(input);
14
+ }
15
+ return true;
16
+ }
17
+ /**
18
+ * Execute a tool with approval check.
19
+ * If the tool requires approval and the handler denies it, throws ApprovalDeniedError.
20
+ */
21
+ async function executeWithApproval(tool, input, context, approvalHandler) {
22
+ if (needsApproval(tool, input)) {
23
+ if (!approvalHandler) {
24
+ throw new shared_1.ApprovalDeniedError(tool.id);
25
+ }
26
+ const approved = await approvalHandler({
27
+ toolId: tool.id,
28
+ input,
29
+ description: tool.description,
30
+ });
31
+ if (!approved) {
32
+ throw new shared_1.ApprovalDeniedError(tool.id);
33
+ }
34
+ }
35
+ return tool.execute(input, context);
36
+ }
@@ -0,0 +1,22 @@
1
+ import type { ToolDefinition, Tool } from "./types";
2
+ /**
3
+ * Create an enhanced tool with approval, abort, and context support.
4
+ *
5
+ * Tools created with this function can be converted to AI SDK tool() format
6
+ * via ToolRegistry.toAISDKTools() or toAISDKTool().
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const searchTool = createTool({
11
+ * id: 'search-docs',
12
+ * description: 'Search documentation',
13
+ * inputSchema: z.object({ query: z.string() }),
14
+ * execute: async (input, ctx) => {
15
+ * // ctx.abortSignal, ctx.memory, ctx.resourceId available
16
+ * return { results: [...] };
17
+ * },
18
+ * requireApproval: true,
19
+ * });
20
+ * ```
21
+ */
22
+ export declare function createTool<TInput, TOutput>(definition: ToolDefinition<TInput, TOutput>): Tool<TInput, TOutput>;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createTool = createTool;
4
+ /**
5
+ * Create an enhanced tool with approval, abort, and context support.
6
+ *
7
+ * Tools created with this function can be converted to AI SDK tool() format
8
+ * via ToolRegistry.toAISDKTools() or toAISDKTool().
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const searchTool = createTool({
13
+ * id: 'search-docs',
14
+ * description: 'Search documentation',
15
+ * inputSchema: z.object({ query: z.string() }),
16
+ * execute: async (input, ctx) => {
17
+ * // ctx.abortSignal, ctx.memory, ctx.resourceId available
18
+ * return { results: [...] };
19
+ * },
20
+ * requireApproval: true,
21
+ * });
22
+ * ```
23
+ */
24
+ function createTool(definition) {
25
+ return {
26
+ id: definition.id,
27
+ description: definition.description,
28
+ inputSchema: definition.inputSchema,
29
+ outputSchema: definition.outputSchema,
30
+ execute: definition.execute,
31
+ requireApproval: definition.requireApproval,
32
+ toModelOutput: definition.toModelOutput,
33
+ };
34
+ }
@@ -0,0 +1,7 @@
1
+ export type { ToolDefinition, Tool, ToolContext, ApprovalRequest } from "./types";
2
+ export { createTool } from "./create-tool";
3
+ export { ToolRegistry } from "./registry";
4
+ export type { ApprovalHandler } from "./approval";
5
+ export { needsApproval, executeWithApproval } from "./approval";
6
+ export type { AISDKToolOptions } from "./adapters/ai-sdk";
7
+ export { toAISDKTool, toAISDKTools } from "./adapters/ai-sdk";
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toAISDKTools = exports.toAISDKTool = exports.executeWithApproval = exports.needsApproval = exports.ToolRegistry = exports.createTool = void 0;
4
+ var create_tool_1 = require("./create-tool");
5
+ Object.defineProperty(exports, "createTool", { enumerable: true, get: function () { return create_tool_1.createTool; } });
6
+ // Registry
7
+ var registry_1 = require("./registry");
8
+ Object.defineProperty(exports, "ToolRegistry", { enumerable: true, get: function () { return registry_1.ToolRegistry; } });
9
+ var approval_1 = require("./approval");
10
+ Object.defineProperty(exports, "needsApproval", { enumerable: true, get: function () { return approval_1.needsApproval; } });
11
+ Object.defineProperty(exports, "executeWithApproval", { enumerable: true, get: function () { return approval_1.executeWithApproval; } });
12
+ var ai_sdk_1 = require("./adapters/ai-sdk");
13
+ Object.defineProperty(exports, "toAISDKTool", { enumerable: true, get: function () { return ai_sdk_1.toAISDKTool; } });
14
+ Object.defineProperty(exports, "toAISDKTools", { enumerable: true, get: function () { return ai_sdk_1.toAISDKTools; } });
@@ -0,0 +1,56 @@
1
+ import type { Tool } from "./types";
2
+ import { type AISDKToolOptions } from "./adapters/ai-sdk";
3
+ /**
4
+ * Registry for managing a named collection of tools.
5
+ * Provides lookup by ID and bulk conversion to AI SDK format.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const registry = new ToolRegistry();
10
+ * registry.register(searchTool);
11
+ * registry.register(createTicketTool);
12
+ *
13
+ * // Use with AI SDK streamText directly
14
+ * const result = await streamText({
15
+ * model: openai('gpt-4o'),
16
+ * tools: registry.toAISDKTools(),
17
+ * messages,
18
+ * });
19
+ * ```
20
+ */
21
+ export declare class ToolRegistry {
22
+ private tools;
23
+ /**
24
+ * Register a tool. Throws if a tool with the same ID already exists.
25
+ */
26
+ register(tool: Tool<any, any>): void;
27
+ /**
28
+ * Get a tool by ID. Returns undefined if not found.
29
+ */
30
+ get(id: string): Tool<any, any> | undefined;
31
+ /**
32
+ * Check if a tool with the given ID is registered.
33
+ */
34
+ has(id: string): boolean;
35
+ /**
36
+ * Remove a tool by ID.
37
+ */
38
+ remove(id: string): boolean;
39
+ /**
40
+ * Get all registered tools.
41
+ */
42
+ all(): Tool<any, any>[];
43
+ /**
44
+ * Get the number of registered tools.
45
+ */
46
+ get size(): number;
47
+ /**
48
+ * Convert all registered tools to AI SDK tool() format.
49
+ * The returned object can be passed directly to streamText/generateText.
50
+ */
51
+ toAISDKTools(options?: AISDKToolOptions): Record<string, any>;
52
+ /**
53
+ * Get tool IDs that require approval for the given input context.
54
+ */
55
+ getApprovalRequired(inputs: Record<string, unknown>): string[];
56
+ }
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToolRegistry = void 0;
4
+ const approval_1 = require("./approval");
5
+ const ai_sdk_1 = require("./adapters/ai-sdk");
6
+ /**
7
+ * Registry for managing a named collection of tools.
8
+ * Provides lookup by ID and bulk conversion to AI SDK format.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const registry = new ToolRegistry();
13
+ * registry.register(searchTool);
14
+ * registry.register(createTicketTool);
15
+ *
16
+ * // Use with AI SDK streamText directly
17
+ * const result = await streamText({
18
+ * model: openai('gpt-4o'),
19
+ * tools: registry.toAISDKTools(),
20
+ * messages,
21
+ * });
22
+ * ```
23
+ */
24
+ class ToolRegistry {
25
+ constructor() {
26
+ this.tools = new Map();
27
+ }
28
+ /**
29
+ * Register a tool. Throws if a tool with the same ID already exists.
30
+ */
31
+ register(tool) {
32
+ if (this.tools.has(tool.id)) {
33
+ throw new Error(`Tool with id "${tool.id}" already registered`);
34
+ }
35
+ this.tools.set(tool.id, tool);
36
+ }
37
+ /**
38
+ * Get a tool by ID. Returns undefined if not found.
39
+ */
40
+ get(id) {
41
+ return this.tools.get(id);
42
+ }
43
+ /**
44
+ * Check if a tool with the given ID is registered.
45
+ */
46
+ has(id) {
47
+ return this.tools.has(id);
48
+ }
49
+ /**
50
+ * Remove a tool by ID.
51
+ */
52
+ remove(id) {
53
+ return this.tools.delete(id);
54
+ }
55
+ /**
56
+ * Get all registered tools.
57
+ */
58
+ all() {
59
+ return Array.from(this.tools.values());
60
+ }
61
+ /**
62
+ * Get the number of registered tools.
63
+ */
64
+ get size() {
65
+ return this.tools.size;
66
+ }
67
+ /**
68
+ * Convert all registered tools to AI SDK tool() format.
69
+ * The returned object can be passed directly to streamText/generateText.
70
+ */
71
+ toAISDKTools(options) {
72
+ const result = {};
73
+ for (const tool of this.tools.values()) {
74
+ result[tool.id] = (0, ai_sdk_1.toAISDKTool)(tool, options);
75
+ }
76
+ return result;
77
+ }
78
+ /**
79
+ * Get tool IDs that require approval for the given input context.
80
+ */
81
+ getApprovalRequired(inputs) {
82
+ const result = [];
83
+ for (const tool of this.tools.values()) {
84
+ const input = inputs[tool.id];
85
+ if (input !== undefined && (0, approval_1.needsApproval)(tool, input)) {
86
+ result.push(tool.id);
87
+ }
88
+ }
89
+ return result;
90
+ }
91
+ }
92
+ exports.ToolRegistry = ToolRegistry;
@@ -0,0 +1,74 @@
1
+ import type { ZodType } from "zod";
2
+ import type { ResourceId, Metadata } from "@kognitivedev/shared";
3
+ /**
4
+ * Context provided to tool execute functions.
5
+ * Enriched with memory, abort signal, and event emission.
6
+ */
7
+ export interface ToolContext {
8
+ /** Signal for aborting long-running tool operations. */
9
+ abortSignal: AbortSignal;
10
+ /** Resource scope (user, project, session). */
11
+ resourceId: ResourceId;
12
+ /** Memory snapshot if available (injected by agent runtime). */
13
+ memory?: {
14
+ systemBlock: string | null;
15
+ userContextBlock: string | null;
16
+ };
17
+ /** Emit events for streaming partial results or progress updates. */
18
+ emit: (event: string, data: unknown) => void;
19
+ /** Arbitrary metadata passed through from the caller. */
20
+ metadata?: Metadata;
21
+ }
22
+ /**
23
+ * Definition for creating an enhanced tool.
24
+ */
25
+ export interface ToolDefinition<TInput = any, TOutput = any> {
26
+ /** Unique identifier for the tool. */
27
+ id: string;
28
+ /** Human-readable description (sent to the model). */
29
+ description: string;
30
+ /** Zod schema for validating tool input. */
31
+ inputSchema: ZodType<TInput>;
32
+ /** Optional Zod schema for validating tool output. */
33
+ outputSchema?: ZodType<TOutput>;
34
+ /** Execute the tool with validated input and context. */
35
+ execute: (input: TInput, context: ToolContext) => Promise<TOutput>;
36
+ /**
37
+ * Whether this tool requires human approval before execution.
38
+ * - `true`: Always require approval
39
+ * - Function: Conditionally require based on input
40
+ */
41
+ requireApproval?: boolean | ((input: TInput) => boolean);
42
+ /**
43
+ * Transform tool output before sending to the model.
44
+ * Useful for large outputs — keep full result in application, send summary to model.
45
+ */
46
+ toModelOutput?: (output: TOutput) => string;
47
+ }
48
+ /**
49
+ * A created tool instance with its definition and metadata.
50
+ */
51
+ export interface Tool<TInput = any, TOutput = any> {
52
+ /** Unique identifier. */
53
+ id: string;
54
+ /** Human-readable description. */
55
+ description: string;
56
+ /** Input schema. */
57
+ inputSchema: ZodType<TInput>;
58
+ /** Output schema. */
59
+ outputSchema?: ZodType<TOutput>;
60
+ /** Execute the tool. */
61
+ execute: (input: TInput, context: ToolContext) => Promise<TOutput>;
62
+ /** Approval requirement. */
63
+ requireApproval?: boolean | ((input: TInput) => boolean);
64
+ /** Output transformation for model context. */
65
+ toModelOutput?: (output: TOutput) => string;
66
+ }
67
+ /**
68
+ * Request for human approval of a tool execution.
69
+ */
70
+ export interface ApprovalRequest {
71
+ toolId: string;
72
+ input: unknown;
73
+ description: string;
74
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@kognitivedev/tools",
3
+ "version": "0.2.2",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsc -w",
12
+ "prepublishOnly": "npm run build",
13
+ "test": "vitest run"
14
+ },
15
+ "dependencies": {
16
+ "@kognitivedev/shared": "workspace:*"
17
+ },
18
+ "peerDependencies": {
19
+ "ai": ">=5.0.0",
20
+ "zod": ">=3.23.0"
21
+ },
22
+ "devDependencies": {
23
+ "typescript": "^5.0.0",
24
+ "@types/node": "^20.0.0",
25
+ "ai": "^6.0.0",
26
+ "zod": "^3.23.8",
27
+ "vitest": "^3.0.0"
28
+ },
29
+ "description": "Tool system with approval workflows and AI SDK conversion",
30
+ "keywords": [
31
+ "kognitive",
32
+ "ai",
33
+ "tools",
34
+ "approval",
35
+ "vercel-ai-sdk"
36
+ ],
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/kognitivedev/kognitive",
41
+ "directory": "packages/tools"
42
+ },
43
+ "homepage": "https://kognitive.dev"
44
+ }
@@ -0,0 +1,143 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { z } from "zod";
3
+ import { createTool, ToolRegistry, needsApproval, executeWithApproval } from "../index";
4
+ import type { ToolContext } from "../types";
5
+
6
+ const mockContext: ToolContext = {
7
+ abortSignal: new AbortController().signal,
8
+ resourceId: { projectId: "test" },
9
+ emit: vi.fn(),
10
+ };
11
+
12
+ describe("createTool", () => {
13
+ it("creates a tool with correct properties", () => {
14
+ const tool = createTool({
15
+ id: "test-tool",
16
+ description: "A test tool",
17
+ inputSchema: z.object({ query: z.string() }),
18
+ execute: async (input) => ({ result: input.query }),
19
+ });
20
+
21
+ expect(tool.id).toBe("test-tool");
22
+ expect(tool.description).toBe("A test tool");
23
+ expect(tool.inputSchema).toBeDefined();
24
+ expect(tool.execute).toBeTypeOf("function");
25
+ });
26
+
27
+ it("executes with input and context", async () => {
28
+ const tool = createTool({
29
+ id: "echo",
30
+ description: "Echo",
31
+ inputSchema: z.object({ msg: z.string() }),
32
+ execute: async (input) => input.msg,
33
+ });
34
+
35
+ const result = await tool.execute({ msg: "hello" }, mockContext);
36
+ expect(result).toBe("hello");
37
+ });
38
+ });
39
+
40
+ describe("ToolRegistry", () => {
41
+ it("registers and retrieves tools", () => {
42
+ const registry = new ToolRegistry();
43
+ const tool = createTool({
44
+ id: "t1",
45
+ description: "Tool 1",
46
+ inputSchema: z.object({}),
47
+ execute: async () => "ok",
48
+ });
49
+
50
+ registry.register(tool);
51
+ expect(registry.get("t1")).toBe(tool);
52
+ expect(registry.has("t1")).toBe(true);
53
+ expect(registry.size).toBe(1);
54
+ });
55
+
56
+ it("throws on duplicate registration", () => {
57
+ const registry = new ToolRegistry();
58
+ const tool = createTool({
59
+ id: "t1",
60
+ description: "Tool",
61
+ inputSchema: z.object({}),
62
+ execute: async () => "ok",
63
+ });
64
+
65
+ registry.register(tool);
66
+ expect(() => registry.register(tool)).toThrow("already registered");
67
+ });
68
+
69
+ it("all returns all tools", () => {
70
+ const registry = new ToolRegistry();
71
+ const t1 = createTool({ id: "t1", description: "1", inputSchema: z.object({}), execute: async () => 1 });
72
+ const t2 = createTool({ id: "t2", description: "2", inputSchema: z.object({}), execute: async () => 2 });
73
+ registry.register(t1);
74
+ registry.register(t2);
75
+ expect(registry.all()).toHaveLength(2);
76
+ });
77
+
78
+ it("remove deletes tool", () => {
79
+ const registry = new ToolRegistry();
80
+ const tool = createTool({ id: "t1", description: "1", inputSchema: z.object({}), execute: async () => 1 });
81
+ registry.register(tool);
82
+ registry.remove("t1");
83
+ expect(registry.has("t1")).toBe(false);
84
+ });
85
+
86
+ it("toAISDKTools returns record with tool ids as keys", () => {
87
+ const registry = new ToolRegistry();
88
+ registry.register(createTool({ id: "search", description: "Search", inputSchema: z.object({ q: z.string() }), execute: async () => "result" }));
89
+ const sdkTools = registry.toAISDKTools();
90
+ expect(sdkTools).toHaveProperty("search");
91
+ });
92
+ });
93
+
94
+ describe("needsApproval", () => {
95
+ it("returns false when no requireApproval", () => {
96
+ const tool = createTool({ id: "t", description: "t", inputSchema: z.object({}), execute: async () => null });
97
+ expect(needsApproval(tool, {})).toBe(false);
98
+ });
99
+
100
+ it("returns true when requireApproval is true", () => {
101
+ const tool = createTool({ id: "t", description: "t", inputSchema: z.object({}), execute: async () => null, requireApproval: true });
102
+ expect(needsApproval(tool, {})).toBe(true);
103
+ });
104
+
105
+ it("evaluates function requireApproval", () => {
106
+ const tool = createTool({
107
+ id: "t",
108
+ description: "t",
109
+ inputSchema: z.object({ amount: z.number() }),
110
+ execute: async () => null,
111
+ requireApproval: (input: { amount: number }) => input.amount > 100,
112
+ });
113
+ expect(needsApproval(tool, { amount: 50 })).toBe(false);
114
+ expect(needsApproval(tool, { amount: 200 })).toBe(true);
115
+ });
116
+ });
117
+
118
+ describe("executeWithApproval", () => {
119
+ it("executes when no approval needed", async () => {
120
+ const tool = createTool({ id: "t", description: "t", inputSchema: z.object({}), execute: async () => "done" });
121
+ const result = await executeWithApproval(tool, {}, mockContext);
122
+ expect(result).toBe("done");
123
+ });
124
+
125
+ it("throws when approval needed but no handler", async () => {
126
+ const tool = createTool({ id: "t", description: "t", inputSchema: z.object({}), execute: async () => "done", requireApproval: true });
127
+ await expect(executeWithApproval(tool, {}, mockContext)).rejects.toThrow("Approval denied");
128
+ });
129
+
130
+ it("executes when handler approves", async () => {
131
+ const tool = createTool({ id: "t", description: "t", inputSchema: z.object({}), execute: async () => "done", requireApproval: true });
132
+ const handler = vi.fn().mockResolvedValue(true);
133
+ const result = await executeWithApproval(tool, {}, mockContext, handler);
134
+ expect(result).toBe("done");
135
+ expect(handler).toHaveBeenCalled();
136
+ });
137
+
138
+ it("throws when handler denies", async () => {
139
+ const tool = createTool({ id: "t", description: "t", inputSchema: z.object({}), execute: async () => "done", requireApproval: true });
140
+ const handler = vi.fn().mockResolvedValue(false);
141
+ await expect(executeWithApproval(tool, {}, mockContext, handler)).rejects.toThrow("Approval denied");
142
+ });
143
+ });
@@ -0,0 +1,94 @@
1
+ import type { ToolSet } from "ai";
2
+ import type { Tool, ToolContext } from "../types";
3
+ import type { ResourceId } from "@kognitivedev/shared";
4
+
5
+ /**
6
+ * Options for converting enhanced tools to AI SDK format.
7
+ */
8
+ export interface AISDKToolOptions {
9
+ /** Resource context to inject into tool execution. */
10
+ resourceId?: ResourceId;
11
+ /** Memory snapshot to inject into tool context. */
12
+ memory?: { systemBlock: string | null; userContextBlock: string | null };
13
+ /** Abort signal to pass to tool execution. */
14
+ abortSignal?: AbortSignal;
15
+ /** Event handler for tool emissions. */
16
+ onEmit?: (toolId: string, event: string, data: unknown) => void;
17
+ }
18
+
19
+ /**
20
+ * Build a ToolContext from AISDKToolOptions for a specific tool.
21
+ */
22
+ function buildContext(toolId: string, options: AISDKToolOptions): ToolContext {
23
+ return {
24
+ abortSignal: options.abortSignal ?? new AbortController().signal,
25
+ resourceId: options.resourceId ?? { projectId: "default" },
26
+ memory: options.memory,
27
+ emit: (event, data) => {
28
+ options.onEmit?.(toolId, event, data);
29
+ },
30
+ };
31
+ }
32
+
33
+ /**
34
+ * Convert a single enhanced Tool to an AI SDK-compatible tool object.
35
+ *
36
+ * Returns a plain object matching the AI SDK Tool interface shape.
37
+ * This can be used directly with streamText, generateText, etc.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * import { streamText } from 'ai';
42
+ *
43
+ * const sdkTool = toAISDKTool(myTool, {
44
+ * resourceId: { projectId: 'proj_1', userId: 'user_1' },
45
+ * });
46
+ * const result = await streamText({
47
+ * model: openai('gpt-4o'),
48
+ * tools: { search: sdkTool },
49
+ * messages,
50
+ * });
51
+ * ```
52
+ */
53
+ export function toAISDKTool(
54
+ tool: Tool<any, any>,
55
+ options: AISDKToolOptions = {}
56
+ ): ToolSet[string] {
57
+ const context = buildContext(tool.id, options);
58
+
59
+ // Construct the AI SDK tool object directly.
60
+ // The AI SDK tool() function is a passthrough identity function for type safety.
61
+ // Building the object directly avoids generic type inference issues with `any`.
62
+ // AI SDK v6 uses `inputSchema` (not `parameters`).
63
+ return {
64
+ description: tool.description,
65
+ inputSchema: tool.inputSchema,
66
+ execute: async (input: any) => {
67
+ const result = await tool.execute(input, context);
68
+ if (tool.toModelOutput) {
69
+ return tool.toModelOutput(result);
70
+ }
71
+ return result;
72
+ },
73
+ } as unknown as ToolSet[string];
74
+ }
75
+
76
+ /**
77
+ * Convert an array of enhanced Tools to an AI SDK ToolSet record.
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * const tools = toAISDKTools([searchTool, createTool], { resourceId });
82
+ * const result = await streamText({ model, tools, messages });
83
+ * ```
84
+ */
85
+ export function toAISDKTools(
86
+ tools: Tool<any, any>[],
87
+ options: AISDKToolOptions = {}
88
+ ): ToolSet {
89
+ const result: ToolSet = {};
90
+ for (const t of tools) {
91
+ result[t.id] = toAISDKTool(t, options);
92
+ }
93
+ return result;
94
+ }
@@ -0,0 +1,48 @@
1
+ import type { Tool, ToolContext, ApprovalRequest } from "./types";
2
+ import { ApprovalDeniedError } from "@kognitivedev/shared";
3
+
4
+ /**
5
+ * Callback type for handling tool approval requests.
6
+ * Return true to approve, false to deny.
7
+ */
8
+ export type ApprovalHandler = (request: ApprovalRequest) => Promise<boolean>;
9
+
10
+ /**
11
+ * Check if a tool requires approval for the given input.
12
+ */
13
+ export function needsApproval<TInput>(
14
+ tool: Tool<TInput, any>,
15
+ input: TInput
16
+ ): boolean {
17
+ if (!tool.requireApproval) return false;
18
+ if (typeof tool.requireApproval === "function") {
19
+ return tool.requireApproval(input);
20
+ }
21
+ return true;
22
+ }
23
+
24
+ /**
25
+ * Execute a tool with approval check.
26
+ * If the tool requires approval and the handler denies it, throws ApprovalDeniedError.
27
+ */
28
+ export async function executeWithApproval<TInput, TOutput>(
29
+ tool: Tool<TInput, TOutput>,
30
+ input: TInput,
31
+ context: ToolContext,
32
+ approvalHandler?: ApprovalHandler
33
+ ): Promise<TOutput> {
34
+ if (needsApproval(tool, input)) {
35
+ if (!approvalHandler) {
36
+ throw new ApprovalDeniedError(tool.id);
37
+ }
38
+ const approved = await approvalHandler({
39
+ toolId: tool.id,
40
+ input,
41
+ description: tool.description,
42
+ });
43
+ if (!approved) {
44
+ throw new ApprovalDeniedError(tool.id);
45
+ }
46
+ }
47
+ return tool.execute(input, context);
48
+ }
@@ -0,0 +1,35 @@
1
+ import type { ToolDefinition, Tool } from "./types";
2
+
3
+ /**
4
+ * Create an enhanced tool with approval, abort, and context support.
5
+ *
6
+ * Tools created with this function can be converted to AI SDK tool() format
7
+ * via ToolRegistry.toAISDKTools() or toAISDKTool().
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const searchTool = createTool({
12
+ * id: 'search-docs',
13
+ * description: 'Search documentation',
14
+ * inputSchema: z.object({ query: z.string() }),
15
+ * execute: async (input, ctx) => {
16
+ * // ctx.abortSignal, ctx.memory, ctx.resourceId available
17
+ * return { results: [...] };
18
+ * },
19
+ * requireApproval: true,
20
+ * });
21
+ * ```
22
+ */
23
+ export function createTool<TInput, TOutput>(
24
+ definition: ToolDefinition<TInput, TOutput>
25
+ ): Tool<TInput, TOutput> {
26
+ return {
27
+ id: definition.id,
28
+ description: definition.description,
29
+ inputSchema: definition.inputSchema,
30
+ outputSchema: definition.outputSchema,
31
+ execute: definition.execute,
32
+ requireApproval: definition.requireApproval,
33
+ toModelOutput: definition.toModelOutput,
34
+ };
35
+ }
package/src/index.ts ADDED
@@ -0,0 +1,14 @@
1
+ // Core
2
+ export type { ToolDefinition, Tool, ToolContext, ApprovalRequest } from "./types";
3
+ export { createTool } from "./create-tool";
4
+
5
+ // Registry
6
+ export { ToolRegistry } from "./registry";
7
+
8
+ // Approval
9
+ export type { ApprovalHandler } from "./approval";
10
+ export { needsApproval, executeWithApproval } from "./approval";
11
+
12
+ // AI SDK Adapter
13
+ export type { AISDKToolOptions } from "./adapters/ai-sdk";
14
+ export { toAISDKTool, toAISDKTools } from "./adapters/ai-sdk";
@@ -0,0 +1,97 @@
1
+ import type { Tool, ToolContext } from "./types";
2
+ import type { ApprovalHandler } from "./approval";
3
+ import { needsApproval } from "./approval";
4
+ import { toAISDKTool, type AISDKToolOptions } from "./adapters/ai-sdk";
5
+
6
+ /**
7
+ * Registry for managing a named collection of tools.
8
+ * Provides lookup by ID and bulk conversion to AI SDK format.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const registry = new ToolRegistry();
13
+ * registry.register(searchTool);
14
+ * registry.register(createTicketTool);
15
+ *
16
+ * // Use with AI SDK streamText directly
17
+ * const result = await streamText({
18
+ * model: openai('gpt-4o'),
19
+ * tools: registry.toAISDKTools(),
20
+ * messages,
21
+ * });
22
+ * ```
23
+ */
24
+ export class ToolRegistry {
25
+ private tools = new Map<string, Tool<any, any>>();
26
+
27
+ /**
28
+ * Register a tool. Throws if a tool with the same ID already exists.
29
+ */
30
+ register(tool: Tool<any, any>): void {
31
+ if (this.tools.has(tool.id)) {
32
+ throw new Error(`Tool with id "${tool.id}" already registered`);
33
+ }
34
+ this.tools.set(tool.id, tool);
35
+ }
36
+
37
+ /**
38
+ * Get a tool by ID. Returns undefined if not found.
39
+ */
40
+ get(id: string): Tool<any, any> | undefined {
41
+ return this.tools.get(id);
42
+ }
43
+
44
+ /**
45
+ * Check if a tool with the given ID is registered.
46
+ */
47
+ has(id: string): boolean {
48
+ return this.tools.has(id);
49
+ }
50
+
51
+ /**
52
+ * Remove a tool by ID.
53
+ */
54
+ remove(id: string): boolean {
55
+ return this.tools.delete(id);
56
+ }
57
+
58
+ /**
59
+ * Get all registered tools.
60
+ */
61
+ all(): Tool<any, any>[] {
62
+ return Array.from(this.tools.values());
63
+ }
64
+
65
+ /**
66
+ * Get the number of registered tools.
67
+ */
68
+ get size(): number {
69
+ return this.tools.size;
70
+ }
71
+
72
+ /**
73
+ * Convert all registered tools to AI SDK tool() format.
74
+ * The returned object can be passed directly to streamText/generateText.
75
+ */
76
+ toAISDKTools(options?: AISDKToolOptions): Record<string, any> {
77
+ const result: Record<string, any> = {};
78
+ for (const tool of this.tools.values()) {
79
+ result[tool.id] = toAISDKTool(tool, options);
80
+ }
81
+ return result;
82
+ }
83
+
84
+ /**
85
+ * Get tool IDs that require approval for the given input context.
86
+ */
87
+ getApprovalRequired(inputs: Record<string, unknown>): string[] {
88
+ const result: string[] = [];
89
+ for (const tool of this.tools.values()) {
90
+ const input = inputs[tool.id];
91
+ if (input !== undefined && needsApproval(tool, input)) {
92
+ result.push(tool.id);
93
+ }
94
+ }
95
+ return result;
96
+ }
97
+ }
package/src/types.ts ADDED
@@ -0,0 +1,75 @@
1
+ import type { ZodType } from "zod";
2
+ import type { ResourceId, Metadata } from "@kognitivedev/shared";
3
+
4
+ /**
5
+ * Context provided to tool execute functions.
6
+ * Enriched with memory, abort signal, and event emission.
7
+ */
8
+ export interface ToolContext {
9
+ /** Signal for aborting long-running tool operations. */
10
+ abortSignal: AbortSignal;
11
+ /** Resource scope (user, project, session). */
12
+ resourceId: ResourceId;
13
+ /** Memory snapshot if available (injected by agent runtime). */
14
+ memory?: { systemBlock: string | null; userContextBlock: string | null };
15
+ /** Emit events for streaming partial results or progress updates. */
16
+ emit: (event: string, data: unknown) => void;
17
+ /** Arbitrary metadata passed through from the caller. */
18
+ metadata?: Metadata;
19
+ }
20
+
21
+ /**
22
+ * Definition for creating an enhanced tool.
23
+ */
24
+ export interface ToolDefinition<TInput = any, TOutput = any> {
25
+ /** Unique identifier for the tool. */
26
+ id: string;
27
+ /** Human-readable description (sent to the model). */
28
+ description: string;
29
+ /** Zod schema for validating tool input. */
30
+ inputSchema: ZodType<TInput>;
31
+ /** Optional Zod schema for validating tool output. */
32
+ outputSchema?: ZodType<TOutput>;
33
+ /** Execute the tool with validated input and context. */
34
+ execute: (input: TInput, context: ToolContext) => Promise<TOutput>;
35
+ /**
36
+ * Whether this tool requires human approval before execution.
37
+ * - `true`: Always require approval
38
+ * - Function: Conditionally require based on input
39
+ */
40
+ requireApproval?: boolean | ((input: TInput) => boolean);
41
+ /**
42
+ * Transform tool output before sending to the model.
43
+ * Useful for large outputs — keep full result in application, send summary to model.
44
+ */
45
+ toModelOutput?: (output: TOutput) => string;
46
+ }
47
+
48
+ /**
49
+ * A created tool instance with its definition and metadata.
50
+ */
51
+ export interface Tool<TInput = any, TOutput = any> {
52
+ /** Unique identifier. */
53
+ id: string;
54
+ /** Human-readable description. */
55
+ description: string;
56
+ /** Input schema. */
57
+ inputSchema: ZodType<TInput>;
58
+ /** Output schema. */
59
+ outputSchema?: ZodType<TOutput>;
60
+ /** Execute the tool. */
61
+ execute: (input: TInput, context: ToolContext) => Promise<TOutput>;
62
+ /** Approval requirement. */
63
+ requireApproval?: boolean | ((input: TInput) => boolean);
64
+ /** Output transformation for model context. */
65
+ toModelOutput?: (output: TOutput) => string;
66
+ }
67
+
68
+ /**
69
+ * Request for human approval of a tool execution.
70
+ */
71
+ export interface ApprovalRequest {
72
+ toolId: string;
73
+ input: unknown;
74
+ description: string;
75
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "module": "commonjs",
5
+ "rootDir": "src",
6
+ "outDir": "dist",
7
+ "declaration": true,
8
+ "noEmit": false,
9
+ "incremental": false
10
+ },
11
+ "include": [
12
+ "src"
13
+ ]
14
+ }
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: "node",
7
+ },
8
+ });