toolwire 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.
@@ -0,0 +1,325 @@
1
+ import { ZodType, ZodIssue } from 'zod';
2
+
3
+ type JsonSchema = Record<string, unknown>;
4
+ interface ToolConfig<TInput = unknown, TOutput = unknown> {
5
+ /** Unique name. 1–64 chars: letters, digits, underscores, hyphens. */
6
+ name: string;
7
+ /** Human description — explain when and how to call this tool. */
8
+ description: string;
9
+ /** Zod schema for input arguments. */
10
+ input: ZodType<TInput>;
11
+ /** Optional Zod schema for the return value. Validates handler output. */
12
+ output?: ZodType<TOutput>;
13
+ /** The implementation. Receives validated input and a ToolContext. */
14
+ handler: (input: TInput, context: ToolContext) => TOutput | Promise<TOutput>;
15
+ /** Timeout in milliseconds. Default: 30_000 */
16
+ timeout?: number;
17
+ /** Extra retry attempts on execution failure (not validation/timeout). Default: 0 */
18
+ retries?: number;
19
+ /** MCP-style behavioural hints (informational only — not enforced). */
20
+ annotations?: ToolAnnotations;
21
+ /**
22
+ * Override the auto-computed JSON Schema for the input.
23
+ * Useful when loading tools from remote manifests.
24
+ */
25
+ _jsonSchema?: JsonSchema;
26
+ }
27
+ interface ToolContext {
28
+ /** AbortSignal tied to the timeout. Handlers should honour this for cooperative cancellation. */
29
+ signal: AbortSignal;
30
+ /** Current attempt index (0 = first try, 1 = first retry, …). */
31
+ attempt: number;
32
+ }
33
+ interface ToolAnnotations {
34
+ /** Human-readable display title. */
35
+ title?: string;
36
+ /** Hint: tool only reads data, no side-effects. */
37
+ readOnly?: boolean;
38
+ /** Hint: tool modifies or deletes data. */
39
+ destructive?: boolean;
40
+ /** Hint: tool makes expensive external calls — consider caching. */
41
+ expensive?: boolean;
42
+ /** Hint: prompt user for confirmation before calling. */
43
+ requiresConfirmation?: boolean;
44
+ [key: string]: unknown;
45
+ }
46
+ interface ToolDefinition<TInput = unknown, TOutput = unknown> {
47
+ readonly name: string;
48
+ readonly description: string;
49
+ readonly input: ZodType<TInput>;
50
+ readonly output: ZodType<TOutput> | undefined;
51
+ readonly handler: (input: TInput, context: ToolContext) => TOutput | Promise<TOutput>;
52
+ readonly timeout: number;
53
+ readonly retries: number;
54
+ readonly annotations: ToolAnnotations;
55
+ /** Pre-computed JSON Schema for the input. Used by provider adapters. */
56
+ readonly inputSchema: JsonSchema;
57
+ /** Pre-computed JSON Schema for the output, if an output schema was provided. */
58
+ readonly outputSchema: JsonSchema | undefined;
59
+ }
60
+ type ToolResult<T = unknown> = ToolSuccess<T> | ToolFailure;
61
+ interface ToolSuccess<T = unknown> {
62
+ readonly success: true;
63
+ readonly data: T;
64
+ readonly toolName: string;
65
+ readonly durationMs: number;
66
+ }
67
+ interface ToolFailure {
68
+ readonly success: false;
69
+ readonly error: ToolError;
70
+ readonly toolName: string;
71
+ readonly durationMs: number;
72
+ }
73
+ type ToolErrorCode = 'VALIDATION_INPUT' | 'VALIDATION_OUTPUT' | 'EXECUTION' | 'TIMEOUT' | 'NOT_FOUND' | 'DISABLED';
74
+ interface ToolError {
75
+ readonly code: ToolErrorCode;
76
+ /** Developer-readable message (suitable for logs). */
77
+ readonly message: string;
78
+ /** LLM-readable message formatted to help the model understand and retry. */
79
+ readonly llmMessage: string;
80
+ readonly toolName: string;
81
+ /** Whether the LLM should retry the call. */
82
+ readonly retryable: boolean;
83
+ /** Suggested wait before retrying (ms). */
84
+ readonly retryAfterMs?: number;
85
+ /** Full Zod issue list — only present for VALIDATION_* errors. */
86
+ readonly issues?: ReadonlyArray<ZodIssue>;
87
+ /** Original thrown value — only present for EXECUTION errors. */
88
+ readonly cause?: unknown;
89
+ }
90
+ interface Middleware {
91
+ /** Optional name for logging / debugging. */
92
+ name?: string;
93
+ /**
94
+ * Runs before execution, in registration order.
95
+ * Return a value to replace the tool arguments; return void/undefined to keep them.
96
+ */
97
+ beforeCall?: (toolName: string, args: unknown) => unknown | Promise<unknown> | void | Promise<void>;
98
+ /**
99
+ * Runs after a successful execution, in reverse registration order.
100
+ * Return a ToolSuccess to replace the result; return void/undefined to keep it.
101
+ */
102
+ afterCall?: (toolName: string, args: unknown, result: ToolSuccess) => ToolSuccess | Promise<ToolSuccess> | void | Promise<void>;
103
+ /**
104
+ * Runs on any failure (validation, execution, timeout, not-found, disabled).
105
+ * Return a ToolResult to recover from the error; return void/undefined to propagate the failure.
106
+ */
107
+ onError?: (toolName: string, args: unknown, failure: ToolFailure) => ToolResult | Promise<ToolResult> | void | Promise<void>;
108
+ }
109
+ interface ToolCallRequest {
110
+ /** Name of the tool to call. */
111
+ name: string;
112
+ /** Raw arguments from the LLM (validated against the input schema at runtime). */
113
+ arguments: unknown;
114
+ }
115
+ interface RegistryOptions {
116
+ /** Default timeout for tools that don't specify their own (ms). */
117
+ defaultTimeout?: number;
118
+ }
119
+ interface OpenAITool {
120
+ type: 'function';
121
+ function: {
122
+ name: string;
123
+ description: string;
124
+ parameters: JsonSchema;
125
+ strict?: boolean;
126
+ };
127
+ }
128
+ interface AnthropicTool {
129
+ name: string;
130
+ description: string;
131
+ input_schema: JsonSchema;
132
+ }
133
+ interface GeminiFunctionDeclaration {
134
+ name: string;
135
+ description: string;
136
+ parametersJsonSchema: JsonSchema;
137
+ }
138
+ interface GeminiToolConfig {
139
+ functionDeclarations: GeminiFunctionDeclaration[];
140
+ }
141
+ interface VercelAIToolDef {
142
+ description: string;
143
+ parameters: ZodType;
144
+ }
145
+ type VercelAIToolSet = Record<string, VercelAIToolDef>;
146
+ interface ToolManifestEntry {
147
+ name: string;
148
+ description: string;
149
+ inputSchema: JsonSchema;
150
+ endpoint: string;
151
+ }
152
+ interface ToolManifest {
153
+ version: '1.0';
154
+ tools: ToolManifestEntry[];
155
+ }
156
+ /** Extract the input type from a ToolDefinition. */
157
+ type InferInput<T> = T extends ToolDefinition<infer I, unknown> ? I : never;
158
+ /** Extract the output type from a ToolDefinition. */
159
+ type InferOutput<T> = T extends ToolDefinition<unknown, infer O> ? O : never;
160
+
161
+ /**
162
+ * Define a tool. Returns a frozen ToolDefinition with pre-computed JSON schemas.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * const search = tool({
167
+ * name: 'search_web',
168
+ * description: 'Search the web for current information',
169
+ * input: z.object({ query: z.string().min(1) }),
170
+ * handler: async ({ query }) => mySearchAPI(query),
171
+ * timeout: 10_000,
172
+ * });
173
+ * ```
174
+ */
175
+ declare function tool<TInput = unknown, TOutput = unknown>(config: ToolConfig<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
176
+
177
+ type AnyTool = ToolDefinition<any, any>;
178
+ declare class ToolRegistry {
179
+ private readonly tools;
180
+ private readonly disabledTools;
181
+ private readonly _middleware;
182
+ private readonly options;
183
+ constructor(tools?: AnyTool[], options?: RegistryOptions);
184
+ /** Add one or more tools. Returns `this` for chaining. */
185
+ register(tools: AnyTool | AnyTool[]): this;
186
+ /**
187
+ * Replace a registered tool in-place (hot-swap).
188
+ * Useful for swapping slow tools with cached versions mid-run.
189
+ */
190
+ swap(name: string, newTool: AnyTool): this;
191
+ /** Temporarily prevent a tool from being called. */
192
+ disable(name: string): this;
193
+ /** Re-enable a previously disabled tool. */
194
+ enable(name: string): this;
195
+ /** Add middleware. Returns `this` for chaining. */
196
+ use(middleware: Middleware | Middleware[]): this;
197
+ /** Return the names of all registered tools (including disabled ones). */
198
+ list(): string[];
199
+ /** Return a tool definition by name, or undefined if not found. */
200
+ get(name: string): AnyTool | undefined;
201
+ /**
202
+ * Return a human-readable list of enabled tools.
203
+ * Handy for injecting into a system prompt.
204
+ */
205
+ describe(): string;
206
+ /**
207
+ * Execute a tool call from an LLM.
208
+ * Always resolves (never throws) — check `result.success` to distinguish outcomes.
209
+ */
210
+ call(request: ToolCallRequest): Promise<ToolResult>;
211
+ /** Export tool schemas in OpenAI function-calling format. */
212
+ toOpenAI(options?: {
213
+ strict?: boolean;
214
+ }): OpenAITool[];
215
+ /** Export tool schemas in Anthropic tool-use format. */
216
+ toAnthropic(): AnthropicTool[];
217
+ /** Export tool schemas in Google Gemini format. */
218
+ toGemini(): GeminiToolConfig;
219
+ /** Export tool schemas in Vercel AI SDK format (passes Zod schemas directly). */
220
+ toVercelAI(): VercelAIToolSet;
221
+ /** Load tools from a directory of compiled JS/MJS files. */
222
+ static fromDir(dirPath: string): Promise<ToolRegistry>;
223
+ /** Load tools from a remote JSON manifest. */
224
+ static fromManifest(url: string): Promise<ToolRegistry>;
225
+ private enabledTools;
226
+ }
227
+ /** Convenience factory — same as `new ToolRegistry(tools, options)`. */
228
+ declare function registry(tools?: AnyTool[], options?: RegistryOptions): ToolRegistry;
229
+
230
+ /**
231
+ * Convert tool definitions to OpenAI function-calling format.
232
+ *
233
+ * @example
234
+ * ```ts
235
+ * const response = await openai.chat.completions.create({
236
+ * model: 'gpt-4o',
237
+ * tools: reg.toOpenAI({ strict: true }),
238
+ * messages,
239
+ * });
240
+ * ```
241
+ */
242
+ declare function toOpenAI(tools: ToolDefinition<any, any>[], options?: {
243
+ strict?: boolean;
244
+ }): OpenAITool[];
245
+
246
+ /**
247
+ * Convert tool definitions to Anthropic tool-use format.
248
+ * Note: uses `input_schema` (not `parameters`).
249
+ *
250
+ * @example
251
+ * ```ts
252
+ * const response = await anthropic.messages.create({
253
+ * model: 'claude-opus-4-6',
254
+ * tools: reg.toAnthropic(),
255
+ * messages,
256
+ * });
257
+ * ```
258
+ */
259
+ declare function toAnthropic(tools: ToolDefinition<any, any>[]): AnthropicTool[];
260
+
261
+ /**
262
+ * Convert tool definitions to Google Gemini format.
263
+ * Uses `parametersJsonSchema` (not `parameters`) and wraps in `functionDeclarations`.
264
+ *
265
+ * @example
266
+ * ```ts
267
+ * const response = await model.generateContent({
268
+ * tools: [reg.toGemini()],
269
+ * contents,
270
+ * });
271
+ * ```
272
+ */
273
+ declare function toGemini(tools: ToolDefinition<any, any>[]): GeminiToolConfig;
274
+
275
+ /**
276
+ * Convert tool definitions to Vercel AI SDK format.
277
+ * Unlike other adapters, this passes the original Zod schema directly
278
+ * (Vercel AI SDK handles JSON Schema conversion internally).
279
+ *
280
+ * @example
281
+ * ```ts
282
+ * const { text } = await generateText({
283
+ * model: openai('gpt-4o'),
284
+ * tools: reg.toVercelAI(),
285
+ * prompt,
286
+ * });
287
+ * ```
288
+ */
289
+ declare function toVercelAI(tools: ToolDefinition<any, any>[]): VercelAIToolSet;
290
+
291
+ /**
292
+ * Load tools from a directory of compiled JavaScript files.
293
+ * Each file may export:
294
+ * - `export default tool(...)` — a single tool as the default export
295
+ * - `export const tools = [tool(...), ...]` — an array under the `tools` named export
296
+ * - `export const myTool = tool(...)` — any named export that is a ToolDefinition
297
+ *
298
+ * Only `.js`, `.mjs`, and `.cjs` files are scanned.
299
+ * Files that fail to import are skipped with a warning.
300
+ */
301
+ declare function fromDir(dirPath: string): Promise<ToolRegistry>;
302
+ /**
303
+ * Load tools from a remote JSON manifest.
304
+ * The manifest must conform to the ToolManifest schema:
305
+ * ```json
306
+ * {
307
+ * "version": "1.0",
308
+ * "tools": [
309
+ * { "name": "...", "description": "...", "inputSchema": {...}, "endpoint": "https://..." }
310
+ * ]
311
+ * }
312
+ * ```
313
+ * Each tool is proxied as an HTTP POST to its `endpoint`.
314
+ */
315
+ declare function fromManifest(url: string): Promise<ToolRegistry>;
316
+
317
+ declare function makeNotFoundError(toolName: string, available: string[]): ToolError;
318
+ declare function makeDisabledError(toolName: string): ToolError;
319
+ declare function makeValidationInputError(toolName: string, issues: ZodIssue[]): ToolError;
320
+ declare function makeValidationOutputError(toolName: string, issues: ZodIssue[]): ToolError;
321
+ declare function makeTimeoutError(toolName: string, timeoutMs: number): ToolError;
322
+ declare function makeExecutionError(toolName: string, cause: unknown, attempts: number): ToolError;
323
+ declare function makeFailure(toolName: string, error: ToolError, durationMs: number): ToolFailure;
324
+
325
+ export { type AnthropicTool, type GeminiFunctionDeclaration, type GeminiToolConfig, type InferInput, type InferOutput, type JsonSchema, type Middleware, type OpenAITool, type RegistryOptions, type ToolAnnotations, type ToolCallRequest, type ToolConfig, type ToolContext, type ToolDefinition, type ToolError, type ToolErrorCode, type ToolFailure, type ToolManifest, type ToolManifestEntry, ToolRegistry, type ToolResult, type ToolSuccess, type VercelAIToolDef, type VercelAIToolSet, fromDir, fromManifest, makeDisabledError, makeExecutionError, makeFailure, makeNotFoundError, makeTimeoutError, makeValidationInputError, makeValidationOutputError, registry, toAnthropic, toGemini, toOpenAI, toVercelAI, tool };