Generate chat, task and learning models from agent-models.json. Use WaterNetwork fast/expert models with 272k context and validate upstream names before readiness. Add an isolated model check command with signal-safe cleanup and plugin, Skill and MCP management docs. Verified in isolation: type checks, 26 focused tests and both model catalog checks; no model inference requests.
52 lines
2.5 KiB
TypeScript
52 lines
2.5 KiB
TypeScript
import { randomBytes } from "node:crypto";
|
|
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { config } from "../src/config.js";
|
|
import { assertModelCheckPassed, modelCheckReportSchema, modelCheckTargets } from "../src/runtime/model-check.js";
|
|
import { serviceOpencodeConfig } from "../src/runtime/opencode2-config.js";
|
|
import { startOpencode2 } from "../src/runtime/opencode2-server.js";
|
|
|
|
// Validate the saved configuration in a fresh OpenCode, without model inference.
|
|
const controller = new AbortController();
|
|
let root: string | undefined;
|
|
let runtime: Awaited<ReturnType<typeof startOpencode2>> | undefined;
|
|
const cancel = (exitCode: number) => {
|
|
if (controller.signal.aborted) return;
|
|
process.exitCode = exitCode;
|
|
controller.abort();
|
|
};
|
|
const onInterrupt = () => cancel(130);
|
|
const onTerminate = () => cancel(143);
|
|
process.on("SIGINT", onInterrupt);
|
|
process.on("SIGTERM", onTerminate);
|
|
try {
|
|
root = await mkdtemp(join(tmpdir(), "tjwater-model-check-"));
|
|
runtime = await startOpencode2({
|
|
command: config.OPENCODE_COMMAND, hostname: "127.0.0.1", port: 0, timeout: 30_000,
|
|
signal: controller.signal,
|
|
config: serviceOpencodeConfig(JSON.parse(await readFile("opencode.json", "utf8")), config.MODEL_CONFIG),
|
|
env: {
|
|
AGENT_INTERNAL_TOKEN: randomBytes(32).toString("hex"), TJWATER_AGENT_WORKSPACE_ROOT: join(root, "workspaces"),
|
|
XDG_DATA_HOME: join(root, "data"), XDG_CONFIG_HOME: join(root, "config"), XDG_CACHE_HOME: join(root, "cache"), XDG_STATE_HOME: join(root, "state"),
|
|
},
|
|
});
|
|
const result = await runtime.client.rpc.call({ rpcID: "tjwater.tools", method: "check_models", input: modelCheckTargets(config.MODEL_CONFIG), location: { directory: process.cwd() } }, { signal: AbortSignal.any([controller.signal, AbortSignal.timeout(30_000)]) });
|
|
const report = modelCheckReportSchema.parse(result.output);
|
|
console.log(JSON.stringify(report, null, 2));
|
|
assertModelCheckPassed(report);
|
|
console.log(`OpenCode model check passed: ${report.models.length} models; no inference requests.`);
|
|
} catch (error) {
|
|
if (controller.signal.aborted) console.error("OpenCode model check cancelled.");
|
|
else {
|
|
console.error(error instanceof Error ? error.message : "OpenCode model check failed");
|
|
process.exitCode = 1;
|
|
}
|
|
} finally {
|
|
runtime?.close();
|
|
if (runtime) await runtime.exited;
|
|
if (root) await rm(root, { recursive: true, force: true });
|
|
process.removeListener("SIGINT", onInterrupt);
|
|
process.removeListener("SIGTERM", onTerminate);
|
|
}
|