Migrate harness from in-memory stores to CloudNativePG
Replace all in-memory Map-backed stores (credentials, models, agents, tasks, iterations, usage) with Drizzle ORM queries against the homelab-pg PostgreSQL cluster. All store functions are now async. - Add 6 harness_* tables to @homelab/db schema - Generate and apply initial Drizzle migration - Add lazy DB connection proxy to avoid build-time errors - Wire DATABASE_URL from sealed secret into harness deployment - Update all API routes, orchestrator, executor, and boot to await async store operations
This commit is contained in:
@@ -1,4 +1,16 @@
|
||||
import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
|
||||
import {
|
||||
pgTable,
|
||||
serial,
|
||||
text,
|
||||
timestamp,
|
||||
boolean,
|
||||
integer,
|
||||
real,
|
||||
jsonb,
|
||||
bigint,
|
||||
} from "drizzle-orm/pg-core";
|
||||
|
||||
// ─── EXISTING ───────────────────────────────────────────────
|
||||
|
||||
export const users = pgTable("users", {
|
||||
id: serial("id").primaryKey(),
|
||||
@@ -7,3 +19,101 @@ export const users = pgTable("users", {
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
// ─── HARNESS: CREDENTIALS ──────────────────────────────────
|
||||
|
||||
export const credentials = pgTable("harness_credentials", {
|
||||
id: text("id").primaryKey(),
|
||||
provider: text("provider").notNull(),
|
||||
label: text("label").notNull(),
|
||||
token: text("token").notNull(),
|
||||
baseUrl: text("base_url"),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
// ─── HARNESS: CURATED MODELS ───────────────────────────────
|
||||
|
||||
export const curatedModels = pgTable("harness_curated_models", {
|
||||
id: text("id").primaryKey(),
|
||||
name: text("name").notNull(),
|
||||
provider: text("provider").notNull(),
|
||||
enabled: boolean("enabled").default(true).notNull(),
|
||||
contextWindow: integer("context_window"),
|
||||
costPer1kInput: real("cost_per_1k_input"),
|
||||
costPer1kOutput: real("cost_per_1k_output"),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
// ─── HARNESS: MODEL USAGE ──────────────────────────────────
|
||||
|
||||
export const modelUsage = pgTable("harness_model_usage", {
|
||||
id: serial("id").primaryKey(),
|
||||
modelId: text("model_id").notNull(),
|
||||
provider: text("provider").notNull(),
|
||||
taskId: text("task_id").notNull(),
|
||||
taskSlug: text("task_slug").notNull(),
|
||||
iteration: integer("iteration").notNull(),
|
||||
inputTokens: integer("input_tokens").notNull(),
|
||||
outputTokens: integer("output_tokens").notNull(),
|
||||
durationMs: integer("duration_ms").notNull(),
|
||||
timestamp: bigint("timestamp", { mode: "number" }).notNull(),
|
||||
});
|
||||
|
||||
// ─── HARNESS: AGENT CONFIGS ────────────────────────────────
|
||||
|
||||
export const agentConfigs = pgTable("harness_agent_configs", {
|
||||
id: text("id").primaryKey(),
|
||||
name: text("name").notNull(),
|
||||
runtime: text("runtime").notNull(), // "claude-code" | "codex" | "opencode"
|
||||
modelId: text("model_id").notNull(),
|
||||
provider: text("provider").notNull(),
|
||||
maxTokens: integer("max_tokens"),
|
||||
env: jsonb("env").$type<Record<string, string>>(),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
// ─── HARNESS: TASKS ────────────────────────────────────────
|
||||
|
||||
export const tasks = pgTable("harness_tasks", {
|
||||
id: text("id").primaryKey(),
|
||||
slug: text("slug").notNull(),
|
||||
goal: text("goal").notNull(),
|
||||
status: text("status").notNull().default("pending"), // pending | running | completed | failed
|
||||
iteration: integer("iteration").notNull().default(0),
|
||||
maxIterations: integer("max_iterations").notNull().default(6),
|
||||
startedAt: bigint("started_at", { mode: "number" }),
|
||||
completedAt: bigint("completed_at", { mode: "number" }),
|
||||
project: text("project").notNull().default("—"),
|
||||
evals: jsonb("evals").$type<Record<string, unknown>>().default({}).notNull(),
|
||||
pr: jsonb("pr").$type<{ number: number; title: string; status: string }>(),
|
||||
spec: jsonb("spec").$type<{
|
||||
slug: string;
|
||||
goal: string;
|
||||
project: string;
|
||||
agentId: string;
|
||||
maxIterations: number;
|
||||
criteria: { label: string; target: string }[];
|
||||
constraints: string[];
|
||||
knowledgeRefs: string[];
|
||||
}>().notNull(),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
// ─── HARNESS: ITERATIONS ───────────────────────────────────
|
||||
|
||||
export const iterations = pgTable("harness_iterations", {
|
||||
id: serial("id").primaryKey(),
|
||||
taskId: text("task_id").notNull(),
|
||||
n: integer("n").notNull(),
|
||||
status: text("status").notNull().default("pending"), // pending | running | passed | failed
|
||||
diagnosis: text("diagnosis"),
|
||||
agentOutput: text("agent_output"),
|
||||
evals: jsonb("evals").$type<Record<string, unknown>>(),
|
||||
diffStats: text("diff_stats"),
|
||||
startedAt: bigint("started_at", { mode: "number" }),
|
||||
completedAt: bigint("completed_at", { mode: "number" }),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user