@@ -108,3 +112,33 @@ export function ChatThreadPanel({
);
}
+
+function AuditReplay({ events }: { events: AuditEventRecord[] }) {
+ return (
+
+ Audit
+
+ {events.map((event) => (
+
+ {formatTime(event.createdAt)}
+
+ {event.entityType}.{event.action}
+
+
+ ))}
+
+
+ );
+}
diff --git a/AgentCompany-New/src/renderer/src/pages/chat/chat-helpers.ts b/AgentCompany-New/src/renderer/src/pages/chat/chat-helpers.ts
index e5f088d7..77c1c7b1 100644
--- a/AgentCompany-New/src/renderer/src/pages/chat/chat-helpers.ts
+++ b/AgentCompany-New/src/renderer/src/pages/chat/chat-helpers.ts
@@ -1,6 +1,7 @@
import type {
AgentRecord,
ApprovalRecord,
+ AuditEventRecord,
ChatAttachmentRecord,
ChatMessageRecord,
ChatSpaceRecord,
@@ -80,6 +81,33 @@ export function countMessagesIn(spaceId: string, messages: ChatMessageRecord[]):
return messages.filter((message) => message.spaceId === spaceId).length;
}
+export function replayEventsForThread(
+ events: AuditEventRecord[],
+ thread: ChatThreadRecord,
+ messages: ChatMessageRecord[],
+): AuditEventRecord[] {
+ const messageIds = new Set(
+ messages
+ .filter((message) => message.threadId === thread.id || message.id === thread.rootMessageId)
+ .map((message) => message.id),
+ );
+ return events
+ .filter((event) => {
+ if (event.entityType === "chat_message" && messageIds.has(event.entityId)) return true;
+ const payload = auditPayload(event);
+ return payload.threadId === thread.id || payload.sourceThreadId === thread.id;
+ })
+ .sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
+}
+
+function auditPayload(event: AuditEventRecord): Record
{
+ const parsed = JSON.parse(event.payloadJson) as unknown;
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
+ throw new Error("Audit event payload is invalid.");
+ }
+ return parsed as Record;
+}
+
export function formatDay(iso: string): string {
const date = new Date(iso);
if (Number.isNaN(date.getTime())) return "—";
diff --git a/AgentCompany-New/tests/e2e/desktop.spec.ts b/AgentCompany-New/tests/e2e/desktop.spec.ts
index 2a235872..96b1ba37 100644
--- a/AgentCompany-New/tests/e2e/desktop.spec.ts
+++ b/AgentCompany-New/tests/e2e/desktop.spec.ts
@@ -61,6 +61,10 @@ test("onboards, hires, and creates work in the Electron shell", async () => {
await page.getByRole("button", { name: "Send" }).click();
await expect(page.getByText("@Board").first()).toBeVisible();
await expect(page.getByText("/escalate").first()).toBeVisible();
+ await page.getByRole("button", { name: "Open thread" }).first().click();
+ await expect(page.getByText("Audit")).toBeVisible();
+ await expect(page.getByText("chat_message.sent").first()).toBeVisible();
+ await expect(page.getByText("approval.requested").first()).toBeVisible();
await page.getByRole("button", { name: "Approvals" }).click();
await expect(page.getByText("Escalate release").first()).toBeVisible();