feat(db): Llm.kind discriminator + virtual-provider lifecycle (v1 Stage 1)
First step of the virtual-LLM feature. A virtual Llm row is one that gets *registered by an mcplocal client* rather than created via \`mcpctl create llm\`. Its inference is relayed back through an SSE control channel to the publishing session (mcpd routes added in Stage 3). The lifecycle fields below let mcpd reap stale rows when the publisher goes away. Schema additions: - enum LlmKind (public | virtual). Default public. - enum LlmStatus (active | inactive | hibernating). Default active. hibernating is reserved for v2 wake-on-demand. - Llm.kind, providerSessionId, lastHeartbeatAt, status, inactiveSince. - @@index([kind, status]) for the GC sweep. - @@index([providerSessionId]) for the reconnect lookup. All existing rows backfill with kind=public/status=active so v1 is purely additive — public LLMs ignore the lifecycle columns entirely. 7 new prisma-level assertions in tests/llm-virtual-schema.test.ts cover: defaults, persisting kind=virtual + lifecycle together, the active→inactive flip, hibernating value, enum rejection, the (kind,status) GC index, the providerSessionId reconnect index. mcpd suite still 801/801 (regenerated client) and typecheck clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -182,21 +182,44 @@ model Secret {
|
||||
// provider API key server-side so credentials never leave the cluster.
|
||||
// Credentials are stored by reference: `apiKeySecret` points at a Secret, and
|
||||
// `apiKeySecretKey` names the key within that secret's data.
|
||||
//
|
||||
// `kind=virtual` rows are *registered by an mcplocal client* (rather than a
|
||||
// human via `mcpctl create llm`). Their inference is relayed back through
|
||||
// the SSE control channel to the publishing mcplocal session. The lifecycle
|
||||
// fields (lastHeartbeatAt, status, inactiveSince) belong to virtual rows;
|
||||
// public rows ignore them.
|
||||
|
||||
enum LlmKind {
|
||||
public // upstream-URL row, mcpd calls directly
|
||||
virtual // mcplocal-registered, inference relayed via SSE control channel
|
||||
}
|
||||
|
||||
enum LlmStatus {
|
||||
active // healthy, accepting requests
|
||||
inactive // publisher went away; row pending 4-h GC
|
||||
hibernating // publisher present but backend asleep — wakes on demand (v2)
|
||||
}
|
||||
|
||||
model Llm {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
type String // anthropic | openai | deepseek | vllm | ollama | gemini-cli
|
||||
model String // e.g. claude-3-5-sonnet-20241022
|
||||
url String @default("") // endpoint (empty for provider default)
|
||||
tier String @default("fast") // fast | heavy
|
||||
description String @default("")
|
||||
apiKeySecretId String? // FK to Secret
|
||||
apiKeySecretKey String? // key inside the Secret's data
|
||||
extraConfig Json @default("{}") // per-type extras
|
||||
version Int @default(1)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
type String // anthropic | openai | deepseek | vllm | ollama | gemini-cli
|
||||
model String // e.g. claude-3-5-sonnet-20241022
|
||||
url String @default("") // endpoint (empty for provider default)
|
||||
tier String @default("fast") // fast | heavy
|
||||
description String @default("")
|
||||
apiKeySecretId String? // FK to Secret
|
||||
apiKeySecretKey String? // key inside the Secret's data
|
||||
extraConfig Json @default("{}") // per-type extras
|
||||
// ── Virtual-provider lifecycle (NULL/default for kind=public) ──
|
||||
kind LlmKind @default(public)
|
||||
providerSessionId String? // mcplocal session that owns this row when virtual
|
||||
lastHeartbeatAt DateTime? // bumped on every publisher heartbeat
|
||||
status LlmStatus @default(active)
|
||||
inactiveSince DateTime? // when status flipped from active; used for 4-h GC
|
||||
version Int @default(1)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
apiKeySecret Secret? @relation(fields: [apiKeySecretId], references: [id], onDelete: SetNull)
|
||||
agents Agent[]
|
||||
@@ -204,6 +227,8 @@ model Llm {
|
||||
@@index([name])
|
||||
@@index([tier])
|
||||
@@index([apiKeySecretId])
|
||||
@@index([kind, status])
|
||||
@@index([providerSessionId])
|
||||
}
|
||||
|
||||
// ── Groups ──
|
||||
|
||||
Reference in New Issue
Block a user