import { z } from "zod"; import { randomBytes, randomUUID } from "node:crypto"; import type { JSONSchema7 } from "json-schema"; import type { ToolExecutor, ToolContext, ToolResult } from "../../registry"; import type { UuidToolConfig } from "./config"; export const uuidInputSchema = z.object({ operation: z .enum(["uuid", "random-string", "random-int"]) .describe("操作类型: uuid=生成UUID, random-string=随机字符串, random-int=随机整数"), version: z .enum(["v4", "v7"]) .optional() .describe("UUID 版本 (uuid 操作使用)"), length: z .number() .int() .positive() .max(256) .optional() .describe("随机字符串长度 (random-string 操作使用)"), encoding: z .enum(["hex", "base64", "base64url", "alphanumeric"]) .optional() .describe("随机字符串编码方式 (random-string 操作使用)"), min: z .number() .int() .optional() .describe("最小值 (random-int 操作使用)"), max: z .number() .int() .optional() .describe("最大值 (random-int 操作使用)"), count: z .number() .int() .positive() .max(100) .optional() .describe("生成数量,默认 1"), }); type UuidInput = z.infer; const ALPHANUMERIC_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; function generateUuidV7(): string { const timestamp = Date.now(); const timestampHex = timestamp.toString(16).padStart(12, "0"); const random = randomBytes(10); random[0] = (random[0]! & 0x0f) | 0x70; random[2] = (random[2]! & 0x3f) | 0x80; const randomHex = random.toString("hex"); return `${timestampHex.slice(0, 8)}-${timestampHex.slice(8, 12)}-${randomHex.slice(0, 4)}-${randomHex.slice(4, 8)}-${randomHex.slice(8, 20)}`; } function generateRandomString(length: number, encoding: string): string { switch (encoding) { case "hex": return randomBytes(Math.ceil(length / 2)).toString("hex").slice(0, length); case "base64": return randomBytes(Math.ceil(length * 0.75)).toString("base64").slice(0, length); case "base64url": return randomBytes(Math.ceil(length * 0.75)) .toString("base64url") .slice(0, length); case "alphanumeric": { const bytes = randomBytes(length); let result = ""; for (let i = 0; i < length; i++) { result += ALPHANUMERIC_CHARS[bytes[i]! % ALPHANUMERIC_CHARS.length]; } return result; } default: throw new Error(`未知编码: ${encoding}`); } } function generateRandomInt(min: number, max: number): number { if (min >= max) throw new Error("min 必须小于 max"); const range = max - min; const bytes = randomBytes(8); const randomValue = bytes.readBigUInt64BE(); return min + Number(randomValue % BigInt(range)); } export const uuidExecutor: ToolExecutor = { buildInputSchema(_config: UuidToolConfig): JSONSchema7 { return { type: "object", properties: { operation: { type: "string", enum: ["uuid", "random-string", "random-int"], description: "操作类型", }, version: { type: "string", enum: ["v4", "v7"], description: "UUID 版本" }, length: { type: "number", description: "随机字符串长度" }, encoding: { type: "string", enum: ["hex", "base64", "base64url", "alphanumeric"], description: "编码方式", }, min: { type: "number", description: "最小值" }, max: { type: "number", description: "最大值" }, count: { type: "number", description: "生成数量" }, }, required: ["operation"], }; }, buildDescription(config: UuidToolConfig): string { return `生成随机标识符。支持 UUID v4/v7、随机字符串(hex/base64/base64url/alphanumeric)、随机整数。默认 UUID 版本: ${config.defaultVersion},默认字符串长度: ${config.defaultLength}。`; }, async execute( input: unknown, config: UuidToolConfig, _ctx: ToolContext, ): Promise { const start = Date.now(); const parsed = uuidInputSchema.safeParse(input); if (!parsed.success) { return { success: false, data: null, error: `输入参数校验失败: ${parsed.error.message}`, metadata: { durationMs: Date.now() - start }, }; } const inp = parsed.data as UuidInput; const count = inp.count ?? 1; try { const results: unknown[] = []; for (let i = 0; i < count; i++) { switch (inp.operation) { case "uuid": { const version = inp.version ?? config.defaultVersion; if (version === "v4") { results.push(randomUUID()); } else { results.push(generateUuidV7()); } break; } case "random-string": { const length = inp.length ?? config.defaultLength; const encoding = inp.encoding ?? "hex"; results.push(generateRandomString(length, encoding)); break; } case "random-int": { const min = inp.min ?? 0; const max = inp.max ?? 100; results.push(generateRandomInt(min, max)); break; } default: throw new Error(`未知操作: ${inp.operation}`); } } return { success: true, data: { operation: inp.operation, count, results: count === 1 ? results[0] : results, }, metadata: { durationMs: Date.now() - start }, }; } catch (e) { return { success: false, data: null, error: e instanceof Error ? e.message : String(e), metadata: { durationMs: Date.now() - start }, }; } }, };