Menu
popagent
publicLatest change 4565eb356975518dfc0202eab29b56dff51e8f71 - add deterministic agent health validation by AkurAI Build
import { afterEach, describe, expect, test } from "bun:test";
import { mkdir, mkdtemp, readFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import {
CodeIntelligenceService,
OpenCodebaseIndexBackend,
type CodeIndexCall,
type CodeIndexResult,
type CodeIndexSession,
} from "./code-intelligence";
const temporaryPaths: string[] = [];
afterEach(async () => {
await Promise.all(temporaryPaths.splice(0).map((path) => rm(path, { recursive: true, force: true })));
});
function fakeWorkspace(path: string) {
return {
resolveRepository: async (id: string) => ({
workspace: { id, name: id, repositoryPath: ".", createdAt: "", updatedAt: "" },
path,
}),
};
}
function recordingBackend(results: Record<string, string> = {}) {
const batches: Array<{ repositoryPath: string; calls: CodeIndexCall[] }> = [];
return {
batches,
backend: {
execute: async (repositoryPath: string, calls: CodeIndexCall[]): Promise<CodeIndexResult[]> => {
batches.push({ repositoryPath, calls });
return calls.map(({ name }) => ({ text: results[name] ?? `${name} evidence`, isError: false }));
},
},
};
}
describe("CodeIntelligenceService", () => {
test("uses the contained workspace and bounded context operation", async () => {
const { backend, batches } = recordingBackend({ codebase_context: "bounded context" });
const service = new CodeIntelligenceService(fakeWorkspace("/contained/repository"), backend);
await expect(service.codeContext("workspace-a", "browser host policy", 8)).resolves.toEqual({
evidence: "bounded context",
});
expect(batches).toEqual([{
repositoryPath: "/contained/repository",
calls: [{
name: "codebase_context",
arguments: { query: "browser host policy", limit: 8, tokenBudget: 4_000 },
}],
}]);
});
test("combines definition and direct relationship evidence for a symbol", async () => {
const { backend, batches } = recordingBackend({
implementation_lookup: "definition",
call_graph: "graph",
});
const service = new CodeIntelligenceService(fakeWorkspace("/contained/repository"), backend);
await expect(service.symbolContext("workspace-a", "RepositoryBriefService", "src/repo-brief.ts")).resolves.toEqual({
definition: "definition",
callers: "graph",
callees: "graph",
});
expect(batches[0]!.calls).toEqual([
{
name: "implementation_lookup",
arguments: { query: "RepositoryBriefService", limit: 5, directory: "src" },
},
{
name: "call_graph",
arguments: { name: "RepositoryBriefService", direction: "callers", filePath: "src/repo-brief.ts" },
},
{
name: "call_graph",
arguments: { name: "RepositoryBriefService", direction: "callees", filePath: "src/repo-brief.ts" },
},
]);
});
test("uses current changed paths when impact paths are omitted", async () => {
const { backend, batches } = recordingBackend({
codebase_edit_context: "file impact",
pr_impact: "branch impact",
});
const service = new CodeIntelligenceService(
fakeWorkspace("/contained/repository"),
backend,
async () => ["src/api-types.ts", "src/server.ts"],
);
await expect(service.changeImpact("workspace-a", [])).resolves.toEqual({
paths: ["src/api-types.ts", "src/server.ts"],
branchImpact: "branch impact",
files: [
{ path: "src/api-types.ts", evidence: "file impact" },
{ path: "src/server.ts", evidence: "file impact" },
],
unresolved: [],
});
expect(batches[0]!.calls).toEqual([
{
name: "pr_impact",
arguments: { maxDepth: 5, direction: "both", checkConflicts: false },
},
{
name: "codebase_edit_context",
arguments: {
query: "Assess the blast radius and affected tests for changes in src/api-types.ts.",
filePath: "src/api-types.ts",
callerLimit: 8,
calleeLimit: 8,
tokenBudget: 4_000,
},
},
{
name: "codebase_edit_context",
arguments: {
query: "Assess the blast radius and affected tests for changes in src/server.ts.",
filePath: "src/server.ts",
callerLimit: 8,
calleeLimit: 8,
tokenBudget: 4_000,
},
},
]);
});
});
describe("OpenCodebaseIndexBackend", () => {
test("refreshes the local index before queries and keeps index state out of source", async () => {
const repositoryPath = await mkdtemp(join(tmpdir(), "popagent-code-index-"));
temporaryPaths.push(repositoryPath);
await mkdir(join(repositoryPath, ".git", "info"), { recursive: true });
const calls: CodeIndexCall[] = [];
let closed = false;
const session: CodeIndexSession = {
call: async (call) => {
calls.push(call);
return { text: `${call.name} result`, isError: false };
},
close: async () => {
closed = true;
},
};
const dataRoot = await mkdtemp(join(tmpdir(), "popagent-code-index-data-"));
temporaryPaths.push(dataRoot);
const backend = new OpenCodebaseIndexBackend({
dataRoot,
embedding: {
baseUrl: "http://127.0.0.1:8081/v1",
model: "text-embedding-3-small",
dimensions: 1_024,
},
openSession: async () => session,
});
await expect(backend.execute(repositoryPath, [{ name: "codebase_context", arguments: { query: "auth" } }]))
.resolves.toEqual([{ text: "codebase_context result", isError: false }]);
expect(calls).toEqual([
{ name: "index_codebase", arguments: { force: false, estimateOnly: false, verbose: false } },
{ name: "codebase_context", arguments: { query: "auth" } },
]);
expect(closed).toBe(true);
expect(await readFile(join(repositoryPath, ".git", "info", "exclude"), "utf8"))
.toContain("/.codebase-index/");
expect(await Bun.file(join(repositoryPath, ".gitignore")).exists()).toBe(false);
});
});