-
Notifications
You must be signed in to change notification settings - Fork 72
Expand file tree
/
Copy pathruntime.ts
More file actions
74 lines (66 loc) · 2.03 KB
/
runtime.ts
File metadata and controls
74 lines (66 loc) · 2.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import { z } from "zod";
import type { ToolExecutionContext, ToolExecutionResult } from "../tools/executor";
export type ValidationResult = { ok: true; input: Record<string, unknown> } | { ok: false; error: string };
export function semanticBoolean(defaultValue = false) {
return z.preprocess((value) => {
if (value === "true") {
return true;
}
if (value === "false") {
return false;
}
return value;
}, z.boolean().default(defaultValue));
}
export function semanticInteger(label: string, options: { min?: number } = {}) {
return z.preprocess(
(value) => {
if (typeof value === "string" && value.trim()) {
return Number(value);
}
return value;
},
z
.number()
.int()
.min(options.min ?? Number.MIN_SAFE_INTEGER, `${label} must be >= ${options.min ?? Number.MIN_SAFE_INTEGER}.`)
);
}
export async function executeValidatedTool<TSchema extends z.ZodType<Record<string, unknown>>>(
name: string,
schema: TSchema,
rawArgs: Record<string, unknown>,
context: ToolExecutionContext,
handler: (input: z.infer<TSchema>, context: ToolExecutionContext) => Promise<ToolExecutionResult>,
options: {
preprocess?: (args: Record<string, unknown>) => ValidationResult;
} = {}
): Promise<ToolExecutionResult> {
const preprocessed: ValidationResult = options.preprocess
? options.preprocess(rawArgs)
: { ok: true, input: rawArgs };
if (!preprocessed.ok) {
return {
ok: false,
name,
error: `InputValidationError: ${preprocessed.error}`,
};
}
const parsed = schema.safeParse(preprocessed.input);
if (!parsed.success) {
return {
ok: false,
name,
error: `InputValidationError: ${formatZodError(parsed.error)}`,
};
}
return handler(parsed.data, context);
}
function formatZodError(error: z.ZodError): string {
const issue = error.issues[0];
if (!issue) {
return "Invalid tool input.";
}
const path = issue.path.length > 0 ? `${issue.path.join(".")}: ` : "";
return `${path}${issue.message}`;
}