Extract agent archive projection (#877)

This commit is contained in:
Mohamed Boudra
2026-05-10 07:32:14 +00:00
committed by GitHub
parent ed2a97fda8
commit 183cda2b66
3 changed files with 103 additions and 27 deletions
@@ -0,0 +1,70 @@
import { expect, test } from "vitest";
import { buildArchivedAgentRecord } from "./agent-archive.js";
import type { StoredAgentRecord } from "./agent-storage.js";
const BASE_RECORD: StoredAgentRecord = {
id: "agent-1",
provider: "codex",
cwd: "/workspace/project",
createdAt: "2025-01-01T00:00:00.000Z",
updatedAt: "2025-01-02T00:00:00.000Z",
labels: {},
lastStatus: "idle",
config: null,
};
test("archives a stored agent without changing terminal statuses", () => {
const statuses: Array<StoredAgentRecord["lastStatus"]> = ["idle", "error", "closed"];
for (const status of statuses) {
const archived = buildArchivedAgentRecord(
{ ...BASE_RECORD, lastStatus: status },
{ archivedAt: "2025-01-03T00:00:00.000Z" },
);
expect(archived.lastStatus).toBe(status);
expect(archived.archivedAt).toBe("2025-01-03T00:00:00.000Z");
expect(archived.updatedAt).toBe(BASE_RECORD.updatedAt);
}
});
test("archives busy stored agents as idle", () => {
const statuses: Array<StoredAgentRecord["lastStatus"]> = ["initializing", "running"];
for (const status of statuses) {
const archived = buildArchivedAgentRecord(
{ ...BASE_RECORD, lastStatus: status },
{ archivedAt: "2025-01-03T00:00:00.000Z" },
);
expect(archived.lastStatus).toBe("idle");
}
});
test("clears persisted attention when archiving", () => {
const archived = buildArchivedAgentRecord(
{
...BASE_RECORD,
requiresAttention: true,
attentionReason: "finished",
attentionTimestamp: "2025-01-02T12:00:00.000Z",
},
{ archivedAt: "2025-01-03T00:00:00.000Z" },
);
expect(archived).toMatchObject({
requiresAttention: false,
attentionReason: null,
attentionTimestamp: null,
});
});
test("can stamp updatedAt to the archive timestamp", () => {
const archived = buildArchivedAgentRecord(BASE_RECORD, {
archivedAt: "2025-01-03T00:00:00.000Z",
updatedAt: "2025-01-03T00:00:00.000Z",
});
expect(archived.updatedAt).toBe("2025-01-03T00:00:00.000Z");
});
@@ -0,0 +1,30 @@
import type { StoredAgentRecord } from "./agent-storage.js";
export type ArchivedStoredAgentRecord = StoredAgentRecord & { archivedAt: string };
interface BuildArchivedAgentRecordOptions {
archivedAt?: string;
updatedAt?: string;
}
export function buildArchivedAgentRecord(
record: StoredAgentRecord,
options?: BuildArchivedAgentRecordOptions,
): ArchivedStoredAgentRecord {
const archivedAt = options?.archivedAt ?? new Date().toISOString();
return {
...record,
archivedAt,
updatedAt: options?.updatedAt ?? record.updatedAt,
lastStatus: normalizeArchivedStatus(record.lastStatus),
requiresAttention: false,
attentionReason: null,
attentionTimestamp: null,
};
}
function normalizeArchivedStatus(
status: StoredAgentRecord["lastStatus"],
): StoredAgentRecord["lastStatus"] {
return status === "running" || status === "initializing" ? "idle" : status;
}
@@ -35,6 +35,7 @@ import type {
ListPersistedAgentsOptions,
PersistedAgentDescriptor,
} from "./agent-sdk-types.js";
import { buildArchivedAgentRecord, type ArchivedStoredAgentRecord } from "./agent-archive.js";
import type { StoredAgentRecord, AgentStorage } from "./agent-storage.js";
import {
InMemoryAgentTimelineStore,
@@ -66,7 +67,6 @@ const STORED_AGENT_CAPABILITIES: AgentCapabilityFlags = {
};
type TimeoutResult = "completed" | "timed_out";
type ArchivedStoredAgentRecord = StoredAgentRecord & { archivedAt: string };
interface TimeoutOptions {
operation: Promise<void>;
@@ -1071,19 +1071,7 @@ export class AgentManager {
private async markRecordArchived(record: StoredAgentRecord): Promise<ArchivedStoredAgentRecord> {
const registry = this.requireRegistry();
const archivedAt = new Date().toISOString();
const normalizedStatus =
record.lastStatus === "running" || record.lastStatus === "initializing"
? "idle"
: record.lastStatus;
const archivedRecord: ArchivedStoredAgentRecord = {
...record,
archivedAt,
updatedAt: archivedAt,
lastStatus: normalizedStatus,
requiresAttention: false,
attentionReason: null,
attentionTimestamp: null,
};
const archivedRecord = buildArchivedAgentRecord(record, { archivedAt, updatedAt: archivedAt });
await registry.upsert(archivedRecord);
@@ -1259,19 +1247,7 @@ export class AgentManager {
throw new Error(`Agent not found: ${agentId}`);
}
const normalizedStatus =
record.lastStatus === "running" || record.lastStatus === "initializing"
? "idle"
: record.lastStatus;
const nextRecord: StoredAgentRecord = {
...record,
archivedAt,
lastStatus: normalizedStatus,
requiresAttention: false,
attentionReason: null,
attentionTimestamp: null,
};
const nextRecord = buildArchivedAgentRecord(record, { archivedAt });
await registry.upsert(nextRecord);
await this.archiveNativeSessionBestEffort(record.provider, record.persistence);