UNPKG

@tanstack/ai-code-mode

Version:

Secure TypeScript Code Mode for TanStack AI agents to execute sandboxed tool orchestration programs.

90 lines (89 loc) 3.46 kB
//#region src/type-generator/json-schema-to-ts.ts /** * Generate TypeScript type stubs for all tool bindings * * These stubs are included in the LLM system prompt so it knows * the exact type signatures of available tools. * * Tool names match the actual function names injected into the sandbox. */ function generateTypeStubs(bindings, options = {}) { const { includeDescriptions = true } = options; const declarations = []; for (const [name, binding] of Object.entries(bindings)) { const inputTypeName = `${capitalize(name)}Input`; const outputTypeName = `${capitalize(name)}Output`; const inputType = jsonSchemaToTypeScript(binding.inputSchema, inputTypeName); if (inputType.declaration) declarations.push(inputType.declaration); let outputTypeRef = "unknown"; if (binding.outputSchema) { const outputType = jsonSchemaToTypeScript(binding.outputSchema, outputTypeName); if (outputType.declaration) declarations.push(outputType.declaration); outputTypeRef = outputType.name; } const description = includeDescriptions && binding.description ? `/** ${binding.description} */\n` : ""; declarations.push(`${description}declare function ${name}(input: ${inputType.name}): Promise<${outputTypeRef}>;`); } return declarations.join("\n\n"); } /** * Convert a JSON Schema to a TypeScript type * * Supports basic types: string, number, boolean, object, array */ function jsonSchemaToTypeScript(schema, typeName) { const type = schemaToType(schema); if (schema.type === "object" && schema.properties && Object.keys(schema.properties).length > 0) return { name: typeName, declaration: `interface ${typeName} ${type}` }; return { name: type, declaration: "" }; } /** * Convert a JSON Schema to a TypeScript type string */ function schemaToType(schema) { if (typeof schema !== "object") return "unknown"; const schemaType = schema.type; if (schemaType === "string") return "string"; if (schemaType === "number" || schemaType === "integer") return "number"; if (schemaType === "boolean") return "boolean"; if (schemaType === "null") return "null"; if (schemaType === "array") { const items = schema.items; return `Array<${items ? schemaToType(items) : "unknown"}>`; } if (schemaType === "object" && schema.properties) { const properties = schema.properties; const required = new Set(schema.required ?? []); return `{\n${Object.entries(properties).map(([key, propSchema]) => { const optional = required.has(key) ? "" : "?"; const propType = schemaToType(propSchema); return ` ${/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : `"${key}"`}${optional}: ${propType};`; }).join("\n")}\n}`; } if (schema.enum) return schema.enum.map((v) => JSON.stringify(v)).join(" | "); if (schema.anyOf || schema.oneOf) return (schema.anyOf || schema.oneOf).map((v) => schemaToType(v)).join(" | "); if (Array.isArray(schemaType)) return schemaType.map((t) => { if (t === "string") return "string"; if (t === "number" || t === "integer") return "number"; if (t === "boolean") return "boolean"; if (t === "null") return "null"; if (t === "array") return "Array<unknown>"; if (t === "object") return "object"; return "unknown"; }).join(" | "); return "unknown"; } /** * Capitalize the first letter of a string */ function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } //#endregion export { generateTypeStubs, jsonSchemaToTypeScript }; //# sourceMappingURL=json-schema-to-ts.js.map