35 lines
2.1 KiB
TypeScript
35 lines
2.1 KiB
TypeScript
import "server-only";
|
|
import { eq, sql } from "drizzle-orm";
|
|
import { db } from "@/lib/db";
|
|
import { aiModelHealthEvent, systemSettings } from "@/lib/db/schema";
|
|
import { AGENT_MODEL_COOLDOWN_MS, type AgentCircuitStore } from "./agent-model-failover";
|
|
|
|
const prefix = "agent_multimodal_circuit:";
|
|
// PostgreSQL is shared by every process and release. Do not reuse the general
|
|
// image-model health ban (which has a different, two-hour recovery policy).
|
|
export const agentModelCircuitStore: AgentCircuitStore = {
|
|
async isPaused(entry) {
|
|
const [row] = await db.select({ value: systemSettings.value, now: sql<string>`clock_timestamp()` })
|
|
.from(systemSettings).where(eq(systemSettings.key, prefix + entry.model.id)).limit(1);
|
|
const value = row?.value as { pausedUntil?: string } | undefined;
|
|
return Boolean(value?.pausedUntil && Date.parse(value.pausedUntil) > Date.parse(row.now));
|
|
},
|
|
async fail(entry, fault) {
|
|
await db.transaction(async tx => {
|
|
const [{ now }] = await tx.execute<{ now: string }>(sql`select clock_timestamp() as now`);
|
|
const failedAt = new Date(now);
|
|
const pausedUntil = new Date(failedAt.getTime() + AGENT_MODEL_COOLDOWN_MS).toISOString();
|
|
const value = { modelId: entry.model.id, reason: fault.reason, status: fault.status, failedAt: failedAt.toISOString(), pausedUntil };
|
|
await tx.insert(systemSettings).values({ key: prefix + entry.model.id, value, updatedAt: failedAt })
|
|
.onConflictDoUpdate({ target: systemSettings.key, set: { value, updatedAt: failedAt },
|
|
setWhere: sql`${systemSettings.updatedAt} <= ${failedAt.toISOString()}::timestamp` });
|
|
await tx.insert(aiModelHealthEvent).values({
|
|
modelId: entry.model.id, providerId: entry.provider.id, modelRuntimeId: entry.model.modelId,
|
|
modelDisplayName: entry.model.displayName, providerType: entry.provider.type, providerName: entry.provider.name,
|
|
eventType: "agent_circuit_open", severity: "warning", context: "canvas-agent-multimodal",
|
|
counted: false, errorMessage: fault.reason, metadata: { ...value, cooldownMs: AGENT_MODEL_COOLDOWN_MS },
|
|
});
|
|
});
|
|
},
|
|
};
|