179 lines
6.3 KiB
JavaScript
179 lines
6.3 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
AGENT_SESSION_STATUSES,
|
|
WORKER_SESSION_STATUSES,
|
|
advanceAgentSession,
|
|
advanceWorkerSession,
|
|
createAgentRunPlan,
|
|
createSkillsManifest,
|
|
finalizeAgentRun
|
|
} from "./index.mjs";
|
|
import {
|
|
createLocalAgentSession,
|
|
getLocalAgentEvidence,
|
|
getLocalAgentStatus,
|
|
getLocalAgentTrace,
|
|
runLocalWorkerDryRun
|
|
} from "./runtime.mjs";
|
|
|
|
test("agent runtime run plan exposes create/start/trace/finish/cleanup", () => {
|
|
const plan = createAgentRunPlan({
|
|
agentSessionId: "agt_01J00000000000000000000000",
|
|
projectId: "prj_01J00000000000000000000000",
|
|
goal: "verify runtime skeleton",
|
|
prompt: "dry run"
|
|
});
|
|
|
|
assert.deepEqual(AGENT_SESSION_STATUSES, ["create", "start", "trace", "finish", "cleanup"]);
|
|
assert.deepEqual(WORKER_SESSION_STATUSES, ["create", "start", "trace", "finish", "cleanup"]);
|
|
assert.equal(plan.agentSession.status, "start");
|
|
assert.equal(plan.workerSession.status, "start");
|
|
assert.equal(plan.events.map((event) => event.state).join(","), "create,start,trace,finish,cleanup");
|
|
assert.equal(plan.traceEvent.message, "dry run");
|
|
assert.equal(plan.evidenceRecord.projectId, "prj_01J00000000000000000000000");
|
|
assert.equal(plan.evidenceRecord.metadata.workspaceVolumeId, "vol_agt_01J00000000000000000000000");
|
|
});
|
|
|
|
test("finalizeAgentRun marks cleanup and keeps evidence visible", () => {
|
|
const plan = createAgentRunPlan({
|
|
agentSessionId: "agt_01J00000000000000000000001",
|
|
projectId: "prj_01J00000000000000000000001",
|
|
goal: "cleanup coverage"
|
|
});
|
|
const finished = finalizeAgentRun(plan);
|
|
|
|
assert.equal(finished.agentSession.status, "cleanup");
|
|
assert.equal(finished.workerSession.status, "cleanup");
|
|
assert.equal(finished.cleanup.removed, true);
|
|
assert.ok(finished.evidenceRecord.sha256);
|
|
});
|
|
|
|
test("skills manifest requires explicit commitId", () => {
|
|
assert.throws(() => createSkillsManifest({}), /explicit commitId/);
|
|
assert.throws(() => createSkillsManifest({ commitId: "6509a35" }), /explicit version/);
|
|
|
|
const manifest = createSkillsManifest({ commitId: "6509a35", version: "v1" });
|
|
assert.equal(manifest.commitId, "6509a35");
|
|
assert.equal(manifest.version, "v1");
|
|
assert.equal(manifest.services[0].serviceId, "hwlab-agent-skills");
|
|
assert.equal(manifest.services[0].env.HWLAB_SKILLS_VERSION, "v1");
|
|
});
|
|
|
|
test("advance helpers preserve completedAt on non-finish states", () => {
|
|
const session = {
|
|
status: "start",
|
|
completedAt: undefined,
|
|
metadata: {}
|
|
};
|
|
|
|
const agent = advanceAgentSession(session, "trace");
|
|
const worker = advanceWorkerSession(session, "trace");
|
|
|
|
assert.equal(agent.status, "trace");
|
|
assert.equal(worker.status, "trace");
|
|
assert.equal(agent.completedAt, undefined);
|
|
assert.equal(worker.completedAt, undefined);
|
|
});
|
|
|
|
test("local runtime degrades health and evidence when skills fields are missing", async () => {
|
|
const stateDir = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-runtime-missing-"));
|
|
try {
|
|
const created = await createLocalAgentSession({
|
|
stateDir,
|
|
agentSessionId: "agt_runtime_missing_skills",
|
|
projectId: "prj_runtime_missing_skills",
|
|
goal: "verify degraded skills evidence",
|
|
prompt: "missing skills smoke"
|
|
});
|
|
assert.equal(created.health.status, "degraded");
|
|
assert.deepEqual(created.health.skills.manager.missing, ["skillCommitId", "skillVersion"]);
|
|
|
|
const worker = await runLocalWorkerDryRun({
|
|
stateDir,
|
|
agentSessionId: "agt_runtime_missing_skills"
|
|
});
|
|
assert.equal(worker.health.status, "degraded");
|
|
assert.equal(worker.evidenceRecord.metadata.health.status, "degraded");
|
|
assert.deepEqual(worker.evidenceRecord.metadata.health.skills.worker.missing, [
|
|
"skillCommitId",
|
|
"skillVersion"
|
|
]);
|
|
assert.equal(worker.cleanup.removed, true);
|
|
assert.equal(worker.workspace.existsAfterCleanup, false);
|
|
|
|
const evidence = await getLocalAgentEvidence({
|
|
stateDir,
|
|
agentSessionId: "agt_runtime_missing_skills"
|
|
});
|
|
assert.equal(evidence.status, "degraded");
|
|
assert.equal(evidence.evidenceRecords.length, 1);
|
|
} finally {
|
|
await rm(stateDir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("local runtime closes create/status/trace/evidence/cleanup loop", async () => {
|
|
const stateDir = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-runtime-loop-"));
|
|
try {
|
|
const created = await createLocalAgentSession({
|
|
stateDir,
|
|
agentSessionId: "agt_runtime_loop",
|
|
projectId: "prj_runtime_loop",
|
|
goal: "verify local worker bootstrap",
|
|
prompt: "closed loop smoke",
|
|
skillCommitId: "abc1234",
|
|
skillVersion: "v1"
|
|
});
|
|
assert.equal(created.health.status, "ok");
|
|
assert.equal(created.task.status, "queued");
|
|
assert.equal(created.traceCount, 1);
|
|
|
|
const worker = await runLocalWorkerDryRun({
|
|
stateDir,
|
|
agentSessionId: "agt_runtime_loop",
|
|
skillCommitId: "abc1234",
|
|
skillVersion: "v1"
|
|
});
|
|
assert.equal(worker.health.status, "ok");
|
|
assert.equal(worker.agentSession.status, "cleanup");
|
|
assert.equal(worker.workerSession.status, "cleanup");
|
|
assert.equal(worker.task.status, "completed");
|
|
assert.equal(worker.evidenceRecord.metadata.skills.worker.commitId, "abc1234");
|
|
assert.equal(worker.evidenceRecord.metadata.skills.worker.version, "v1");
|
|
assert.equal(worker.workspace.cleaned, true);
|
|
assert.equal(worker.workspace.existsAfterCleanup, false);
|
|
|
|
const status = await getLocalAgentStatus({
|
|
stateDir,
|
|
agentSessionId: "agt_runtime_loop"
|
|
});
|
|
assert.equal(status.health.status, "ok");
|
|
assert.equal(status.evidenceCount, 1);
|
|
assert.equal(status.cleanup.removed, true);
|
|
|
|
const trace = await getLocalAgentTrace({
|
|
stateDir,
|
|
agentSessionId: "agt_runtime_loop"
|
|
});
|
|
assert.deepEqual(
|
|
trace.traceEvents.map((event) => event.metadata.state),
|
|
["create", "start", "trace", "finish", "cleanup"]
|
|
);
|
|
|
|
const evidence = await getLocalAgentEvidence({
|
|
stateDir,
|
|
agentSessionId: "agt_runtime_loop"
|
|
});
|
|
assert.equal(evidence.status, "ok");
|
|
assert.equal(evidence.evidenceRecords[0].kind, "report");
|
|
assert.equal(evidence.evidenceRecords[0].sha256.length, 64);
|
|
} finally {
|
|
await rm(stateDir, { recursive: true, force: true });
|
|
}
|
|
});
|