Files
AgentCompany/tests/unit/runtime-thread-projector.test.ts
T

173 lines
5.5 KiB
TypeScript

import { join } from "node:path";
import { tmpdir } from "node:os";
import { mkdtemp, rm } from "node:fs/promises";
import { afterEach, describe, expect, it } from "vitest";
import { AppDatabase } from "../../src/main/database";
import { RuntimeThreadProjector } from "../../src/main/agent-runtime/runtime-thread-projector";
import { findTaskThread } from "../../src/main/thread-integration/thread-helpers";
const tempDirs: string[] = [];
async function createTempDir(prefix: string): Promise<string> {
const dir = await mkdtemp(join(tmpdir(), prefix));
tempDirs.push(dir);
return dir;
}
afterEach(async () => {
await Promise.all(tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
});
function textMessage(role: string, text: string, timestamp = Date.now()) {
return {
role,
timestamp,
content: [{ type: "text", text }],
};
}
describe("RuntimeThreadProjector", () => {
it("projects assistant messages without internal prompt and tool noise", async () => {
const profileDir = await createTempDir("agentcompany-thread-projector-");
const db = new AppDatabase(profileDir);
db.init();
try {
const companyId = db.core.company.saveCompany({
name: "Thread Co",
description: "Thread projection test",
status: "active",
});
const agentId = db.core.agents.saveAgent({
companyId,
name: "CTO",
role: "CTO",
title: "Chief Technology Officer",
status: "active",
reportsTo: null,
connectorId: "openai-codex",
workspaceId: null,
model: null,
capabilities: "Engineering",
budgetMonthlyUsd: 100,
});
const taskId = db.core.tasks.saveTask({
companyId,
title: "Coordinate launch",
description: "Keep the launch thread readable.",
assigneeAgentId: agentId,
priority: "high",
status: "todo",
});
const projector = new RuntimeThreadProjector({
db,
logger: { warn: () => {} },
resolveAgentName: () => "CTO",
lookupInboundCorrelation: () => null,
});
const envelope = { runId: "run-1", agentId, companyId, taskId };
projector.recordThreadEvent(envelope, textMessage("user", "Internal initial user turn."));
projector.recordThreadEvent(envelope, textMessage("toolResult", "Tool output."));
projector.recordThreadEvent(envelope, {
role: "assistant",
timestamp: Date.now(),
content: [{ type: "toolCall", name: "bash" }],
});
projector.recordThreadEvent(envelope, textMessage("assistant", "Launch owner update sent to Product."));
const thread = findTaskThread(db, taskId, companyId);
if (!thread) throw new Error("Expected task thread to be created.");
const events = db.core.threads.listThreadEvents(thread.id, companyId, { limit: 10 });
expect(events.map((event) => event.body)).toEqual(["Launch owner update sent to Product."]);
expect(events[0].actorId).toBe(agentId);
expect(events[0].actorType).toBe("agent");
expect(events[0].eventType).toBe("message");
} finally {
db.close();
}
});
it("keeps live correlated inbound messages in the thread", async () => {
const profileDir = await createTempDir("agentcompany-thread-inbound-");
const db = new AppDatabase(profileDir);
db.init();
try {
const companyId = db.core.company.saveCompany({
name: "Inbound Co",
description: "Inbound projection test",
status: "active",
});
const agentId = db.core.agents.saveAgent({
companyId,
name: "CEO",
role: "CEO",
title: "Chief Executive Officer",
status: "active",
reportsTo: null,
connectorId: "openai-codex",
workspaceId: null,
model: null,
capabilities: "Leadership",
budgetMonthlyUsd: 100,
});
const peerId = db.core.agents.saveAgent({
companyId,
name: "CTO",
role: "CTO",
title: "Chief Technology Officer",
status: "active",
reportsTo: agentId,
connectorId: "openai-codex",
workspaceId: null,
model: null,
capabilities: "Engineering",
budgetMonthlyUsd: 100,
});
const taskId = db.core.tasks.saveTask({
companyId,
title: "Answer engineering",
description: "Respond in the thread.",
assigneeAgentId: agentId,
priority: "high",
status: "todo",
});
const timestamp = Date.now();
const projector = new RuntimeThreadProjector({
db,
logger: { warn: () => {} },
resolveAgentName: () => "CEO",
lookupInboundCorrelation: () => ({
messageId: "message-1",
fromAgentId: peerId,
senderKind: "agent",
piTimestamp: timestamp,
}),
});
projector.recordThreadEvent(
{ runId: "run-1", agentId, companyId, taskId },
textMessage("user", "Can you approve the deployment?", timestamp),
);
const thread = findTaskThread(db, taskId, companyId);
if (!thread) throw new Error("Expected task thread to be created.");
const events = db.core.threads.listThreadEvents(thread.id, companyId, { limit: 10 });
expect(events).toHaveLength(1);
expect(events[0]).toMatchObject({
actorId: peerId,
actorType: "agent",
eventType: "message",
body: "Can you approve the deployment?",
});
} finally {
db.close();
}
});
});