feat(agents): add Agent + ChatThread + ChatMessage schema (Stage 1)
Introduces the persistence layer for the upcoming Agent feature: an LLM persona pinned to a specific Llm, optionally attached to a Project, with persisted chat threads/messages so conversations survive REPL exits. Constraint shape: - Agent.llm uses ON DELETE RESTRICT — deleting an Llm in active use fails. - Agent.project uses ON DELETE SET NULL — agents survive project deletion. - ChatThread → ChatMessage cascade so deleting an agent purges its history. - ChatMessage @@unique([threadId, turnIndex]) gives append ordering even under racing writers (services retry on collision). LiteLLM-style per-call overrides will live in Agent.defaultParams (Json); the loose extras Json field is reserved for future LoRA/tool-allowlist work. Pinned vitest fileParallelism=false in @mcpctl/db: all suites share the same Postgres, and adding a second suite exposed FK contention between a clearAllTables in one file and a create in another. Per-test isolation still comes from beforeEach. Tests: 8/8 green in src/db/tests/agent-schema.test.ts (defaults, name uniqueness, llm-in-use Restrict, project-delete SetNull, agent-delete cascade, duplicate (threadId, turnIndex) blocked, tool-call payload round-trip, lastTurnAt DESC ordering). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Agent" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL DEFAULT '',
|
||||
"systemPrompt" TEXT NOT NULL DEFAULT '',
|
||||
"llmId" TEXT NOT NULL,
|
||||
"projectId" TEXT,
|
||||
"proxyModelName" TEXT,
|
||||
"defaultParams" JSONB NOT NULL DEFAULT '{}',
|
||||
"extras" JSONB NOT NULL DEFAULT '{}',
|
||||
"ownerId" TEXT NOT NULL,
|
||||
"version" INTEGER NOT NULL DEFAULT 1,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Agent_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ChatThread" (
|
||||
"id" TEXT NOT NULL,
|
||||
"agentId" TEXT NOT NULL,
|
||||
"ownerId" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL DEFAULT '',
|
||||
"lastTurnAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "ChatThread_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ChatMessage" (
|
||||
"id" TEXT NOT NULL,
|
||||
"threadId" TEXT NOT NULL,
|
||||
"turnIndex" INTEGER NOT NULL,
|
||||
"role" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"toolCalls" JSONB,
|
||||
"toolCallId" TEXT,
|
||||
"status" TEXT NOT NULL DEFAULT 'complete',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "ChatMessage_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Agent_name_key" ON "Agent"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Agent_name_idx" ON "Agent"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Agent_llmId_idx" ON "Agent"("llmId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Agent_projectId_idx" ON "Agent"("projectId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Agent_ownerId_idx" ON "Agent"("ownerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ChatThread_agentId_lastTurnAt_idx" ON "ChatThread"("agentId", "lastTurnAt" DESC);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ChatThread_ownerId_idx" ON "ChatThread"("ownerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ChatMessage_threadId_createdAt_idx" ON "ChatMessage"("threadId", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ChatMessage_threadId_turnIndex_key" ON "ChatMessage"("threadId", "turnIndex");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Agent" ADD CONSTRAINT "Agent_llmId_fkey" FOREIGN KEY ("llmId") REFERENCES "Llm"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Agent" ADD CONSTRAINT "Agent_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Agent" ADD CONSTRAINT "Agent_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ChatThread" ADD CONSTRAINT "ChatThread_agentId_fkey" FOREIGN KEY ("agentId") REFERENCES "Agent"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ChatThread" ADD CONSTRAINT "ChatThread_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ChatMessage" ADD CONSTRAINT "ChatMessage_threadId_fkey" FOREIGN KEY ("threadId") REFERENCES "ChatThread"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
Reference in New Issue
Block a user