refactor(artifacts): reconcile workspace artifacts at completion

This commit is contained in:
ZacharyZhang-NY committed 2026-04-24 00:58:07 -04:00
1 parent 2ddc67cc3d
commit fd86fc6668
17 files changed
+114 -436

No files matched your search

@@ -5,6 +5,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
import { RuntimeBridge } from "../../src/main/agent-runtime";
import { AppDatabase } from "../../src/main/database";
import type { CredentialResolver } from "../../src/main/credentials";
import { workerRpcMethodSchema } from "../../src/main/worker/entry/types";
const tempDirs: string[] = [];
@@ -108,42 +109,8 @@ async function createHarness() {
}
describe("artifact projection durable ack", () => {
it("persists afterToolCall projection outcomes to the run event tail", async () => {
const harness = await createHarness();
try {
await mkdir(join(harness.workspacePath, "reports"), { recursive: true });
await writeFile(join(harness.workspacePath, "reports", "hook.md"), "hook artifact", "utf8");
const response = await harness.bridge.handleRpc({
rpcId: "after-tool",
method: "afterToolCall",
runId: harness.runId,
payload: {
toolName: "write",
toolCallId: "tool-call-hook",
args: { path: "reports/hook.md" },
resultContent: [],
resultDetails: null,
isError: false,
},
});
expect(response.ok).toBe(true);
const event = harness.db.core.runs.listRunEvents(harness.runId, harness.companyId)[0];
expect(event).toMatchObject({
eventType: "artifact_projection",
level: "info",
});
expect(event?.payload).toMatchObject({
phase: "after_tool_call",
toolName: "write",
toolCallId: "tool-call-hook",
workspaceMode: "none",
counts: { inserted: 1, updated: 0, retired: 0, skipped: 0 },
});
} finally {
harness.db.close();
}
it("keeps artifact projection out of the per-tool RPC method surface", () => {
expect(workerRpcMethodSchema.safeParse("afterToolCall").success).toBe(false);
});
it("runs completion reconciliation before resource release for non-exclusive observation workspaces", async () => {
@@ -170,6 +137,8 @@ describe("artifact projection durable ack", () => {
workspaceMode: "none",
counts: { inserted: 1, updated: 0, retired: 0, skipped: 0 },
});
expect(events[0]?.payload).not.toHaveProperty("toolName");
expect(events[0]?.payload).not.toHaveProperty("toolCallId");
} finally {
harness.db.close();
}
@@ -62,8 +62,8 @@ describe("pi runtime integration contract", () => {
expect(agent.state.tools).toEqual([]);
expect(agent.state.messages).toEqual([]);
expect(typeof agent.beforeToolCall).toBe("function");
expect(typeof agent.afterToolCall).toBe("function");
expect(typeof agent.transformContext).toBe("function");
expect(agent.afterToolCall).toBeUndefined();
});
it("keeps the coding-tool surface expected by worker runs", () => {
@@ -133,12 +133,10 @@ describe("pi runtime integration contract", () => {
it("keeps the aggregated hook bundle assignable to pi Agent options at runtime", () => {
const hooks = buildAgentHooks({ runId: "run-contract", rpc: createRpc() });
expect(Object.keys(hooks).sort()).toEqual([
"afterToolCall",
"beforeToolCall",
"transformContext",
]);
expect(typeof hooks.beforeToolCall).toBe("function");
expect(typeof hooks.afterToolCall).toBe("function");
expect(typeof hooks.transformContext).toBe("function");
});
});
@@ -5,7 +5,6 @@ import { tmpdir } from "node:os";
import { afterEach, describe, expect, it } from "vitest";
import { AppDatabase } from "../../src/main/database";
import {
projectToolExecutionToWorkProduct,
reconcileWorkspaceArtifacts,
type ArtifactProjectorRunContext,
} from "../../src/main/agent-runtime/artifact-projector";
@@ -237,7 +236,7 @@ describe("work_products archived visibility", () => {
});
describe("work_products bulk retirement", () => {
it("registers bash artifacts from non-exclusive observation workspaces", async () => {
it("registers changed artifacts from non-exclusive observation workspaces", async () => {
const harness = await createHarness();
try {
const ctx: ArtifactProjectorRunContext = {
@@ -257,12 +256,7 @@ describe("work_products bulk retirement", () => {
await mkdir(join(harness.workspacePath, "reports"), { recursive: true });
await writeFile(join(harness.workspacePath, "reports", "non-exclusive.md"), "observed", "utf8");
const outcomes = projectToolExecutionToWorkProduct(harness.db, ctx, {
toolName: "bash",
args: { command: "printf observed > reports/non-exclusive.md" },
result: null,
isError: false,
});
const outcomes = reconcileWorkspaceArtifacts(harness.db, ctx);
expect(outcomes).toEqual([
expect.objectContaining({
@@ -280,6 +274,44 @@ describe("work_products bulk retirement", () => {
}
});
it("registers every changed artifact past the previous 50-path budget", async () => {
const harness = await createHarness();
try {
const paths: string[] = [];
await mkdir(join(harness.workspacePath, "bulk"), { recursive: true });
for (let i = 0; i < 120; i += 1) {
const rel = `bulk/new-${i}.md`;
paths.push(rel);
await writeFile(join(harness.workspacePath, rel), `artifact ${i}`, "utf8");
}
const outcomes = reconcileWorkspaceArtifacts(harness.db, {
runId: harness.runId,
agentId: harness.agentId,
companyId: harness.companyId,
taskId: harness.taskId,
workspaceId: null,
workspacePath: harness.workspacePath,
workspaceMode: "none",
workspaceBaseline: {
mtimeByRelPath: new Map<string, number>(),
capturedAt: Date.now(),
truncated: false,
},
});
expect(outcomes.filter((o) => o.kind === "inserted")).toHaveLength(120);
const visible = new Set(
harness.db.projection.snapshot.listSnapshot().workProducts.map((entry) => entry.externalId),
);
for (const path of paths) {
expect(visible.has(path)).toBe(true);
}
} finally {
harness.db.close();
}
});
it("retires deleted artifacts from non-exclusive observation workspaces", async () => {
const harness = await createHarness();
try {