#!/usr/bin/env tsx // Usage: ./{agent_name}.ts import { readFileSync, writeFileSync, existsSync } from "fs"; import { join } from "path"; import { pathToFileURL } from "url"; async function main(): Promise { const { agentFunc, rawData } = parseArgv(); const agentData = parseRawData(rawData); const configDir = "{config_dir}"; setupEnv(configDir, agentFunc); const agentToolsPath = join(configDir, "agents", "{agent_name}", "tools.ts"); await run(agentToolsPath, agentFunc, agentData); } function parseRawData(data: string): Record { if (!data) { throw new Error("No JSON data"); } try { return JSON.parse(data); } catch { throw new Error("Invalid JSON data"); } } function parseArgv(): { agentFunc: string; rawData: string } { const agentFunc = process.argv[2]; const toolDataFile = process.env["LLM_TOOL_DATA_FILE"]; let agentData: string; if (toolDataFile && existsSync(toolDataFile)) { agentData = readFileSync(toolDataFile, "utf-8"); } else { agentData = process.argv[3]; } if (!agentFunc || !agentData) { process.stderr.write("Usage: ./{agent_name}.ts \n"); process.exit(1); } return { agentFunc, rawData: agentData }; } function setupEnv(configDir: string, agentFunc: string): void { loadEnv(join(configDir, ".env")); process.env["LLM_ROOT_DIR"] = configDir; process.env["LLM_AGENT_NAME"] = "{agent_name}"; process.env["LLM_AGENT_FUNC"] = agentFunc; process.env["LLM_AGENT_ROOT_DIR"] = join(configDir, "agents", "{agent_name}"); process.env["LLM_AGENT_CACHE_DIR"] = join(configDir, "cache", "{agent_name}"); } function loadEnv(filePath: string): void { let lines: string[]; try { lines = readFileSync(filePath, "utf-8").split("\n"); } catch { return; } for (const raw of lines) { const line = raw.trim(); if (line.startsWith("#") || !line) { continue; } const eqIdx = line.indexOf("="); if (eqIdx === -1) { continue; } const key = line.slice(0, eqIdx).trim(); if (key in process.env) { continue; } let value = line.slice(eqIdx + 1).trim(); if ( (value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")) ) { value = value.slice(1, -1); } process.env[key] = value; } } async function run( agentPath: string, agentFunc: string, agentData: Record, ): Promise { const mod = await import(pathToFileURL(agentPath).href); if (typeof mod[agentFunc] !== "function") { throw new Error(`No module function '${agentFunc}' at '${agentPath}'`); } const value = await mod[agentFunc](agentData); returnToLlm(value); dumpResult(`{agent_name}:${agentFunc}`); } function returnToLlm(value: unknown): void { if (value === null || value === undefined) { return; } const output = process.env["LLM_OUTPUT"]; const write = (s: string) => { if (output) { writeFileSync(output, s, "utf-8"); } else { process.stdout.write(s); } }; if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { write(String(value)); } else if (typeof value === "object") { write(JSON.stringify(value, null, 2)); } } function dumpResult(name: string): void { const dumpResults = process.env["LLM_DUMP_RESULTS"]; const llmOutput = process.env["LLM_OUTPUT"]; if (!dumpResults || !llmOutput || !process.stdout.isTTY) { return; } try { const pattern = new RegExp(`\\b(${dumpResults})\\b`); if (!pattern.test(name)) { return; } } catch { return; } let data: string; try { data = readFileSync(llmOutput, "utf-8"); } catch { return; } process.stdout.write( `\x1b[2m----------------------\n${data}\n----------------------\x1b[0m\n`, ); } main().catch((err) => { process.stderr.write(`${err}\n`); process.exit(1); });