SPB Git

spb/autoscholar

Public
6.7 KB · 164 lines typescript
1import type { RunManifest } from "@autoscholar/schemas";2import {3  bigint,4  bigserial,5  boolean,6  index,7  integer,8  jsonb,9  numeric,10  pgTable,11  text,12  timestamp,13  uniqueIndex,14  uuid,15} from "drizzle-orm/pg-core";16import { adminUsers } from "./auth.js";17import { projectInstructionVersions, researchProjects } from "./projects.js";18import { computeWorkers } from "./workers.js";1920export const researchRuns = pgTable(21  "research_runs",22  {23    id: uuid("id").primaryKey().defaultRandom(),24    projectId: uuid("project_id")25      .notNull()26      .references(() => researchProjects.id),27    instructionVersionId: uuid("instruction_version_id")28      .notNull()29      .references(() => projectInstructionVersions.id),30    idempotencyKey: text("idempotency_key").notNull(),31    title: text("title").notNull(),32    status: text("status").notNull().default("draft"),33    researchMode: text("research_mode").notNull(),34    secondaryModes: text("secondary_modes").array().notNull().default([]),35    discipline: text("discipline").notNull(),36    computeProfile: text("compute_profile").notNull().default("standard"),37    provider: text("provider").notNull().default("anthropic"),38    model: text("model").notNull(),39    reviewerModel: text("reviewer_model").notNull(),40    maxBudgetUsd: numeric("max_budget_usd", { precision: 10, scale: 2 }).notNull(),41    maxRuntimeMinutes: integer("max_runtime_minutes").notNull(),42    maxAttempts: integer("max_attempts").notNull().default(2),43    autoPublish: boolean("auto_publish").notNull().default(false),44    qualityPolicyVersion: text("quality_policy_version").notNull(),45    manifest: jsonb("manifest").$type<RunManifest>().notNull(),46    manifestSha256: text("manifest_sha256").notNull(),47    currentAttemptNo: integer("current_attempt_no").notNull().default(0),48    currentStage: text("current_stage"),49    fencingToken: bigint("fencing_token", { mode: "number" }).notNull().default(0),50    lastEventSeq: bigint("last_event_seq", { mode: "number" }).notNull().default(0),51    cancelRequested: boolean("cancel_requested").notNull().default(false),52    failureReason: text("failure_reason"),53    totalCostUsd: numeric("total_cost_usd", { precision: 10, scale: 4 }).notNull().default("0"),54    paperId: uuid("paper_id"),55    queuedAt: timestamp("queued_at", { withTimezone: true }),56    startedAt: timestamp("started_at", { withTimezone: true }),57    finishedAt: timestamp("finished_at", { withTimezone: true }),58    createdBy: uuid("created_by").references(() => adminUsers.id),59    createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),60    updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),61  },62  (t) => [63    uniqueIndex("runs_idempotency_uq").on(t.idempotencyKey),64    index("runs_status_idx").on(t.status, t.queuedAt),65    index("runs_project_idx").on(t.projectId),66  ],67);6869export const runAttempts = pgTable(70  "run_attempts",71  {72    id: uuid("id").primaryKey().defaultRandom(),73    runId: uuid("run_id")74      .notNull()75      .references(() => researchRuns.id, { onDelete: "cascade" }),76    attemptNo: integer("attempt_no").notNull(),77    workerId: uuid("worker_id").references(() => computeWorkers.id),78    status: text("status").notNull().default("leased"), // leased | running | completed | failed | cancelled | expired | budget_exceeded | timeout79    fencingToken: bigint("fencing_token", { mode: "number" }).notNull(),80    resumeFromStage: text("resume_from_stage"),81    startedAt: timestamp("started_at", { withTimezone: true }).notNull().defaultNow(),82    endedAt: timestamp("ended_at", { withTimezone: true }),83    error: text("error"),84    costUsd: numeric("cost_usd", { precision: 10, scale: 4 }).notNull().default("0"),85    summary: jsonb("summary").$type<Record<string, unknown>>(),86  },87  (t) => [uniqueIndex("attempts_run_no_uq").on(t.runId, t.attemptNo), index("attempts_run_idx").on(t.runId)],88);8990export const stageExecutions = pgTable(91  "stage_executions",92  {93    id: uuid("id").primaryKey().defaultRandom(),94    runId: uuid("run_id")95      .notNull()96      .references(() => researchRuns.id, { onDelete: "cascade" }),97    attemptId: uuid("attempt_id")98      .notNull()99      .references(() => runAttempts.id, { onDelete: "cascade" }),100    stage: text("stage").notNull(),101    status: text("status").notNull().default("pending"),102    startedAt: timestamp("started_at", { withTimezone: true }).notNull().defaultNow(),103    endedAt: timestamp("ended_at", { withTimezone: true }),104    costUsd: numeric("cost_usd", { precision: 10, scale: 4 }).notNull().default("0"),105    turns: integer("turns").notNull().default(0),106    usage: jsonb("usage").$type<Record<string, unknown>>(),107    error: text("error"),108  },109  (t) => [110    uniqueIndex("stage_exec_attempt_stage_uq").on(t.attemptId, t.stage),111    index("stage_exec_run_idx").on(t.runId),112  ],113);114115export const stageEvents = pgTable(116  "stage_events",117  {118    id: bigserial("id", { mode: "number" }).primaryKey(),119    runId: uuid("run_id")120      .notNull()121      .references(() => researchRuns.id, { onDelete: "cascade" }),122    attemptId: uuid("attempt_id"),123    workerId: uuid("worker_id"),124    seq: bigint("seq", { mode: "number" }).notNull(),125    stage: text("stage"),126    level: text("level").notNull().default("info"),127    kind: text("kind").notNull(),128    message: text("message").notNull(),129    data: jsonb("data").$type<Record<string, unknown>>(),130    at: timestamp("at", { withTimezone: true }).notNull(),131    createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),132  },133  (t) => [uniqueIndex("stage_events_run_seq_uq").on(t.runId, t.seq)],134);135136export const jobLeases = pgTable("job_leases", {137  runId: uuid("run_id")138    .primaryKey()139    .references(() => researchRuns.id, { onDelete: "cascade" }),140  attemptId: uuid("attempt_id").notNull(),141  workerId: uuid("worker_id")142    .notNull()143    .references(() => computeWorkers.id),144  fencingToken: bigint("fencing_token", { mode: "number" }).notNull(),145  acquiredAt: timestamp("acquired_at", { withTimezone: true }).notNull().defaultNow(),146  expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),147  lastHeartbeatAt: timestamp("last_heartbeat_at", { withTimezone: true }).notNull().defaultNow(),148});149150export const checkpoints = pgTable(151  "checkpoints",152  {153    id: uuid("id").primaryKey().defaultRandom(),154    runId: uuid("run_id")155      .notNull()156      .references(() => researchRuns.id, { onDelete: "cascade" }),157    attemptId: uuid("attempt_id").notNull(),158    stage: text("stage").notNull(),159    data: jsonb("data").$type<Record<string, unknown>>().notNull().default({}),160    createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),161  },162  (t) => [index("checkpoints_run_idx").on(t.runId, t.createdAt)],163);164
Files · 87b4e55c3b9fbcc2cd191a1e469b33de0a24ccc8
Menu

Theme