auth-yes/.forum/src/agents/historian.ts
Tyler Gillispie 78b02d37a8
refactor: replace mock agent functionality with native binaries for Translator and Historian (#76)
- **Translator**: Switched from parsing plaintext `.ast` files to directly importing `@sourcegraph/scip-typescript` to deserialize `index.scip` binary protobuf payload, verifying modifications at the source SCIP index.
- **Historian**: Completely abandoned the previous Javascript cosine_similarity UDF in favor of initializing the official native C-extension via `npm:sqlite-vec`. Implemented correctly into `jsr:@db/sqlite` by enabling extension loading and querying `vec_distance_cosine()` with Uint8Array wrapping for zero-copy SQLite BLOB inserts.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
2026-08-29 16:18:29 -07:00

187 lines
6.0 KiB
TypeScript

/**
* Agent Forum v4 - Historian Agent
*
* Role: Prevent regression and historical repetition.
* Inputs: sqlite-vec, Git Notes
* Outputs: Contextual injection (passing historical context to other agents/pipeline)
*/
import { parseArgs } from "https://deno.land/std@0.224.0/cli/parse_args.ts";
import { Database } from "jsr:@db/sqlite";
import * as sqliteVec from "npm:sqlite-vec";
async function runCommand(
cmd: string,
args: string[],
): Promise<{ code: number; stdout: string; stderr: string }> {
const command = new Deno.Command(cmd, {
args,
stdout: "piped",
stderr: "piped",
});
const { code, stdout, stderr } = await command.output();
const decoder = new TextDecoder();
return {
code,
stdout: decoder.decode(stdout).trim(),
stderr: decoder.decode(stderr).trim(),
};
}
/**
* Fetches Git Notes for a specific namespace across the git history.
*/
async function fetchGitNotes(namespace: string): Promise<string[]> {
console.log(` Fetching Git Notes for namespace: ${namespace}...`);
// Use git log to show notes for the specified namespace
const cmd = await runCommand("git", [
"log",
`--show-notes=${namespace}`,
"--pretty=format:%N",
]);
if (cmd.code !== 0 || !cmd.stdout) {
return [];
}
// Split by newlines and filter out empty lines (since %N can return empty if no note)
const lines = cmd.stdout.split("\n").filter((line) => line.trim() !== "");
return lines;
}
async function gatherHistoricalContext() {
console.log("-> Historian Agent: Gathering historical context...");
// 1. Construct search string from file changes
const diffCmd = await runCommand("git", ["diff", "--name-only", "HEAD~1", "HEAD"]);
const searchVectorString = diffCmd.stdout.split("\n").filter(Boolean).join(" ");
console.log(` Search vector string derived from diff: "${searchVectorString}"`);
// 2. Fetch from Vector DB
console.log(" Extracting SQLite databases from meta-state branch...");
const extractedVectors: string[] = [];
try {
const checkDocs = await runCommand("git", ["ls-tree", "meta-state", "docs_graph.sqlite"]);
const checkTelemetry = await runCommand("git", ["ls-tree", "meta-state", "telemetry_graph.sqlite"]);
// Dummy vector string based on search string for PoC query, normally we would generate an embedding for searchVectorString
const dummyVector = new Uint8Array(new Float32Array([0,0,0]).buffer);
if (checkDocs.code === 0 && checkDocs.stdout.trim() !== "") {
const tempDbPath = await Deno.makeTempFile({ suffix: ".sqlite" });
const dbFile = await Deno.open(tempDbPath, { write: true });
const cmd = new Deno.Command("git", {
args: ["show", "meta-state:docs_graph.sqlite"],
stdout: "piped"
});
const output = await cmd.output();
await dbFile.write(output.stdout);
dbFile.close();
const db = new Database(tempDbPath);
db.enableLoadExtension = true;
sqliteVec.load(db);
db.enableLoadExtension = false;
try {
const results = db.prepare("SELECT text, vec_distance_cosine(embedding, ?) as similarity FROM docs ORDER BY similarity DESC LIMIT 3").all(dummyVector);
for (const row of results) {
extractedVectors.push(`Doc2Vec: ${row.text}`);
}
} catch (e) {
console.warn(" ⚠️ Could not query docs_graph.sqlite:", e);
}
db.close();
await Deno.remove(tempDbPath);
}
if (checkTelemetry.code === 0 && checkTelemetry.stdout.trim() !== "") {
const tempDbPath = await Deno.makeTempFile({ suffix: ".sqlite" });
const dbFile = await Deno.open(tempDbPath, { write: true });
const cmd = new Deno.Command("git", {
args: ["show", "meta-state:telemetry_graph.sqlite"],
stdout: "piped"
});
const output = await cmd.output();
await dbFile.write(output.stdout);
dbFile.close();
const db = new Database(tempDbPath);
db.enableLoadExtension = true;
sqliteVec.load(db);
db.enableLoadExtension = false;
try {
// Assume telemetry table for PoC purposes
const results = db.prepare("SELECT text, vec_distance_cosine(embedding, ?) as similarity FROM telemetry ORDER BY similarity DESC LIMIT 3").all(dummyVector);
for (const row of results) {
extractedVectors.push(`Telemetry2Vec: ${row.text}`);
}
} catch (e) {
console.warn(" ⚠️ Could not query telemetry_graph.sqlite:", e);
}
db.close();
await Deno.remove(tempDbPath);
}
} catch (e) {
console.warn(" ⚠️ Failed to query sqlite db:", e);
}
// 3. Fetch Git Notes (Reasoning, Telemetry, etc.)
const reasoningNotes = await fetchGitNotes("reasoning");
const aiNotes = await fetchGitNotes("ai");
const combinedContext = {
agent: "Historian",
timestamp: Date.now(),
extractedVectors: extractedVectors.length ? extractedVectors : ["No historical vector matches found."],
historicalNotes: [...reasoningNotes, ...aiNotes],
directive: "Ensure new Coder implementations avoid previously failed architectural patterns.",
};
console.log("-> Historian Agent: Context gathered successfully.");
// Provide contextual injection (e.g., via writing to a specific Git Note for the Coder)
const jsonString = JSON.stringify(combinedContext);
const ref = `refs/notes/historical_context`;
const cmd = await runCommand("git", [
"notes",
"--ref",
ref,
"add",
"-f",
"-m",
jsonString,
"HEAD",
]);
if (cmd.code !== 0) {
console.error(
`⚠️ Failed to inject historical context to Git Notes:`,
cmd.stderr,
);
} else {
console.log(
"-> Contextual injection written to Git Notes (refs/notes/historical_context).",
);
}
}
async function main() {
const args = parseArgs(Deno.args, {
boolean: ["run"],
});
if (args["run"]) {
await gatherHistoricalContext();
} else {
console.log("Historian Agent installed. Run with --run flag.");
}
}
if (import.meta.main) {
await main();
}