@juspay/neurolink
Version:
Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio
131 lines (130 loc) • 5.41 kB
JavaScript
/**
* Experiment result recording — TSV + optional JSONL.
*/
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
import path from "node:path";
import { logger } from "../utils/logger.js";
import { AutoresearchError } from "./errors.js";
export class ResultRecorder {
config;
tsvPath;
jsonlPath;
constructor(config) {
this.config = config;
this.tsvPath = path.join(config.repoPath, config.resultsPath);
this.jsonlPath = path.join(config.repoPath, ".autoresearch", "runs.jsonl");
}
/** Creates results.tsv with header if it doesn't exist */
async ensureResultsFile() {
if (!existsSync(this.tsvPath)) {
try {
// Ensure parent directory exists (handles custom resultsPath like "artifacts/results.tsv")
const dir = path.dirname(this.tsvPath);
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
// Use the actual metric name in header
const header = `commit\t${this.config.metric.name}\tmemory_gb\tstatus\tdescription`;
writeFileSync(this.tsvPath, header + "\n", "utf-8");
logger.info("[Autoresearch] Created results file", {
path: this.tsvPath,
});
}
catch (error) {
throw AutoresearchError.create("RESULTS_WRITE_FAILED", `Failed to create results file: ${this.tsvPath}`, {
cause: error instanceof Error ? error : undefined,
});
}
}
}
/** Appends one TSV row to results.tsv */
async appendTsv(record) {
await this.ensureResultsFile();
const metricStr = record.metric !== null ? record.metric.toFixed(6) : "N/A";
const memoryStr = record.memoryGb !== null ? record.memoryGb.toFixed(1) : "N/A";
const safeDescription = record.description.replace(/[\t\n\r]/g, " ").trim();
const line = `${record.commit}\t${metricStr}\t${memoryStr}\t${record.status}\t${safeDescription}`;
try {
appendFileSync(this.tsvPath, line + "\n", "utf-8");
logger.debug("[Autoresearch] Appended TSV record", {
commit: record.commit,
status: record.status,
});
}
catch (error) {
throw AutoresearchError.create("RESULTS_WRITE_FAILED", `Failed to append to results file`, {
cause: error instanceof Error ? error : undefined,
});
}
}
/** Appends one JSON line to runs.jsonl */
async appendJsonl(record) {
try {
const dir = path.dirname(this.jsonlPath);
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
appendFileSync(this.jsonlPath, JSON.stringify(record) + "\n", "utf-8");
}
catch (error) {
// JSONL is optional — log warning but don't throw
logger.warn("[Autoresearch] Failed to append JSONL audit entry", {
error: error instanceof Error ? error.message : String(error),
});
}
}
/** Reads all records from results.tsv */
async readAll() {
if (!existsSync(this.tsvPath)) {
return [];
}
try {
const content = readFileSync(this.tsvPath, "utf-8");
const lines = content.trim().split("\n");
if (lines.length <= 1) {
return [];
} // Header only
return lines.slice(1).map((line) => {
const [commit, metricStr, memoryStr, status, ...descParts] = line.split("\t");
return {
commit: commit || "",
metric: metricStr && metricStr !== "N/A" ? parseFloat(metricStr) : null,
memoryGb: memoryStr && memoryStr !== "N/A" ? parseFloat(memoryStr) : null,
status: (status || "crash"),
description: descParts.join("\t"),
timestamp: new Date().toISOString(), // Not stored in TSV, use current
};
});
}
catch {
return [];
}
}
/** Returns summary stats */
async getStats() {
const records = await this.readAll();
const keeps = records.filter((r) => r.status === "keep");
const bestKeep = keeps.reduce((best, r) => {
if (r.metric === null) {
return best;
}
if (best === null || best.metric === null) {
return r;
}
if (this.config.metric.direction === "lower") {
return r.metric < best.metric ? r : best;
}
return r.metric > best.metric ? r : best;
}, null);
return {
total: records.length,
keepCount: keeps.length,
discardCount: records.filter((r) => r.status === "discard").length,
crashCount: records.filter((r) => r.status === "crash").length,
timeoutCount: records.filter((r) => r.status === "timeout").length,
keepRate: records.length > 0 ? keeps.length / records.length : 0,
bestMetric: bestKeep?.metric ?? null,
bestCommit: bestKeep?.commit ?? null,
};
}
}