实现 v0.1 Postgres durable store 骨架
This commit is contained in:
+44
-14
@@ -3,20 +3,46 @@ import { AgentRunError } from "../common/errors.js";
|
||||
import { newId, nowIso, stableHash } from "../common/validation.js";
|
||||
import { redactJson } from "../common/redaction.js";
|
||||
|
||||
export type MaybePromise<T> = T | Promise<T>;
|
||||
|
||||
export interface StoreHealth extends JsonRecord {
|
||||
adapter: "memory-self-test" | "postgres";
|
||||
ready: boolean;
|
||||
reachable: boolean;
|
||||
migrationReady: boolean;
|
||||
migrationId: string | null;
|
||||
failureKind: FailureKind | null;
|
||||
message: string | null;
|
||||
credentialValuesPrinted: false;
|
||||
}
|
||||
|
||||
export interface AgentRunStore {
|
||||
createRun(input: CreateRunInput): RunRecord;
|
||||
getRun(runId: string): RunRecord;
|
||||
listEvents(runId: string, afterSeq: number, limit: number): RunEvent[];
|
||||
createCommand(runId: string, input: CreateCommandInput): CommandRecord;
|
||||
getCommand(commandId: string): CommandRecord;
|
||||
listCommands(runId: string, afterSeq: number, limit: number): CommandRecord[];
|
||||
registerRunner(input: Partial<RunnerRecord>): RunnerRecord;
|
||||
claimRun(runId: string, runnerId: string, leaseMs: number): RunRecord;
|
||||
heartbeat(runId: string, runnerId: string, leaseMs: number): RunRecord;
|
||||
ackCommand(commandId: string): CommandRecord;
|
||||
appendEvent(runId: string, type: RunEvent["type"], payload: JsonRecord): RunEvent;
|
||||
finishRun(runId: string, result: Pick<BackendTurnResult, "terminalStatus" | "failureKind" | "failureMessage">): RunRecord;
|
||||
backends(): JsonRecord[];
|
||||
health(): MaybePromise<StoreHealth>;
|
||||
createRun(input: CreateRunInput): MaybePromise<RunRecord>;
|
||||
getRun(runId: string): MaybePromise<RunRecord>;
|
||||
listEvents(runId: string, afterSeq: number, limit: number): MaybePromise<RunEvent[]>;
|
||||
createCommand(runId: string, input: CreateCommandInput): MaybePromise<CommandRecord>;
|
||||
getCommand(commandId: string): MaybePromise<CommandRecord>;
|
||||
listCommands(runId: string, afterSeq: number, limit: number): MaybePromise<CommandRecord[]>;
|
||||
registerRunner(input: Partial<RunnerRecord>): MaybePromise<RunnerRecord>;
|
||||
claimRun(runId: string, runnerId: string, leaseMs: number): MaybePromise<RunRecord>;
|
||||
heartbeat(runId: string, runnerId: string, leaseMs: number): MaybePromise<RunRecord>;
|
||||
ackCommand(commandId: string): MaybePromise<CommandRecord>;
|
||||
appendEvent(runId: string, type: RunEvent["type"], payload: JsonRecord): MaybePromise<RunEvent>;
|
||||
finishRun(runId: string, result: Pick<BackendTurnResult, "terminalStatus" | "failureKind" | "failureMessage">): MaybePromise<RunRecord>;
|
||||
backends(): MaybePromise<JsonRecord[]>;
|
||||
close?(): MaybePromise<void>;
|
||||
}
|
||||
|
||||
export async function openAgentRunStoreFromEnv(env: NodeJS.ProcessEnv = process.env): Promise<AgentRunStore> {
|
||||
const databaseUrl = env.DATABASE_URL?.trim();
|
||||
if (databaseUrl) {
|
||||
const { createPostgresAgentRunStore } = await import("./postgres-store.js");
|
||||
return createPostgresAgentRunStore({ connectionString: databaseUrl });
|
||||
}
|
||||
const storeMode = env.AGENTRUN_STORE ?? env.AGENTRUN_MGR_STORE;
|
||||
if (storeMode === "memory") return new MemoryAgentRunStore();
|
||||
throw new AgentRunError("infra-failed", "DATABASE_URL is required for agentrun-mgr live runtime; set AGENTRUN_STORE=memory only for explicit self-test/dev mode", { httpStatus: 503, details: { adapter: "postgres", databaseUrl: "missing", memoryFallback: "disabled" } });
|
||||
}
|
||||
|
||||
export class MemoryAgentRunStore implements AgentRunStore {
|
||||
@@ -25,6 +51,10 @@ export class MemoryAgentRunStore implements AgentRunStore {
|
||||
private readonly eventsByRun = new Map<string, RunEvent[]>();
|
||||
private readonly runners = new Map<string, RunnerRecord>();
|
||||
|
||||
health(): StoreHealth {
|
||||
return { adapter: "memory-self-test", ready: true, reachable: true, migrationReady: true, migrationId: "memory-self-test", failureKind: null, message: null, credentialValuesPrinted: false };
|
||||
}
|
||||
|
||||
createRun(input: CreateRunInput): RunRecord {
|
||||
const at = nowIso();
|
||||
const run: RunRecord = { ...input, id: newId("run"), status: "pending", terminalStatus: null, failureKind: null, failureMessage: null, createdAt: at, updatedAt: at, claimedBy: null, leaseExpiresAt: null };
|
||||
@@ -130,7 +160,7 @@ export class MemoryAgentRunStore implements AgentRunStore {
|
||||
}
|
||||
}
|
||||
|
||||
function statusFromTerminal(terminalStatus: TerminalStatus): RunRecord["status"] {
|
||||
export function statusFromTerminal(terminalStatus: TerminalStatus): RunRecord["status"] {
|
||||
if (terminalStatus === "completed") return "completed";
|
||||
if (terminalStatus === "cancelled") return "cancelled";
|
||||
if (terminalStatus === "blocked") return "blocked";
|
||||
|
||||
Reference in New Issue
Block a user