diff --git a/.changeset/tame-agent-inference-loops.md b/.changeset/tame-agent-inference-loops.md new file mode 100644 index 0000000000..946c23c056 --- /dev/null +++ b/.changeset/tame-agent-inference-loops.md @@ -0,0 +1,11 @@ +--- +'@roomote/api': patch +'@roomote/worker': patch +'@roomote/web': patch +'@roomote/cloud-agents': patch +'@roomote/db': patch +'@roomote/sdk': patch +'@roomote/types': patch +--- + +Stop repeated identical tool-call loops and bound subagent passes. Enforce a durable task-wide inference request ceiling before dispatch, retain partial work, and save a visible safety notice without requiring another model response. diff --git a/apps/api/src/handlers/inference/__tests__/inference-gateway.test.ts b/apps/api/src/handlers/inference/__tests__/inference-gateway.test.ts index dad3b31787..553b138b67 100644 --- a/apps/api/src/handlers/inference/__tests__/inference-gateway.test.ts +++ b/apps/api/src/handlers/inference/__tests__/inference-gateway.test.ts @@ -22,6 +22,7 @@ const { mockGetGitHubCopilotAccessToken, mockGetFreshXaiAccessToken, mockRecordLlmUsage, + mockAdmitTaskInferenceRequest, } = vi.hoisted(() => ({ mockFindTaskRun: vi.fn(), mockResolveModelProviderEnvValue: vi.fn(), @@ -29,6 +30,7 @@ const { mockGetGitHubCopilotAccessToken: vi.fn(), mockGetFreshXaiAccessToken: vi.fn(), mockRecordLlmUsage: vi.fn(), + mockAdmitTaskInferenceRequest: vi.fn().mockResolvedValue(true), })); vi.mock('@roomote/db/server', () => ({ @@ -45,6 +47,7 @@ vi.mock('@roomote/db/server', () => ({ }, }, taskRuns: { id: 'id' }, + admitTaskInferenceRequest: mockAdmitTaskInferenceRequest, isDeploymentExperimentEnabled: vi.fn().mockResolvedValue(true), eq: vi.fn((column: unknown, value: unknown) => ({ column, value })), resolveModelProviderEnvValue: mockResolveModelProviderEnvValue, @@ -141,7 +144,8 @@ describe('inference gateway', () => { // The Roomote trial key resolution is cached with a TTL; drop it so each // test observes its own mockResolveModelProviderEnvValue behavior. resetRoomoteInferenceKeyCache(); - mockFindTaskRun.mockResolvedValue({ id: 42 }); + mockFindTaskRun.mockResolvedValue({ id: 42, taskId: 'task-42' }); + mockAdmitTaskInferenceRequest.mockResolvedValue(true); mockGetGitHubCopilotAccessToken.mockResolvedValue(null); mockGetFreshXaiAccessToken.mockResolvedValue(null); mockResolveModelProviderEnvValue.mockImplementation( @@ -170,6 +174,27 @@ describe('inference gateway', () => { expect(fetchMock).not.toHaveBeenCalled(); }); + it('refuses dispatch after durable admission is exhausted, independent of provider usage', async () => { + const fetchMock = stubUpstreamFetch(); + mockAdmitTaskInferenceRequest.mockResolvedValue(false); + const response = await postMessages(createApp(createRunToken())); + expect(response.status).toBe(400); + expect(await response.json()).toMatchObject({ + error: { code: 'roomote_agent_safety_stop' }, + }); + expect(mockAdmitTaskInferenceRequest).toHaveBeenCalledWith('task-42', 42); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + it('fails closed if durable admission is unavailable', async () => { + const fetchMock = stubUpstreamFetch(); + mockAdmitTaskInferenceRequest.mockRejectedValueOnce( + new Error('database unavailable'), + ); + expect((await postMessages(createApp(createRunToken()))).status).toBe(502); + expect(fetchMock).not.toHaveBeenCalled(); + }); + it('reports the local dev-login placeholder without contacting an upstream', async () => { const fetchMock = stubUpstreamFetch(); mockResolveModelProviderEnvValue.mockRejectedValueOnce( @@ -1593,7 +1618,10 @@ describe('Jevgrep gateway', () => { headers: { 'content-type': 'application/json' }, body: JSON.stringify(body), }); - beforeEach(() => mockFindTaskRun.mockResolvedValue({ id: 42 })); + beforeEach(() => { + mockFindTaskRun.mockResolvedValue({ id: 42, taskId: 'task-42' }); + mockAdmitTaskInferenceRequest.mockResolvedValue(true); + }); it('requires run authentication before accepting source', async () => { expect((await post(createUserToken())).status).toBe(403); diff --git a/apps/api/src/handlers/inference/index.ts b/apps/api/src/handlers/inference/index.ts index a282fa1442..81e434e04e 100644 --- a/apps/api/src/handlers/inference/index.ts +++ b/apps/api/src/handlers/inference/index.ts @@ -6,12 +6,15 @@ import { formatSingleLineLog, rebaseRoomoteModelIdToUpstream, ROOMOTE_INFERENCE_PROVIDER_ID, + AGENT_SAFETY_STOP_CODE, + AGENT_SAFETY_STOP_TEXT, } from '@roomote/types'; import { db, DevLoginInferencePlaceholderError, eq, taskRuns, + admitTaskInferenceRequest, } from '@roomote/db/server'; import { recordLlmUsage } from '@roomote/sdk/server'; @@ -362,7 +365,7 @@ inference.on(['POST', 'GET'], '/:provider/*', async (c) => { } const taskRun = await db.query.taskRuns.findFirst({ - columns: { id: true }, + columns: { id: true, taskId: true }, where: eq(taskRuns.id, auth.runId), }); @@ -383,6 +386,21 @@ inference.on(['POST', 'GET'], '/:provider/*', async (c) => { } catch { return c.json({ error: 'Invalid JSON' }, 400); } + if ( + !taskRun.taskId || + !(await admitTaskInferenceRequest(taskRun.taskId, auth.runId)) + ) { + return c.json( + { + error: { + code: AGENT_SAFETY_STOP_CODE, + message: AGENT_SAFETY_STOP_TEXT, + type: 'invalid_request_error', + }, + }, + 400, + ); + } return evaluateJevgrepRequest(body); } @@ -480,6 +498,24 @@ inference.on(['POST', 'GET'], '/:provider/*', async (c) => { } try { + // GET catalog/metadata reads are free; every POST attempt (including failed + // requests and provider retries) consumes one durable admission before fetch. + if ( + method === 'POST' && + (!taskRun.taskId || + !(await admitTaskInferenceRequest(taskRun.taskId, auth.runId))) + ) { + return c.json( + { + error: { + code: AGENT_SAFETY_STOP_CODE, + message: AGENT_SAFETY_STOP_TEXT, + type: 'invalid_request_error', + }, + }, + 400, + ); + } const upstreamResponse = await fetchWithLongLivedStreamDispatcher( upstreamUrl, { diff --git a/apps/docs/cost-analytics.mdx b/apps/docs/cost-analytics.mdx index c7d2fdf0b2..dc50b77628 100644 --- a/apps/docs/cost-analytics.mdx +++ b/apps/docs/cost-analytics.mdx @@ -53,6 +53,20 @@ you intend to share or analyze elsewhere. ## Reading the results +### Execution limits and financial caps + +Tasks have [finite safety limits](/tasks#safety-stops-for-repeated-activity), +including a 1,000-request lifetime ceiling enforced before managed inference +dispatch. A provider attempt consumes an allowance even if the request fails +or reports no usage or price. Concurrent children and resumed runs share it. + +This is not a hard monetary cap. Models have different request prices, provider +usage can arrive late or be missing, and requests already admitted can still +be billed. The Costs view is accounting, not pre-dispatch dollar reservation. +Configure provider-side spending limits when a fixed financial ceiling is +required. External services called by tools or user scripts can have their own +charges outside Roomote's managed inference boundary. + Cost Analytics records inference usage reported by the configured model providers. It is separate from [Privacy](/privacy): cost data stays inside your deployment for your team to review, while anonymous diff --git a/apps/docs/tasks.mdx b/apps/docs/tasks.mdx index d16ffebb5b..4f12af3249 100644 --- a/apps/docs/tasks.mdx +++ b/apps/docs/tasks.mdx @@ -100,6 +100,38 @@ environment. Review or change those values before starting it. This creates a new task instead of retrying the failed task, and attachments are not copied, so reattach any files the new task needs. +## Safety stops for repeated activity + +Roomote stops a task when an agent repeats an identical completed tool call +with the same arguments and result five times in succession. Empty search +results count. Changed arguments or results reset the repetition streak; +duplicate streaming updates for one invocation do not count as more calls. +The read-only task-update polling tool has a larger, finite allowance of 20 +identical completions. Shell commands and search tools have no polling exception. + +Subagent passes, including review, judge, explore, and custom subagents, also +stop at 100 model steps, 200 completed tools, or 20 minutes. Activity does not +extend the deadline. The main task also has repetition and completed-tool +protection. A task has a lifetime ceiling of 1,000 admitted provider requests, +shared across its models, children, retries, and resumed runs. Unknown prices +do not disable that request ceiling. + +A safety stop cancels the task's agent tree instead of asking the parent agent +to retry the stopped pass. A notice is saved in the task and its owning session, +when there is one, without needing another model response. Refresh the history +if a notice has not appeared in an already-open view. Partial work is retained; +an interrupted review must not be treated as a clean review. An already-admitted +provider request can still finish and incur cost while cancellation settles. + +Automatic retry, model fallback, restart, and resume do not reset a stopped +task's admission state. Inspect the partial work and the stop reason before +explicitly starting a new task with a narrower request. There is no automatic +budget reset or in-product allowance-extension control. + +These are request and execution bounds, not a dollar spending limit. Use your +inference provider's own billing controls for a financial cap; see +[Cost analytics](/cost-analytics). + ## Task view The task view gives you the working context for a run: diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/hooks/services/__tests__/acp-protocol-service.client.test.ts b/apps/web/src/app/(sandbox)/task/[taskId]/hooks/services/__tests__/acp-protocol-service.client.test.ts index fbcea19050..9426ae5461 100644 --- a/apps/web/src/app/(sandbox)/task/[taskId]/hooks/services/__tests__/acp-protocol-service.client.test.ts +++ b/apps/web/src/app/(sandbox)/task/[taskId]/hooks/services/__tests__/acp-protocol-service.client.test.ts @@ -82,6 +82,32 @@ function subagentActivityUpdate( } describe('AcpProtocolService', () => { + it('renders durable safety notices on history reload without requiring a live model event', () => { + const service = new AcpProtocolService(); + const event = { + ...assistantChunk('Stopped at a safety limit. Review partial work.', 1), + eventType: ACP_ENVELOPE_EVENT_TYPES.AgentSafetyStop, + }; + const history = service.loadAcpEnvelopes([ + { + ...event, + taskId: 'task-1', + createdAt: event.ts, + sequence: 0, + protocol: 'roomote_runtime', + userId: null, + userName: null, + userEmail: null, + userImageUrl: null, + }, + ]); + expect(history.acpMessages).toHaveLength(1); + expect(history.acpMessages[0]).toMatchObject({ + kind: 'text', + text: event.text, + role: 'assistant', + }); + }); describe.each(['live', 'history'] as const)('%s tool replay', (mode) => { it.each([ { diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/hooks/services/acp-protocol-service.ts b/apps/web/src/app/(sandbox)/task/[taskId]/hooks/services/acp-protocol-service.ts index 4439333813..b60ff56f26 100644 --- a/apps/web/src/app/(sandbox)/task/[taskId]/hooks/services/acp-protocol-service.ts +++ b/apps/web/src/app/(sandbox)/task/[taskId]/hooks/services/acp-protocol-service.ts @@ -1845,6 +1845,7 @@ export class AcpProtocolService { if ( envelope.eventType === ACP_ENVELOPE_EVENT_TYPES.UserPrompt || envelope.eventType === ACP_ENVELOPE_EVENT_TYPES.AssistantMessage || + envelope.eventType === ACP_ENVELOPE_EVENT_TYPES.AgentSafetyStop || envelope.eventType === ACP_ENVELOPE_EVENT_TYPES.AssistantThought ) { const message = toAcpUiMessage(envelope); diff --git a/apps/worker/src/sandbox-server/lib/harnesses/__tests__/opencode-server-subagent-watchdog.test.ts b/apps/worker/src/sandbox-server/lib/harnesses/__tests__/opencode-server-subagent-watchdog.test.ts index a64e0e6a41..4b01cb8f22 100644 --- a/apps/worker/src/sandbox-server/lib/harnesses/__tests__/opencode-server-subagent-watchdog.test.ts +++ b/apps/worker/src/sandbox-server/lib/harnesses/__tests__/opencode-server-subagent-watchdog.test.ts @@ -1,5 +1,6 @@ import { ACP_ENVELOPE_EVENT_TYPES, + AGENT_SAFETY, TaskEventName, type AcpPersistedEnvelope, type TaskEvent, @@ -15,8 +16,7 @@ import type { } from '../opencode-server/types'; const TEST_OPENCODE_MODEL = 'test-provider/main-model'; -// Far beyond any plausible run length: subagent runs are not time-bounded, so -// nothing may abort even at this horizon. +// Legacy subtask markers without a running child do not start an execution pass. const SIX_HOURS_MS = 6 * 60 * 60_000; class FakeOpenCodeServerClient { @@ -240,12 +240,272 @@ describe('OpenCode subagent run tracking', () => { vi.useRealTimers(); }); - it('never aborts a foreground child, no matter how long it runs', async () => { + it.each(['judge', 'explore', 'general', 'code-review'])( + 'stops repeated empty grep in %s, releases the parent, and suppresses late retries', + async (agent) => { + const client = new FakeOpenCodeServerClient(); + const onSafetyStop = vi.fn(async () => undefined); + const harness = new OpenCodeServerHarness({ + client: client as unknown as OpenCodeServerClient, + workspacePath: '/tmp/workspace', + logger: createLogger(), + model: TEST_OPENCODE_MODEL, + onSafetyStop, + }); + const events: TaskEvent[] = []; + harness.on('taskEvent', (event) => events.push(event)); + try { + await connectHarness(harness, client); + await armSpawn(client, harness); + await client.emit({ + type: 'message.part.updated', + properties: { + part: createTaskToolPart({ + input: { subagent_type: agent }, + metadata: { sessionId: 'ses_child_1' }, + }), + }, + }); + await client.emit({ + type: 'session.created', + properties: { + info: { id: 'ses_grandchild', parentID: 'ses_child_1' }, + }, + }); + for (let index = 0; index < 1_000; index++) { + const part = { + ...createChildToolPart({ + callId: `grep-${index}`, + tool: 'grep', + status: 'completed', + }), + state: { + status: 'completed', + input: { pattern: 'missing-snapshot' }, + output: '', + }, + }; + await client.emit({ + type: 'message.part.updated', + properties: { part }, + }); + } + expect(onSafetyStop).toHaveBeenCalledExactlyOnceWith( + 'identical_tool_loop', + expect.objectContaining({ + sessionId: 'ses_child_1', + completedTools: 5, + identicalCompletions: 5, + }), + ); + expect( + new Set(client.abort.mock.calls.map(([call]) => call.sessionId)), + ).toEqual(new Set(['ses_1', 'ses_child_1', 'ses_grandchild'])); + expect( + events.filter( + (event) => event.eventName === TaskEventName.TaskAborted, + ), + ).toHaveLength(1); + await client.emit({ + type: 'session.created', + properties: { info: { id: 'late-child', parentID: 'ses_child_1' } }, + }); + expect(client.abort).toHaveBeenCalledWith( + expect.objectContaining({ sessionId: 'late-child' }), + ); + await client.emit({ + type: 'session.status', + properties: { + sessionID: 'ses_1', + status: { type: 'retry', attempt: 1, message: 'temporary error' }, + }, + }); + await client.emit({ + type: 'session.idle', + properties: { sessionID: 'ses_1' }, + }); + expect(client.promptAsync).toHaveBeenCalledTimes(1); + expect( + harness.sendCommand({ + commandName: TaskCommandName.SendMessage, + data: { text: 'continue' }, + }), + ).toBe(false); + } finally { + harness.dispose(); + } + }, + ); + + it('ignores duplicate completed events and allows changed results', async () => { + const { client, harness } = createHarness(); + try { + await connectHarness(harness, client); + await armSpawn(client, harness); + for (let index = 0; index < 20; index++) { + const part = { + ...createChildToolPart({ + callId: `grep-${Math.floor(index / 2)}`, + tool: 'grep', + status: 'completed', + }), + state: { + status: 'completed', + input: {}, + output: String(Math.floor(index / 2)), + }, + }; + await client.emit({ + type: 'message.part.updated', + properties: { part }, + }); + } + expect(client.abort).not.toHaveBeenCalled(); + } finally { + harness.dispose(); + } + }); + + it('releases the task even when durable stop delivery and child abort requests fail', async () => { + const client = new FakeOpenCodeServerClient(); + client.abort.mockRejectedValue(new Error('server unavailable')); + const harness = new OpenCodeServerHarness({ + client: client as unknown as OpenCodeServerClient, + workspacePath: '/tmp/workspace', + logger: createLogger(), + model: TEST_OPENCODE_MODEL, + onSafetyStop: vi.fn().mockRejectedValue(new Error('API unavailable')), + }); + const events: TaskEvent[] = []; + harness.on('taskEvent', (event) => events.push(event)); + try { + await connectHarness(harness, client); + await armSpawn(client, harness); + for (let index = 0; index < 5; index++) + await client.emit({ + type: 'message.part.updated', + properties: { + part: { + ...createChildToolPart({ + callId: String(index), + tool: 'grep', + status: 'completed', + }), + state: { status: 'completed', input: {}, output: '' }, + }, + }, + }); + expect( + events.filter((event) => event.eventName === TaskEventName.TaskAborted), + ).toHaveLength(1); + expect(client.abort).toHaveBeenCalledTimes(2); + expect(client.promptAsync).toHaveBeenCalledTimes(1); + } finally { + harness.dispose(); + } + }); + + it('does not re-arm completed passes from late duplicate task and child events', async () => { + vi.useFakeTimers(); + const { client, harness } = createHarness(); + try { + await connectHarness(harness, client); + await armSpawn(client, harness); + const complete = { + type: 'message.part.updated', + properties: { + part: createTaskToolPart({ + status: 'completed', + metadata: { sessionId: 'ses_child_1' }, + }), + }, + }; + await client.emit(complete); + await client.emit({ + type: 'session.idle', + properties: { sessionID: 'ses_1' }, + }); + await client.emit(complete); + await client.emit({ + type: 'session.updated', + properties: { info: { id: 'ses_child_1', parentID: 'ses_1' } }, + }); + await client.emit({ + type: 'message.part.updated', + properties: { + part: createChildToolPart({ callId: 'old', status: 'completed' }), + }, + }); + await vi.advanceTimersByTimeAsync(AGENT_SAFETY.passTimeoutMs + 1_000); + expect(client.abort).not.toHaveBeenCalled(); + } finally { + harness.dispose(); + } + }); + + it('does not extend an older pass deadline when a sibling starts or child progress arrives', async () => { + vi.useFakeTimers(); + const { client, harness } = createHarness(); + try { + await connectHarness(harness, client); + await armSpawn(client, harness); + await vi.advanceTimersByTimeAsync(AGENT_SAFETY.passTimeoutMs / 2); + await client.emit({ + type: 'message.part.updated', + properties: { + part: createTaskToolPart({ + callId: 'second-spawn', + metadata: { sessionId: 'ses_child_2' }, + }), + }, + }); + await client.emit({ + type: 'message.part.updated', + properties: { + part: createChildToolPart({ callId: 'useful-progress' }), + }, + }); + await vi.advanceTimersByTimeAsync(AGENT_SAFETY.passTimeoutMs / 2 + 1_000); + expect(client.abort).toHaveBeenCalledWith( + expect.objectContaining({ sessionId: 'ses_1' }), + ); + } finally { + harness.dispose(); + } + }); + + it('caps unique model steps even without tool calls', async () => { + const { client, harness } = createHarness(); + try { + await connectHarness(harness, client); + await armSpawn(client, harness); + for (let index = 0; index < 100; index++) { + await client.emit({ + type: 'message.updated', + properties: { + info: { + id: `step-${index}`, + sessionID: 'ses_child_1', + role: 'assistant', + time: { created: Date.now() }, + }, + }, + }); + } + expect(client.abort).toHaveBeenCalledWith( + expect.objectContaining({ sessionId: 'ses_1' }), + ); + } finally { + harness.dispose(); + } + }); + + it('bounds a foreground child independently of activity', async () => { + vi.useFakeTimers(); const { client, harness } = createHarness(); try { await connectHarness(harness, client); - vi.useFakeTimers(); await client.emit({ type: 'message.part.updated', @@ -256,42 +516,44 @@ describe('OpenCode subagent run tracking', () => { }), }, }); - await vi.advanceTimersByTimeAsync(SIX_HOURS_MS); + await vi.advanceTimersByTimeAsync(AGENT_SAFETY.passTimeoutMs + 1_000); - expect(client.abort).not.toHaveBeenCalled(); + expect(client.abort).toHaveBeenCalledWith( + expect.objectContaining({ sessionId: 'ses_child_1' }), + ); expect(client.children).not.toHaveBeenCalled(); } finally { harness.dispose(); } }); - it('never aborts a spawn whose child session id is unknown', async () => { + it('bounds a spawn even before its child session id arrives', async () => { + vi.useFakeTimers(); const { client, harness } = createHarness(); try { await connectHarness(harness, client); - vi.useFakeTimers(); await client.emit({ type: 'message.part.updated', properties: { part: createTaskToolPart({ status: 'pending' }) }, }); - await vi.advanceTimersByTimeAsync(SIX_HOURS_MS); + await vi.advanceTimersByTimeAsync(AGENT_SAFETY.passTimeoutMs + 1_000); - expect(client.abort).not.toHaveBeenCalled(); + expect(client.abort).toHaveBeenCalled(); expect(client.children).not.toHaveBeenCalled(); } finally { harness.dispose(); } }); - it('never aborts a child that goes silent between tools', async () => { + it('bounds a child that goes silent between tools', async () => { + vi.useFakeTimers(); const { client, harness } = createHarness(); try { await connectHarness(harness, client); - vi.useFakeTimers(); await armSpawn(client, harness); await client.emit({ @@ -307,11 +569,11 @@ describe('OpenCode subagent run tracking', () => { }, }); - // Silence after the completed tool: a reasoning model may think for a - // long stretch without emitting any events. Nothing may kill it. - await vi.advanceTimersByTimeAsync(SIX_HOURS_MS); + await vi.advanceTimersByTimeAsync(AGENT_SAFETY.passTimeoutMs + 1_000); - expect(client.abort).not.toHaveBeenCalled(); + expect(client.abort).toHaveBeenCalledWith( + expect.objectContaining({ sessionId: 'ses_child_1' }), + ); expect(client.children).not.toHaveBeenCalled(); } finally { await harness.dispose(); diff --git a/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/harness.ts b/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/harness.ts index 1097b5dae4..2b0e7a7830 100644 --- a/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/harness.ts +++ b/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/harness.ts @@ -1,4 +1,5 @@ import EventEmitter from 'node:events'; +import { createHash } from 'node:crypto'; import fs from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; @@ -6,6 +7,12 @@ import { spawnSync } from 'node:child_process'; import { asBoolean, + AGENT_SAFETY_STOP_TEXT, + AgentSafetyPass, + AGENT_SAFETY, + isAgentSafetyStop, + type AgentSafetyReason, + type AgentSafetyStopDetails, asFiniteNumber, asRecord, asString, @@ -124,6 +131,10 @@ import { } from '../../../../run-task/opencode-model'; interface OpenCodeServerHarnessOptions { + onSafetyStop?: ( + reason: AgentSafetyReason, + details: AgentSafetyStopDetails, + ) => Promise; client: OpenCodeServerClient; workspacePath: string; logger: { @@ -290,7 +301,7 @@ interface ActiveOpenCodeExecuteToolProgress { timer: ReturnType; } -// Tracks a live subagent spawn. Subagent runs are not time-bounded: the only +// Tracks a live subagent spawn. AgentSafetyPass independently bounds live work; // terminal signals are the task tool part settling, the child session going // idle (background launches), or parent-turn teardown. This tracker exists to // route child-session events — live activity folded into the spawn row, @@ -1639,6 +1650,13 @@ export class OpenCodeServerHarness implements Harness { private readonly client: OpenCodeServerClient; + private readonly safetyPasses = new Map(); + private readonly onSafetyStop: OpenCodeServerHarnessOptions['onSafetyStop']; + private readonly safetyTimer: ReturnType; + private safetyStopped = false; + private readonly safetyStoppedSessionIds = new Set(); + private readonly settledSafetySessions = new Set(); + private readonly settledSubagentWatchdogKeys = new Set(); private readonly workspacePath: string; private readonly normalizedWorkspacePath: string; private readonly logger: OpenCodeServerHarnessOptions['logger']; @@ -1835,6 +1853,25 @@ export class OpenCodeServerHarness this.fallbackReasoningEffort = options.fallbackReasoningEffort; this.fallbackRole = options.fallbackRole; this.agentFallbacks = options.agentFallbacks ?? {}; + this.onSafetyStop = options.onSafetyStop; + this.safetyTimer = setInterval(() => { + for (const watchdog of this.activeSubagentWatchdogs.values()) { + if (Date.now() - watchdog.startedAtMs >= AGENT_SAFETY.passTimeoutMs) { + void this.stopForSafety( + 'pass_time_limit', + watchdog.childSessionId ?? watchdog.sessionId, + ); + return; + } + } + for (const [id, pass] of this.safetyPasses) { + if (id !== this.sessionId && pass.checkTime()) { + void this.stopForSafety('pass_time_limit', id); + break; + } + } + }, 1_000); + this.safetyTimer.unref?.(); this.commandEnv = options.commandEnv ? { ...options.commandEnv } : undefined; @@ -2003,7 +2040,7 @@ export class OpenCodeServerHarness } sendCommand(command: TaskCommand): boolean { - if (this.disposed || !this.connected) { + if (this.disposed || this.safetyStopped || !this.connected) { return false; } @@ -2061,6 +2098,8 @@ export class OpenCodeServerHarness } dispose(): void { + clearInterval(this.safetyTimer); + this.safetyPasses.clear(); this.disposed = true; this.connected = false; this.clearReplayAbortErrorSuppression(); @@ -2719,6 +2758,10 @@ export class OpenCodeServerHarness updatePayload: Record; }, ): void { + if (this.settledSubagentWatchdogKeys.has(eventKey)) return; + if (input.childSessionId) + this.settledSafetySessions.delete(input.childSessionId); + if (input.childSessionId) this.safetyPass(input.childSessionId); const existing = this.activeSubagentWatchdogs.get(eventKey); if (existing) { @@ -2852,6 +2895,7 @@ export class OpenCodeServerHarness } private stopSubagentWatchdog(eventKey: string): void { + this.settledSubagentWatchdogKeys.add(eventKey); const watchdog = this.activeSubagentWatchdogs.get(eventKey); if (!watchdog) { @@ -2863,6 +2907,8 @@ export class OpenCodeServerHarness } this.clearSubagentActivityFlush(watchdog); if (watchdog.childSessionId) { + this.settledSafetySessions.add(watchdog.childSessionId); + this.safetyPasses.delete(watchdog.childSessionId); this.childSessionWatchdogKeys.delete(watchdog.childSessionId); this.linkedChildSessions.delete(watchdog.childSessionId); } @@ -2895,8 +2941,11 @@ export class OpenCodeServerHarness clearTimeout(watchdog.settlementTimer); } this.clearSubagentActivityFlush(watchdog); + this.settledSubagentWatchdogKeys.add(eventKey); this.activeSubagentWatchdogs.delete(eventKey); if (watchdog.childSessionId) { + this.settledSafetySessions.add(watchdog.childSessionId); + this.safetyPasses.delete(watchdog.childSessionId); this.childSessionWatchdogKeys.delete(watchdog.childSessionId); this.linkedChildSessions.delete(watchdog.childSessionId); } @@ -3954,9 +4003,11 @@ export class OpenCodeServerHarness } private async submitPrompt(prompt: PromptInput): Promise { + if (this.safetyStopped || this.disposed) return; this.suppressAssistantOutputUntilNextPrompt = false; this.latestUserRequest = prompt.text; const sessionId = await this.ensureSession(prompt.text); + if (this.safetyStopped || this.disposed) return; // OpenCode determines whether a user turn is pending by comparing message // IDs lexicographically. A snapshot can resume on a process whose clock or // generator state trails the process that wrote the restored assistant @@ -4013,6 +4064,7 @@ export class OpenCodeServerHarness promptModel && agent !== OPENCODE_ARCHITECT_AGENT, ); try { + if (this.safetyStopped || this.disposed) return; await this.client.promptAsync({ sessionId, signal: this.eventAbortController.signal, @@ -4058,6 +4110,47 @@ export class OpenCodeServerHarness } const payload = unwrapped.payload; + if (this.safetyStopped) { + // A late child creation must not become an orphan after tree cancellation. + const info = asRecord(asRecord(payload.properties)?.info); + const lateId = asString(info?.id); + if ( + payload.type === 'session.created' && + lateId && + this.safetyStoppedSessionIds.has(asString(info?.parentID) ?? '') + ) { + this.safetyStoppedSessionIds.add(lateId); + void this.client + .abort({ sessionId: lateId, signal: AbortSignal.timeout(5_000) }) + .catch(() => undefined); + } + return; + } + + const properties = asRecord(payload.properties); + const created = asRecord(properties?.info); + if ( + payload.type === 'session.created' || + payload.type === 'session.updated' + ) { + const parentId = asString(created?.parentID); + const childId = asString(created?.id) ?? asString(properties?.sessionID); + if ( + childId && + parentId && + (parentId === this.sessionId || this.linkedChildSessions.has(parentId)) + ) { + this.linkedChildSessions.set(childId, { + parentSessionId: parentId, + agentType: this.linkedChildSessions.get(childId)?.agentType ?? null, + }); + if ( + payload.type === 'session.created' && + !this.settledSafetySessions.has(childId) + ) + this.safetyPass(childId); + } + } // A subagent's gated call pauses its own session, so an ask is relayed // whichever session in this workspace raised it. @@ -4068,6 +4161,72 @@ export class OpenCodeServerHarness const sessionId = eventSessionId(payload); + if ( + sessionId && + (sessionId === this.sessionId || this.linkedChildSessions.has(sessionId)) + ) { + const error = + properties?.error ?? + asRecord(properties?.status)?.message ?? + asRecord(properties?.info)?.error; + if (isAgentSafetyStop(error)) { + await this.stopForSafety('task_request_limit', sessionId); + return; + } + const pass = + this.safetyPasses.get(sessionId) ?? + (!this.settledSafetySessions.has(sessionId) && + (['message.part.updated', 'message.updated'].includes(payload.type) || + ['busy', 'retry'].includes( + asString(asRecord(properties?.status)?.type) ?? '', + )) + ? this.safetyPass(sessionId) + : undefined); + const part = asRecord(properties?.part); + let reason: AgentSafetyReason | undefined; + if (payload.type === 'message.part.updated' && part?.type === 'tool') { + const state = asRecord(part.state); + if ( + ['completed', 'error', 'failed'].includes( + asString(state?.status) ?? '', + ) && + asString(part.callID) + ) { + reason = pass?.completed({ + id: String(part.callID), + name: asString(part.tool) ?? '', + args: state?.input, + result: { + status: state?.status, + output: state?.output, + error: state?.error, + }, + }); + } + } + // A model step is an assistant message, not every streaming update. + const info = asRecord(properties?.info); + if ( + sessionId !== this.sessionId && + payload.type === 'message.updated' && + info?.role === 'assistant' && + asString(info.id) + ) + reason ??= pass?.step(String(info.id)); + if (reason) { + await this.stopForSafety(reason, sessionId); + return; + } + if ( + sessionId !== this.sessionId && + payload.type === 'session.idle' && + !this.childSessionWatchdogKeys.has(sessionId) + ) { + this.safetyPasses.delete(sessionId); + this.settledSafetySessions.add(sessionId); + } + } + if (sessionId && this.sessionId && sessionId !== this.sessionId) { const relationship = this.linkedChildSessions.get(sessionId); if (!relationship) { @@ -4161,9 +4320,95 @@ export class OpenCodeServerHarness } } + private safetyPass(sessionId: string): AgentSafetyPass { + let pass = this.safetyPasses.get(sessionId); + if (!pass) { + pass = new AgentSafetyPass((value) => + createHash('sha256').update(value).digest('hex'), + ); + this.safetyPasses.set(sessionId, pass); + } + return pass; + } + + /** Stop the entire tree: a parent cannot retry or replace a safety-stopped pass. */ + private async stopForSafety( + reason: AgentSafetyReason, + stoppedSessionId: string, + ): Promise { + if (this.safetyStopped || this.disposed) return; + this.safetyStopped = true; + clearInterval(this.safetyTimer); + const sessionId = this.sessionId; + const ids = new Set([ + stoppedSessionId, + ...this.linkedChildSessions.keys(), + ...(sessionId ? [sessionId] : []), + ]); + for (const id of ids) this.safetyStoppedSessionIds.add(id); + const details = { + sessionId: stoppedSessionId, + ...this.safetyPasses.get(stoppedSessionId)?.snapshot(), + }; + this.prompts.clear(); + this.clearQueuedPromptRetryTimer(); + this.clearProviderErrorRecoveryState(); + this.clearAllExecuteToolProgress(); + this.clearVisualProofTimeout(); + this.pendingUserInputRequests.clear(); + this.nativeQuestionRequestIds.clear(); + this.inFlight = false; + // Commit the admission latch and parent notice before cancelling. A bounded + // persistence failure still stops locally; the gateway ceiling remains. + try { + await this.onSafetyStop?.(reason, details); + } catch { + this.logger.error( + 'Could not persist agent safety stop; stopping local execution.', + ); + } + await Promise.allSettled( + [...ids].map((id) => + this.client.abort({ + sessionId: id, + signal: AbortSignal.timeout(5_000), + }), + ), + ); + if (!sessionId) return; + const text = `${AGENT_SAFETY_STOP_TEXT}\n\nReason: ${reason}. Stopped pass: ${stoppedSessionId}.`; + this.runtimeEvents.assistantMessage({ + sessionId, + text, + metadata: { + [TERMINAL_PROVIDER_ERROR_PAYLOAD_KEY]: { errorSummary: text }, + }, + payload: { + [TERMINAL_PROVIDER_ERROR_PAYLOAD_KEY]: { errorSummary: text }, + }, + }); + this.emit('taskEvent', { + eventName: TaskEventName.Message, + payload: [ + { + taskId: sessionId, + action: 'created', + message: { + ts: Date.now(), + type: 'say', + say: TERMINAL_PROVIDER_ERROR_SAY, + text, + }, + }, + ], + }); + this.runtimeEvents.taskAborted(sessionId); + } + private async handleSessionStatus( payload: OpenCodeEventPayload, ): Promise { + if (this.safetyStopped) return; const properties = asRecord(payload.properties); const status = asRecord(properties?.status); const statusType = asString(status?.type); @@ -4174,6 +4419,10 @@ export class OpenCodeServerHarness asString(properties?.sessionId) ?? this.sessionId; const message = asString(status?.message); + if (sessionId && isAgentSafetyStop(message)) { + await this.stopForSafety('task_request_limit', sessionId); + return; + } const retryAttempt = asFiniteNumber(status?.attempt); const isTerminalProviderError = isOpenCodeTerminalProviderError(status); const exhaustedRetryBudget = @@ -4329,6 +4578,7 @@ export class OpenCodeServerHarness `Failed to abort OpenCode before model fallback sessionId=${sessionId}: ${abortError instanceof Error ? abortError.message : String(abortError)}`, ); } + if (this.safetyStopped) return; this.emit('modelFallbackRequested', { role: this.fallbackRole, fromModelId: this.activeModelId, @@ -4437,6 +4687,7 @@ export class OpenCodeServerHarness }) : Promise.resolve(), ]); + if (this.safetyStopped) return true; this.emit('modelFallbackRequested', { role: fallback.role, fromModelId: fallback.activeModelId, @@ -4539,12 +4790,17 @@ export class OpenCodeServerHarness private async handleSessionError( payload: OpenCodeEventPayload, ): Promise { + if (this.safetyStopped) return; const properties = asRecord(payload.properties); const sessionId = asString(properties?.sessionID) ?? asString(properties?.sessionId) ?? this.sessionId; const error = properties?.error; + if (sessionId && isAgentSafetyStop(error)) { + await this.stopForSafety('task_request_limit', sessionId); + return; + } if (isOpenCodeContextOverflowError(error)) { if (this.pendingContextOverflowError === null) { @@ -5610,6 +5866,7 @@ export class OpenCodeServerHarness private async finishCurrentTurn( source: 'session_status' | 'session_idle' = 'session_idle', ): Promise { + if (this.safetyStopped) return; if (!this.inFlight && !this.prompts.hasQueuedMessages()) { return; } @@ -5628,6 +5885,7 @@ export class OpenCodeServerHarness const finalized = (await this.finalizeLatestAssistantMessage()) ?? this.finalizedAssistantTurn; + if (this.safetyStopped) return; const sessionId = this.sessionId; this.inFlight = false; @@ -5722,6 +5980,8 @@ export class OpenCodeServerHarness this.runtimeEvents.turnCompleted(sessionId, completionText); } + if (this.safetyStopped) return; + this.safetyPasses.delete(sessionId); this.runtimeEvents.taskCompleted(sessionId, finalized?.tokenUsage, { ...(missingChatCloseoutReminderCount !== null ? { diff --git a/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/start.ts b/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/start.ts index cb8e1d29ad..2d8ce00bef 100644 --- a/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/start.ts +++ b/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/start.ts @@ -4,6 +4,7 @@ import net from 'node:net'; import { execa, type ResultPromise } from 'execa'; import type { ReasoningEffort, TaskModelRole } from '@roomote/types'; +import { sdk } from '@roomote/sdk/client'; import type { HarnessLogger } from '../../../../logging'; @@ -365,6 +366,17 @@ export async function startOpenCodeServerHarness({ fallbackRole, activeModelId, agentFallbacks, + onSafetyStop: async (reason, details) => { + const runId = Number( + runtimeEnv.ROOMOTE_TASK_RUN_ID ?? process.env.ROOMOTE_TASK_RUN_ID, + ); + if (!Number.isSafeInteger(runId) || runId <= 0) + throw new Error('Missing run id for safety stop'); + await sdk.taskRuns.stopForAgentSafety( + { runId, reason, details }, + { signal: AbortSignal.timeout(5_000) }, + ); + }, stopHookReminderStallTimeoutMs: parseTimeoutMs( process.env.ROOMOTE_STOP_HOOK_REMINDER_STALL_TIMEOUT_MS, ), diff --git a/packages/cloud-agents/src/server/__tests__/non-task-provider-usage.test.ts b/packages/cloud-agents/src/server/__tests__/non-task-provider-usage.test.ts index 697a1dc2f4..fa76a3207b 100644 --- a/packages/cloud-agents/src/server/__tests__/non-task-provider-usage.test.ts +++ b/packages/cloud-agents/src/server/__tests__/non-task-provider-usage.test.ts @@ -2,6 +2,7 @@ import * as fs from 'node:fs'; import { EventEmitter } from 'node:events'; import { z } from 'zod'; +import { AGENT_SAFETY } from '@roomote/types'; const { createOpencodeClientMock, @@ -43,6 +44,10 @@ vi.mock('@opencode-ai/sdk/v2/client', () => ({ createOpencodeClient: createOpencodeClientMock, })); +vi.mock('@roomote/auth', () => ({ + createRunToken: vi.fn().mockResolvedValue('test-run-token'), +})); + vi.mock('node:child_process', () => ({ execFile: execFileMock, execFileSync: execFileSyncMock, @@ -66,6 +71,8 @@ vi.mock('@roomote/db/server', () => ({ eq: (column: unknown, value: unknown) => ({ type: 'eq', column, value }), recordLlmUsage: recordLlmUsageMock, resolveEffectiveModelRuntimeEnv: mockResolveEffectiveModelRuntimeEnv, + resolveSandboxModelRuntimeEnv: vi.fn().mockResolvedValue({}), + stopTaskForAgentSafety: vi.fn().mockResolvedValue(undefined), taskRuns: { id: 'taskRuns.id', taskId: 'taskRuns.taskId' }, })); @@ -141,7 +148,7 @@ describe('resolveOpenCodeSmallModel', () => { vi.clearAllMocks(); process.env = originalEnv; mockResolveEffectiveModelRuntimeEnv.mockResolvedValue({}); - mockTaskRunFindFirst.mockResolvedValue(undefined); + mockTaskRunFindFirst.mockResolvedValue({ id: 42, actingUserId: null }); recordLlmUsageMock.mockResolvedValue({ recorded: true }); spawnedServers.length = 0; let nextServerPort = 4100; @@ -208,6 +215,83 @@ describe('resolveOpenCodeSmallModel', () => { expect(resolveOpenCodeSmallModel()).toBe('openrouter/openai/gpt-4.1-mini'); }); + it('stops identical empty child searches, cancels the tree, persists the task stop, and does not retry', async () => { + const { stopTaskForAgentSafety } = await import('@roomote/db/server'); + mockResolveEffectiveModelRuntimeEnv.mockResolvedValue({ + R_MODEL: 'openrouter/openai/gpt-5.4', + OPENCODE_CONFIG_CONTENT: '', + }); + sessionPromptMock.mockImplementation(() => new Promise(() => {})); + eventSubscribeMock.mockImplementation(async () => ({ + stream: (async function* () { + yield { + type: 'session.created', + properties: { + sessionID: 'child', + info: { id: 'child', parentID: 'session-1' }, + }, + }; + yield { + type: 'session.created', + properties: { + sessionID: 'grandchild', + info: { id: 'grandchild', parentID: 'child' }, + }, + }; + for (let index = 0; index < 1_000; index++) { + yield { + type: 'message.part.updated', + properties: { + part: { + type: 'tool', + id: `part-${index}`, + callID: `call-${index}`, + sessionID: 'child', + messageID: 'message', + tool: 'grep', + state: { + status: 'completed', + input: { pattern: 'missing' }, + output: '', + }, + }, + }, + }; + } + })(), + })); + const { generateTrackedNonTaskText } = + await import('../non-task-provider-usage'); + await expect( + generateTrackedNonTaskText({ + surface: 'test', + taskId: 'task-1', + prompt: 'Do work', + }), + ).rejects.toThrow('Roomote stopped this task at a safety limit'); + expect(stopTaskForAgentSafety).toHaveBeenCalledExactlyOnceWith( + expect.objectContaining({ + taskId: 'task-1', + reason: 'identical_tool_loop', + details: expect.objectContaining({ + sessionId: 'child', + completedTools: 5, + }), + }), + ); + expect( + new Set(sessionAbortMock.mock.calls.map(([input]) => input.sessionID)), + ).toEqual(new Set(['session-1', 'child', 'grandchild'])); + expect(sessionPromptMock).toHaveBeenCalledTimes(1); + const config = JSON.parse( + spawnMock.mock.calls.at(-1)?.[2]?.env.OPENCODE_CONFIG_CONTENT, + ); + expect(config.provider.openrouter.options.apiKey).toBe('test-run-token'); + expect(config.provider.openrouter.options.baseURL).toContain( + '/api/inference/openrouter', + ); + }); + it('falls back to the deployment task model', () => { process.env = { ...originalEnv, @@ -1517,7 +1601,7 @@ describe('resolveOpenCodeSmallModel', () => { ]); }); - it('lets OpenCode own a Fast prompt lifecycle when the deadline is disabled', async () => { + it('allows Fast prompts beyond the ordinary deadline within the finite platform maximum', async () => { vi.useFakeTimers(); try { mockResolveEffectiveModelRuntimeEnv.mockResolvedValue({ @@ -1563,6 +1647,32 @@ describe('resolveOpenCodeSmallModel', () => { } }); + it('cannot disable the finite pass deadline with timeoutMs null, even when prompt cancellation does not settle', async () => { + vi.useFakeTimers(); + try { + mockResolveEffectiveModelRuntimeEnv.mockResolvedValue({ + R_MODEL: 'openrouter/openai/gpt-5.4', + }); + sessionPromptMock.mockReturnValue(new Promise(() => {})); + const { generateTrackedNonTaskTextInOpenCodeSession } = + await import('../non-task-provider-usage'); + const result = generateTrackedNonTaskTextInOpenCodeSession( + { surface: 'test', prompt: 'Keep working', timeoutMs: null }, + {}, + { directory: '/tmp/roomote-fast-native-test', tools: { task: true } }, + ); + const rejected = expect(result).rejects.toThrow( + 'Roomote stopped this task at a safety limit', + ); + await vi.advanceTimersByTimeAsync(AGENT_SAFETY.passTimeoutMs + 10_000); + await rejected; + expect(sessionAbortMock).toHaveBeenCalled(); + expect(sessionPromptMock).toHaveBeenCalledTimes(1); + } finally { + vi.useRealTimers(); + } + }); + it('passes files into a held Fast OpenCode session prompt', async () => { mockResolveEffectiveModelRuntimeEnv.mockResolvedValue({ R_MODEL: 'openrouter/openai/gpt-5.4', diff --git a/packages/cloud-agents/src/server/__tests__/opencode-runtime.test.ts b/packages/cloud-agents/src/server/__tests__/opencode-runtime.test.ts index 5edcebd491..2404e146ee 100644 --- a/packages/cloud-agents/src/server/__tests__/opencode-runtime.test.ts +++ b/packages/cloud-agents/src/server/__tests__/opencode-runtime.test.ts @@ -1,4 +1,11 @@ -import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; import { tmpdir } from 'node:os'; import path from 'node:path'; @@ -55,6 +62,7 @@ describe('buildOpenCodeCliEnv', () => { 'MISTRAL_API_KEY', 'BASH_ENV', 'OPENCODE_COMMAND', + 'OPENCODE_AUTH_CONTENT', ] as const; const originalValues = new Map(); @@ -77,6 +85,32 @@ describe('buildOpenCodeCliEnv', () => { } }); + it.each([false, true])( + 'strips subscription OAuth in task-gateway mode (explicit=%s), without changing ordinary helpers', + (explicit) => { + const oauth = JSON.stringify({ + openai: { + type: 'oauth', + access: 'synthetic-access', + refresh: 'synthetic-refresh', + expires: Date.now() + 60_000, + }, + }); + process.env.OPENCODE_AUTH_CONTENT = oauth; + const authEnv = explicit ? { OPENCODE_AUTH_CONTENT: oauth } : {}; + const env = buildOpenCodeCliEnv({ + ...authEnv, + R_MODEL: 'openai/gpt-5.4', + R_SMALL_MODEL: 'openai/gpt-5.4', + ROOMOTE_TASK_INFERENCE_GATEWAY: 'http://127.0.0.1:9999/api/inference', + ROOMOTE_TASK_INFERENCE_TOKEN: 'synthetic-run-token', + }); + expect(env.OPENCODE_AUTH_CONTENT).toBeUndefined(); + expect(buildOpenCodeCliEnv(authEnv).OPENCODE_AUTH_CONTENT).toBe(oauth); + expect(process.env.OPENCODE_AUTH_CONTENT).toBe(oauth); + }, + ); + it("does not pass the launching service's deployment secrets to the helper", () => { const inherited = { DATABASE_URL: 'postgres://postgres:password@postgres:5432/roomote', @@ -957,7 +991,8 @@ describe('buildOpenCodeCliEnv', () => { // whole process tree dies on shutdown. const FIXTURE_SERVER_SOURCE = ` const { spawn } = require('node:child_process'); -const { writeFileSync } = require('node:fs'); +const { existsSync, writeFileSync } = require('node:fs'); +const path = require('node:path'); const { createServer } = require('node:http'); const portArg = process.argv.find((arg) => arg.startsWith('--port=')); @@ -970,7 +1005,7 @@ createServer((req, res) => { }).listen(port, '127.0.0.1', () => { writeFileSync( process.env.OPENCODE_FIXTURE_PID_FILE, - JSON.stringify({ serverPid: process.pid, grandchildPid: grandchild.pid }), + JSON.stringify({ serverPid: process.pid, grandchildPid: grandchild.pid, dataHome: process.env.XDG_DATA_HOME, hasInlineAuth: Boolean(process.env.OPENCODE_AUTH_CONTENT), hasPersistedAuth: existsSync(path.join(process.env.XDG_DATA_HOME || '', 'opencode', 'auth.json')) }), ); }); `; @@ -1088,6 +1123,66 @@ describe('OpenCode SDK server shutdown', () => { expect(process.listenerCount('SIGHUP')).toBeGreaterThanOrEqual(1); }); + it.each([false, true])( + 'isolates and cleans up task helper auth storage (startup failure=%s)', + async (failStartup) => { + const fixturePath = path.join(fixtureDir, 'fixture-server.cjs'); + const pidFilePath = path.join(fixtureDir, 'pids.json'); + const sharedDataHome = path.join(fixtureDir, 'shared-data'); + mkdirSync(path.join(sharedDataHome, 'opencode'), { recursive: true }); + const oauth = JSON.stringify({ + openai: { + type: 'oauth', + access: 'synthetic-access', + refresh: 'synthetic-refresh', + expires: Date.now() + 60_000, + }, + }); + const sharedAuthPath = path.join(sharedDataHome, 'opencode', 'auth.json'); + writeFileSync(sharedAuthPath, oauth); + writeFileSync( + fixturePath, + failStartup + ? `require('node:fs').writeFileSync(process.env.OPENCODE_FIXTURE_PID_FILE, JSON.stringify({ dataHome: process.env.XDG_DATA_HOME, hasInlineAuth: Boolean(process.env.OPENCODE_AUTH_CONTENT) })); process.exit(7);` + : FIXTURE_SERVER_SOURCE, + ); + process.env.OPENCODE_COMMAND = `${process.execPath} ${fixturePath}`; + const request = leaseOpenCodeSdkServer({ + env: { + OPENCODE_FIXTURE_PID_FILE: pidFilePath, + OPENCODE_AUTH_CONTENT: oauth, + XDG_DATA_HOME: sharedDataHome, + R_MODEL: 'openai/gpt-5.4', + R_SMALL_MODEL: 'openai/gpt-5.4', + ROOMOTE_TASK_INFERENCE_GATEWAY: 'http://127.0.0.1:9999/api/inference', + ROOMOTE_TASK_INFERENCE_TOKEN: `synthetic-token-${failStartup}`, + }, + ephemeral: true, + useConfiguredServer: false, + startTimeoutMs: 15_000, + }); + if (failStartup) + await expect(request).rejects.toThrow('exited before it was ready'); + const lease = failStartup ? undefined : await request; + try { + expect(await waitFor(() => existsSync(pidFilePath), 5_000)).toBe(true); + const fixture = JSON.parse(readFileSync(pidFilePath, 'utf8')); + if (fixture.serverPid) + trackedPids = [fixture.serverPid, fixture.grandchildPid]; + expect(fixture.dataHome).not.toBe(sharedDataHome); + expect(fixture.hasInlineAuth).toBe(false); + expect(readFileSync(sharedAuthPath, 'utf8')).toBe(oauth); + if (!failStartup) expect(fixture.hasPersistedAuth).toBe(false); + lease?.release(); + expect(await waitFor(() => !existsSync(fixture.dataHome), 5_000)).toBe( + true, + ); + } finally { + lease?.release(); + } + }, + ); + it('seeds the plugin install into every config dir before spawning the server', async () => { const fixturePath = path.join(fixtureDir, 'fixture-server.cjs'); const pidFilePath = path.join(fixtureDir, 'pids.json'); diff --git a/packages/cloud-agents/src/server/__tests__/task-helper-inference.test.ts b/packages/cloud-agents/src/server/__tests__/task-helper-inference.test.ts new file mode 100644 index 0000000000..b67c859806 --- /dev/null +++ b/packages/cloud-agents/src/server/__tests__/task-helper-inference.test.ts @@ -0,0 +1,57 @@ +import { rebaseTaskHelperInference } from '../opencode-runtime'; + +it.each(['openrouter', 'anthropic', 'openai', 'vllm', 'bedrock-mantle-openai'])( + 'rebases task helper %s before it can dispatch provider inference', + (provider) => { + const config = JSON.parse( + rebaseTaskHelperInference( + JSON.stringify({ + model: `${provider}/test`, + small_model: `${provider}/test`, + provider: { + [provider]: { + options: { + apiKey: 'direct-key', + baseURL: 'https://direct.invalid', + }, + models: { test: { name: 'test' } }, + }, + }, + }), + { + R_MODEL: `${provider}/test`, + ROOMOTE_TASK_INFERENCE_GATEWAY: 'https://api.example/api/inference', + ROOMOTE_TASK_INFERENCE_TOKEN: 'run-token', + }, + ), + ); + expect(config.enabled_providers).toEqual([provider]); + expect(config.provider[provider].options.apiKey).toBe('run-token'); + expect(config.provider[provider].options.baseURL).toContain( + `https://api.example/api/inference/${provider}`, + ); + expect(config.provider[provider].models.test.name).toBe('test'); + }, +); + +it('fails closed for an unmediated provider', () => { + expect(() => + rebaseTaskHelperInference('{"model":"custom/test"}', { + R_MODEL: 'custom/test', + ROOMOTE_TASK_INFERENCE_GATEWAY: 'https://api.example', + ROOMOTE_TASK_INFERENCE_TOKEN: 'token', + }), + ).toThrow('no admission-controlled gateway'); +}); + +it('uses the subscription gateway for ChatGPT', () => { + const config = JSON.parse( + rebaseTaskHelperInference('{"model":"openai/gpt-5.4"}', { + R_MODEL: 'openai/gpt-5.4', + ROOMOTE_TASK_INFERENCE_GATEWAY: 'https://api.example/api/inference', + ROOMOTE_TASK_INFERENCE_TOKEN: 'token', + R_INFERENCE_GATEWAY_CHATGPT: '1', + }), + ); + expect(config.provider.openai.options.baseURL).toContain('/openai-chatgpt'); +}); diff --git a/packages/cloud-agents/src/server/__tests__/task-helper-subscription-transport.test.ts b/packages/cloud-agents/src/server/__tests__/task-helper-subscription-transport.test.ts new file mode 100644 index 0000000000..30a295846f --- /dev/null +++ b/packages/cloud-agents/src/server/__tests__/task-helper-subscription-transport.test.ts @@ -0,0 +1,172 @@ +import { createServer } from 'node:http'; +import { + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { createOpencodeClient } from '@opencode-ai/sdk/v2/client'; +import { + AGENT_SAFETY_STOP_CODE, + AGENT_SAFETY_STOP_TEXT, + isAgentSafetyStop, +} from '@roomote/types'; +import { leaseOpenCodeSdkServer } from '../opencode-runtime'; +import { OPENCODE_PLUGIN_SEED_DIR_ENV } from '../opencode-plugin-seed'; +import { writeOpenCodePluginSeedFixture } from './helpers/opencode-plugin-seed-fixture'; + +// Real pinned OpenCode and its built-in OAuth plugins, with synthetic auth and +// a local gateway denial. No live provider credentials or paid inference. +describe.skipIf(process.env.ROOMOTE_TEST_OPENCODE_SUBSCRIPTIONS !== '1')( + 'task helper subscription transport', + () => { + it.each(['openai', 'github-copilot'])( + 'keeps %s OAuth off the direct transport and observes the gateway stop', + async (provider) => { + const home = mkdtempSync( + join(tmpdir(), 'roomote-subscription-transport-'), + ); + const dataHome = join(home, 'shared-data'); + const oauth = JSON.stringify( + Object.fromEntries( + ['openai', 'github-copilot'].map((id) => [ + id, + { + type: 'oauth', + access: 'synthetic-access', + refresh: 'synthetic-refresh', + expires: Date.now() + 600_000, + }, + ]), + ), + ); + for (const dir of [ + join(dataHome, 'opencode'), + join(home, '.local', 'share', 'opencode'), + ]) { + mkdirSync(dir, { recursive: true }); + writeFileSync(join(dir, 'auth.json'), oauth); + } + const seed = join(home, 'seed'); + writeOpenCodePluginSeedFixture(seed, '1.18.30'); + const requests: Array<{ + url: string; + authorization: string | undefined; + }> = []; + const gateway = createServer((req, res) => { + if (req.method === 'POST') + requests.push({ + url: req.url ?? '', + authorization: req.headers.authorization, + }); + res.writeHead(400, { 'content-type': 'application/json' }); + res.end( + JSON.stringify({ + error: { + code: AGENT_SAFETY_STOP_CODE, + message: AGENT_SAFETY_STOP_TEXT, + type: 'invalid_request_error', + }, + }), + ); + }); + await new Promise((resolve) => + gateway.listen(0, '127.0.0.1', resolve), + ); + const address = gateway.address(); + if (!address || typeof address === 'string') + throw new Error('Gateway did not bind'); + const model = `${provider}/gpt-5.4`; + let lease: + | Awaited> + | undefined; + let client: ReturnType | undefined; + let sessionId: string | undefined; + try { + lease = await leaseOpenCodeSdkServer({ + env: { + HOME: home, + XDG_CONFIG_HOME: join(home, 'config'), + XDG_CACHE_HOME: join(home, 'cache'), + XDG_DATA_HOME: dataHome, + OPENCODE_CONFIG_CONTENT: JSON.stringify({ + model, + small_model: model, + provider: { + [provider]: { + models: { + 'gpt-5.4': { + name: 'Transport fixture', + limit: { context: 272_000, output: 8_192 }, + modalities: { input: ['text'], output: ['text'] }, + }, + }, + }, + }, + }), + R_MODEL: model, + R_SMALL_MODEL: model, + OPENCODE_AUTH_CONTENT: oauth, + ROOMOTE_TASK_INFERENCE_GATEWAY: `http://127.0.0.1:${address.port}/api/inference`, + ROOMOTE_TASK_INFERENCE_TOKEN: 'synthetic-run-token', + R_INFERENCE_GATEWAY_CHATGPT: provider === 'openai' ? '1' : '', + OPENCODE_DISABLE_AUTOUPDATE: '1', + OPENCODE_DISABLE_MODELS_FETCH: '1', + OPENCODE_DISABLE_DEFAULT_PLUGINS: undefined, + [OPENCODE_PLUGIN_SEED_DIR_ENV]: seed, + }, + ephemeral: true, + useConfiguredServer: false, + startTimeoutMs: 15_000, + }); + client = createOpencodeClient({ baseUrl: lease.url }); + const session = await client.session.create( + { directory: home, title: 'Gateway auth transport fixture' }, + { signal: AbortSignal.timeout(10_000) }, + ); + if (session.error || !session.data) + throw new Error('Could not create transport test session'); + sessionId = session.data.id; + const result = await client.session.prompt( + { + sessionID: sessionId, + directory: home, + model: { providerID: provider, modelID: 'gpt-5.4' }, + parts: [{ type: 'text', text: 'Say done.' }], + }, + { signal: AbortSignal.timeout(10_000) }, + ); + expect(requests).toHaveLength(1); + expect(requests[0]).toMatchObject({ + authorization: 'Bearer synthetic-run-token', + }); + expect(requests[0]?.url).toContain( + `/api/inference/${provider === 'openai' ? 'openai-chatgpt' : provider}/`, + ); + expect( + isAgentSafetyStop(result.error ?? result.data?.info.error), + ).toBe(true); + expect( + readFileSync(join(dataHome, 'opencode', 'auth.json'), 'utf8'), + ).toBe(oauth); + } finally { + if (sessionId && client) + await client.session + .abort( + { sessionID: sessionId, directory: home }, + { signal: AbortSignal.timeout(2_000) }, + ) + .catch(() => undefined); + lease?.release(); + gateway.closeAllConnections(); + await new Promise((resolve) => gateway.close(() => resolve())); + rmSync(home, { recursive: true, force: true }); + } + }, + 45_000, + ); + }, +); diff --git a/packages/cloud-agents/src/server/__tests__/typesafe-judgment.test.ts b/packages/cloud-agents/src/server/__tests__/typesafe-judgment.test.ts index 46cabddc6a..c5043dd70c 100644 --- a/packages/cloud-agents/src/server/__tests__/typesafe-judgment.test.ts +++ b/packages/cloud-agents/src/server/__tests__/typesafe-judgment.test.ts @@ -7,6 +7,7 @@ const { mockCaptureJudgment, mockIsJudgmentCaptureEnabled, mockEnv, + mockAdmitTaskInference, } = vi.hoisted(() => ({ mockResolveModelProviderEnvValue: vi.fn(), mockGetJudgmentSelection: vi.fn(), @@ -15,6 +16,7 @@ const { mockRecordLlmUsage: vi.fn(), mockCaptureJudgment: vi.fn(), mockIsJudgmentCaptureEnabled: vi.fn(), + mockAdmitTaskInference: vi.fn().mockResolvedValue(true), mockEnv: { R_JUDGMENT_MODEL: undefined as string | undefined, R_JUDGMENT_UPSTREAM_URL: undefined as string | undefined, @@ -29,6 +31,7 @@ vi.mock('@roomote/db/server', () => ({ getDeploymentJudgmentModelSelection: mockGetJudgmentSelection, recordLlmUsage: mockRecordLlmUsage, resolveModelProviderEnvValue: mockResolveModelProviderEnvValue, + admitTaskInferenceRequest: mockAdmitTaskInference, })); vi.mock('../non-task-provider-usage', () => ({ @@ -110,6 +113,7 @@ const directAnswers = { describe('evaluateTypeSafeJudgments', () => { beforeEach(() => { vi.clearAllMocks(); + mockAdmitTaskInference.mockResolvedValue(true); resetJudgmentBackendCache(); resetDecisionModelCache(); mockEnv.R_JUDGMENT_MODEL = undefined; @@ -131,6 +135,17 @@ describe('evaluateTypeSafeJudgments', () => { vi.restoreAllMocks(); }); + it('admits direct task-associated decisions before dispatch and stops when their allowance is gone', async () => { + const upstream = mockFetchResponse({ answers: directAnswers }); + mockAdmitTaskInference.mockResolvedValue(false); + await expect( + evaluateDecisionModel({ taskId: 'task-1', state: 'test', questions }), + ).rejects.toThrow('Roomote stopped this task at a safety limit'); + expect(mockAdmitTaskInference).toHaveBeenCalledWith('task-1'); + expect(upstream).not.toHaveBeenCalled(); + expect(mockGenerateTrackedNonTaskObject).not.toHaveBeenCalled(); + }); + it.each(['typesafe', 'openrouter', 'vercel'] as const)( 'returns only normalized token usage for %s evaluations', async (provider) => { diff --git a/packages/cloud-agents/src/server/judge-file.ts b/packages/cloud-agents/src/server/judge-file.ts index 7c4c02dfd2..c939c1fbfb 100644 --- a/packages/cloud-agents/src/server/judge-file.ts +++ b/packages/cloud-agents/src/server/judge-file.ts @@ -48,6 +48,7 @@ function judgeFileQuestion( * closed-set Choice answers. */ export async function evaluateJudgeFileCriteria(input: { + taskId?: string; state: JudgeFileState; criteria: JudgeCriterionInput[]; timeoutMs?: number; @@ -60,6 +61,7 @@ export async function evaluateJudgeFileCriteria(input: { ) as Record>; const answers = await evaluateDecisionModel({ + taskId: input.taskId, state: { ...input.state, criteria: input.criteria, @@ -94,7 +96,10 @@ export async function evaluateJudgeFileCriteria(input: { } /** Shared Judgement protocol; credentials and model selection stay on the API. */ -export async function evaluateRepositoryJudgement(request: JudgeRequest) { +export async function evaluateRepositoryJudgement( + request: JudgeRequest, + taskId?: string, +) { const questions = { result: question(request) }; if ( Buffer.byteLength(JSON.stringify({ state: request, questions })) > @@ -103,6 +108,7 @@ export async function evaluateRepositoryJudgement(request: JudgeRequest) { throw new Error('Judgement evidence exceeds the request budget'); } const answers = await evaluateDecisionModel({ + taskId, state: request, questions, timeoutMs: 2500, diff --git a/packages/cloud-agents/src/server/non-task-provider-usage.ts b/packages/cloud-agents/src/server/non-task-provider-usage.ts index 74cd7848a5..c3b32881c4 100644 --- a/packages/cloud-agents/src/server/non-task-provider-usage.ts +++ b/packages/cloud-agents/src/server/non-task-provider-usage.ts @@ -1,4 +1,7 @@ import { mkdtempSync } from 'node:fs'; +import { createHash } from 'node:crypto'; +import { createRunToken } from '@roomote/auth'; +import { Env } from '@roomote/env'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; @@ -14,9 +17,17 @@ import { recordLlmUsage, resolveEffectiveModelRuntimeEnv, taskRuns, + resolveSandboxModelRuntimeEnv, + stopTaskForAgentSafety, } from '@roomote/db/server'; import { formatErrorForLog, + AGENT_SAFETY, + AGENT_SAFETY_STOP_TEXT, + AgentSafetyPass, + isAgentSafetyStop, + buildInferenceGatewayUrl, + type AgentSafetyReason, getOpenAiCompatibleRuntimeConfigs, getTaskModelDisplayName, isInferenceCreditsExhaustedError, @@ -197,7 +208,7 @@ interface GenerateTrackedNonTaskBaseParams extends NonTaskInferenceTrackingInput /** Explicit reasoning-effort override applied to the resolved model. */ reasoningEffort?: ReasoningEffort; maxOutputTokens?: number; - /** null lets OpenCode own the prompt lifecycle without a Roomote deadline. */ + /** null uses the finite platform maximum; a prompt cannot disable safety. */ timeoutMs?: number | null; /** * OpenCode retries some provider failures internally before the prompt @@ -1626,7 +1637,39 @@ async function runNonTaskSdkPrompt( }> { const { model, resolvedModelRuntimeEnv } = runtime; const reasoningEffort = runtime.reasoningEffort ?? params.reasoningEffort; - const timeoutMs = params.timeoutMs === undefined ? 120_000 : params.timeoutMs; + const timeoutMs = Math.min( + params.timeoutMs === undefined + ? 120_000 + : (params.timeoutMs ?? AGENT_SAFETY.passTimeoutMs), + AGENT_SAFETY.passTimeoutMs, + ); + let taskGatewayEnv: Partial> = {}; + if (params.taskId) { + const run = await db.query.taskRuns.findFirst({ + where: eq(taskRuns.taskId, params.taskId), + orderBy: desc(taskRuns.id), + columns: { id: true, actingUserId: true }, + }); + if (!run) + throw new Error( + 'Task helper requires a persisted run for inference admission', + ); + const gatewayMarkers = await resolveSandboxModelRuntimeEnv({ + runtimeEnv: { ...resolvedModelRuntimeEnv, R_MODEL: model }, + }); + taskGatewayEnv = { + ROOMOTE_TASK_INFERENCE_GATEWAY: buildInferenceGatewayUrl(Env.TRPC_URL), + ROOMOTE_TASK_INFERENCE_TOKEN: await createRunToken({ + runId: run.id, + userId: run.actingUserId, + timeoutMs, + }), + R_INFERENCE_GATEWAY_CHATGPT: + gatewayMarkers.R_INFERENCE_GATEWAY_CHATGPT ?? '', + R_MODEL: model, + R_SMALL_MODEL: model, + }; + } const promptErrorLabel = options.promptErrorLabel ?? `OpenCode structured prompt failed (model ${model})`; @@ -1638,8 +1681,8 @@ async function runNonTaskSdkPrompt( totalMs: 0, }; const server = await leaseOpenCodeSdkServer({ - env: { ...resolvedModelRuntimeEnv, ...options.env }, - ephemeral: options.ephemeral, + env: { ...resolvedModelRuntimeEnv, ...options.env, ...taskGatewayEnv }, + ephemeral: params.taskId ? true : options.ephemeral, preserveReasoning: options.preserveReasoning ?? Boolean(reasoningEffort), promptOnlySubagents: options.promptOnlySubagents, reasoningOverride: reasoningEffort @@ -1649,15 +1692,25 @@ async function runNonTaskSdkPrompt( timeoutMs === null ? DEFAULT_OPENCODE_SDK_SERVER_START_TIMEOUT_MS : Math.min(timeoutMs, DEFAULT_OPENCODE_SDK_SERVER_START_TIMEOUT_MS), - useConfiguredServer: options.useConfiguredServer, + useConfiguredServer: params.taskId ? false : options.useConfiguredServer, }); setupTiming.serverLeaseMs = Date.now() - setupStartedAtMs; options.onServerLeased?.(server.url); const abortController = new AbortController(); + let safetyPersistence: Promise | undefined; const timeout = timeoutMs === null ? undefined : setTimeout(() => { + if (timeoutMs === AGENT_SAFETY.passTimeoutMs) { + if (params.taskId) + safetyPersistence = stopTaskForAgentSafety({ + taskId: params.taskId, + reason: 'pass_time_limit', + }).catch(() => undefined); + abortController.abort(new Error(AGENT_SAFETY_STOP_TEXT)); + return; + } abortController.abort( new NonTaskOpenCodePromptTimeoutError(timeoutMs), ); @@ -1825,6 +1878,50 @@ async function runNonTaskSdkPrompt( await options.onSessionReady?.(sessionId); const trackedSessionIds = new Set([sessionId]); + const safetyPasses = new Map(); + const safetyPass = (id: string) => { + let pass = safetyPasses.get(id); + if (!pass) { + pass = new AgentSafetyPass((value) => + createHash('sha256').update(value).digest('hex'), + ); + safetyPasses.set(id, pass); + } + return pass; + }; + safetyPass(sessionId); + let safetyStopped = false; + const safetyStop = async ( + reason: AgentSafetyReason, + stoppedSessionId = sessionId, + ) => { + if (safetyStopped) return; + safetyStopped = true; + safetyPersistence = params.taskId + ? stopTaskForAgentSafety({ + taskId: params.taskId, + reason, + details: { + sessionId: stoppedSessionId, + ...safetyPasses.get(stoppedSessionId)?.snapshot(), + }, + }) + : Promise.resolve(); + // Reject and abort locally immediately, then persist the durable latch. + const error = new Error(AGENT_SAFETY_STOP_TEXT); + rejectSessionError(error); + abortController.abort(error); + await safetyPersistence; + }; + const safetyTimer = setInterval(() => { + for (const [id, pass] of safetyPasses) { + if (pass.checkTime()) { + void safetyStop('pass_time_limit', id).catch(() => undefined); + break; + } + } + }, 1_000); + safetyTimer.unref(); const sessionsCreatedThisTurn = new Set(); const usageRecordings = new Map>(); const observedUsageEventKeys = new Set(); @@ -1965,9 +2062,12 @@ async function runNonTaskSdkPrompt( if ( (event.type === 'session.created' || event.type === 'session.updated') && - event.properties.info.parentID === sessionId + trackedSessionIds.has(event.properties.info.parentID ?? '') ) { - trackedSessionIds.add(event.properties.sessionID); + const childId = + event.properties.info.id ?? event.properties.sessionID; + trackedSessionIds.add(childId); + safetyPass(childId); if (event.type === 'session.created') { sessionsCreatedThisTurn.add(event.properties.sessionID); } @@ -1979,7 +2079,39 @@ async function runNonTaskSdkPrompt( rejectSessionError(error); return; } + } else if ( + event.type === 'session.idle' && + event.properties.sessionID !== sessionId + ) { + safetyPasses.delete(event.properties.sessionID); } else if (event.type === 'message.part.updated') { + const part = event.properties.part; + if ( + part.type === 'tool' && + trackedSessionIds.has(part.sessionID) && + ['completed', 'error'].includes(part.state.status) + ) { + const state = part.state as { + status: string; + input?: unknown; + output?: unknown; + error?: unknown; + }; + const reason = safetyPass(part.sessionID).completed({ + id: part.callID, + name: part.tool, + args: state.input, + result: { + status: state.status, + output: state.output, + error: state.error, + }, + }); + if (reason) { + await safetyStop(reason, part.sessionID); + return; + } + } const taskPart = normalizeParentOpenCodeTaskPart( event.properties.part, sessionId, @@ -2024,6 +2156,15 @@ async function runNonTaskSdkPrompt( trackedSessionIds.has(event.properties.info.sessionID) ) { const info = event.properties.info; + if (isAgentSafetyStop(info.error)) { + await safetyStop('task_request_limit'); + return; + } + const reason = safetyPass(info.sessionID).step(info.id); + if (reason) { + await safetyStop(reason, info.sessionID); + return; + } const messageId = asString(info.id); if ( info.sessionID === sessionId && @@ -2081,6 +2222,7 @@ async function runNonTaskSdkPrompt( // can succeed until the account is topped up, so end the // prompt instead of reporting a temporary error. if ( + isAgentSafetyStop(event.properties.status.message) || isInferenceCreditsExhaustedError( event.properties.status.message, ) @@ -2375,17 +2517,20 @@ async function runNonTaskSdkPrompt( }, NON_TASK_SESSION_ABORT_TIMEOUT_MS); sessionAbortTimeout.unref(); try { - await client.session - .abort( - { sessionID: sessionId, directory: sessionDirectory }, - { signal: sessionAbortController.signal }, - ) - .catch(() => undefined); + await Promise.allSettled( + [...trackedSessionIds].map((id) => + client.session.abort( + { sessionID: id, directory: sessionDirectory }, + { signal: sessionAbortController.signal }, + ), + ), + ); } finally { clearTimeout(sessionAbortTimeout); } throw error; } finally { + clearInterval(safetyTimer); abortController.signal.removeEventListener('abort', abortEventMonitor); eventAbortController.abort(); void eventMonitor?.catch(() => undefined); @@ -2404,6 +2549,23 @@ async function runNonTaskSdkPrompt( externalSignal?.removeEventListener('abort', abortFromExternalSignal); if (timeout) clearTimeout(timeout); server.release(); + if (safetyPersistence) { + let persistenceTimeout: ReturnType | undefined; + try { + await Promise.race([ + safetyPersistence.catch(() => undefined), + new Promise((resolve) => { + persistenceTimeout = setTimeout( + resolve, + NON_TASK_SESSION_ABORT_TIMEOUT_MS, + ); + persistenceTimeout.unref(); + }), + ]); + } finally { + if (persistenceTimeout) clearTimeout(persistenceTimeout); + } + } } } @@ -2566,6 +2728,8 @@ async function runControlPlaneWithFallback( try { return await execute(runtime, false); } catch (error) { + if (isAgentSafetyStop(error instanceof Error ? error.message : error)) + throw error; const trigger = classifyModelFallbackTrigger(error, { retriesUsed: attempt - 1, }); diff --git a/packages/cloud-agents/src/server/opencode-runtime.ts b/packages/cloud-agents/src/server/opencode-runtime.ts index 9f6cffbdb5..224606be73 100644 --- a/packages/cloud-agents/src/server/opencode-runtime.ts +++ b/packages/cloud-agents/src/server/opencode-runtime.ts @@ -1,12 +1,16 @@ import { execFileSync, spawn, type ChildProcess } from 'node:child_process'; import { createHash } from 'node:crypto'; -import { mkdtempSync, writeFileSync } from 'node:fs'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; import { createServer } from 'node:net'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { pathToFileURL } from 'node:url'; import { + asRecord, + CHATGPT_GATEWAY_PROVIDER_ID, + buildInferenceGatewayOpenCodeBaseUrl, + getInferenceGatewayProvider, collectOpenRouterVariantModelAlias, CHATGPT_FAST_MODE_ENV_VAR_NAME, DISABLED_MODEL_PROVIDER_ENV_VAR_NAMES, @@ -678,6 +682,16 @@ export function buildOpenCodeCliEnv( options, ); + if ( + extraEnv?.ROOMOTE_TASK_INFERENCE_GATEWAY && + extraEnv.ROOMOTE_TASK_INFERENCE_TOKEN + ) { + env.OPENCODE_CONFIG_CONTENT = rebaseTaskHelperInference( + env.OPENCODE_CONFIG_CONTENT, + extraEnv, + ); + } + // Do not inherit or accept disabled-provider credentials in helper model // processes, including callers that bypass the task dequeue path. for (const envVarName of DISABLED_MODEL_PROVIDER_ENV_VAR_NAMES) { @@ -694,9 +708,66 @@ export function buildOpenCodeCliEnv( // launching service's own configuration. scrubOpenCodeHelperEnv(env, extraEnv); + // An OAuth loader can replace the SDK fetch and ignore baseURL entirely. + // Keep direct auth for ordinary sessions, never gateway-bound task helpers. + if (isTaskHelperGatewayEnv(extraEnv)) delete env.OPENCODE_AUTH_CONTENT; + return env; } +function isTaskHelperGatewayEnv( + env?: Partial>, +): boolean { + return Boolean( + env?.ROOMOTE_TASK_INFERENCE_GATEWAY && env.ROOMOTE_TASK_INFERENCE_TOKEN, + ); +} + +/** Task-associated control-plane helpers use the same admission boundary as + * sandbox children. Dedicated leases prevent cross-task credential/config reuse. */ +export function rebaseTaskHelperInference( + content: string, + env: Partial>, +): string { + const config = JSON.parse(content) as Record; + const providers = asRecord(config.provider) ?? {}; + const ids = new Set(); + for (const model of [config.model, config.small_model]) { + if (typeof model === 'string') ids.add(model.split('/')[0]!); + } + // Only the selected helper model is needed; exclude ambient role models. + const selected = env.R_MODEL?.split('/')[0]; + if (selected) ids.add(selected); + for (const id of ids) { + const routeId = + id === 'openai' && env.R_INFERENCE_GATEWAY_CHATGPT === '1' + ? CHATGPT_GATEWAY_PROVIDER_ID + : id; + const provider = getInferenceGatewayProvider(routeId); + if (!provider) + throw new Error( + `Task helper provider ${id} has no admission-controlled gateway`, + ); + const existing = asRecord(providers[id]) ?? {}; + providers[id] = { + ...existing, + options: { + ...asRecord(existing.options), + baseURL: buildInferenceGatewayOpenCodeBaseUrl( + env.ROOMOTE_TASK_INFERENCE_GATEWAY!, + provider, + ), + apiKey: env.ROOMOTE_TASK_INFERENCE_TOKEN, + }, + }; + } + return JSON.stringify({ + ...config, + provider: Object.fromEntries([...ids].map((id) => [id, providers[id]])), + enabled_providers: [...ids], + }); +} + function shellEscape(value: string): string { return `'${value.replaceAll("'", "'\\''")}'`; } @@ -961,6 +1032,20 @@ async function startManagedOpenCodeSdkServer( `--port=${port}`, ]); const env = buildOpenCodeCliEnv(extraEnv, options); + // Do not delete the service's shared auth.json: unrelated sessions still use + // it. Give this managed lease an empty auth store, overriding caller paths. + const taskDataHome = isTaskHelperGatewayEnv(extraEnv) + ? mkdtempSync(join(tmpdir(), 'roomote-task-helper-data-')) + : undefined; + if (taskDataHome) env.XDG_DATA_HOME = taskDataHome; + const cleanupTaskData = () => { + if (!taskDataHome) return; + try { + rmSync(taskDataHome, { recursive: true, force: true }); + } catch { + console.warn('[OpenCode] Could not clean up isolated task-helper data.'); + } + }; // OpenCode blocks its first request on an `@opencode-ai/plugin` registry // install into each config directory it loads; a fresh container after a // deploy paid that in full (minutes, or a 300s timeout). Copy the @@ -974,13 +1059,20 @@ async function startManagedOpenCodeSdkServer( }`, ); } - const proc = spawn(command.command, command.args, { - env, - stdio: ['ignore', 'pipe', 'pipe'], - // Own process group, so shutdown can signal the entire tree (shell - // wrappers included) via the negative pid. - detached: true, - }); + let proc: ChildProcess; + try { + proc = spawn(command.command, command.args, { + env, + stdio: ['ignore', 'pipe', 'pipe'], + // Own process group, so shutdown can signal the entire tree (shell + // wrappers included) via the negative pid. + detached: true, + }); + } catch (error) { + cleanupTaskData(); + throw error; + } + proc.once('close', cleanupTaskData); liveOpenCodeSdkServerProcs.add(proc); proc.once('exit', () => { @@ -1023,6 +1115,7 @@ async function startManagedOpenCodeSdkServer( settled = true; clearTimeout(timeout); stopChildProcess(proc); + cleanupTaskData(); reject(error); }; diff --git a/packages/cloud-agents/src/server/typesafe-judgment.ts b/packages/cloud-agents/src/server/typesafe-judgment.ts index 8f93d9428f..bfeee4e8f8 100644 --- a/packages/cloud-agents/src/server/typesafe-judgment.ts +++ b/packages/cloud-agents/src/server/typesafe-judgment.ts @@ -5,9 +5,11 @@ import { getDeploymentJudgmentModelSelection, recordLlmUsage, resolveModelProviderEnvValue, + admitTaskInferenceRequest, } from '@roomote/db/server'; import { resolveEffectiveJudgmentModelSelection, + AGENT_SAFETY_STOP_TEXT, TYPESAFE_API_KEY_ENV_VAR_NAME, type ReasoningEffort, } from '@roomote/types'; @@ -986,6 +988,7 @@ async function requestFromBackend( type TypeSafeJudgmentParams< TQuestions extends Record, > = { + taskId?: string | null; /** JSON-serializable context the questions are answered over. */ state: unknown; questions: TQuestions; @@ -1048,6 +1051,8 @@ export async function evaluateTypeSafeJudgmentsWithUsage< let response: TrackedJudgmentResponse | undefined; try { + if (params.taskId && !(await admitTaskInferenceRequest(params.taskId))) + throw new Error(AGENT_SAFETY_STOP_TEXT); ({ answers, response } = await requestFromBackend( backend, params.state, @@ -1273,7 +1278,11 @@ function shadowFailureCategory(error: unknown): string { async function shadowRoomoteJudgment( primaryProvider: JudgmentBackend['provider'], requestId: string, - params: { state: unknown; questions: Record }, + params: { + state: unknown; + questions: Record; + taskId?: string | null; + }, primary: Record | undefined, ): Promise { const upstream = resolveRoomoteJudgmentUpstream(); @@ -1286,6 +1295,8 @@ async function shadowRoomoteJudgment( let response: TrackedJudgmentResponse | undefined; try { + if (params.taskId && !(await admitTaskInferenceRequest(params.taskId))) + return; const request = await requestRoomoteDecisions( upstream, params.state, diff --git a/packages/db/agent-safety.md b/packages/db/agent-safety.md new file mode 100644 index 0000000000..a59375a4bb --- /dev/null +++ b/packages/db/agent-safety.md @@ -0,0 +1,94 @@ +# Agent safety admission and operational limits + +The task row is the durable admission authority. `inference_request_limit` +defaults to 1,000; `inference_requests` counts admitted attempts, not successful +responses or accounting events. `safety_stopped_at` and `safety_stop_reason` +are an irreversible application-level latch for the task. No resume, new run, +provider fallback, or ordinary message clears these fields. There is no UI or +public API to grant more allowance in this release; explicit continuation is a +new task after inspecting the retained work. Operators should not clear a latch +while an old runtime is alive. + +## Admission guarantees + +- PostgreSQL transactions serialize admissions on the task row, across API + processes, concurrent children, helper calls, retries, and resumed runs. +- Every allowed inference-gateway POST reserves one request before upstream + fetch, including retries, Jevgrep evaluations, and POST token-count endpoints. + GET model/catalog metadata does not consume allowance. Failed attempts are + not refunded. Failure to read/write admission state fails closed. +- Task-associated SDK OpenCode helpers receive a dedicated gateway-backed + lease. Their internal model steps and retries therefore use the same task + counter, rather than one reservation per helper prompt. An unsupported + gateway provider fails closed. Typed decision calls with task context also + reserve before direct dispatch (including optional shadow evaluations). + Gateway-bound helper startup strips inline subscription OAuth and overrides + the data home with a private, empty auth store, cleaned up when the process + closes or startup fails. Shared session auth files remain untouched. This + prevents a built-in OAuth loader from replacing the SDK transport and + bypassing the configured gateway URL. +- A rejected admission beyond the ceiling atomically latches the task and + inserts a task notice plus an owning-session notice, if present. Worker pass + limits call the same durable stop mutation. Concurrent/late stop events do + not insert another notice. These history rows need no LLM, Redis job, or + outbound chat success. Existing open views may need refresh. Standalone chat + delivery uses the existing terminal-error notification path, best effort. +- Admission is not a dollar budget. Existing post-response usage records are + unchanged and are not reservations. No price or usage data is required to + enforce the request count; in-flight admitted requests may still be billed. + +## Pass guarantees + +The worker and control-plane OpenCode prompt runner share `AgentSafetyPass`. +SHA-256 hashes cover tool name, recursively key-sorted arguments, and terminal +result/error. Only hashes and unique invocation/step IDs are retained by the +guard; arguments and results are not written to safety logs/notices. Five +consecutive identical completed invocations stop a pass, including empty +results. Changed arguments/results reset that streak. Duplicate/out-of-order +updates for the same invocation are ignored. The exact read-only +`manage_tasks`/`roomote_manage_tasks` action `get_updates` gets 20 identical +completions; it is not an unlimited polling exception. + +Each live child gets its own 100 unique assistant-message starts, 200 unique +terminal tool completions, and 20-minute wall deadline, independent of progress +and siblings. A pending task-tool spawn is time-bounded even before its child ID +arrives. The worker checks wall deadlines every second. Root tool completions +are guarded too. Control-plane prompts retain their normal shorter deadlines +(120 seconds by default); `timeoutMs: null` and larger timeouts cannot disable +the 20-minute maximum. Their root prompt and recursive children are guarded. + +A pass breach stops the **whole task**, retains partial work, clears local +retry/fallback queues, aborts the root and discovered descendants with bounded +abort requests, emits the terminal task event to release worker/parent waits, +and refuses late local commands/events. This intentionally does not let the +parent spawn a replacement pass. The durable task latch refuses all subsequent +managed provider dispatch even if the worker restarts. The existing parent +settle/error relays do not wake parent inference for a safety-stopped task. + +## Boundaries to keep in mind + +- Tool/step detection observes OpenCode events, not a synchronous upstream tool + interceptor. Work or requests already in flight when the fifth completion is + observed may finish. Missing events degrade detection to wall/request limits. +- Pass clocks/fingerprints are in-memory and restart with a runtime; the task + request counter and stop latch survive runtime/API restart and resume. Old + tasks begin counting after this additive migration; historical provider calls + cannot be reconstructed as admissions. +- If the stop mutation cannot reach the API/database, the worker still stops + locally; durable notices/latching cannot be promised during that outage. The + gateway independently fails closed while its database is unavailable, and + its lifetime request ceiling still applies after recovery. +- Independent session orchestration without task context is outside a task's + lifetime counter (its prompt passes still have finite guards). User scripts, + arbitrary integration tools, external MCP servers, and independently billed + services are not an inference egress firewall. These bounds do not replace + provider-side financial limits. +- Rollback is additive/N-1 safe. Rolling application code back removes these + enforcement checks; the four columns remain readable by the newer release. + +The opt-in `task-helper-subscription-transport.test.ts` regression runs the real +pinned OpenCode binary against a local denying gateway with synthetic ChatGPT +and Copilot OAuth fixtures. Enable it with +`ROOMOTE_TEST_OPENCODE_SUBSCRIPTIONS=1`; it uses no live provider credentials or +paid inference. The normal suite covers environment stripping and private-store +startup/cleanup without requiring the binary. diff --git a/packages/db/drizzle/0137_colorful_nightcrawler.sql b/packages/db/drizzle/0137_colorful_nightcrawler.sql new file mode 100644 index 0000000000..ba7784b66a --- /dev/null +++ b/packages/db/drizzle/0137_colorful_nightcrawler.sql @@ -0,0 +1,4 @@ +ALTER TABLE "tasks" ADD COLUMN "inference_request_limit" integer DEFAULT 1000 NOT NULL;--> statement-breakpoint +ALTER TABLE "tasks" ADD COLUMN "inference_requests" integer DEFAULT 0 NOT NULL;--> statement-breakpoint +ALTER TABLE "tasks" ADD COLUMN "safety_stopped_at" timestamp;--> statement-breakpoint +ALTER TABLE "tasks" ADD COLUMN "safety_stop_reason" text; \ No newline at end of file diff --git a/packages/db/drizzle/meta/0137_snapshot.json b/packages/db/drizzle/meta/0137_snapshot.json new file mode 100644 index 0000000000..20f5df2ba6 --- /dev/null +++ b/packages/db/drizzle/meta/0137_snapshot.json @@ -0,0 +1,20179 @@ +{ + "id": "80b20466-9897-4b6a-8b46-24b4b2db813e", + "prevId": "21ad79fe-db62-412e-8586-7d39c817b917", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.agentmail_conversation_participants": { + "name": "agentmail_conversation_participants", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "conversation_id": { + "name": "conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "inbox_id": { + "name": "inbox_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_thread_id": { + "name": "provider_thread_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "added_at": { + "name": "added_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "agentmail_conversation_participants_user_idx": { + "name": "agentmail_conversation_participants_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "agentmail_conversation_participants_user_id_users_id_fk": { + "name": "agentmail_conversation_participants_user_id_users_id_fk", + "tableFrom": "agentmail_conversation_participants", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "agentmail_conversation_participants_conversation_fk": { + "name": "agentmail_conversation_participants_conversation_fk", + "tableFrom": "agentmail_conversation_participants", + "tableTo": "agentmail_conversations", + "columnsFrom": ["conversation_id", "inbox_id", "provider_thread_id"], + "columnsTo": ["id", "inbox_id", "provider_thread_id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "agentmail_conversation_participants_conversation_user_unique": { + "name": "agentmail_conversation_participants_conversation_user_unique", + "nullsNotDistinct": false, + "columns": ["conversation_id", "user_id"] + }, + "agentmail_conversation_participants_thread_user_unique": { + "name": "agentmail_conversation_participants_thread_user_unique", + "nullsNotDistinct": false, + "columns": ["inbox_id", "provider_thread_id", "user_id"] + } + }, + "policies": {}, + "checkConstraints": { + "agentmail_conversation_participants_role_check": { + "name": "agentmail_conversation_participants_role_check", + "value": "\"agentmail_conversation_participants\".\"role\" in ('owner', 'participant')" + }, + "agentmail_conversation_participants_source_check": { + "name": "agentmail_conversation_participants_source_check", + "value": "\"agentmail_conversation_participants\".\"source\" in ('initiator', 'cc', 'link_code', 'outbound')" + } + }, + "isRLSEnabled": false + }, + "public.agentmail_conversations": { + "name": "agentmail_conversations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "inbox_id": { + "name": "inbox_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_thread_id": { + "name": "provider_thread_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "outbound_identity_id": { + "name": "outbound_identity_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subject": { + "name": "subject", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "latest_inbound_message_id": { + "name": "latest_inbound_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "latest_inbound_at": { + "name": "latest_inbound_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "latest_inbound_sender_email": { + "name": "latest_inbound_sender_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "latest_inbound_user_id": { + "name": "latest_inbound_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "latest_outbound_message_id": { + "name": "latest_outbound_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "agentmail_conversations_thread_idx": { + "name": "agentmail_conversations_thread_idx", + "columns": [ + { + "expression": "inbox_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_thread_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "agentmail_conversations_owner_idx": { + "name": "agentmail_conversations_owner_idx", + "columns": [ + { + "expression": "owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "agentmail_conversations_owner_user_id_users_id_fk": { + "name": "agentmail_conversations_owner_user_id_users_id_fk", + "tableFrom": "agentmail_conversations", + "tableTo": "users", + "columnsFrom": ["owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "agentmail_conversations_latest_inbound_user_id_users_id_fk": { + "name": "agentmail_conversations_latest_inbound_user_id_users_id_fk", + "tableFrom": "agentmail_conversations", + "tableTo": "users", + "columnsFrom": ["latest_inbound_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "agentmail_conversations_id_thread_unique": { + "name": "agentmail_conversations_id_thread_unique", + "nullsNotDistinct": false, + "columns": ["id", "inbox_id", "provider_thread_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.agentmail_inbound_turns": { + "name": "agentmail_inbound_turns", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "conversation_id": { + "name": "conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "webhook_event_id": { + "name": "webhook_event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider_message_id": { + "name": "provider_message_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_timestamp": { + "name": "provider_timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "sender_email": { + "name": "sender_email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sender_user_id": { + "name": "sender_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "body_text": { + "name": "body_text", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "retry_at": { + "name": "retry_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "consumed_at": { + "name": "consumed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "agentmail_inbound_turns_drain_idx": { + "name": "agentmail_inbound_turns_drain_idx", + "columns": [ + { + "expression": "conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "state", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_timestamp", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "agentmail_inbound_turns_pending_idx": { + "name": "agentmail_inbound_turns_pending_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"agentmail_inbound_turns\".\"state\" = 'pending'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "agentmail_inbound_turns_conversation_id_agentmail_conversations_id_fk": { + "name": "agentmail_inbound_turns_conversation_id_agentmail_conversations_id_fk", + "tableFrom": "agentmail_inbound_turns", + "tableTo": "agentmail_conversations", + "columnsFrom": ["conversation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "agentmail_inbound_turns_webhook_event_id_agentmail_webhook_events_id_fk": { + "name": "agentmail_inbound_turns_webhook_event_id_agentmail_webhook_events_id_fk", + "tableFrom": "agentmail_inbound_turns", + "tableTo": "agentmail_webhook_events", + "columnsFrom": ["webhook_event_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "agentmail_inbound_turns_sender_user_id_users_id_fk": { + "name": "agentmail_inbound_turns_sender_user_id_users_id_fk", + "tableFrom": "agentmail_inbound_turns", + "tableTo": "users", + "columnsFrom": ["sender_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "agentmail_inbound_turns_webhook_event_unique": { + "name": "agentmail_inbound_turns_webhook_event_unique", + "nullsNotDistinct": false, + "columns": ["webhook_event_id"] + } + }, + "policies": {}, + "checkConstraints": { + "agentmail_inbound_turns_state_check": { + "name": "agentmail_inbound_turns_state_check", + "value": "\"agentmail_inbound_turns\".\"state\" in ('pending', 'consumed', 'failed')" + } + }, + "isRLSEnabled": false + }, + "public.agentmail_reply_verification_proofs": { + "name": "agentmail_reply_verification_proofs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_address": { + "name": "email_address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "consumed_at": { + "name": "consumed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "agentmail_reply_verification_proofs_user_idx": { + "name": "agentmail_reply_verification_proofs_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "email_address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "agentmail_reply_verification_proofs_user_id_users_id_fk": { + "name": "agentmail_reply_verification_proofs_user_id_users_id_fk", + "tableFrom": "agentmail_reply_verification_proofs", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "agentmail_reply_verification_proofs_token_unique": { + "name": "agentmail_reply_verification_proofs_token_unique", + "nullsNotDistinct": false, + "columns": ["token_hash"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.agentmail_suppressions": { + "name": "agentmail_suppressions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "email_address": { + "name": "email_address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "details": { + "name": "details", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_message_id": { + "name": "provider_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "agentmail_suppressions_email_unique": { + "name": "agentmail_suppressions_email_unique", + "nullsNotDistinct": false, + "columns": ["email_address"] + } + }, + "policies": {}, + "checkConstraints": { + "agentmail_suppressions_reason_check": { + "name": "agentmail_suppressions_reason_check", + "value": "\"agentmail_suppressions\".\"reason\" in ('bounce', 'complaint', 'unsubscribe')" + } + }, + "isRLSEnabled": false + }, + "public.agentmail_user_mappings": { + "name": "agentmail_user_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "email_address": { + "name": "email_address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "agentmail_user_mappings_user_id_idx": { + "name": "agentmail_user_mappings_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "agentmail_user_mappings_user_id_users_id_fk": { + "name": "agentmail_user_mappings_user_id_users_id_fk", + "tableFrom": "agentmail_user_mappings", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "agentmail_user_mappings_unique": { + "name": "agentmail_user_mappings_unique", + "nullsNotDistinct": false, + "columns": ["email_address"] + } + }, + "policies": {}, + "checkConstraints": { + "agentmail_user_mappings_source_check": { + "name": "agentmail_user_mappings_source_check", + "value": "\"agentmail_user_mappings\".\"source\" in ('verified_match', 'link_code')" + } + }, + "isRLSEnabled": false + }, + "public.agentmail_webhook_events": { + "name": "agentmail_webhook_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "delivery_id": { + "name": "delivery_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'received'" + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "received_at": { + "name": "received_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "agentmail_webhook_events_state_idx": { + "name": "agentmail_webhook_events_state_idx", + "columns": [ + { + "expression": "state", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "received_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "agentmail_webhook_events_delivery_unique": { + "name": "agentmail_webhook_events_delivery_unique", + "nullsNotDistinct": false, + "columns": ["delivery_id"] + } + }, + "policies": {}, + "checkConstraints": { + "agentmail_webhook_events_state_check": { + "name": "agentmail_webhook_events_state_check", + "value": "\"agentmail_webhook_events\".\"state\" in ('received', 'queued', 'processing', 'processed', 'failed')" + } + }, + "isRLSEnabled": false + }, + "public.auth_accounts": { + "name": "auth_accounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "auth_accounts_user_id_idx": { + "name": "auth_accounts_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "auth_accounts_provider_account_unique": { + "name": "auth_accounts_provider_account_unique", + "columns": [ + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "auth_accounts_user_id_auth_users_id_fk": { + "name": "auth_accounts_user_id_auth_users_id_fk", + "tableFrom": "auth_accounts", + "tableTo": "auth_users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth_sessions": { + "name": "auth_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "auth_sessions_token_unique": { + "name": "auth_sessions_token_unique", + "columns": [ + { + "expression": "token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "auth_sessions_user_id_idx": { + "name": "auth_sessions_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "auth_sessions_user_id_auth_users_id_fk": { + "name": "auth_sessions_user_id_auth_users_id_fk", + "tableFrom": "auth_sessions", + "tableTo": "auth_users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth_users": { + "name": "auth_users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "auth_users_email_unique": { + "name": "auth_users_email_unique", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "auth_users_created_at_idx": { + "name": "auth_users_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth_verifications": { + "name": "auth_verifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "auth_verifications_identifier_idx": { + "name": "auth_verifications_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.automation_results": { + "name": "automation_results", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "automation_key": { + "name": "automation_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "custom_automation_id": { + "name": "custom_automation_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "source_task_id": { + "name": "source_task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_run_id": { + "name": "source_run_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "source_session_id": { + "name": "source_session_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "result_visibility": { + "name": "result_visibility", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "automation_name": { + "name": "automation_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "launch_criteria_snapshot": { + "name": "launch_criteria_snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "launch_criteria_answers": { + "name": "launch_criteria_answers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "launch_criteria_outcome": { + "name": "launch_criteria_outcome", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "result_kind": { + "name": "result_kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'outcome'" + }, + "headline": { + "name": "headline", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "decision_context": { + "name": "decision_context", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "selected_reference_keys": { + "name": "selected_reference_keys", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "preparation_status": { + "name": "preparation_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "preparation_attempts": { + "name": "preparation_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "preparation_version": { + "name": "preparation_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "prepared_at": { + "name": "prepared_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "preparation_error_code": { + "name": "preparation_error_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'normal'" + }, + "dedupe_key": { + "name": "dedupe_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "accepted_at": { + "name": "accepted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "acceptance_reason": { + "name": "acceptance_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ignored_at": { + "name": "ignored_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "superseded_at": { + "name": "superseded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "automation_results_dedupe_key_unique_idx": { + "name": "automation_results_dedupe_key_unique_idx", + "columns": [ + { + "expression": "dedupe_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "automation_results_inbox_idx": { + "name": "automation_results_inbox_idx", + "columns": [ + { + "expression": "priority", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "automation_results_user_id_idx": { + "name": "automation_results_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "automation_results_source_task_id_idx": { + "name": "automation_results_source_task_id_idx", + "columns": [ + { + "expression": "source_task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "automation_results_source_run_id_idx": { + "name": "automation_results_source_run_id_idx", + "columns": [ + { + "expression": "source_run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "automation_results_source_session_id_idx": { + "name": "automation_results_source_session_id_idx", + "columns": [ + { + "expression": "source_session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "automation_results_preparation_status_created_at_idx": { + "name": "automation_results_preparation_status_created_at_idx", + "columns": [ + { + "expression": "preparation_status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "automation_results_automation_key_automations_key_fk": { + "name": "automation_results_automation_key_automations_key_fk", + "tableFrom": "automation_results", + "tableTo": "automations", + "columnsFrom": ["automation_key"], + "columnsTo": ["key"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "automation_results_custom_automation_id_custom_automations_id_fk": { + "name": "automation_results_custom_automation_id_custom_automations_id_fk", + "tableFrom": "automation_results", + "tableTo": "custom_automations", + "columnsFrom": ["custom_automation_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "automation_results_source_task_id_tasks_id_fk": { + "name": "automation_results_source_task_id_tasks_id_fk", + "tableFrom": "automation_results", + "tableTo": "tasks", + "columnsFrom": ["source_task_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "automation_results_source_run_id_task_runs_id_fk": { + "name": "automation_results_source_run_id_task_runs_id_fk", + "tableFrom": "automation_results", + "tableTo": "task_runs", + "columnsFrom": ["source_run_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "automation_results_source_session_id_sessions_id_fk": { + "name": "automation_results_source_session_id_sessions_id_fk", + "tableFrom": "automation_results", + "tableTo": "sessions", + "columnsFrom": ["source_session_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "automation_results_user_id_users_id_fk": { + "name": "automation_results_user_id_users_id_fk", + "tableFrom": "automation_results", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "automation_results_result_kind_check": { + "name": "automation_results_result_kind_check", + "value": "\"automation_results\".\"result_kind\" in ('outcome', 'input_request')" + }, + "automation_results_preparation_status_check": { + "name": "automation_results_preparation_status_check", + "value": "\"automation_results\".\"preparation_status\" in ('pending', 'ready', 'failed')" + } + }, + "isRLSEnabled": false + }, + "public.automations": { + "name": "automations", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "internal": { + "name": "internal", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "webhook_secret": { + "name": "webhook_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schedule": { + "name": "schedule", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "instructions": { + "name": "instructions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "settings": { + "name": "settings", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "targets": { + "name": "targets", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_succeeded_at": { + "name": "last_succeeded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_failed_at": { + "name": "last_failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scan_cursor": { + "name": "scan_cursor", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.brain_collector_items": { + "name": "brain_collector_items", + "schema": "", + "columns": { + "collector_id": { + "name": "collector_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "brain_collector_items_collector_seen_idx": { + "name": "brain_collector_items_collector_seen_idx", + "columns": [ + { + "expression": "collector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_seen_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "brain_collector_items_collector_item_pk": { + "name": "brain_collector_items_collector_item_pk", + "columns": ["collector_id", "item_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.brain_memory_events": { + "name": "brain_memory_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "agent_summary": { + "name": "agent_summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "revision": { + "name": "revision", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "brain_memory_events_status_created_idx": { + "name": "brain_memory_events_status_created_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "brain_memory_events_run_id_task_runs_id_fk": { + "name": "brain_memory_events_run_id_task_runs_id_fk", + "tableFrom": "brain_memory_events", + "tableTo": "task_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "brain_memory_events_run_unique": { + "name": "brain_memory_events_run_unique", + "nullsNotDistinct": false, + "columns": ["run_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.brain_page_retirements": { + "name": "brain_page_retirements", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "revision": { + "name": "revision", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "brain_page_retirements_status_created_idx": { + "name": "brain_page_retirements_status_created_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "brain_page_retirements_slug_unique": { + "name": "brain_page_retirements_slug_unique", + "nullsNotDistinct": false, + "columns": ["slug"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.brain_sync_state": { + "name": "brain_sync_state", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "collector_id": { + "name": "collector_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "watermark": { + "name": "watermark", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "backfill_cursor": { + "name": "backfill_cursor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "backfill_completed_at": { + "name": "backfill_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "brain_sync_state_collector_id_unique": { + "name": "brain_sync_state_collector_id_unique", + "nullsNotDistinct": false, + "columns": ["collector_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compute_provider_usage": { + "name": "compute_provider_usage", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_usage_id": { + "name": "provider_usage_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auth_kind": { + "name": "auth_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "run_id": { + "name": "run_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "instance_id": { + "name": "instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "launch_mode": { + "name": "launch_mode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lifecycle_action": { + "name": "lifecycle_action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measurement_source": { + "name": "measurement_source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "configured_vcpus": { + "name": "configured_vcpus", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "configured_cpu_cores": { + "name": "configured_cpu_cores", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "configured_memory_mib": { + "name": "configured_memory_mib", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "wall_clock_duration_ms": { + "name": "wall_clock_duration_ms", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "active_cpu_duration_ms": { + "name": "active_cpu_duration_ms", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "observed_memory_mib_milliseconds": { + "name": "observed_memory_mib_milliseconds", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "network_ingress_bytes": { + "name": "network_ingress_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "network_egress_bytes": { + "name": "network_egress_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "details": { + "name": "details", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "compute_provider_usage_provider_usage_id_unique": { + "name": "compute_provider_usage_provider_usage_id_unique", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_usage_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "compute_provider_usage_run_id_idx": { + "name": "compute_provider_usage_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "compute_provider_usage_task_id_idx": { + "name": "compute_provider_usage_task_id_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "compute_provider_usage_created_at_idx": { + "name": "compute_provider_usage_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "compute_provider_usage_run_id_task_runs_id_fk": { + "name": "compute_provider_usage_run_id_task_runs_id_fk", + "tableFrom": "compute_provider_usage", + "tableTo": "task_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compute_provider_usage_task_id_tasks_id_fk": { + "name": "compute_provider_usage_task_id_tasks_id_fk", + "tableFrom": "compute_provider_usage", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compute_provider_usage_samples": { + "name": "compute_provider_usage_samples", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_usage_id": { + "name": "provider_usage_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "run_id": { + "name": "run_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "instance_id": { + "name": "instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sampled_at": { + "name": "sampled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "cpu_usage_ns_total": { + "name": "cpu_usage_ns_total", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "memory_usage_bytes": { + "name": "memory_usage_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "memory_peak_usage_bytes": { + "name": "memory_peak_usage_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "details": { + "name": "details", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "compute_provider_usage_samples_provider_usage_sampled_at_unique": { + "name": "compute_provider_usage_samples_provider_usage_sampled_at_unique", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_usage_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sampled_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "compute_provider_usage_samples_run_id_idx": { + "name": "compute_provider_usage_samples_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "compute_provider_usage_samples_task_id_idx": { + "name": "compute_provider_usage_samples_task_id_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "compute_provider_usage_samples_created_at_idx": { + "name": "compute_provider_usage_samples_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "compute_provider_usage_samples_run_id_task_runs_id_fk": { + "name": "compute_provider_usage_samples_run_id_task_runs_id_fk", + "tableFrom": "compute_provider_usage_samples", + "tableTo": "task_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compute_provider_usage_samples_task_id_tasks_id_fk": { + "name": "compute_provider_usage_samples_task_id_tasks_id_fk", + "tableFrom": "compute_provider_usage_samples", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credential_egress_audit": { + "name": "credential_egress_audit", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "authorization_id": { + "name": "authorization_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workload_id": { + "name": "workload_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "actor_user_id": { + "name": "actor_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_ref": { + "name": "secret_ref", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "phase": { + "name": "phase", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "destination": { + "name": "destination", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "decision": { + "name": "decision", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credential_egress_revocations": { + "name": "credential_egress_revocations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "identity": { + "type": "always", + "name": "credential_egress_revocations_id_seq", + "schema": "public", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "2147483647", + "cache": "1", + "cycle": false + } + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workload_id": { + "name": "workload_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "secret_ref": { + "name": "secret_ref", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credential_egress_substitutes": { + "name": "credential_egress_substitutes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workload_id": { + "name": "workload_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "secret_id": { + "name": "secret_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_egress_substitutes_token_hash_unique": { + "name": "credential_egress_substitutes_token_hash_unique", + "columns": [ + { + "expression": "token_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_egress_substitutes_workload_secret_generation_unique": { + "name": "credential_egress_substitutes_workload_secret_generation_unique", + "columns": [ + { + "expression": "workload_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "generation", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_egress_substitutes_workload_id_credential_egress_workloads_id_fk": { + "name": "credential_egress_substitutes_workload_id_credential_egress_workloads_id_fk", + "tableFrom": "credential_egress_substitutes", + "tableTo": "credential_egress_workloads", + "columnsFrom": ["workload_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_egress_substitutes_secret_id_service_credentials_id_fk": { + "name": "credential_egress_substitutes_secret_id_service_credentials_id_fk", + "tableFrom": "credential_egress_substitutes", + "tableTo": "service_credentials", + "columnsFrom": ["secret_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credential_egress_workloads": { + "name": "credential_egress_workloads", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "task_run_id": { + "name": "task_run_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connector_identity": { + "name": "connector_identity", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "terminated_at": { + "name": "terminated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "termination_reason": { + "name": "termination_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_egress_workloads_active_run_unique": { + "name": "credential_egress_workloads_active_run_unique", + "columns": [ + { + "expression": "task_run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"credential_egress_workloads\".\"status\" = 'active'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_egress_workloads_active_connector_unique": { + "name": "credential_egress_workloads_active_connector_unique", + "columns": [ + { + "expression": "connector_identity", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"credential_egress_workloads\".\"status\" = 'active'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_egress_workloads_session_idx": { + "name": "credential_egress_workloads_session_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_egress_workloads_session_id_sessions_id_fk": { + "name": "credential_egress_workloads_session_id_sessions_id_fk", + "tableFrom": "credential_egress_workloads", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_egress_workloads_owner_user_id_users_id_fk": { + "name": "credential_egress_workloads_owner_user_id_users_id_fk", + "tableFrom": "credential_egress_workloads", + "tableTo": "users", + "columnsFrom": ["owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_egress_workloads_task_run_id_task_runs_id_fk": { + "name": "credential_egress_workloads_task_run_id_task_runs_id_fk", + "tableFrom": "credential_egress_workloads", + "tableTo": "task_runs", + "columnsFrom": ["task_run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "credential_egress_workloads_status_check": { + "name": "credential_egress_workloads_status_check", + "value": "\"credential_egress_workloads\".\"status\" in ('active', 'terminated')" + } + }, + "isRLSEnabled": false + }, + "public.custom_automations": { + "name": "custom_automations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "webhook_secret": { + "name": "webhook_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "launch_criteria": { + "name": "launch_criteria", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "run_when": { + "name": "run_when", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "result_priority": { + "name": "result_priority", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'normal'" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "schedule_mode": { + "name": "schedule_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'off'" + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reasoning_effort": { + "name": "reasoning_effort", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "all_repositories": { + "name": "all_repositories", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "no_repositories": { + "name": "no_repositories", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "execution_mode": { + "name": "execution_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'sandbox_task'" + }, + "target": { + "name": "target", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_succeeded_at": { + "name": "last_succeeded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_failed_at": { + "name": "last_failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_launched_task_id": { + "name": "last_launched_task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "launch_claimed_at": { + "name": "launch_claimed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "custom_automations_name_unique_idx": { + "name": "custom_automations_name_unique_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "custom_automations_enabled_idx": { + "name": "custom_automations_enabled_idx", + "columns": [ + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "custom_automations_environment_id_idx": { + "name": "custom_automations_environment_id_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "custom_automations_environment_id_environments_id_fk": { + "name": "custom_automations_environment_id_environments_id_fk", + "tableFrom": "custom_automations", + "tableTo": "environments", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "custom_automations_created_by_user_id_users_id_fk": { + "name": "custom_automations_created_by_user_id_users_id_fk", + "tableFrom": "custom_automations", + "tableTo": "users", + "columnsFrom": ["created_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "custom_automations_last_launched_task_id_tasks_id_fk": { + "name": "custom_automations_last_launched_task_id_tasks_id_fk", + "tableFrom": "custom_automations", + "tableTo": "tasks", + "columnsFrom": ["last_launched_task_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_mcp_servers": { + "name": "custom_mcp_servers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "headers": { + "name": "headers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "stdio": { + "name": "stdio", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "disabled_tools": { + "name": "disabled_tools", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "manual_client_id": { + "name": "manual_client_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "manual_client_secret": { + "name": "manual_client_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_server_metadata": { + "name": "oauth_server_metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "oauth_server_metadata_fetched_at": { + "name": "oauth_server_metadata_fetched_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "oauth_resource_indicator_disabled": { + "name": "oauth_resource_indicator_disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "custom_mcp_servers_created_by_user_id_users_id_fk": { + "name": "custom_mcp_servers_created_by_user_id_users_id_fk", + "tableFrom": "custom_mcp_servers", + "tableTo": "users", + "columnsFrom": ["created_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "custom_mcp_servers_name_unique": { + "name": "custom_mcp_servers_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_mcp_enablements": { + "name": "deployment_mcp_enablements", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "mcp_id": { + "name": "mcp_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "enabled_by_user_id": { + "name": "enabled_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "disabled_tools": { + "name": "disabled_tools", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "tool_access_mode": { + "name": "tool_access_mode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_mcp_enablements_enabled_by_user_id_users_id_fk": { + "name": "deployment_mcp_enablements_enabled_by_user_id_users_id_fk", + "tableFrom": "deployment_mcp_enablements", + "tableTo": "users", + "columnsFrom": ["enabled_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "deployment_mcp_enablements_mcp_unique": { + "name": "deployment_mcp_enablements_mcp_unique", + "nullsNotDistinct": false, + "columns": ["mcp_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_secrets": { + "name": "deployment_secrets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "deployment_secrets_name_unique": { + "name": "deployment_secrets_name_unique", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_settings": { + "name": "deployment_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "'default'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "task_model_settings": { + "name": "task_model_settings", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workspace_routing_settings": { + "name": "workspace_routing_settings", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "router_debug_provider": { + "name": "router_debug_provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "router_debug_channel_id": { + "name": "router_debug_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "router_debug_disabled": { + "name": "router_debug_disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "router_debug_slack_channel_id": { + "name": "router_debug_slack_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "runtime_model_config": { + "name": "runtime_model_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "model_fallback_config": { + "name": "model_fallback_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "runtime_compute_config": { + "name": "runtime_compute_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "access_policy": { + "name": "access_policy", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "brain_enabled": { + "name": "brain_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "email_outbound_enabled": { + "name": "email_outbound_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "session_done_webhook_enabled": { + "name": "session_done_webhook_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "session_done_webhook_url": { + "name": "session_done_webhook_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_done_webhook_secret": { + "name": "session_done_webhook_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "license_key": { + "name": "license_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "license_cloud_state": { + "name": "license_cloud_state", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "instance_analytics_id": { + "name": "instance_analytics_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "latest_known_version": { + "name": "latest_known_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "latest_version_checked_at": { + "name": "latest_version_checked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "installed_release_version": { + "name": "installed_release_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installed_release_recorded_at": { + "name": "installed_release_recorded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "setup_completed_at": { + "name": "setup_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "setup_new_state": { + "name": "setup_new_state", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "slack_onboarding_stage": { + "name": "slack_onboarding_stage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "manager_slack_channel_id": { + "name": "manager_slack_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "manager_discord_channel_id": { + "name": "manager_discord_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_automation_target": { + "name": "default_automation_target", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "global_agent_instructions": { + "name": "global_agent_instructions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "time_zone": { + "name": "time_zone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "time_zone_updated_at": { + "name": "time_zone_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "authorship_instructions": { + "name": "authorship_instructions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "compiled_authorship_rules": { + "name": "compiled_authorship_rules", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "compiled_authorship_issues": { + "name": "compiled_authorship_issues", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "compiled_authorship_at": { + "name": "compiled_authorship_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "style_guidance": { + "name": "style_guidance", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slack_summon_emoji": { + "name": "slack_summon_emoji", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slack_ack_emoji": { + "name": "slack_ack_emoji", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'eyes'" + }, + "slack_completion_emoji": { + "name": "slack_completion_emoji", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'white_check_mark'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.discord_gateway_sessions": { + "name": "discord_gateway_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resume_gateway_url": { + "name": "resume_gateway_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sequence": { + "name": "sequence", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "shard_count": { + "name": "shard_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_connected_at": { + "name": "last_connected_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_heartbeat_ack_at": { + "name": "last_heartbeat_ack_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "disconnected_at": { + "name": "disconnected_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.discord_installation_channels": { + "name": "discord_installation_channels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "discord_installation_id": { + "name": "discord_installation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel_name": { + "name": "channel_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "channel_type": { + "name": "channel_type", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_available": { + "name": "is_available", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "discord_installation_channels_installation_id_idx": { + "name": "discord_installation_channels_installation_id_idx", + "columns": [ + { + "expression": "discord_installation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "discord_installation_channels_unique": { + "name": "discord_installation_channels_unique", + "columns": [ + { + "expression": "discord_installation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "channel_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "discord_installation_channels_discord_installation_id_discord_installations_id_fk": { + "name": "discord_installation_channels_discord_installation_id_discord_installations_id_fk", + "tableFrom": "discord_installation_channels", + "tableTo": "discord_installations", + "columnsFrom": ["discord_installation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.discord_installations": { + "name": "discord_installations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "guild_name": { + "name": "guild_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "application_id": { + "name": "application_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bot_user_id": { + "name": "bot_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "installed_by_user_id": { + "name": "installed_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_channel_id": { + "name": "default_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_channel_name": { + "name": "default_channel_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_channel_type": { + "name": "default_channel_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "discord_installations_guild_id_unique": { + "name": "discord_installations_guild_id_unique", + "columns": [ + { + "expression": "guild_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "discord_installations_active_idx": { + "name": "discord_installations_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "discord_installations_default_channel_idx": { + "name": "discord_installations_default_channel_idx", + "columns": [ + { + "expression": "default_channel_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "discord_installations_installed_by_user_id_users_id_fk": { + "name": "discord_installations_installed_by_user_id_users_id_fk", + "tableFrom": "discord_installations", + "tableTo": "users", + "columnsFrom": ["installed_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.discord_user_mappings": { + "name": "discord_user_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "discord_user_id": { + "name": "discord_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "discord_username": { + "name": "discord_username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discord_global_name": { + "name": "discord_global_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discord_dm_channel_id": { + "name": "discord_dm_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "discord_user_mappings_user_id_idx": { + "name": "discord_user_mappings_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "discord_user_mappings_discord_user_id_unique": { + "name": "discord_user_mappings_discord_user_id_unique", + "columns": [ + { + "expression": "discord_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "discord_user_mappings_user_id_users_id_fk": { + "name": "discord_user_mappings_user_id_users_id_fk", + "tableFrom": "discord_user_mappings", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.environment_config_versions": { + "name": "environment_config_versions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "environment_config_versions_environment_id_idx": { + "name": "environment_config_versions_environment_id_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "environment_config_versions_environment_version_unique": { + "name": "environment_config_versions_environment_version_unique", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "version", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "environment_config_versions_environment_id_environments_id_fk": { + "name": "environment_config_versions_environment_id_environments_id_fk", + "tableFrom": "environment_config_versions", + "tableTo": "environments", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "environment_config_versions_created_by_user_id_users_id_fk": { + "name": "environment_config_versions_created_by_user_id_users_id_fk", + "tableFrom": "environment_config_versions", + "tableTo": "users", + "columnsFrom": ["created_by_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.environment_repository_mappings": { + "name": "environment_repository_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "repository_id": { + "name": "repository_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "env_repo_mappings_env_id_idx": { + "name": "env_repo_mappings_env_id_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "env_repo_mappings_repo_id_idx": { + "name": "env_repo_mappings_repo_id_idx", + "columns": [ + { + "expression": "repository_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "environment_repository_mappings_environment_id_environments_id_fk": { + "name": "environment_repository_mappings_environment_id_environments_id_fk", + "tableFrom": "environment_repository_mappings", + "tableTo": "environments", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "environment_repository_mappings_repository_id_repositories_id_fk": { + "name": "environment_repository_mappings_repository_id_repositories_id_fk", + "tableFrom": "environment_repository_mappings", + "tableTo": "repositories", + "columnsFrom": ["repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "env_repo_mappings_unique": { + "name": "env_repo_mappings_unique", + "nullsNotDistinct": false, + "columns": ["environment_id", "repository_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.environment_snapshots": { + "name": "environment_snapshots", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "snapshot_id": { + "name": "snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "snapshot_created_at": { + "name": "snapshot_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "snapshot_expires_at": { + "name": "snapshot_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "snapshot_status": { + "name": "snapshot_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "worker_version": { + "name": "worker_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "environment_snapshots_environment_id_idx": { + "name": "environment_snapshots_environment_id_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "environment_snapshots_env_provider_unique": { + "name": "environment_snapshots_env_provider_unique", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"environment_snapshots\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "environment_snapshots_environment_id_environments_id_fk": { + "name": "environment_snapshots_environment_id_environments_id_fk", + "tableFrom": "environment_snapshots", + "tableTo": "environments", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.environment_variables": { + "name": "environment_variables", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_updated_by_user_id": { + "name": "last_updated_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "environment_variables_user_id_idx": { + "name": "environment_variables_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "environment_variables_name_unique": { + "name": "environment_variables_name_unique", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "environment_variables_user_id_users_id_fk": { + "name": "environment_variables_user_id_users_id_fk", + "tableFrom": "environment_variables", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "environment_variables_created_by_user_id_users_id_fk": { + "name": "environment_variables_created_by_user_id_users_id_fk", + "tableFrom": "environment_variables", + "tableTo": "users", + "columnsFrom": ["created_by_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "environment_variables_last_updated_by_user_id_users_id_fk": { + "name": "environment_variables_last_updated_by_user_id_users_id_fk", + "tableFrom": "environment_variables", + "tableTo": "users", + "columnsFrom": ["last_updated_by_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.environments": { + "name": "environments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "is_eval": { + "name": "is_eval", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "declarative_source": { + "name": "declarative_source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_verified": { + "name": "is_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "verification_task_id": { + "name": "verification_task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "verified_at": { + "name": "verified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "verification_error": { + "name": "verification_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "snapshot_id": { + "name": "snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "snapshot_created_at": { + "name": "snapshot_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "snapshot_expires_at": { + "name": "snapshot_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "snapshot_status": { + "name": "snapshot_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "environments_user_id_idx": { + "name": "environments_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "environments_created_by_user_id_idx": { + "name": "environments_created_by_user_id_idx", + "columns": [ + { + "expression": "created_by_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "environments_snapshot_expires_at_idx": { + "name": "environments_snapshot_expires_at_idx", + "columns": [ + { + "expression": "snapshot_expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "environments_name_unique": { + "name": "environments_name_unique", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "environments_user_id_users_id_fk": { + "name": "environments_user_id_users_id_fk", + "tableFrom": "environments", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "environments_created_by_user_id_users_id_fk": { + "name": "environments_created_by_user_id_users_id_fk", + "tableFrom": "environments", + "tableTo": "users", + "columnsFrom": ["created_by_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.fast_agent_conversations": { + "name": "fast_agent_conversations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_automation": { + "name": "owner_automation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "privacy": { + "name": "privacy", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'shared'" + }, + "private_owner_user_id": { + "name": "private_owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surface": { + "name": "surface", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "conversation_id": { + "name": "conversation_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "current_reply_channel_id": { + "name": "current_reply_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "current_reply_thread_id": { + "name": "current_reply_thread_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "current_reply_service_url": { + "name": "current_reply_service_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reply_target_verified": { + "name": "reply_target_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "compatibility_messages": { + "name": "compatibility_messages", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "opencode_session_id": { + "name": "opencode_session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reasoning_effort": { + "name": "reasoning_effort", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title_edited_by_user_at": { + "name": "title_edited_by_user_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "llm_title_checkpoint": { + "name": "llm_title_checkpoint", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "legacy_conversation_ids": { + "name": "legacy_conversation_ids", + "type": "uuid[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::uuid[]" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "fast_agent_conversations_identity_unique": { + "name": "fast_agent_conversations_identity_unique", + "columns": [ + { + "expression": "surface", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "fast_agent_conversations_user_idx": { + "name": "fast_agent_conversations_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "fast_agent_conversations_owner_automation_idx": { + "name": "fast_agent_conversations_owner_automation_idx", + "columns": [ + { + "expression": "owner_automation", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "fast_agent_conversations_legacy_ids_idx": { + "name": "fast_agent_conversations_legacy_ids_idx", + "columns": [ + { + "expression": "legacy_conversation_ids", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": { + "fast_agent_conversations_user_id_users_id_fk": { + "name": "fast_agent_conversations_user_id_users_id_fk", + "tableFrom": "fast_agent_conversations", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "fast_agent_conversations_private_owner_user_id_users_id_fk": { + "name": "fast_agent_conversations_private_owner_user_id_users_id_fk", + "tableFrom": "fast_agent_conversations", + "tableTo": "users", + "columnsFrom": ["private_owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "fast_agent_conversations_owner_shape_check": { + "name": "fast_agent_conversations_owner_shape_check", + "value": "(\n (\"fast_agent_conversations\".\"user_id\" is not null and \"fast_agent_conversations\".\"owner_automation\" is null)\n or\n (\"fast_agent_conversations\".\"user_id\" is null and \"fast_agent_conversations\".\"owner_automation\" is not null)\n )" + }, + "fast_agent_conversations_privacy_check": { + "name": "fast_agent_conversations_privacy_check", + "value": "\"fast_agent_conversations\".\"privacy\" in ('shared', 'private')" + }, + "fast_agent_conversations_private_owner_check": { + "name": "fast_agent_conversations_private_owner_check", + "value": "(\"fast_agent_conversations\".\"privacy\" = 'shared' AND \"fast_agent_conversations\".\"private_owner_user_id\" IS NULL) OR (\"fast_agent_conversations\".\"privacy\" = 'private' AND \"fast_agent_conversations\".\"private_owner_user_id\" IS NOT NULL AND \"fast_agent_conversations\".\"private_owner_user_id\" = \"fast_agent_conversations\".\"user_id\")" + } + }, + "isRLSEnabled": false + }, + "public.fast_agent_memory_events": { + "name": "fast_agent_memory_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "conversation_id": { + "name": "conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "memory": { + "name": "memory", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "revision": { + "name": "revision", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "fast_agent_memory_events_status_created_idx": { + "name": "fast_agent_memory_events_status_created_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "fast_agent_memory_events_conversation_id_fast_agent_conversations_id_fk": { + "name": "fast_agent_memory_events_conversation_id_fast_agent_conversations_id_fk", + "tableFrom": "fast_agent_memory_events", + "tableTo": "fast_agent_conversations", + "columnsFrom": ["conversation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "fast_agent_memory_events_conversation_unique": { + "name": "fast_agent_memory_events_conversation_unique", + "nullsNotDistinct": false, + "columns": ["conversation_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.fast_agent_messages": { + "name": "fast_agent_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "conversation_id": { + "name": "conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "turn_id": { + "name": "turn_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "turn_seq": { + "name": "turn_seq", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "ts": { + "name": "ts", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_blocks": { + "name": "content_blocks", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "native_session_id": { + "name": "native_session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "native_message_id": { + "name": "native_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "fast_agent_messages_conversation_event_unique": { + "name": "fast_agent_messages_conversation_event_unique", + "columns": [ + { + "expression": "conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "event_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "fast_agent_messages_conversation_order_idx": { + "name": "fast_agent_messages_conversation_order_idx", + "columns": [ + { + "expression": "conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "ts", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "turn_seq", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "fast_agent_messages_visible_user_order_idx": { + "name": "fast_agent_messages_visible_user_order_idx", + "columns": [ + { + "expression": "conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "ts", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\n \"fast_agent_messages\".\"role\" = 'user'\n AND (\n \"fast_agent_messages\".\"metadata\" ->> 'visibleInTranscript' = 'true'\n OR (\n \"fast_agent_messages\".\"metadata\" ->> 'visibleInTranscript' IS NULL\n AND \"fast_agent_messages\".\"event_type\" <> 'roomote_runtime.user_prompt'\n )\n )\n ", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "fast_agent_messages_conversation_id_fast_agent_conversations_id_fk": { + "name": "fast_agent_messages_conversation_id_fast_agent_conversations_id_fk", + "tableFrom": "fast_agent_messages", + "tableTo": "fast_agent_conversations", + "columnsFrom": ["conversation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.fast_agent_parent_events": { + "name": "fast_agent_parent_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "conversation_id": { + "name": "conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_key": { + "name": "event_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent": { + "name": "parent", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "event": { + "name": "event", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "retry_task_start_run_id": { + "name": "retry_task_start_run_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "delivered_at": { + "name": "delivered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "discarded_at": { + "name": "discarded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "admission": { + "name": "admission", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "claimed_until": { + "name": "claimed_until", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "retry_at": { + "name": "retry_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "inference_retries": { + "name": "inference_retries", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "fast_agent_parent_events_pending_idx": { + "name": "fast_agent_parent_events_pending_idx", + "columns": [ + { + "expression": "conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "delivered_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "discarded_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "fast_agent_parent_events_retry_run_idx": { + "name": "fast_agent_parent_events_retry_run_idx", + "columns": [ + { + "expression": "retry_task_start_run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "fast_agent_parent_events_conversation_id_fast_agent_conversations_id_fk": { + "name": "fast_agent_parent_events_conversation_id_fast_agent_conversations_id_fk", + "tableFrom": "fast_agent_parent_events", + "tableTo": "fast_agent_conversations", + "columnsFrom": ["conversation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "fast_agent_parent_events_retry_task_start_run_id_task_runs_id_fk": { + "name": "fast_agent_parent_events_retry_task_start_run_id_task_runs_id_fk", + "tableFrom": "fast_agent_parent_events", + "tableTo": "task_runs", + "columnsFrom": ["retry_task_start_run_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "fast_agent_parent_events_event_key_unique": { + "name": "fast_agent_parent_events_event_key_unique", + "nullsNotDistinct": false, + "columns": ["event_key"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.fast_agent_personalization_snapshots": { + "name": "fast_agent_personalization_snapshots", + "schema": "", + "columns": { + "conversation_id": { + "name": "conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "instructions": { + "name": "instructions", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "learn_from_conversations": { + "name": "learn_from_conversations", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "fast_agent_personalization_snapshots_conversation_id_fast_agent_conversations_id_fk": { + "name": "fast_agent_personalization_snapshots_conversation_id_fast_agent_conversations_id_fk", + "tableFrom": "fast_agent_personalization_snapshots", + "tableTo": "fast_agent_conversations", + "columnsFrom": ["conversation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "fast_agent_personalization_snapshots_user_id_users_id_fk": { + "name": "fast_agent_personalization_snapshots_user_id_users_id_fk", + "tableFrom": "fast_agent_personalization_snapshots", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "fast_agent_personalization_snapshots_conversation_id_user_id_pk": { + "name": "fast_agent_personalization_snapshots_conversation_id_user_id_pk", + "columns": ["conversation_id", "user_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.fast_agent_pr_feedback_deliveries": { + "name": "fast_agent_pr_feedback_deliveries", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "conversation_id": { + "name": "conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "feedback_id": { + "name": "feedback_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lease_token": { + "name": "lease_token", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "lease_expires_at": { + "name": "lease_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "delivered_at": { + "name": "delivered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "fast_agent_pr_feedback_deliveries_identity_unique": { + "name": "fast_agent_pr_feedback_deliveries_identity_unique", + "columns": [ + { + "expression": "conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "feedback_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "fast_agent_pr_feedback_deliveries_task_idx": { + "name": "fast_agent_pr_feedback_deliveries_task_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "fast_agent_pr_feedback_deliveries_conversation_id_fast_agent_conversations_id_fk": { + "name": "fast_agent_pr_feedback_deliveries_conversation_id_fast_agent_conversations_id_fk", + "tableFrom": "fast_agent_pr_feedback_deliveries", + "tableTo": "fast_agent_conversations", + "columnsFrom": ["conversation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "fast_agent_pr_feedback_deliveries_task_id_tasks_id_fk": { + "name": "fast_agent_pr_feedback_deliveries_task_id_tasks_id_fk", + "tableFrom": "fast_agent_pr_feedback_deliveries", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.fast_agent_provider_messages": { + "name": "fast_agent_provider_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "conversation_id": { + "name": "conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "fast_agent_provider_messages_route_unique": { + "name": "fast_agent_provider_messages_route_unique", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "channel_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "fast_agent_provider_messages_conversation_idx": { + "name": "fast_agent_provider_messages_conversation_idx", + "columns": [ + { + "expression": "conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "fast_agent_provider_messages_thread_idx": { + "name": "fast_agent_provider_messages_thread_idx", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "channel_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "thread_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "fast_agent_provider_messages_conversation_id_fast_agent_conversations_id_fk": { + "name": "fast_agent_provider_messages_conversation_id_fast_agent_conversations_id_fk", + "tableFrom": "fast_agent_provider_messages", + "tableTo": "fast_agent_conversations", + "columnsFrom": ["conversation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "fast_agent_provider_messages_provider_v3_check": { + "name": "fast_agent_provider_messages_provider_v3_check", + "value": "\"fast_agent_provider_messages\".\"provider\" in ('discord', 'slack', 'teams', 'telegram', 'agentmail')" + } + }, + "isRLSEnabled": false + }, + "public.github_installations": { + "name": "github_installations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installation_id": { + "name": "installation_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "app_id": { + "name": "app_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "account_login": { + "name": "account_login", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_type": { + "name": "account_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permissions": { + "name": "permissions", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "installed_by_user_id": { + "name": "installed_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "members_count": { + "name": "members_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "suspended_at": { + "name": "suspended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "github_installations_account_login_idx": { + "name": "github_installations_account_login_idx", + "columns": [ + { + "expression": "account_login", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "github_installations_deployment_installation_unique": { + "name": "github_installations_deployment_installation_unique", + "columns": [ + { + "expression": "installation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "github_installations_user_id_users_id_fk": { + "name": "github_installations_user_id_users_id_fk", + "tableFrom": "github_installations", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "github_installations_installed_by_user_id_users_id_fk": { + "name": "github_installations_installed_by_user_id_users_id_fk", + "tableFrom": "github_installations", + "tableTo": "users", + "columnsFrom": ["installed_by_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.github_pending_installations": { + "name": "github_pending_installations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "requested_by_user_id": { + "name": "requested_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "app_id": { + "name": "app_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "github_pending_installations_requested_by_user_id_idx": { + "name": "github_pending_installations_requested_by_user_id_idx", + "columns": [ + { + "expression": "requested_by_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "github_pending_installations_user_id_users_id_fk": { + "name": "github_pending_installations_user_id_users_id_fk", + "tableFrom": "github_pending_installations", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "github_pending_installations_requested_by_user_id_users_id_fk": { + "name": "github_pending_installations_requested_by_user_id_users_id_fk", + "tableFrom": "github_pending_installations", + "tableTo": "users", + "columnsFrom": ["requested_by_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.github_user_mappings": { + "name": "github_user_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "github_login": { + "name": "github_login", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "github_user_id": { + "name": "github_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token_expires_at": { + "name": "token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "github_user_mappings_github_login_idx": { + "name": "github_user_mappings_github_login_idx", + "columns": [ + { + "expression": "github_login", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "github_user_mappings_user_id_idx": { + "name": "github_user_mappings_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "github_user_mappings_user_id_users_id_fk": { + "name": "github_user_mappings_user_id_users_id_fk", + "tableFrom": "github_user_mappings", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "github_user_mappings_unique": { + "name": "github_user_mappings_unique", + "nullsNotDistinct": false, + "columns": ["github_user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.instance_skills": { + "name": "instance_skills", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "instance_skills_name_unique_idx": { + "name": "instance_skills_name_unique_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "instance_skills_created_by_user_id_users_id_fk": { + "name": "instance_skills_created_by_user_id_users_id_fk", + "tableFrom": "instance_skills", + "tableTo": "users", + "columnsFrom": ["created_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integration_tool_approval_requests": { + "name": "integration_tool_approval_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "requester_user_id": { + "name": "requester_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "native_request_id": { + "name": "native_request_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "args_fingerprint": { + "name": "args_fingerprint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "args_summary": { + "name": "args_summary", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "decided_by_user_id": { + "name": "decided_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "decided_at": { + "name": "decided_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cancel_reason": { + "name": "cancel_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "auto_evaluation": { + "name": "auto_evaluation", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "integration_tool_approvals_session_requester_idx": { + "name": "integration_tool_approvals_session_requester_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "requester_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "integration_tool_approvals_task_call_idx": { + "name": "integration_tool_approvals_task_call_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "args_fingerprint", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "integration_tool_approvals_pending_native_idx": { + "name": "integration_tool_approvals_pending_native_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "native_request_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "status = 'pending'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "integration_tool_approval_requests_session_id_sessions_id_fk": { + "name": "integration_tool_approval_requests_session_id_sessions_id_fk", + "tableFrom": "integration_tool_approval_requests", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_tool_approval_requests_requester_user_id_users_id_fk": { + "name": "integration_tool_approval_requests_requester_user_id_users_id_fk", + "tableFrom": "integration_tool_approval_requests", + "tableTo": "users", + "columnsFrom": ["requester_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_tool_approval_requests_task_id_tasks_id_fk": { + "name": "integration_tool_approval_requests_task_id_tasks_id_fk", + "tableFrom": "integration_tool_approval_requests", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_tool_approval_requests_decided_by_user_id_users_id_fk": { + "name": "integration_tool_approval_requests_decided_by_user_id_users_id_fk", + "tableFrom": "integration_tool_approval_requests", + "tableTo": "users", + "columnsFrom": ["decided_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integration_tool_auto_evaluations": { + "name": "integration_tool_auto_evaluations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "args_summary": { + "name": "args_summary", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "evaluation": { + "name": "evaluation", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "integration_tool_auto_evaluations_created_at_idx": { + "name": "integration_tool_auto_evaluations_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "integration_tool_auto_evaluations_user_id_users_id_fk": { + "name": "integration_tool_auto_evaluations_user_id_users_id_fk", + "tableFrom": "integration_tool_auto_evaluations", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "integration_tool_auto_evaluations_task_id_tasks_id_fk": { + "name": "integration_tool_auto_evaluations_task_id_tasks_id_fk", + "tableFrom": "integration_tool_auto_evaluations", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integration_tool_policies": { + "name": "integration_tool_policies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mode": { + "name": "mode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auto": { + "name": "auto", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "updated_by_user_id": { + "name": "updated_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "integration_tool_policies_tool_idx": { + "name": "integration_tool_policies_tool_idx", + "columns": [ + { + "expression": "integration_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tool_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "integration_tool_policies_updated_by_user_id_users_id_fk": { + "name": "integration_tool_policies_updated_by_user_id_users_id_fk", + "tableFrom": "integration_tool_policies", + "tableTo": "users", + "columnsFrom": ["updated_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integration_tool_session_overrides": { + "name": "integration_tool_session_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mode": { + "name": "mode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "set_by_user_id": { + "name": "set_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "integration_tool_session_overrides_tool_idx": { + "name": "integration_tool_session_overrides_tool_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "integration_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tool_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "integration_tool_session_overrides_session_id_sessions_id_fk": { + "name": "integration_tool_session_overrides_session_id_sessions_id_fk", + "tableFrom": "integration_tool_session_overrides", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_tool_session_overrides_set_by_user_id_users_id_fk": { + "name": "integration_tool_session_overrides_set_by_user_id_users_id_fk", + "tableFrom": "integration_tool_session_overrides", + "tableTo": "users", + "columnsFrom": ["set_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integration_tool_user_policies": { + "name": "integration_tool_user_policies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mode": { + "name": "mode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auto": { + "name": "auto", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "integration_tool_user_policies_tool_idx": { + "name": "integration_tool_user_policies_tool_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "integration_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tool_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "integration_tool_user_policies_user_id_users_id_fk": { + "name": "integration_tool_user_policies_user_id_users_id_fk", + "tableFrom": "integration_tool_user_policies", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invites": { + "name": "invites", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "invited_by_user_id": { + "name": "invited_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "max_uses": { + "name": "max_uses", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "used_count": { + "name": "used_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "invites_token_hash_unique": { + "name": "invites_token_hash_unique", + "columns": [ + { + "expression": "token_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invites_created_at_idx": { + "name": "invites_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "invites_invited_by_user_id_users_id_fk": { + "name": "invites_invited_by_user_id_users_id_fk", + "tableFrom": "invites", + "tableTo": "users", + "columnsFrom": ["invited_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session_egress_audit": { + "name": "session_egress_audit", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "authorization_id": { + "name": "authorization_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workload_id": { + "name": "workload_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "actor_user_id": { + "name": "actor_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_ref": { + "name": "secret_ref", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "phase": { + "name": "phase", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "destination": { + "name": "destination", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "decision": { + "name": "decision", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session_egress_revocations": { + "name": "session_egress_revocations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "identity": { + "type": "always", + "name": "session_egress_revocations_id_seq", + "schema": "public", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "2147483647", + "cache": "1", + "cycle": false + } + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workload_id": { + "name": "workload_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "secret_ref": { + "name": "secret_ref", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session_egress_substitutes": { + "name": "session_egress_substitutes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workload_id": { + "name": "workload_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "secret_id": { + "name": "secret_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_egress_substitutes_token_hash_unique": { + "name": "session_egress_substitutes_token_hash_unique", + "columns": [ + { + "expression": "token_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_egress_substitutes_workload_secret_generation_unique": { + "name": "session_egress_substitutes_workload_secret_generation_unique", + "columns": [ + { + "expression": "workload_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "generation", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_egress_substitutes_workload_id_session_egress_workloads_id_fk": { + "name": "session_egress_substitutes_workload_id_session_egress_workloads_id_fk", + "tableFrom": "session_egress_substitutes", + "tableTo": "session_egress_workloads", + "columnsFrom": ["workload_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_egress_substitutes_secret_id_session_secrets_id_fk": { + "name": "session_egress_substitutes_secret_id_session_secrets_id_fk", + "tableFrom": "session_egress_substitutes", + "tableTo": "session_secrets", + "columnsFrom": ["secret_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session_egress_workloads": { + "name": "session_egress_workloads", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "task_run_id": { + "name": "task_run_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connector_identity": { + "name": "connector_identity", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "terminated_at": { + "name": "terminated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "termination_reason": { + "name": "termination_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_egress_workloads_active_run_unique": { + "name": "session_egress_workloads_active_run_unique", + "columns": [ + { + "expression": "task_run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"session_egress_workloads\".\"status\" = 'active'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_egress_workloads_active_connector_unique": { + "name": "session_egress_workloads_active_connector_unique", + "columns": [ + { + "expression": "connector_identity", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"session_egress_workloads\".\"status\" = 'active'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_egress_workloads_session_idx": { + "name": "session_egress_workloads_session_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_egress_workloads_session_id_sessions_id_fk": { + "name": "session_egress_workloads_session_id_sessions_id_fk", + "tableFrom": "session_egress_workloads", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_egress_workloads_owner_user_id_users_id_fk": { + "name": "session_egress_workloads_owner_user_id_users_id_fk", + "tableFrom": "session_egress_workloads", + "tableTo": "users", + "columnsFrom": ["owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_egress_workloads_task_run_id_task_runs_id_fk": { + "name": "session_egress_workloads_task_run_id_task_runs_id_fk", + "tableFrom": "session_egress_workloads", + "tableTo": "task_runs", + "columnsFrom": ["task_run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "session_egress_workloads_status_check": { + "name": "session_egress_workloads_status_check", + "value": "\"session_egress_workloads\".\"status\" in ('active', 'terminated')" + } + }, + "isRLSEnabled": false + }, + "public.session_secret_approvals": { + "name": "session_secret_approvals", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "origin": { + "name": "origin", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_name": { + "name": "header_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_prefix": { + "name": "header_prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "allowed_methods": { + "name": "allowed_methods", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{GET,HEAD}'::text[]" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "consumed_at": { + "name": "consumed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_secret_approvals_session_owner_idx": { + "name": "session_secret_approvals_session_owner_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_secret_approvals_session_id_sessions_id_fk": { + "name": "session_secret_approvals_session_id_sessions_id_fk", + "tableFrom": "session_secret_approvals", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_secret_approvals_owner_user_id_users_id_fk": { + "name": "session_secret_approvals_owner_user_id_users_id_fk", + "tableFrom": "session_secret_approvals", + "tableTo": "users", + "columnsFrom": ["owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session_secret_audit": { + "name": "session_secret_audit", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "actor_user_id": { + "name": "actor_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_ref": { + "name": "secret_ref", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "destination": { + "name": "destination", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session_secrets": { + "name": "session_secrets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "origin": { + "name": "origin", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_name": { + "name": "header_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_prefix": { + "name": "header_prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "allowed_methods": { + "name": "allowed_methods", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{GET,HEAD}'::text[]" + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_secrets_session_owner_idx": { + "name": "session_secrets_session_owner_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_secrets_session_id_sessions_id_fk": { + "name": "session_secrets_session_id_sessions_id_fk", + "tableFrom": "session_secrets", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_secrets_owner_user_id_users_id_fk": { + "name": "session_secrets_owner_user_id_users_id_fk", + "tableFrom": "session_secrets", + "tableTo": "users", + "columnsFrom": ["owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.license_usage_observations": { + "name": "license_usage_observations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "observed_at": { + "name": "observed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "active_users": { + "name": "active_users", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "delivered_at": { + "name": "delivered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_attempted_at": { + "name": "last_attempted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "license_usage_observations_pending_idx": { + "name": "license_usage_observations_pending_idx", + "columns": [ + { + "expression": "delivered_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "observed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.linear_pending_selections": { + "name": "linear_pending_selections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "linear_organization_id": { + "name": "linear_organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "step": { + "name": "step", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'awaiting_workspace'" + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "selected_repo": { + "name": "selected_repo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_options": { + "name": "workspace_options", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "linear_pending_selections_expires_at_idx": { + "name": "linear_pending_selections_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "linear_pending_selections_step_idx": { + "name": "linear_pending_selections_step_idx", + "columns": [ + { + "expression": "step", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "linear_pending_selections_user_id_users_id_fk": { + "name": "linear_pending_selections_user_id_users_id_fk", + "tableFrom": "linear_pending_selections", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "linear_pending_selections_session_id_unique": { + "name": "linear_pending_selections_session_id_unique", + "nullsNotDistinct": false, + "columns": ["session_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.task_inference_usage_events": { + "name": "task_inference_usage_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'opencode'" + }, + "usage_type": { + "name": "usage_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'inference'" + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "run_id": { + "name": "run_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "event_key": { + "name": "event_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "harness_session_id": { + "name": "harness_session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent": { + "name": "agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "input_tokens": { + "name": "input_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "output_tokens": { + "name": "output_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "reasoning_tokens": { + "name": "reasoning_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "cache_read_tokens": { + "name": "cache_read_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "cache_write_tokens": { + "name": "cache_write_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_tokens": { + "name": "total_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "context_tokens": { + "name": "context_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "cost_micro_usd": { + "name": "cost_micro_usd", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "cost_source": { + "name": "cost_source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pricing_metadata": { + "name": "pricing_metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "message_created_at": { + "name": "message_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "message_completed_at": { + "name": "message_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "details": { + "name": "details", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "task_inference_usage_events_session_message_unique": { + "name": "task_inference_usage_events_session_message_unique", + "columns": [ + { + "expression": "harness_session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_inference_usage_events_event_key_unique": { + "name": "task_inference_usage_events_event_key_unique", + "columns": [ + { + "expression": "event_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_inference_usage_events_task_id_idx": { + "name": "task_inference_usage_events_task_id_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_inference_usage_events_run_id_idx": { + "name": "task_inference_usage_events_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_inference_usage_events_user_id_idx": { + "name": "task_inference_usage_events_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_inference_usage_events_environment_id_idx": { + "name": "task_inference_usage_events_environment_id_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_inference_usage_events_session_id_idx": { + "name": "task_inference_usage_events_session_id_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_inference_usage_events_provider_model_idx": { + "name": "task_inference_usage_events_provider_model_idx", + "columns": [ + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "model_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_inference_usage_events_created_at_idx": { + "name": "task_inference_usage_events_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "task_inference_usage_events_task_id_tasks_id_fk": { + "name": "task_inference_usage_events_task_id_tasks_id_fk", + "tableFrom": "task_inference_usage_events", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_inference_usage_events_run_id_task_runs_id_fk": { + "name": "task_inference_usage_events_run_id_task_runs_id_fk", + "tableFrom": "task_inference_usage_events", + "tableTo": "task_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_inference_usage_events_user_id_users_id_fk": { + "name": "task_inference_usage_events_user_id_users_id_fk", + "tableFrom": "task_inference_usage_events", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_inference_usage_events_environment_id_environments_id_fk": { + "name": "task_inference_usage_events_environment_id_environments_id_fk", + "tableFrom": "task_inference_usage_events", + "tableTo": "environments", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_inference_usage_events_session_id_sessions_id_fk": { + "name": "task_inference_usage_events_session_id_sessions_id_fk", + "tableFrom": "task_inference_usage_events", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mcp_connections": { + "name": "mcp_connections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_id": { + "name": "mcp_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connection_role": { + "name": "connection_role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'default'" + }, + "auth_config": { + "name": "auth_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "auth_status": { + "name": "auth_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token_expires_at": { + "name": "token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "mcp_connections_user_id_idx": { + "name": "mcp_connections_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_connections_role_idx": { + "name": "mcp_connections_role_idx", + "columns": [ + { + "expression": "mcp_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "connection_role", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mcp_connections_user_id_users_id_fk": { + "name": "mcp_connections_user_id_users_id_fk", + "tableFrom": "mcp_connections", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mcp_connections_user_mcp_id_unique": { + "name": "mcp_connections_user_mcp_id_unique", + "nullsNotDistinct": true, + "columns": ["user_id", "mcp_id", "connection_role"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mcp_oauth_replays": { + "name": "mcp_oauth_replays", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_id": { + "name": "mcp_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connection_role": { + "name": "connection_role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'default'" + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "redirect_to": { + "name": "redirect_to", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "mcp_oauth_replays_connection_id_idx": { + "name": "mcp_oauth_replays_connection_id_idx", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_oauth_replays_user_id_idx": { + "name": "mcp_oauth_replays_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_oauth_replays_expires_at_idx": { + "name": "mcp_oauth_replays_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mcp_oauth_replays_connection_id_mcp_connections_id_fk": { + "name": "mcp_oauth_replays_connection_id_mcp_connections_id_fk", + "tableFrom": "mcp_oauth_replays", + "tableTo": "mcp_connections", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mcp_oauth_replays_user_id_users_id_fk": { + "name": "mcp_oauth_replays_user_id_users_id_fk", + "tableFrom": "mcp_oauth_replays", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mcp_oauth_replays_token_unique": { + "name": "mcp_oauth_replays_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.microsoft_auth_user_mappings": { + "name": "microsoft_auth_user_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "auth_account_id": { + "name": "auth_account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "microsoft_tenant_id": { + "name": "microsoft_tenant_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "microsoft_aad_object_id": { + "name": "microsoft_aad_object_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "microsoft_auth_user_mappings_user_id_idx": { + "name": "microsoft_auth_user_mappings_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "microsoft_auth_user_mappings_account_id_idx": { + "name": "microsoft_auth_user_mappings_account_id_idx", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "microsoft_auth_user_mappings_auth_account_idx": { + "name": "microsoft_auth_user_mappings_auth_account_idx", + "columns": [ + { + "expression": "auth_account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "microsoft_auth_user_mappings_aad_object_unique": { + "name": "microsoft_auth_user_mappings_aad_object_unique", + "columns": [ + { + "expression": "microsoft_tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "microsoft_aad_object_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "microsoft_auth_user_mappings_auth_account_id_auth_accounts_id_fk": { + "name": "microsoft_auth_user_mappings_auth_account_id_auth_accounts_id_fk", + "tableFrom": "microsoft_auth_user_mappings", + "tableTo": "auth_accounts", + "columnsFrom": ["auth_account_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "microsoft_auth_user_mappings_user_id_auth_users_id_fk": { + "name": "microsoft_auth_user_mappings_user_id_auth_users_id_fk", + "tableFrom": "microsoft_auth_user_mappings", + "tableTo": "auth_users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notion_directory_users": { + "name": "notion_directory_users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "notion_user_id": { + "name": "notion_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_deleted": { + "name": "is_deleted", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "notion_directory_users_unique": { + "name": "notion_directory_users_unique", + "nullsNotDistinct": false, + "columns": ["notion_user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_state": { + "name": "oauth_state", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "code_verifier": { + "name": "code_verifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replay_token": { + "name": "replay_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "oauth_state_connection_id_idx": { + "name": "oauth_state_connection_id_idx", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_state_replay_token_idx": { + "name": "oauth_state_replay_token_idx", + "columns": [ + { + "expression": "replay_token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_state_expires_at_idx": { + "name": "oauth_state_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_state_connection_id_mcp_connections_id_fk": { + "name": "oauth_state_connection_id_mcp_connections_id_fk", + "tableFrom": "oauth_state", + "tableTo": "mcp_connections", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.personal_mcp_servers": { + "name": "personal_mcp_servers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "headers": { + "name": "headers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "disabled_tools": { + "name": "disabled_tools", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "manual_client_id": { + "name": "manual_client_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "manual_client_secret": { + "name": "manual_client_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_server_metadata": { + "name": "oauth_server_metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "oauth_server_metadata_fetched_at": { + "name": "oauth_server_metadata_fetched_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "oauth_resource_indicator_disabled": { + "name": "oauth_resource_indicator_disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "personal_mcp_servers_owner_user_id_users_id_fk": { + "name": "personal_mcp_servers_owner_user_id_users_id_fk", + "tableFrom": "personal_mcp_servers", + "tableTo": "users", + "columnsFrom": ["owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "personal_mcp_servers_owner_name_unique": { + "name": "personal_mcp_servers_owner_name_unique", + "nullsNotDistinct": false, + "columns": ["owner_user_id", "name"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pr_review_auto_preferences": { + "name": "pr_review_auto_preferences", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "source_control_provider": { + "name": "source_control_provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "repository_id": { + "name": "repository_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "repository_identity_key": { + "name": "repository_identity_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pr_number": { + "name": "pr_number", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "enabled_by_user_id": { + "name": "enabled_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled_at": { + "name": "enabled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "source_task_id": { + "name": "source_task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_destination_key": { + "name": "source_destination_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pr_review_auto_preferences_identity_unique": { + "name": "pr_review_auto_preferences_identity_unique", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "repository_identity_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pr_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pr_review_auto_preferences_repository_idx": { + "name": "pr_review_auto_preferences_repository_idx", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "repository", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pr_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pr_review_auto_preferences_repository_id_repositories_id_fk": { + "name": "pr_review_auto_preferences_repository_id_repositories_id_fk", + "tableFrom": "pr_review_auto_preferences", + "tableTo": "repositories", + "columnsFrom": ["repository_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "pr_review_auto_preferences_enabled_by_user_id_users_id_fk": { + "name": "pr_review_auto_preferences_enabled_by_user_id_users_id_fk", + "tableFrom": "pr_review_auto_preferences", + "tableTo": "users", + "columnsFrom": ["enabled_by_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pr_review_auto_preferences_source_task_id_tasks_id_fk": { + "name": "pr_review_auto_preferences_source_task_id_tasks_id_fk", + "tableFrom": "pr_review_auto_preferences", + "tableTo": "tasks", + "columnsFrom": ["source_task_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pr_review_cycles": { + "name": "pr_review_cycles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "source_control_provider": { + "name": "source_control_provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pr_number": { + "name": "pr_number", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "review_head_sha": { + "name": "review_head_sha", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cycle_id": { + "name": "cycle_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "pr_review_cycles_source_unique": { + "name": "pr_review_cycles_source_unique", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "repository", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pr_number", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "review_head_sha", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "cycle_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pr_review_event_deliveries": { + "name": "pr_review_event_deliveries", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "due_at": { + "name": "due_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "deferrals": { + "name": "deferrals", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "lease_token": { + "name": "lease_token", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "lease_expires_at": { + "name": "lease_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pr_review_event_deliveries_event_task_unique": { + "name": "pr_review_event_deliveries_event_task_unique", + "columns": [ + { + "expression": "event_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pr_review_event_deliveries_due_idx": { + "name": "pr_review_event_deliveries_due_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "due_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lease_expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pr_review_event_deliveries_event_id_pr_review_events_id_fk": { + "name": "pr_review_event_deliveries_event_id_pr_review_events_id_fk", + "tableFrom": "pr_review_event_deliveries", + "tableTo": "pr_review_events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pr_review_event_deliveries_task_id_tasks_id_fk": { + "name": "pr_review_event_deliveries_task_id_tasks_id_fk", + "tableFrom": "pr_review_event_deliveries", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "pr_review_event_deliveries_status_check": { + "name": "pr_review_event_deliveries_status_check", + "value": "\"pr_review_event_deliveries\".\"status\" in ('pending', 'processing', 'delivered', 'suppressed')" + } + }, + "isRLSEnabled": false + }, + "public.pr_review_events": { + "name": "pr_review_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_key": { + "name": "event_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_control_provider": { + "name": "source_control_provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pr_number": { + "name": "pr_number", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "pr_url": { + "name": "pr_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "event": { + "name": "event", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "batch_kind": { + "name": "batch_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "batch_id": { + "name": "batch_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "review_head_sha": { + "name": "review_head_sha", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sealed_at": { + "name": "sealed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "superseded": { + "name": "superseded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "available_at": { + "name": "available_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "observed_at": { + "name": "observed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pr_review_events_source_unique": { + "name": "pr_review_events_source_unique", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "repository", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pr_number", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "event_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pr_review_events_pr_idx": { + "name": "pr_review_events_pr_idx", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "repository", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pr_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "pr_review_events_batch_kind_check": { + "name": "pr_review_events_batch_kind_check", + "value": "\"pr_review_events\".\"batch_kind\" in ('human', 'roomote')" + } + }, + "isRLSEnabled": false + }, + "public.pr_review_notification_deliveries": { + "name": "pr_review_notification_deliveries", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "notification_unit_id": { + "name": "notification_unit_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "destination_kind": { + "name": "destination_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destination_key": { + "name": "destination_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "due_at": { + "name": "due_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "deferrals": { + "name": "deferrals", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "attempt": { + "name": "attempt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "lease_token": { + "name": "lease_token", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "lease_expires_at": { + "name": "lease_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "route_provider": { + "name": "route_provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "route_workspace_id": { + "name": "route_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "route_channel_id": { + "name": "route_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "route_thread_id": { + "name": "route_thread_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "follow_up_prompt": { + "name": "follow_up_prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "target_task_id": { + "name": "target_task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "acting_user_id": { + "name": "acting_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_message_id": { + "name": "provider_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "action_claimed_at": { + "name": "action_claimed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "dispatch_key": { + "name": "dispatch_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dispatched_run_id": { + "name": "dispatched_run_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pr_review_notification_deliveries_destination_unique": { + "name": "pr_review_notification_deliveries_destination_unique", + "columns": [ + { + "expression": "notification_unit_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "destination_kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "destination_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pr_review_notification_deliveries_dispatch_key_unique": { + "name": "pr_review_notification_deliveries_dispatch_key_unique", + "columns": [ + { + "expression": "dispatch_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pr_review_notification_deliveries_due_idx": { + "name": "pr_review_notification_deliveries_due_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "due_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lease_expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pr_review_notification_deliveries_destination_idx": { + "name": "pr_review_notification_deliveries_destination_idx", + "columns": [ + { + "expression": "destination_kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "destination_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pr_review_notification_deliveries_notification_unit_id_pr_review_notification_units_id_fk": { + "name": "pr_review_notification_deliveries_notification_unit_id_pr_review_notification_units_id_fk", + "tableFrom": "pr_review_notification_deliveries", + "tableTo": "pr_review_notification_units", + "columnsFrom": ["notification_unit_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pr_review_notification_deliveries_task_id_tasks_id_fk": { + "name": "pr_review_notification_deliveries_task_id_tasks_id_fk", + "tableFrom": "pr_review_notification_deliveries", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "pr_review_notification_deliveries_target_task_id_tasks_id_fk": { + "name": "pr_review_notification_deliveries_target_task_id_tasks_id_fk", + "tableFrom": "pr_review_notification_deliveries", + "tableTo": "tasks", + "columnsFrom": ["target_task_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "pr_review_notification_deliveries_acting_user_id_users_id_fk": { + "name": "pr_review_notification_deliveries_acting_user_id_users_id_fk", + "tableFrom": "pr_review_notification_deliveries", + "tableTo": "users", + "columnsFrom": ["acting_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "pr_review_notification_deliveries_destination_kind_check": { + "name": "pr_review_notification_deliveries_destination_kind_check", + "value": "\"pr_review_notification_deliveries\".\"destination_kind\" in ('fast_conversation', 'task')" + }, + "pr_review_notification_deliveries_status_check": { + "name": "pr_review_notification_deliveries_status_check", + "value": "\"pr_review_notification_deliveries\".\"status\" in ('pending', 'claimed', 'prepared', 'prompt_posting', 'awaiting_user_action', 'auto_dispatch_pending', 'completed', 'suppressed', 'dismissed')" + } + }, + "isRLSEnabled": false + }, + "public.pr_review_notification_unit_events": { + "name": "pr_review_notification_unit_events", + "schema": "", + "columns": { + "unit_id": { + "name": "unit_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "attached_at": { + "name": "attached_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pr_review_notification_unit_events_event_unique": { + "name": "pr_review_notification_unit_events_event_unique", + "columns": [ + { + "expression": "event_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pr_review_notification_unit_events_unit_id_pr_review_notification_units_id_fk": { + "name": "pr_review_notification_unit_events_unit_id_pr_review_notification_units_id_fk", + "tableFrom": "pr_review_notification_unit_events", + "tableTo": "pr_review_notification_units", + "columnsFrom": ["unit_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pr_review_notification_unit_events_event_id_pr_review_events_id_fk": { + "name": "pr_review_notification_unit_events_event_id_pr_review_events_id_fk", + "tableFrom": "pr_review_notification_unit_events", + "tableTo": "pr_review_events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "pr_review_notification_unit_events_pk": { + "name": "pr_review_notification_unit_events_pk", + "columns": ["unit_id", "event_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pr_review_notification_units": { + "name": "pr_review_notification_units", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "source_control_provider": { + "name": "source_control_provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "repository_id": { + "name": "repository_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "repository_identity_key": { + "name": "repository_identity_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pr_number": { + "name": "pr_number", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "pr_url": { + "name": "pr_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "head_sha": { + "name": "head_sha", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "head_identity_key": { + "name": "head_identity_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "episode_kind": { + "name": "episode_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "episode_id": { + "name": "episode_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "due_at": { + "name": "due_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "first_observed_at": { + "name": "first_observed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "last_observed_at": { + "name": "last_observed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "sealed_at": { + "name": "sealed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pr_review_notification_units_identity_unique": { + "name": "pr_review_notification_units_identity_unique", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "repository_identity_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pr_number", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "head_identity_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "episode_kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "episode_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pr_review_notification_units_open_head_idx": { + "name": "pr_review_notification_units_open_head_idx", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "repository", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pr_number", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "head_sha", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sealed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pr_review_notification_units_repository_id_repositories_id_fk": { + "name": "pr_review_notification_units_repository_id_repositories_id_fk", + "tableFrom": "pr_review_notification_units", + "tableTo": "repositories", + "columnsFrom": ["repository_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "pr_review_notification_units_episode_kind_check": { + "name": "pr_review_notification_units_episode_kind_check", + "value": "\"pr_review_notification_units\".\"episode_kind\" in ('roomote_cycle', 'human', 'automated', 'ci')" + } + }, + "isRLSEnabled": false + }, + "public.pull_request_facts": { + "name": "pull_request_facts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "repository_id": { + "name": "repository_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "repository_full_name": { + "name": "repository_full_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_control_provider": { + "name": "source_control_provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "external_pull_request_id": { + "name": "external_pull_request_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "pr_number": { + "name": "pr_number", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "html_url": { + "name": "html_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "author_login": { + "name": "author_login", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "labels": { + "name": "labels", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "changed_files": { + "name": "changed_files", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "changed_file_count": { + "name": "changed_file_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "files_capped": { + "name": "files_capped", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "reviews_capped": { + "name": "reviews_capped", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "additions": { + "name": "additions", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "deletions": { + "name": "deletions", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "reviews": { + "name": "reviews", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "enriched_at": { + "name": "enriched_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "enriched_for_updated_at": { + "name": "enriched_for_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "enrichment_failed_at": { + "name": "enrichment_failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at_remote": { + "name": "created_at_remote", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at_remote": { + "name": "updated_at_remote", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "closed_at_remote": { + "name": "closed_at_remote", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "merged_at_remote": { + "name": "merged_at_remote", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "first_seen_at": { + "name": "first_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "synced_at": { + "name": "synced_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pull_request_facts_deployment_repo_pr_unique": { + "name": "pull_request_facts_deployment_repo_pr_unique", + "columns": [ + { + "expression": "repository_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pr_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pull_request_facts_deployment_created_idx": { + "name": "pull_request_facts_deployment_created_idx", + "columns": [ + { + "expression": "created_at_remote", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pull_request_facts_deployment_repo_created_idx": { + "name": "pull_request_facts_deployment_repo_created_idx", + "columns": [ + { + "expression": "repository_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at_remote", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pull_request_facts_deployment_state_created_idx": { + "name": "pull_request_facts_deployment_state_created_idx", + "columns": [ + { + "expression": "state", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at_remote", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pull_request_facts_deployment_author_created_idx": { + "name": "pull_request_facts_deployment_author_created_idx", + "columns": [ + { + "expression": "author_login", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at_remote", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pull_request_facts_deployment_updated_idx": { + "name": "pull_request_facts_deployment_updated_idx", + "columns": [ + { + "expression": "updated_at_remote", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pull_request_facts_repository_id_repositories_id_fk": { + "name": "pull_request_facts_repository_id_repositories_id_fk", + "tableFrom": "pull_request_facts", + "tableTo": "repositories", + "columnsFrom": ["repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "pull_request_facts_source_control_provider_check": { + "name": "pull_request_facts_source_control_provider_check", + "value": "\"pull_request_facts\".\"source_control_provider\" in ('github', 'gitlab', 'gitea', 'ado', 'bitbucket')" + } + }, + "isRLSEnabled": false + }, + "public.pull_request_sync_states": { + "name": "pull_request_sync_states", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "repository_id": { + "name": "repository_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "last_incremental_updated_at": { + "name": "last_incremental_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "backfill_completed_at": { + "name": "backfill_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cooldown_until": { + "name": "cooldown_until", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_successful_sync_at": { + "name": "last_successful_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_attempted_sync_at": { + "name": "last_attempted_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_error_at": { + "name": "last_error_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_error_message": { + "name": "last_error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pull_request_sync_states_repo_unique": { + "name": "pull_request_sync_states_repo_unique", + "columns": [ + { + "expression": "repository_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pull_request_sync_states_deployment_updated_idx": { + "name": "pull_request_sync_states_deployment_updated_idx", + "columns": [ + { + "expression": "last_successful_sync_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pull_request_sync_states_cooldown_idx": { + "name": "pull_request_sync_states_cooldown_idx", + "columns": [ + { + "expression": "cooldown_until", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pull_request_sync_states_repository_id_repositories_id_fk": { + "name": "pull_request_sync_states_repository_id_repositories_id_fk", + "tableFrom": "pull_request_sync_states", + "tableTo": "repositories", + "columnsFrom": ["repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.release_announcement_deliveries": { + "name": "release_announcement_deliveries", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "previous_version": { + "name": "previous_version", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "installed_version": { + "name": "installed_version", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destination_key": { + "name": "destination_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "service_url": { + "name": "service_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "recipient_user_id": { + "name": "recipient_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_identity_id": { + "name": "email_identity_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "lease_token": { + "name": "lease_token", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "lease_expires_at": { + "name": "lease_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "next_attempt_at": { + "name": "next_attempt_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "provider_message_id": { + "name": "provider_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "delivered_at": { + "name": "delivered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "release_announcement_deliveries_version_destination_unique": { + "name": "release_announcement_deliveries_version_destination_unique", + "columns": [ + { + "expression": "installed_version", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "destination_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "release_announcement_deliveries_due_idx": { + "name": "release_announcement_deliveries_due_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_attempt_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lease_expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "release_announcement_deliveries_recipient_user_id_users_id_fk": { + "name": "release_announcement_deliveries_recipient_user_id_users_id_fk", + "tableFrom": "release_announcement_deliveries", + "tableTo": "users", + "columnsFrom": ["recipient_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "release_announcement_deliveries_status_check": { + "name": "release_announcement_deliveries_status_check", + "value": "\"release_announcement_deliveries\".\"status\" in ('pending', 'delivered', 'skipped')" + }, + "release_announcement_deliveries_provider_check": { + "name": "release_announcement_deliveries_provider_check", + "value": "\"release_announcement_deliveries\".\"provider\" in ('slack', 'teams', 'telegram', 'discord', 'email')" + } + }, + "isRLSEnabled": false + }, + "public.repositories": { + "name": "repositories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "source_control_provider": { + "name": "source_control_provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "installation_id": { + "name": "installation_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "github_repo_id": { + "name": "github_repo_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "external_repo_id": { + "name": "external_repo_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "full_name": { + "name": "full_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "private": { + "name": "private", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "default_branch": { + "name": "default_branch", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'main'" + }, + "clone_url": { + "name": "clone_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "html_url": { + "name": "html_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permissions": { + "name": "permissions", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "linked_by_user_id": { + "name": "linked_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "repositories_source_control_provider_idx": { + "name": "repositories_source_control_provider_idx", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "repositories_installation_id_idx": { + "name": "repositories_installation_id_idx", + "columns": [ + { + "expression": "installation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "repositories_full_name_idx": { + "name": "repositories_full_name_idx", + "columns": [ + { + "expression": "full_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "repositories_provider_host_full_name_idx": { + "name": "repositories_provider_host_full_name_idx", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "host", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "full_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "repositories_deployment_active_installation_idx": { + "name": "repositories_deployment_active_installation_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "installation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "repositories_deployment_github_repo_unique": { + "name": "repositories_deployment_github_repo_unique", + "columns": [ + { + "expression": "github_repo_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "repositories_provider_host_external_repo_unique": { + "name": "repositories_provider_host_external_repo_unique", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"host\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "external_repo_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "repositories_provider_host_full_name_unique": { + "name": "repositories_provider_host_full_name_unique", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"host\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "full_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "repositories_installation_id_github_installations_id_fk": { + "name": "repositories_installation_id_github_installations_id_fk", + "tableFrom": "repositories", + "tableTo": "github_installations", + "columnsFrom": ["installation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "repositories_user_id_users_id_fk": { + "name": "repositories_user_id_users_id_fk", + "tableFrom": "repositories", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "repositories_linked_by_user_id_users_id_fk": { + "name": "repositories_linked_by_user_id_users_id_fk", + "tableFrom": "repositories", + "tableTo": "users", + "columnsFrom": ["linked_by_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "repositories_source_control_provider_check": { + "name": "repositories_source_control_provider_check", + "value": "\"repositories\".\"source_control_provider\" in ('github', 'gitlab', 'gitea', 'ado', 'bitbucket')" + }, + "repositories_github_shape_check": { + "name": "repositories_github_shape_check", + "value": "\"repositories\".\"source_control_provider\" != 'github' OR (\"repositories\".\"installation_id\" IS NOT NULL AND \"repositories\".\"github_repo_id\" IS NOT NULL)" + }, + "repositories_gitlab_shape_check": { + "name": "repositories_gitlab_shape_check", + "value": "\"repositories\".\"source_control_provider\" != 'gitlab' OR \"repositories\".\"external_repo_id\" IS NOT NULL" + }, + "repositories_gitea_shape_check": { + "name": "repositories_gitea_shape_check", + "value": "\"repositories\".\"source_control_provider\" != 'gitea' OR \"repositories\".\"external_repo_id\" IS NOT NULL" + }, + "repositories_ado_shape_check": { + "name": "repositories_ado_shape_check", + "value": "\"repositories\".\"source_control_provider\" != 'ado' OR \"repositories\".\"external_repo_id\" IS NOT NULL" + }, + "repositories_bitbucket_shape_check": { + "name": "repositories_bitbucket_shape_check", + "value": "\"repositories\".\"source_control_provider\" != 'bitbucket' OR \"repositories\".\"external_repo_id\" IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.repository_automation_signals": { + "name": "repository_automation_signals", + "schema": "", + "columns": { + "repository_id": { + "name": "repository_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "signals_version": { + "name": "signals_version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "collected_at": { + "name": "collected_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "partial": { + "name": "partial", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "repository_automation_signals_collected_idx": { + "name": "repository_automation_signals_collected_idx", + "columns": [ + { + "expression": "collected_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "repository_automation_signals_repository_id_repositories_id_fk": { + "name": "repository_automation_signals_repository_id_repositories_id_fk", + "tableFrom": "repository_automation_signals", + "tableTo": "repositories", + "columnsFrom": ["repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "repository_automation_signals_repository_id_signals_version_pk": { + "name": "repository_automation_signals_repository_id_signals_version_pk", + "columns": ["repository_id", "signals_version"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sandbox_oidc_targets": { + "name": "sandbox_oidc_targets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "run_id": { + "name": "run_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "compute_provider": { + "name": "compute_provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "compute_provider_id": { + "name": "compute_provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_kind": { + "name": "target_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "audience": { + "name": "audience", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_file": { + "name": "token_file", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "aws_role_arn": { + "name": "aws_role_arn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "aws_region": { + "name": "aws_region", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_at": { + "name": "refresh_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "sandbox_oidc_targets_environment_id_idx": { + "name": "sandbox_oidc_targets_environment_id_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sandbox_oidc_targets_run_id_idx": { + "name": "sandbox_oidc_targets_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sandbox_oidc_targets_refresh_at_idx": { + "name": "sandbox_oidc_targets_refresh_at_idx", + "columns": [ + { + "expression": "refresh_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sandbox_oidc_targets_provider_target_file_unique": { + "name": "sandbox_oidc_targets_provider_target_file_unique", + "columns": [ + { + "expression": "compute_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "compute_provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "token_file", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sandbox_oidc_targets_environment_id_environments_id_fk": { + "name": "sandbox_oidc_targets_environment_id_environments_id_fk", + "tableFrom": "sandbox_oidc_targets", + "tableTo": "environments", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "sandbox_oidc_targets_run_id_task_runs_id_fk": { + "name": "sandbox_oidc_targets_run_id_task_runs_id_fk", + "tableFrom": "sandbox_oidc_targets", + "tableTo": "task_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "sandbox_oidc_targets_owner_required": { + "name": "sandbox_oidc_targets_owner_required", + "value": "run_id IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.service_credential_approvals": { + "name": "service_credential_approvals", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "origin": { + "name": "origin", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_name": { + "name": "header_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_prefix": { + "name": "header_prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "allowed_methods": { + "name": "allowed_methods", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{GET,HEAD}'::text[]" + }, + "visibility": { + "name": "visibility", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'owner'" + }, + "lifetime_hours": { + "name": "lifetime_hours", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "consumed_at": { + "name": "consumed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "service_credential_approvals_session_owner_idx": { + "name": "service_credential_approvals_session_owner_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "service_credential_approvals_session_id_sessions_id_fk": { + "name": "service_credential_approvals_session_id_sessions_id_fk", + "tableFrom": "service_credential_approvals", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "service_credential_approvals_owner_user_id_users_id_fk": { + "name": "service_credential_approvals_owner_user_id_users_id_fk", + "tableFrom": "service_credential_approvals", + "tableTo": "users", + "columnsFrom": ["owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.service_credential_audit": { + "name": "service_credential_audit", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "actor_user_id": { + "name": "actor_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_ref": { + "name": "secret_ref", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "destination": { + "name": "destination", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.service_credentials": { + "name": "service_credentials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "origin": { + "name": "origin", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_name": { + "name": "header_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_prefix": { + "name": "header_prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "allowed_methods": { + "name": "allowed_methods", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{GET,HEAD}'::text[]" + }, + "visibility": { + "name": "visibility", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'owner'" + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "service_credentials_session_owner_idx": { + "name": "service_credentials_session_owner_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "service_credentials_session_id_sessions_id_fk": { + "name": "service_credentials_session_id_sessions_id_fk", + "tableFrom": "service_credentials", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "service_credentials_owner_user_id_users_id_fk": { + "name": "service_credentials_owner_user_id_users_id_fk", + "tableFrom": "service_credentials", + "tableTo": "users", + "columnsFrom": ["owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session_attention_notification_messages": { + "name": "session_attention_notification_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "notification_id": { + "name": "notification_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fast_message_id": { + "name": "fast_message_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_attention_notification_messages_route_unique": { + "name": "session_attention_notification_messages_route_unique", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "channel_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_attention_notification_messages_thread_idx": { + "name": "session_attention_notification_messages_thread_idx", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "channel_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "thread_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_attention_notification_messages_notification_id_session_attention_notifications_id_fk": { + "name": "session_attention_notification_messages_notification_id_session_attention_notifications_id_fk", + "tableFrom": "session_attention_notification_messages", + "tableTo": "session_attention_notifications", + "columnsFrom": ["notification_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_attention_notification_messages_fast_message_id_fast_agent_messages_id_fk": { + "name": "session_attention_notification_messages_fast_message_id_fast_agent_messages_id_fk", + "tableFrom": "session_attention_notification_messages", + "tableTo": "fast_agent_messages", + "columnsFrom": ["fast_message_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "session_attention_notification_messages_provider_check": { + "name": "session_attention_notification_messages_provider_check", + "value": "\"session_attention_notification_messages\".\"provider\" in ('discord', 'slack', 'teams', 'telegram', 'agentmail')" + } + }, + "isRLSEnabled": false + }, + "public.session_attention_notifications": { + "name": "session_attention_notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "run_id": { + "name": "run_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_key": { + "name": "event_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "presentation_kind": { + "name": "presentation_kind", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lease_token": { + "name": "lease_token", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "lease_expires_at": { + "name": "lease_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "delivery_channel": { + "name": "delivery_channel", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "browser_prompt_eligible_at": { + "name": "browser_prompt_eligible_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "browser_offered_at": { + "name": "browser_offered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "browser_offer_expires_at": { + "name": "browser_offer_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "browser_accepted_at": { + "name": "browser_accepted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "browser_opened_at": { + "name": "browser_opened_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "browser_client_id": { + "name": "browser_client_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_attention_notifications_event_unique": { + "name": "session_attention_notifications_event_unique", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "event_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_attention_notifications_run_idx": { + "name": "session_attention_notifications_run_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_attention_notifications_session_id_sessions_id_fk": { + "name": "session_attention_notifications_session_id_sessions_id_fk", + "tableFrom": "session_attention_notifications", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_attention_notifications_task_id_tasks_id_fk": { + "name": "session_attention_notifications_task_id_tasks_id_fk", + "tableFrom": "session_attention_notifications", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "session_attention_notifications_run_id_task_runs_id_fk": { + "name": "session_attention_notifications_run_id_task_runs_id_fk", + "tableFrom": "session_attention_notifications", + "tableTo": "task_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "session_attention_notifications_user_id_users_id_fk": { + "name": "session_attention_notifications_user_id_users_id_fk", + "tableFrom": "session_attention_notifications", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "session_attention_notifications_kind_check": { + "name": "session_attention_notifications_kind_check", + "value": "\"session_attention_notifications\".\"kind\" in ('result_ready', 'input_needed')" + }, + "session_attention_notifications_outcome_check": { + "name": "session_attention_notifications_outcome_check", + "value": "\"session_attention_notifications\".\"outcome\" IS NULL OR \"session_attention_notifications\".\"outcome\" in ('delivered', 'skipped_present', 'failed')" + }, + "session_attention_notifications_presentation_kind_check": { + "name": "session_attention_notifications_presentation_kind_check", + "value": "\"session_attention_notifications\".\"presentation_kind\" IS NULL OR \"session_attention_notifications\".\"presentation_kind\" in ('response', 'error', 'input')" + }, + "session_attention_notifications_delivery_channel_check": { + "name": "session_attention_notifications_delivery_channel_check", + "value": "\"session_attention_notifications\".\"delivery_channel\" IS NULL OR \"session_attention_notifications\".\"delivery_channel\" in ('browser', 'personal_provider')" + } + }, + "isRLSEnabled": false + }, + "public.session_backfill_state": { + "name": "session_backfill_state", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "phase": { + "name": "phase", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'fast_conversations'" + }, + "cursor_created_at": { + "name": "cursor_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cursor_id": { + "name": "cursor_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "session_backfill_state_phase_check": { + "name": "session_backfill_state_phase_check", + "value": "\"session_backfill_state\".\"phase\" in ('fast_conversations', 'fast_tasks', 'tasks', 'participants')" + }, + "session_backfill_state_cursor_shape_check": { + "name": "session_backfill_state_cursor_shape_check", + "value": "(\"session_backfill_state\".\"cursor_created_at\" IS NULL) = (\"session_backfill_state\".\"cursor_id\" IS NULL)" + } + }, + "isRLSEnabled": false + }, + "public.session_done_webhook_deliveries": { + "name": "session_done_webhook_deliveries", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "judgment_id": { + "name": "judgment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "lease_token": { + "name": "lease_token", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "lease_expires_at": { + "name": "lease_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "next_attempt_at": { + "name": "next_attempt_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "delivered_at": { + "name": "delivered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_done_webhook_deliveries_judgment_unique": { + "name": "session_done_webhook_deliveries_judgment_unique", + "columns": [ + { + "expression": "judgment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_done_webhook_deliveries_due_idx": { + "name": "session_done_webhook_deliveries_due_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_attempt_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lease_expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_done_webhook_deliveries_session_id_sessions_id_fk": { + "name": "session_done_webhook_deliveries_session_id_sessions_id_fk", + "tableFrom": "session_done_webhook_deliveries", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_done_webhook_deliveries_judgment_id_session_status_judgments_id_fk": { + "name": "session_done_webhook_deliveries_judgment_id_session_status_judgments_id_fk", + "tableFrom": "session_done_webhook_deliveries", + "tableTo": "session_status_judgments", + "columnsFrom": ["judgment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "session_done_webhook_deliveries_status_check": { + "name": "session_done_webhook_deliveries_status_check", + "value": "\"session_done_webhook_deliveries\".\"status\" in ('pending', 'delivered', 'failed', 'skipped')" + }, + "session_done_webhook_deliveries_attempts_check": { + "name": "session_done_webhook_deliveries_attempts_check", + "value": "\"session_done_webhook_deliveries\".\"attempts\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.session_goals": { + "name": "session_goals", + "schema": "", + "columns": { + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "objective": { + "name": "objective", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "max_continuations": { + "name": "max_continuations", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "continuations_used": { + "name": "continuations_used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "blocked_reason": { + "name": "blocked_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_continuation_id": { + "name": "last_continuation_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "continuation_ids": { + "name": "continuation_ids", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::text[]" + }, + "generation_ids": { + "name": "generation_ids", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::text[]" + }, + "blocker_candidate_reason": { + "name": "blocker_candidate_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "blocker_candidate_count": { + "name": "blocker_candidate_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "blocker_last_continuation_used": { + "name": "blocker_last_continuation_used", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "session_goals_session_id_sessions_id_fk": { + "name": "session_goals_session_id_sessions_id_fk", + "tableFrom": "session_goals", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_goals_created_by_user_id_users_id_fk": { + "name": "session_goals_created_by_user_id_users_id_fk", + "tableFrom": "session_goals", + "tableTo": "users", + "columnsFrom": ["created_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "session_goals_status_check": { + "name": "session_goals_status_check", + "value": "\"session_goals\".\"status\" in ('active', 'complete', 'blocked', 'budget_limited', 'canceled')" + }, + "session_goals_continuations_check": { + "name": "session_goals_continuations_check", + "value": "\"session_goals\".\"continuations_used\" >= 0 AND \"session_goals\".\"max_continuations\" > 0" + }, + "session_goals_blocker_candidate_count_check": { + "name": "session_goals_blocker_candidate_count_check", + "value": "\"session_goals\".\"blocker_candidate_count\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.session_participants": { + "name": "session_participants", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "last_read_event_at": { + "name": "last_read_event_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "last_read_event_id": { + "name": "last_read_event_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_notified_event_at": { + "name": "last_notified_event_at", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "last_notified_event_id": { + "name": "last_notified_event_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_participants_session_user_unique": { + "name": "session_participants_session_user_unique", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_participants_user_id_idx": { + "name": "session_participants_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_participants_session_id_sessions_id_fk": { + "name": "session_participants_session_id_sessions_id_fk", + "tableFrom": "session_participants", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_participants_user_id_users_id_fk": { + "name": "session_participants_user_id_users_id_fk", + "tableFrom": "session_participants", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "session_participants_role_check": { + "name": "session_participants_role_check", + "value": "\"session_participants\".\"role\" in ('owner', 'member')" + } + }, + "isRLSEnabled": false + }, + "public.session_pins": { + "name": "session_pins", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_pins_user_session_unique": { + "name": "session_pins_user_session_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_pins_user_updated_at_idx": { + "name": "session_pins_user_updated_at_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_pins_session_id_idx": { + "name": "session_pins_session_id_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_pins_session_id_sessions_id_fk": { + "name": "session_pins_session_id_sessions_id_fk", + "tableFrom": "session_pins", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_pins_user_id_users_id_fk": { + "name": "session_pins_user_id_users_id_fk", + "tableFrom": "session_pins", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session_status_judgments": { + "name": "session_status_judgments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "source_event_id": { + "name": "source_event_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "source_kind": { + "name": "source_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confidence": { + "name": "confidence", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "probabilities": { + "name": "probabilities", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "claimed_at": { + "name": "claimed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "settled_at": { + "name": "settled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "judged_at": { + "name": "judged_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_status_judgments_session_event_unique": { + "name": "session_status_judgments_session_event_unique", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_event_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_status_judgments_session_generation_unique": { + "name": "session_status_judgments_session_generation_unique", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "generation", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_status_judgments_pending_idx": { + "name": "session_status_judgments_pending_idx", + "columns": [ + { + "expression": "state", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_status_judgments_session_generation_idx": { + "name": "session_status_judgments_session_generation_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "generation", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_status_judgments_session_id_sessions_id_fk": { + "name": "session_status_judgments_session_id_sessions_id_fk", + "tableFrom": "session_status_judgments", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "session_status_judgments_source_kind_check": { + "name": "session_status_judgments_source_kind_check", + "value": "\"session_status_judgments\".\"source_kind\" in ('fast_turn', 'task_terminal')" + }, + "session_status_judgments_state_check": { + "name": "session_status_judgments_state_check", + "value": "\"session_status_judgments\".\"state\" in ('awaiting_settlement', 'pending', 'processing', 'applied', 'ignored', 'failed', 'stale')" + }, + "session_status_judgments_outcome_check": { + "name": "session_status_judgments_outcome_check", + "value": "\"session_status_judgments\".\"outcome\" IS NULL OR \"session_status_judgments\".\"outcome\" in ('open', 'done', 'blocked', 'needs_input', 'unclear')" + }, + "session_status_judgments_confidence_check": { + "name": "session_status_judgments_confidence_check", + "value": "\"session_status_judgments\".\"confidence\" IS NULL OR (\"session_status_judgments\".\"confidence\" >= 0 AND \"session_status_judgments\".\"confidence\" <= 1)" + }, + "session_status_judgments_attempts_check": { + "name": "session_status_judgments_attempts_check", + "value": "\"session_status_judgments\".\"attempts\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.session_tasks": { + "name": "session_tasks", + "schema": "", + "columns": { + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "attached_at": { + "name": "attached_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "origin": { + "name": "origin", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "session_tasks_task_id_unique": { + "name": "session_tasks_task_id_unique", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_tasks_session_attached_at_idx": { + "name": "session_tasks_session_attached_at_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "attached_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_tasks_session_id_sessions_id_fk": { + "name": "session_tasks_session_id_sessions_id_fk", + "tableFrom": "session_tasks", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_tasks_task_id_tasks_id_fk": { + "name": "session_tasks_task_id_tasks_id_fk", + "tableFrom": "session_tasks", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "session_tasks_session_id_task_id_pk": { + "name": "session_tasks_session_id_task_id_pk", + "columns": ["session_id", "task_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "session_tasks_origin_check": { + "name": "session_tasks_origin_check", + "value": "\"session_tasks\".\"origin\" in ('direct_launch', 'fast_delegation', 'backfill', 'follow_up')" + } + }, + "isRLSEnabled": false + }, + "public.session_wakeups": { + "name": "session_wakeups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "conversation_id": { + "name": "conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prompt_signature": { + "name": "prompt_signature", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "report_policy": { + "name": "report_policy", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "internal": { + "name": "internal", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "run_count": { + "name": "run_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "max_runs": { + "name": "max_runs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "until": { + "name": "until", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "consecutive_failures": { + "name": "consecutive_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "next_run_at": { + "name": "next_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_fired_at": { + "name": "last_fired_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_wakeups_due_idx": { + "name": "session_wakeups_due_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_wakeups_conversation_idx": { + "name": "session_wakeups_conversation_idx", + "columns": [ + { + "expression": "conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_wakeups_conversation_id_fast_agent_conversations_id_fk": { + "name": "session_wakeups_conversation_id_fast_agent_conversations_id_fk", + "tableFrom": "session_wakeups", + "tableTo": "fast_agent_conversations", + "columnsFrom": ["conversation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_wakeups_created_by_user_id_users_id_fk": { + "name": "session_wakeups_created_by_user_id_users_id_fk", + "tableFrom": "session_wakeups", + "tableTo": "users", + "columnsFrom": ["created_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "session_wakeups_status_check": { + "name": "session_wakeups_status_check", + "value": "\"session_wakeups\".\"status\" in ('active', 'completed', 'cancelled', 'failed')" + }, + "session_wakeups_report_policy_check": { + "name": "session_wakeups_report_policy_check", + "value": "\"session_wakeups\".\"report_policy\" in ('always', 'only_when_notable')" + } + }, + "isRLSEnabled": false + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title_edited_by_user_at": { + "name": "title_edited_by_user_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "llm_title_checkpoint": { + "name": "llm_title_checkpoint", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "owner_kind": { + "name": "owner_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_automation": { + "name": "owner_automation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "privacy": { + "name": "privacy", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'shared'" + }, + "private_owner_user_id": { + "name": "private_owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_surface": { + "name": "source_surface", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_trigger": { + "name": "source_trigger", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fast_conversation_id": { + "name": "fast_conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "visibility": { + "name": "visibility", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'visible'" + }, + "activity_at": { + "name": "activity_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "cached_status": { + "name": "cached_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "manual_status": { + "name": "manual_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "manual_status_set_at": { + "name": "manual_status_set_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "auto_tool_approvals_suspended_at": { + "name": "auto_tool_approvals_suspended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "auto_tool_approvals_enabled": { + "name": "auto_tool_approvals_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "inactivity_due_at": { + "name": "inactivity_due_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "responding_until": { + "name": "responding_until", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "sessions_visibility_activity_at_idx": { + "name": "sessions_visibility_activity_at_idx", + "columns": [ + { + "expression": "visibility", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "activity_at", + "isExpression": false, + "asc": false, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sessions_inactivity_due_idx": { + "name": "sessions_inactivity_due_idx", + "columns": [ + { + "expression": "visibility", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "inactivity_due_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"sessions\".\"inactivity_due_at\" IS NOT NULL AND \"sessions\".\"manual_status\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "sessions_owner_user_id_idx": { + "name": "sessions_owner_user_id_idx", + "columns": [ + { + "expression": "owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sessions_fast_conversation_id_unique": { + "name": "sessions_fast_conversation_id_unique", + "columns": [ + { + "expression": "fast_conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"sessions\".\"fast_conversation_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sessions_owner_user_id_users_id_fk": { + "name": "sessions_owner_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": ["owner_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "sessions_owner_automation_automations_key_fk": { + "name": "sessions_owner_automation_automations_key_fk", + "tableFrom": "sessions", + "tableTo": "automations", + "columnsFrom": ["owner_automation"], + "columnsTo": ["key"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "sessions_private_owner_user_id_users_id_fk": { + "name": "sessions_private_owner_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": ["private_owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "sessions_fast_conversation_id_fast_agent_conversations_id_fk": { + "name": "sessions_fast_conversation_id_fast_agent_conversations_id_fk", + "tableFrom": "sessions", + "tableTo": "fast_agent_conversations", + "columnsFrom": ["fast_conversation_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "sessions_owner_shape_check": { + "name": "sessions_owner_shape_check", + "value": "(\"sessions\".\"owner_kind\" = 'user' AND \"sessions\".\"owner_automation\" IS NULL) OR (\"sessions\".\"owner_kind\" = 'automation' AND \"sessions\".\"owner_user_id\" IS NULL) OR (\"sessions\".\"owner_kind\" = 'system' AND \"sessions\".\"owner_user_id\" IS NULL AND \"sessions\".\"owner_automation\" IS NULL)" + }, + "sessions_owner_kind_check": { + "name": "sessions_owner_kind_check", + "value": "\"sessions\".\"owner_kind\" in ('user', 'automation', 'system')" + }, + "sessions_privacy_check": { + "name": "sessions_privacy_check", + "value": "\"sessions\".\"privacy\" in ('shared', 'private')" + }, + "sessions_private_owner_check": { + "name": "sessions_private_owner_check", + "value": "(\"sessions\".\"privacy\" = 'shared' AND \"sessions\".\"private_owner_user_id\" IS NULL) OR (\"sessions\".\"privacy\" = 'private' AND \"sessions\".\"private_owner_user_id\" IS NOT NULL AND \"sessions\".\"private_owner_user_id\" = \"sessions\".\"owner_user_id\")" + }, + "sessions_source_surface_check": { + "name": "sessions_source_surface_check", + "value": "\"sessions\".\"source_surface\" in ('web', 'api', 'slack', 'teams', 'telegram', 'discord', 'agentmail', 'linear', 'github', 'gitlab', 'gitea', 'ado', 'bitbucket', 'system', 'automation')" + }, + "sessions_source_trigger_check": { + "name": "sessions_source_trigger_check", + "value": "\"sessions\".\"source_trigger\" in ('message', 'webhook', 'schedule', 'manual')" + }, + "sessions_visibility_check": { + "name": "sessions_visibility_check", + "value": "\"sessions\".\"visibility\" in ('visible', 'hidden')" + }, + "sessions_cached_status_check": { + "name": "sessions_cached_status_check", + "value": "\"sessions\".\"cached_status\" IS NULL OR \"sessions\".\"cached_status\" in ('active', 'needs_input', 'blocked', 'ready')" + }, + "sessions_manual_status_check": { + "name": "sessions_manual_status_check", + "value": "\"sessions\".\"manual_status\" IS NULL OR \"sessions\".\"manual_status\" in ('active', 'needs_input', 'blocked', 'ready', 'done')" + } + }, + "isRLSEnabled": false + }, + "public.setup_qualification_blocks": { + "name": "setup_qualification_blocks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'blocked'" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_domain": { + "name": "email_domain", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "github_account_login": { + "name": "github_account_login", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "github_account_type": { + "name": "github_account_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "first_blocked_at": { + "name": "first_blocked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_blocked_at": { + "name": "last_blocked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "resolved_at": { + "name": "resolved_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "lifted_by_admin_user_id": { + "name": "lifted_by_admin_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lifted_by_admin_email": { + "name": "lifted_by_admin_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "setup_qualification_blocks_deployment_user_reason_unique": { + "name": "setup_qualification_blocks_deployment_user_reason_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "reason", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "setup_qualification_blocks_deployment_status_idx": { + "name": "setup_qualification_blocks_deployment_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "setup_qualification_blocks_user_status_idx": { + "name": "setup_qualification_blocks_user_status_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "setup_qualification_blocks_user_id_users_id_fk": { + "name": "setup_qualification_blocks_user_id_users_id_fk", + "tableFrom": "setup_qualification_blocks", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack_auth_tokens": { + "name": "slack_auth_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slack_user_id": { + "name": "slack_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slack_team_id": { + "name": "slack_team_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "thread_ts": { + "name": "thread_ts", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message_ts": { + "name": "message_ts", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_text": { + "name": "original_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "slack_auth_tokens_expires_at_idx": { + "name": "slack_auth_tokens_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "slack_auth_tokens_token_unique": { + "name": "slack_auth_tokens_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack_conversation_messages": { + "name": "slack_conversation_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "subject_user_id": { + "name": "subject_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slack_team_id": { + "name": "slack_team_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "subject_slack_user_id": { + "name": "subject_slack_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sender_user_id": { + "name": "sender_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sender_slack_user_id": { + "name": "sender_slack_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slack_channel_id": { + "name": "slack_channel_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "conversation_kind": { + "name": "conversation_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "thread_ts": { + "name": "thread_ts", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message_ts": { + "name": "message_ts", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message_at": { + "name": "message_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "direction": { + "name": "direction", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "author_kind": { + "name": "author_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "text": { + "name": "text", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "run_id": { + "name": "run_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "slack_conversation_messages_deployment_user_message_at_idx": { + "name": "slack_conversation_messages_deployment_user_message_at_idx", + "columns": [ + { + "expression": "subject_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_conversation_messages_deployment_user_thread_idx": { + "name": "slack_conversation_messages_deployment_user_thread_idx", + "columns": [ + { + "expression": "subject_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slack_channel_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "thread_ts", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_conversation_messages_task_id_idx": { + "name": "slack_conversation_messages_task_id_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_conversation_messages_run_id_idx": { + "name": "slack_conversation_messages_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_conversation_messages_team_channel_message_unique": { + "name": "slack_conversation_messages_team_channel_message_unique", + "columns": [ + { + "expression": "slack_team_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slack_channel_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_ts", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "slack_conversation_messages_subject_user_id_users_id_fk": { + "name": "slack_conversation_messages_subject_user_id_users_id_fk", + "tableFrom": "slack_conversation_messages", + "tableTo": "users", + "columnsFrom": ["subject_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "slack_conversation_messages_sender_user_id_users_id_fk": { + "name": "slack_conversation_messages_sender_user_id_users_id_fk", + "tableFrom": "slack_conversation_messages", + "tableTo": "users", + "columnsFrom": ["sender_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "slack_conversation_messages_task_id_tasks_id_fk": { + "name": "slack_conversation_messages_task_id_tasks_id_fk", + "tableFrom": "slack_conversation_messages", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "slack_conversation_messages_run_id_task_runs_id_fk": { + "name": "slack_conversation_messages_run_id_task_runs_id_fk", + "tableFrom": "slack_conversation_messages", + "tableTo": "task_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack_directory_users": { + "name": "slack_directory_users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "slack_user_id": { + "name": "slack_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slack_team_id": { + "name": "slack_team_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "real_name": { + "name": "real_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_deleted": { + "name": "is_deleted", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_bot": { + "name": "is_bot", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_app_user": { + "name": "is_app_user", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "profile_updated_at": { + "name": "profile_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "slack_directory_users_team_id_idx": { + "name": "slack_directory_users_team_id_idx", + "columns": [ + { + "expression": "slack_team_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "slack_directory_users_unique": { + "name": "slack_directory_users_unique", + "nullsNotDistinct": false, + "columns": ["slack_user_id", "slack_team_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack_fast_integration_calls": { + "name": "slack_fast_integration_calls", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "fast_agent_conversation_id": { + "name": "fast_agent_conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slack_team_id": { + "name": "slack_team_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slack_channel": { + "name": "slack_channel", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slack_thread_ts": { + "name": "slack_thread_ts", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slack_message_ts": { + "name": "slack_message_ts", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "arguments": { + "name": "arguments", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "result_preview": { + "name": "result_preview", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "slack_fast_integration_calls_conversation_idx": { + "name": "slack_fast_integration_calls_conversation_idx", + "columns": [ + { + "expression": "fast_agent_conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_fast_integration_calls_user_idx": { + "name": "slack_fast_integration_calls_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_fast_integration_calls_status_idx": { + "name": "slack_fast_integration_calls_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "slack_fast_integration_calls_fast_agent_conversation_id_fast_agent_conversations_id_fk": { + "name": "slack_fast_integration_calls_fast_agent_conversation_id_fast_agent_conversations_id_fk", + "tableFrom": "slack_fast_integration_calls", + "tableTo": "fast_agent_conversations", + "columnsFrom": ["fast_agent_conversation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "slack_fast_integration_calls_user_id_users_id_fk": { + "name": "slack_fast_integration_calls_user_id_users_id_fk", + "tableFrom": "slack_fast_integration_calls", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack_installation_channels": { + "name": "slack_installation_channels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "slack_installation_id": { + "name": "slack_installation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "slack_installation_channels_installation_id_idx": { + "name": "slack_installation_channels_installation_id_idx", + "columns": [ + { + "expression": "slack_installation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "slack_installation_channels_slack_installation_id_slack_installations_id_fk": { + "name": "slack_installation_channels_slack_installation_id_slack_installations_id_fk", + "tableFrom": "slack_installation_channels", + "tableTo": "slack_installations", + "columnsFrom": ["slack_installation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "slack_installation_channels_unique": { + "name": "slack_installation_channels_unique", + "nullsNotDistinct": false, + "columns": ["slack_installation_id", "channel_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack_installations": { + "name": "slack_installations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "team_name": { + "name": "team_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "team_domain": { + "name": "team_domain", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enterprise_id": { + "name": "enterprise_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enterprise_name": { + "name": "enterprise_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "app_id": { + "name": "app_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bot_user_id": { + "name": "bot_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bot_name": { + "name": "bot_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "app_name": { + "name": "app_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bot_access_token": { + "name": "bot_access_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_access_token": { + "name": "user_access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'bot'" + }, + "installed_by_user_id": { + "name": "installed_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "member_count_snapshot": { + "name": "member_count_snapshot", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "member_count_snapshot_at": { + "name": "member_count_snapshot_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "slack_installations_bot_user_id_idx": { + "name": "slack_installations_bot_user_id_idx", + "columns": [ + { + "expression": "bot_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_installations_active_idx": { + "name": "slack_installations_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "slack_installations_installed_by_user_id_users_id_fk": { + "name": "slack_installations_installed_by_user_id_users_id_fk", + "tableFrom": "slack_installations", + "tableTo": "users", + "columnsFrom": ["installed_by_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "slack_installations_team_id_unique": { + "name": "slack_installations_team_id_unique", + "nullsNotDistinct": false, + "columns": ["team_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack_user_mappings": { + "name": "slack_user_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "slack_user_id": { + "name": "slack_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slack_team_id": { + "name": "slack_team_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "slack_user_mappings_user_id_idx": { + "name": "slack_user_mappings_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "slack_user_mappings_user_id_users_id_fk": { + "name": "slack_user_mappings_user_id_users_id_fk", + "tableFrom": "slack_user_mappings", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "slack_user_mappings_unique": { + "name": "slack_user_mappings_unique", + "nullsNotDistinct": false, + "columns": ["slack_user_id", "slack_team_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.source_control_user_mappings": { + "name": "source_control_user_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "auth_account_id": { + "name": "auth_account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_control_provider": { + "name": "source_control_provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "external_account_id": { + "name": "external_account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "source_control_user_mappings_auth_account_unique": { + "name": "source_control_user_mappings_auth_account_unique", + "columns": [ + { + "expression": "auth_account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "source_control_user_mappings_user_provider_host_idx": { + "name": "source_control_user_mappings_user_provider_host_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "host", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "source_control_user_mappings_provider_identity_unique": { + "name": "source_control_user_mappings_provider_identity_unique", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "host", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "source_control_user_mappings_auth_account_id_auth_accounts_id_fk": { + "name": "source_control_user_mappings_auth_account_id_auth_accounts_id_fk", + "tableFrom": "source_control_user_mappings", + "tableTo": "auth_accounts", + "columnsFrom": ["auth_account_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "source_control_user_mappings_user_id_auth_users_id_fk": { + "name": "source_control_user_mappings_user_id_auth_users_id_fk", + "tableFrom": "source_control_user_mappings", + "tableTo": "auth_users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.task_artifacts": { + "name": "task_artifacts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "run_id": { + "name": "run_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "artifact_type": { + "name": "artifact_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'general'" + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "size": { + "name": "size", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "uploaded": { + "name": "uploaded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "upload_url_expires_at": { + "name": "upload_url_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "task_artifacts_task_id_idx": { + "name": "task_artifacts_task_id_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_artifacts_session_id_idx": { + "name": "task_artifacts_session_id_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_artifacts_run_id_idx": { + "name": "task_artifacts_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_artifacts_uploaded_idx": { + "name": "task_artifacts_uploaded_idx", + "columns": [ + { + "expression": "uploaded", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_artifacts_created_at_idx": { + "name": "task_artifacts_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_artifacts_path_idx": { + "name": "task_artifacts_path_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_artifacts_session_id_path_version_unique": { + "name": "task_artifacts_session_id_path_version_unique", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "version", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"task_artifacts\".\"session_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "task_artifacts_task_id_tasks_id_fk": { + "name": "task_artifacts_task_id_tasks_id_fk", + "tableFrom": "task_artifacts", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_artifacts_session_id_sessions_id_fk": { + "name": "task_artifacts_session_id_sessions_id_fk", + "tableFrom": "task_artifacts", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_artifacts_run_id_task_runs_id_fk": { + "name": "task_artifacts_run_id_task_runs_id_fk", + "tableFrom": "task_artifacts", + "tableTo": "task_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "task_artifacts_task_id_path_version_unique": { + "name": "task_artifacts_task_id_path_version_unique", + "nullsNotDistinct": false, + "columns": ["task_id", "path", "version"] + } + }, + "policies": {}, + "checkConstraints": { + "task_artifacts_owner_shape_check": { + "name": "task_artifacts_owner_shape_check", + "value": "(\"task_artifacts\".\"task_id\" IS NOT NULL) <> (\"task_artifacts\".\"session_id\" IS NOT NULL)" + } + }, + "isRLSEnabled": false + }, + "public.task_messages": { + "name": "task_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ts": { + "name": "ts", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "protocol": { + "name": "protocol", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content_blocks": { + "name": "content_blocks", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "task_messages_task_id_ts_idx": { + "name": "task_messages_task_id_ts_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "ts", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_messages_run_id_idx": { + "name": "task_messages_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_messages_created_at_idx": { + "name": "task_messages_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "task_messages_run_id_task_runs_id_fk": { + "name": "task_messages_run_id_task_runs_id_fk", + "tableFrom": "task_messages", + "tableTo": "task_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_messages_task_id_tasks_id_fk": { + "name": "task_messages_task_id_tasks_id_fk", + "tableFrom": "task_messages", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_messages_user_id_users_id_fk": { + "name": "task_messages_user_id_users_id_fk", + "tableFrom": "task_messages", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "task_messages_task_protocol_ts_event_type_unique": { + "name": "task_messages_task_protocol_ts_event_type_unique", + "nullsNotDistinct": false, + "columns": ["task_id", "protocol", "ts", "event_type"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.task_pins": { + "name": "task_pins", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "task_pins_deployment_user_task_unique": { + "name": "task_pins_deployment_user_task_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_pins_deployment_user_updated_at_idx": { + "name": "task_pins_deployment_user_updated_at_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_pins_task_id_idx": { + "name": "task_pins_task_id_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "task_pins_task_id_tasks_id_fk": { + "name": "task_pins_task_id_tasks_id_fk", + "tableFrom": "task_pins", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_pins_user_id_users_id_fk": { + "name": "task_pins_user_id_users_id_fk", + "tableFrom": "task_pins", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.task_platform_issue_reports": { + "name": "task_platform_issue_reports", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "run_id": { + "name": "run_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "task_message_id": { + "name": "task_message_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "fast_conversation_id": { + "name": "fast_conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "fast_event_id": { + "name": "fast_event_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reported_by_user_id": { + "name": "reported_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "report": { + "name": "report", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "slack_posted_at": { + "name": "slack_posted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ping_submitted_at": { + "name": "ping_submitted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ping_submitted_by_user_id": { + "name": "ping_submitted_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "task_platform_issue_reports_created_at_idx": { + "name": "task_platform_issue_reports_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_platform_issue_reports_task_id_created_at_idx": { + "name": "task_platform_issue_reports_task_id_created_at_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_platform_issue_reports_run_id_created_at_idx": { + "name": "task_platform_issue_reports_run_id_created_at_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_platform_issue_reports_task_message_id_unique": { + "name": "task_platform_issue_reports_task_message_id_unique", + "columns": [ + { + "expression": "task_message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_platform_issue_reports_fast_event_unique": { + "name": "task_platform_issue_reports_fast_event_unique", + "columns": [ + { + "expression": "fast_conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "fast_event_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "task_platform_issue_reports_task_id_tasks_id_fk": { + "name": "task_platform_issue_reports_task_id_tasks_id_fk", + "tableFrom": "task_platform_issue_reports", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_platform_issue_reports_run_id_task_runs_id_fk": { + "name": "task_platform_issue_reports_run_id_task_runs_id_fk", + "tableFrom": "task_platform_issue_reports", + "tableTo": "task_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_platform_issue_reports_task_message_id_task_messages_id_fk": { + "name": "task_platform_issue_reports_task_message_id_task_messages_id_fk", + "tableFrom": "task_platform_issue_reports", + "tableTo": "task_messages", + "columnsFrom": ["task_message_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_platform_issue_reports_session_id_sessions_id_fk": { + "name": "task_platform_issue_reports_session_id_sessions_id_fk", + "tableFrom": "task_platform_issue_reports", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_platform_issue_reports_fast_conversation_id_fast_agent_conversations_id_fk": { + "name": "task_platform_issue_reports_fast_conversation_id_fast_agent_conversations_id_fk", + "tableFrom": "task_platform_issue_reports", + "tableTo": "fast_agent_conversations", + "columnsFrom": ["fast_conversation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_platform_issue_reports_reported_by_user_id_users_id_fk": { + "name": "task_platform_issue_reports_reported_by_user_id_users_id_fk", + "tableFrom": "task_platform_issue_reports", + "tableTo": "users", + "columnsFrom": ["reported_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_platform_issue_reports_ping_submitted_by_user_id_users_id_fk": { + "name": "task_platform_issue_reports_ping_submitted_by_user_id_users_id_fk", + "tableFrom": "task_platform_issue_reports", + "tableTo": "users", + "columnsFrom": ["ping_submitted_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "task_platform_issue_reports_source_check": { + "name": "task_platform_issue_reports_source_check", + "value": "(\"task_platform_issue_reports\".\"task_id\" IS NOT NULL AND \"task_platform_issue_reports\".\"run_id\" IS NOT NULL AND \"task_platform_issue_reports\".\"session_id\" IS NULL AND \"task_platform_issue_reports\".\"fast_conversation_id\" IS NULL AND \"task_platform_issue_reports\".\"fast_event_id\" IS NULL) OR (\"task_platform_issue_reports\".\"task_id\" IS NULL AND \"task_platform_issue_reports\".\"run_id\" IS NULL AND \"task_platform_issue_reports\".\"session_id\" IS NOT NULL AND \"task_platform_issue_reports\".\"fast_conversation_id\" IS NOT NULL AND \"task_platform_issue_reports\".\"fast_event_id\" IS NOT NULL)" + } + }, + "isRLSEnabled": false + }, + "public.task_pull_requests": { + "name": "task_pull_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_control_provider": { + "name": "source_control_provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "repository_id": { + "name": "repository_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "pr_url": { + "name": "pr_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pr_number": { + "name": "pr_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pr_title": { + "name": "pr_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pr_sha": { + "name": "pr_sha", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pr_base_ref": { + "name": "pr_base_ref", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pr_base_sha": { + "name": "pr_base_sha", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "github_reaction_id": { + "name": "github_reaction_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "github_check_run_id": { + "name": "github_check_run_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "github_review_comment_id": { + "name": "github_review_comment_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_by_roomote": { + "name": "created_by_roomote", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auto_ready_blocked": { + "name": "auto_ready_blocked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "merged_at": { + "name": "merged_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "mergeability_status": { + "name": "mergeability_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'unknown'" + }, + "conflict_detected_at": { + "name": "conflict_detected_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "conflict_notification_claimed_at": { + "name": "conflict_notification_claimed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "conflict_notified_at": { + "name": "conflict_notified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "auto_handle_feedback_by_user_id": { + "name": "auto_handle_feedback_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "detected_at": { + "name": "detected_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "task_pull_requests_task_id_idx": { + "name": "task_pull_requests_task_id_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_pull_requests_repository_id_idx": { + "name": "task_pull_requests_repository_id_idx", + "columns": [ + { + "expression": "repository_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_pull_requests_provider_repository_pr_number_idx": { + "name": "task_pull_requests_provider_repository_pr_number_idx", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "repository", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pr_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_pull_requests_mergeability_lookup_idx": { + "name": "task_pull_requests_mergeability_lookup_idx", + "columns": [ + { + "expression": "source_control_provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "repository", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_by_roomote", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pr_base_ref", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "task_pull_requests_task_id_tasks_id_fk": { + "name": "task_pull_requests_task_id_tasks_id_fk", + "tableFrom": "task_pull_requests", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_pull_requests_repository_id_repositories_id_fk": { + "name": "task_pull_requests_repository_id_repositories_id_fk", + "tableFrom": "task_pull_requests", + "tableTo": "repositories", + "columnsFrom": ["repository_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "task_pull_requests_auto_handle_feedback_by_user_id_users_id_fk": { + "name": "task_pull_requests_auto_handle_feedback_by_user_id_users_id_fk", + "tableFrom": "task_pull_requests", + "tableTo": "users", + "columnsFrom": ["auto_handle_feedback_by_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "task_pull_requests_task_pr_unique": { + "name": "task_pull_requests_task_pr_unique", + "nullsNotDistinct": false, + "columns": ["task_id", "pr_url"] + } + }, + "policies": {}, + "checkConstraints": { + "task_pull_requests_source_control_provider_check": { + "name": "task_pull_requests_source_control_provider_check", + "value": "\"task_pull_requests\".\"source_control_provider\" in ('github', 'gitlab', 'gitea', 'ado', 'bitbucket')" + } + }, + "isRLSEnabled": false + }, + "public.task_run_events": { + "name": "task_run_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "details": { + "name": "details", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "task_run_events_run_id_created_at_idx": { + "name": "task_run_events_run_id_created_at_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_run_events_task_id_created_at_idx": { + "name": "task_run_events_task_id_created_at_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_run_events_created_at_idx": { + "name": "task_run_events_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_run_events_source_created_at_idx": { + "name": "task_run_events_source_created_at_idx", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "task_run_events_run_id_task_runs_id_fk": { + "name": "task_run_events_run_id_task_runs_id_fk", + "tableFrom": "task_run_events", + "tableTo": "task_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_run_events_task_id_tasks_id_fk": { + "name": "task_run_events_task_id_tasks_id_fk", + "tableFrom": "task_run_events", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.task_runs": { + "name": "task_runs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "identity": { + "type": "always", + "name": "task_runs_id_seq", + "schema": "public", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "2147483647", + "cache": "1", + "cycle": false + } + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'fresh'" + }, + "source_run_id": { + "name": "source_run_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "acting_user_id": { + "name": "acting_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "payload_kind": { + "name": "payload_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "harness": { + "name": "harness", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'opencode-server'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "queue_scope": { + "name": "queue_scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "task_phase": { + "name": "task_phase", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "fast_agent_session_id": { + "name": "fast_agent_session_id", + "type": "uuid", + "primaryKey": false, + "notNull": false, + "generated": { + "as": "((payload ->> 'fastAgentSessionId')::uuid)", + "type": "stored" + } + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "log": { + "name": "log", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "artifacts": { + "name": "artifacts", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "result": { + "name": "result", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "machine_id": { + "name": "machine_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sandbox_cmd_id": { + "name": "sandbox_cmd_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "machine_domain": { + "name": "machine_domain", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "machine_domains": { + "name": "machine_domains", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "initial_paths": { + "name": "initial_paths", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "primary_port_name": { + "name": "primary_port_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sandbox_server_url": { + "name": "sandbox_server_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "proxy_ports": { + "name": "proxy_ports", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "worker_release_tag": { + "name": "worker_release_tag", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "worker_version": { + "name": "worker_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "worker_commit": { + "name": "worker_commit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vendor": { + "name": "vendor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "configured_vcpus": { + "name": "configured_vcpus", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "configured_cpu_cores": { + "name": "configured_cpu_cores", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "configured_memory_mib": { + "name": "configured_memory_mib", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "snapshot_id": { + "name": "snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "snapshot_requested_at": { + "name": "snapshot_requested_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "snapshot_created_at": { + "name": "snapshot_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "snapshot_failed_at": { + "name": "snapshot_failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "keepalive_ms": { + "name": "keepalive_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sleep_at": { + "name": "sleep_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "sleep_requested_at": { + "name": "sleep_requested_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "worker_heartbeat_at": { + "name": "worker_heartbeat_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "source_snapshot_id": { + "name": "source_snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "auth_bypass_value": { + "name": "auth_bypass_value", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "auth_bypass_header_name": { + "name": "auth_bypass_header_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "dequeued_at": { + "name": "dequeued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "provision_started_at": { + "name": "provision_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "provision_ready_at": { + "name": "provision_ready_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "setup_completed_at": { + "name": "setup_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "environment_setup_state": { + "name": "environment_setup_state", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "environment_setup_completed_at": { + "name": "environment_setup_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "harness_started_at": { + "name": "harness_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "runtime_task_started_at": { + "name": "runtime_task_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "first_assistant_output_at": { + "name": "first_assistant_output_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cancel_requested_at": { + "name": "cancel_requested_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "canceled_at": { + "name": "canceled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "launch_mode": { + "name": "launch_mode", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "task_runs_task_id_idx": { + "name": "task_runs_task_id_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_fast_agent_session_id_idx": { + "name": "task_runs_fast_agent_session_id_idx", + "columns": [ + { + "expression": "fast_agent_session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_queue_scope_idx": { + "name": "task_runs_queue_scope_idx", + "columns": [ + { + "expression": "queue_scope", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_acting_user_id_idx": { + "name": "task_runs_acting_user_id_idx", + "columns": [ + { + "expression": "acting_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_snapshot_id_idx": { + "name": "task_runs_snapshot_id_idx", + "columns": [ + { + "expression": "snapshot_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_sleep_at_idx": { + "name": "task_runs_sleep_at_idx", + "columns": [ + { + "expression": "sleep_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_worker_heartbeat_at_idx": { + "name": "task_runs_worker_heartbeat_at_idx", + "columns": [ + { + "expression": "worker_heartbeat_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_sleep_check_due_v2_idx": { + "name": "task_runs_sleep_check_due_v2_idx", + "columns": [ + { + "expression": "sleep_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vendor", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"task_runs\".\"status\" IN ('running', 'idle') AND \"task_runs\".\"machine_id\" IS NOT NULL AND \"task_runs\".\"sleep_at\" IS NOT NULL AND \"task_runs\".\"sleep_requested_at\" IS NULL AND \"task_runs\".\"snapshot_id\" IS NULL AND \"task_runs\".\"snapshot_requested_at\" IS NULL AND \"task_runs\".\"vendor\" IN ('modal', 'daytona', 'e2b', 'docker', 'blaxel', 'box', 'roomote', 'azure')", + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_sleep_check_stale_worker_v2_idx": { + "name": "task_runs_sleep_check_stale_worker_v2_idx", + "columns": [ + { + "expression": "worker_heartbeat_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vendor", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"task_runs\".\"status\" IN ('running', 'idle') AND \"task_runs\".\"machine_id\" IS NOT NULL AND \"task_runs\".\"worker_heartbeat_at\" IS NOT NULL AND \"task_runs\".\"sleep_requested_at\" IS NULL AND \"task_runs\".\"snapshot_id\" IS NULL AND \"task_runs\".\"snapshot_requested_at\" IS NULL AND \"task_runs\".\"vendor\" IN ('modal', 'daytona', 'e2b', 'docker', 'blaxel', 'box', 'roomote', 'azure')", + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_sleep_check_active_v2_idx": { + "name": "task_runs_sleep_check_active_v2_idx", + "columns": [ + { + "expression": "vendor", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"task_runs\".\"status\" IN ('running', 'idle') AND \"task_runs\".\"machine_id\" IS NOT NULL AND \"task_runs\".\"sleep_requested_at\" IS NULL AND \"task_runs\".\"snapshot_id\" IS NULL AND \"task_runs\".\"snapshot_requested_at\" IS NULL AND \"task_runs\".\"vendor\" IN ('modal', 'daytona', 'e2b', 'docker', 'blaxel', 'box', 'roomote', 'azure')", + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_sleep_check_finished_completed_idx": { + "name": "task_runs_sleep_check_finished_completed_idx", + "columns": [ + { + "expression": "completed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"task_runs\".\"status\" IN ('failed', 'canceled', 'completed') AND \"task_runs\".\"machine_id\" IS NOT NULL AND \"task_runs\".\"sleep_requested_at\" IS NULL AND \"task_runs\".\"snapshot_id\" IS NULL AND \"task_runs\".\"snapshot_requested_at\" IS NULL AND \"task_runs\".\"vendor\" IN ('modal', 'daytona', 'e2b', 'docker', 'blaxel', 'box', 'roomote', 'azure') AND \"task_runs\".\"completed_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_sleep_check_finished_canceled_idx": { + "name": "task_runs_sleep_check_finished_canceled_idx", + "columns": [ + { + "expression": "canceled_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"task_runs\".\"status\" IN ('failed', 'canceled', 'completed') AND \"task_runs\".\"machine_id\" IS NOT NULL AND \"task_runs\".\"sleep_requested_at\" IS NULL AND \"task_runs\".\"snapshot_id\" IS NULL AND \"task_runs\".\"snapshot_requested_at\" IS NULL AND \"task_runs\".\"vendor\" IN ('modal', 'daytona', 'e2b', 'docker', 'blaxel', 'box', 'roomote', 'azure') AND \"task_runs\".\"completed_at\" IS NULL AND \"task_runs\".\"canceled_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_source_snapshot_id_idx": { + "name": "task_runs_source_snapshot_id_idx", + "columns": [ + { + "expression": "source_snapshot_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_source_run_id_idx": { + "name": "task_runs_source_run_id_idx", + "columns": [ + { + "expression": "source_run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_discord_source_event_unique": { + "name": "task_runs_discord_source_event_unique", + "columns": [ + { + "expression": "(\"payload\"->>'communicationSourceEventId')", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"task_runs\".\"payload\"->>'communicationProvider' = 'discord' AND \"task_runs\".\"payload\"->>'communicationSourceEventId' IS NOT NULL AND \"task_runs\".\"canceled_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_launch_idempotency_key_unique": { + "name": "task_runs_launch_idempotency_key_unique", + "columns": [ + { + "expression": "(\"payload\"->>'launchIdempotencyKey')", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"task_runs\".\"payload\"->>'launchIdempotencyKey' IS NOT NULL AND \"task_runs\".\"canceled_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_canceled_launch_idempotency_key_idx": { + "name": "task_runs_canceled_launch_idempotency_key_idx", + "columns": [ + { + "expression": "(\"payload\"->>'launchIdempotencyKey')", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"task_runs\".\"payload\"->>'launchIdempotencyKey' IS NOT NULL AND \"task_runs\".\"canceled_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_runs_first_assistant_output_at_idx": { + "name": "task_runs_first_assistant_output_at_idx", + "columns": [ + { + "expression": "first_assistant_output_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "task_runs_task_id_tasks_id_fk": { + "name": "task_runs_task_id_tasks_id_fk", + "tableFrom": "task_runs", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_runs_source_run_id_task_runs_id_fk": { + "name": "task_runs_source_run_id_task_runs_id_fk", + "tableFrom": "task_runs", + "tableTo": "task_runs", + "columnsFrom": ["source_run_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "task_runs_acting_user_id_users_id_fk": { + "name": "task_runs_acting_user_id_users_id_fk", + "tableFrom": "task_runs", + "tableTo": "users", + "columnsFrom": ["acting_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "task_runs_kind_check": { + "name": "task_runs_kind_check", + "value": "\"task_runs\".\"kind\" in ('fresh', 'resume')" + }, + "task_runs_harness_check": { + "name": "task_runs_harness_check", + "value": "\"task_runs\".\"harness\" in ('opencode-server')" + } + }, + "isRLSEnabled": false + }, + "public.task_slack_reply_details": { + "name": "task_slack_reply_details", + "schema": "", + "columns": { + "detail_id": { + "name": "detail_id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "findings": { + "name": "findings", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "task_slack_reply_details_task_id_idx": { + "name": "task_slack_reply_details_task_id_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_slack_reply_details_deployment_task_detail_unique": { + "name": "task_slack_reply_details_deployment_task_detail_unique", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "detail_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "task_slack_reply_details_task_id_tasks_id_fk": { + "name": "task_slack_reply_details_task_id_tasks_id_fk", + "tableFrom": "task_slack_reply_details", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.task_start_parallel_counts": { + "name": "task_start_parallel_counts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "run_id": { + "name": "run_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "payload_kind": { + "name": "payload_kind", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parallel_count": { + "name": "parallel_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "activity_window_seconds": { + "name": "activity_window_seconds", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "task_start_parallel_counts_run_id_unique": { + "name": "task_start_parallel_counts_run_id_unique", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_start_parallel_counts_task_id_started_at_idx": { + "name": "task_start_parallel_counts_task_id_started_at_idx", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "task_start_parallel_counts_started_at_idx": { + "name": "task_start_parallel_counts_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "task_start_parallel_counts_task_id_tasks_id_fk": { + "name": "task_start_parallel_counts_task_id_tasks_id_fk", + "tableFrom": "task_start_parallel_counts", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_start_parallel_counts_run_id_task_runs_id_fk": { + "name": "task_start_parallel_counts_run_id_task_runs_id_fk", + "tableFrom": "task_start_parallel_counts", + "tableTo": "task_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tasks": { + "name": "tasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow": { + "name": "workflow", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "surface": { + "name": "surface", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "trigger": { + "name": "trigger", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "visibility": { + "name": "visibility", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'visible'" + }, + "privacy": { + "name": "privacy", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'shared'" + }, + "private_owner_user_id": { + "name": "private_owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "initiator_kind": { + "name": "initiator_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "initiator_user_id": { + "name": "initiator_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "initiator_automation": { + "name": "initiator_automation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_external_id": { + "name": "actor_external_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_display_name": { + "name": "actor_display_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "commit_author_kind": { + "name": "commit_author_kind", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "commit_author_user_id": { + "name": "commit_author_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "commit_author_login": { + "name": "commit_author_login", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "commit_author_external_id": { + "name": "commit_author_external_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pr_assignee_login": { + "name": "pr_assignee_login", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slack_channel_id": { + "name": "slack_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slack_thread_ts": { + "name": "slack_thread_ts", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "linear_session_id": { + "name": "linear_session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "linear_issue_id": { + "name": "linear_issue_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "linear_organization_id": { + "name": "linear_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "harness": { + "name": "harness", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'opencode-server'" + }, + "harness_session_id": { + "name": "harness_session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inference_request_limit": { + "name": "inference_request_limit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1000 + }, + "inference_requests": { + "name": "inference_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "safety_stopped_at": { + "name": "safety_stopped_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "safety_stop_reason": { + "name": "safety_stop_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model_provider": { + "name": "model_provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title_edited_by_user_at": { + "name": "title_edited_by_user_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "llm_title_checkpoint": { + "name": "llm_title_checkpoint", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "mode": { + "name": "mode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "draft_prompt": { + "name": "draft_prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "requested_work_kind": { + "name": "requested_work_kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'unknown'" + }, + "requested_work_kind_source": { + "name": "requested_work_kind_source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'system_default'" + }, + "requested_work_kind_confidence": { + "name": "requested_work_kind_confidence", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "harness_instructions": { + "name": "harness_instructions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "compute_duration_ms": { + "name": "compute_duration_ms", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "timestamp": { + "name": "timestamp", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "activity_at": { + "name": "activity_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "repository_url": { + "name": "repository_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "repository_name": { + "name": "repository_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_branch": { + "name": "default_branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "tasks_initiator_user_id_idx": { + "name": "tasks_initiator_user_id_idx", + "columns": [ + { + "expression": "initiator_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tasks_initiator_automation_idx": { + "name": "tasks_initiator_automation_idx", + "columns": [ + { + "expression": "initiator_automation", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tasks_workflow_idx": { + "name": "tasks_workflow_idx", + "columns": [ + { + "expression": "workflow", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tasks_visibility_activity_at_idx": { + "name": "tasks_visibility_activity_at_idx", + "columns": [ + { + "expression": "visibility", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "activity_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tasks_harness_session_id_idx": { + "name": "tasks_harness_session_id_idx", + "columns": [ + { + "expression": "harness_session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tasks_timestamp_idx": { + "name": "tasks_timestamp_idx", + "columns": [ + { + "expression": "timestamp", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tasks_deployment_activity_at_idx": { + "name": "tasks_deployment_activity_at_idx", + "columns": [ + { + "expression": "activity_at", + "isExpression": false, + "asc": false, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tasks_created_at_idx": { + "name": "tasks_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "tasks_private_owner_user_id_users_id_fk": { + "name": "tasks_private_owner_user_id_users_id_fk", + "tableFrom": "tasks", + "tableTo": "users", + "columnsFrom": ["private_owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "tasks_initiator_user_id_users_id_fk": { + "name": "tasks_initiator_user_id_users_id_fk", + "tableFrom": "tasks", + "tableTo": "users", + "columnsFrom": ["initiator_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "tasks_initiator_automation_automations_key_fk": { + "name": "tasks_initiator_automation_automations_key_fk", + "tableFrom": "tasks", + "tableTo": "automations", + "columnsFrom": ["initiator_automation"], + "columnsTo": ["key"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "tasks_commit_author_user_id_users_id_fk": { + "name": "tasks_commit_author_user_id_users_id_fk", + "tableFrom": "tasks", + "tableTo": "users", + "columnsFrom": ["commit_author_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "tasks_initiator_shape_check": { + "name": "tasks_initiator_shape_check", + "value": "(\"tasks\".\"initiator_kind\" = 'user' AND \"tasks\".\"initiator_automation\" IS NULL AND (\"tasks\".\"initiator_user_id\" IS NOT NULL OR \"tasks\".\"actor_external_id\" IS NOT NULL)) OR (\"tasks\".\"initiator_kind\" = 'automation' AND \"tasks\".\"initiator_automation\" IS NOT NULL AND \"tasks\".\"initiator_user_id\" IS NULL)" + }, + "tasks_workflow_check": { + "name": "tasks_workflow_check", + "value": "\"tasks\".\"workflow\" in ('standard', 'pr_review', 'pr_conflict_resolve', 'scan', 'mcp_recommendations', 'setup_onboarding', 'env_snapshot', 'eval')" + }, + "tasks_surface_check": { + "name": "tasks_surface_check", + "value": "\"tasks\".\"surface\" in ('web', 'api', 'slack', 'teams', 'telegram', 'discord', 'agentmail', 'linear', 'github', 'gitlab', 'gitea', 'ado', 'bitbucket', 'system')" + }, + "tasks_trigger_check": { + "name": "tasks_trigger_check", + "value": "\"tasks\".\"trigger\" in ('message', 'webhook', 'schedule', 'manual')" + }, + "tasks_visibility_check": { + "name": "tasks_visibility_check", + "value": "\"tasks\".\"visibility\" in ('visible', 'hidden')" + }, + "tasks_privacy_check": { + "name": "tasks_privacy_check", + "value": "\"tasks\".\"privacy\" in ('shared', 'private')" + }, + "tasks_private_owner_check": { + "name": "tasks_private_owner_check", + "value": "(\"tasks\".\"privacy\" = 'shared' AND \"tasks\".\"private_owner_user_id\" IS NULL) OR (\"tasks\".\"privacy\" = 'private' AND \"tasks\".\"private_owner_user_id\" IS NOT NULL)" + }, + "tasks_state_check": { + "name": "tasks_state_check", + "value": "\"tasks\".\"state\" in ('active', 'completed', 'failed', 'canceled')" + }, + "tasks_harness_check": { + "name": "tasks_harness_check", + "value": "\"tasks\".\"harness\" in ('opencode-server')" + }, + "tasks_requested_work_kind_check": { + "name": "tasks_requested_work_kind_check", + "value": "\"tasks\".\"requested_work_kind\" in ('question', 'plan', 'implement', 'unknown')" + }, + "tasks_requested_work_kind_source_check": { + "name": "tasks_requested_work_kind_source_check", + "value": "\"tasks\".\"requested_work_kind_source\" in ('explicit_bootstrap', 'task_tool', 'llm_classifier', 'inherited', 'system_default')" + }, + "tasks_commit_author_kind_check": { + "name": "tasks_commit_author_kind_check", + "value": "\"tasks\".\"commit_author_kind\" IS NULL OR \"tasks\".\"commit_author_kind\" in ('roomote', 'user', 'external')" + } + }, + "isRLSEnabled": false + }, + "public.teams_installations": { + "name": "teams_installations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "installation_key": { + "name": "installation_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tenant_id": { + "name": "tenant_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "team_name": { + "name": "team_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "channel_name": { + "name": "channel_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "conversation_id": { + "name": "conversation_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "conversation_type": { + "name": "conversation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bot_app_id": { + "name": "bot_app_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bot_user_id": { + "name": "bot_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bot_name": { + "name": "bot_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "service_url": { + "name": "service_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_activity_at": { + "name": "last_activity_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "teams_installations_tenant_id_idx": { + "name": "teams_installations_tenant_id_idx", + "columns": [ + { + "expression": "tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "teams_installations_team_id_idx": { + "name": "teams_installations_team_id_idx", + "columns": [ + { + "expression": "team_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "teams_installations_conversation_id_idx": { + "name": "teams_installations_conversation_id_idx", + "columns": [ + { + "expression": "conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "teams_installations_active_idx": { + "name": "teams_installations_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "teams_installations_installation_key_unique": { + "name": "teams_installations_installation_key_unique", + "nullsNotDistinct": false, + "columns": ["installation_key"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.teams_user_mappings": { + "name": "teams_user_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "teams_user_id": { + "name": "teams_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "teams_tenant_id": { + "name": "teams_tenant_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "teams_aad_object_id": { + "name": "teams_aad_object_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "teams_user_mappings_aad_object_idx": { + "name": "teams_user_mappings_aad_object_idx", + "columns": [ + { + "expression": "teams_aad_object_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "teams_tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "teams_user_mappings_user_id_idx": { + "name": "teams_user_mappings_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "teams_user_mappings_user_id_users_id_fk": { + "name": "teams_user_mappings_user_id_users_id_fk", + "tableFrom": "teams_user_mappings", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "teams_user_mappings_unique": { + "name": "teams_user_mappings_unique", + "nullsNotDistinct": false, + "columns": ["teams_user_id", "teams_tenant_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.telegram_user_mappings": { + "name": "telegram_user_mappings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "telegram_user_id": { + "name": "telegram_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "telegram_chat_id": { + "name": "telegram_chat_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "telegram_username": { + "name": "telegram_username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "telegram_user_mappings_user_id_idx": { + "name": "telegram_user_mappings_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "telegram_user_mappings_user_id_users_id_fk": { + "name": "telegram_user_mappings_user_id_users_id_fk", + "tableFrom": "telegram_user_mappings", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "telegram_user_mappings_unique": { + "name": "telegram_user_mappings_unique", + "nullsNotDistinct": false, + "columns": ["telegram_user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tracked_messages": { + "name": "tracked_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "surface": { + "name": "surface", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dedupe_key": { + "name": "dedupe_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message_ts": { + "name": "message_ts", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "thread_ts": { + "name": "thread_ts", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "work_item_id": { + "name": "work_item_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "automation_key": { + "name": "automation_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "summary_text": { + "name": "summary_text", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "posted_at": { + "name": "posted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "dismissed_at": { + "name": "dismissed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "tracked_messages_kind_dedupe_key_unique": { + "name": "tracked_messages_kind_dedupe_key_unique", + "columns": [ + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "dedupe_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tracked_messages_work_item_id_idx": { + "name": "tracked_messages_work_item_id_idx", + "columns": [ + { + "expression": "work_item_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tracked_messages_channel_message_idx": { + "name": "tracked_messages_channel_message_idx", + "columns": [ + { + "expression": "channel_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_ts", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "tracked_messages_automation_channel_posted_idx": { + "name": "tracked_messages_automation_channel_posted_idx", + "columns": [ + { + "expression": "automation_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "channel_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "posted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "tracked_messages_work_item_id_work_items_id_fk": { + "name": "tracked_messages_work_item_id_work_items_id_fk", + "tableFrom": "tracked_messages", + "tableTo": "work_items", + "columnsFrom": ["work_item_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "tracked_messages_automation_key_automations_key_fk": { + "name": "tracked_messages_automation_key_automations_key_fk", + "tableFrom": "tracked_messages", + "tableTo": "automations", + "columnsFrom": ["automation_key"], + "columnsTo": ["key"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "tracked_messages_created_by_user_id_users_id_fk": { + "name": "tracked_messages_created_by_user_id_users_id_fk", + "tableFrom": "tracked_messages", + "tableTo": "users", + "columnsFrom": ["created_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_api_keys": { + "name": "user_api_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_api_keys_user_id_idx": { + "name": "user_api_keys_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_api_keys_user_deployment_provider_unique": { + "name": "user_api_keys_user_deployment_provider_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_api_keys_user_id_users_id_fk": { + "name": "user_api_keys_user_id_users_id_fk", + "tableFrom": "user_api_keys", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_personalizations": { + "name": "user_personalizations", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "manual_instructions": { + "name": "manual_instructions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "explicit_conversation_instructions": { + "name": "explicit_conversation_instructions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inferred_instructions": { + "name": "inferred_instructions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "learn_from_conversations": { + "name": "learn_from_conversations", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "reset_at": { + "name": "reset_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_personalizations_user_id_users_id_fk": { + "name": "user_personalizations_user_id_users_id_fk", + "tableFrom": "user_personalizations", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_task_model_mapping_presets": { + "name": "user_task_model_mapping_presets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name_key": { + "name": "name_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "roles": { + "name": "roles", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_task_model_mapping_presets_owner_name_unique_idx": { + "name": "user_task_model_mapping_presets_owner_name_unique_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_task_model_mapping_presets_owner_created_idx": { + "name": "user_task_model_mapping_presets_owner_created_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_task_model_mapping_presets_user_id_users_id_fk": { + "name": "user_task_model_mapping_presets_user_id_users_id_fk", + "tableFrom": "user_task_model_mapping_presets", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity": { + "name": "entity", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "analytics_id": { + "name": "analytics_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cookie_consented_at": { + "name": "cookie_consented_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "onboarding_completed_at": { + "name": "onboarding_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "invited_by_invite_id": { + "name": "invited_by_invite_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "last_sync_at": { + "name": "last_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "users_email_idx": { + "name": "users_email_idx", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "users_created_at_idx": { + "name": "users_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "users_analytics_id_unique_idx": { + "name": "users_analytics_id_unique_idx", + "columns": [ + { + "expression": "analytics_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vulnerability_findings": { + "name": "vulnerability_findings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "repository_id": { + "name": "repository_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "package_key": { + "name": "package_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "revision": { + "name": "revision", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "evidence": { + "name": "evidence", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "fingerprint": { + "name": "fingerprint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dispatched_fingerprint": { + "name": "dispatched_fingerprint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'investigating'" + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "vulnerability_findings_repository_idx": { + "name": "vulnerability_findings_repository_idx", + "columns": [ + { + "expression": "repository_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "vulnerability_findings_repository_id_repositories_id_fk": { + "name": "vulnerability_findings_repository_id_repositories_id_fk", + "tableFrom": "vulnerability_findings", + "tableTo": "repositories", + "columnsFrom": ["repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "vulnerability_findings_task_id_tasks_id_fk": { + "name": "vulnerability_findings_task_id_tasks_id_fk", + "tableFrom": "vulnerability_findings", + "tableTo": "tasks", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vulnerability_inventories": { + "name": "vulnerability_inventories", + "schema": "", + "columns": { + "repository_id": { + "name": "repository_id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "revision": { + "name": "revision", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fingerprint": { + "name": "fingerprint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dependencies": { + "name": "dependencies", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "gaps": { + "name": "gaps", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "vulnerability_inventories_repository_id_repositories_id_fk": { + "name": "vulnerability_inventories_repository_id_repositories_id_fk", + "tableFrom": "vulnerability_inventories", + "tableTo": "repositories", + "columnsFrom": ["repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vulnerability_watch_state": { + "name": "vulnerability_watch_state", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "cursor": { + "name": "cursor", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "lease_token": { + "name": "lease_token", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "lease_until": { + "name": "lease_until", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "notification_hash": { + "name": "notification_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.webhooks": { + "name": "webhooks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "delivery_id": { + "name": "delivery_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event": { + "name": "event", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "succeeded_at": { + "name": "succeeded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "failed_at": { + "name": "failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "webhooks_provider_delivery_id_unique": { + "name": "webhooks_provider_delivery_id_unique", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "delivery_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhooks_event_idx": { + "name": "webhooks_event_idx", + "columns": [ + { + "expression": "event", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhooks_created_at_idx": { + "name": "webhooks_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "webhooks_status_exclusive": { + "name": "webhooks_status_exclusive", + "value": "(\n (succeeded_at IS NOT NULL)::int +\n (failed_at IS NOT NULL)::int\n ) <= 1" + } + }, + "isRLSEnabled": false + }, + "public.work_items": { + "name": "work_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "automation_key": { + "name": "automation_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_task_id": { + "name": "source_task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "selected_by_user_id": { + "name": "selected_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_work_item_id": { + "name": "source_work_item_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "brief": { + "name": "brief", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "execution_prompt": { + "name": "execution_prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "investigation_context": { + "name": "investigation_context", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "action_kind": { + "name": "action_kind", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "disposition": { + "name": "disposition", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "repository_ids": { + "name": "repository_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "target_repository_full_name": { + "name": "target_repository_full_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "target_environment_id": { + "name": "target_environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workspace_readiness": { + "name": "workspace_readiness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "readiness_message": { + "name": "readiness_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "fingerprint": { + "name": "fingerprint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'open'" + }, + "launch_claimed_at": { + "name": "launch_claimed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "launched_task_id": { + "name": "launched_task_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "launched_at": { + "name": "launched_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "failed_at": { + "name": "failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "launch_error": { + "name": "launch_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dismissed_at": { + "name": "dismissed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "result_accepted_at": { + "name": "result_accepted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "result_ignored_at": { + "name": "result_ignored_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "result_automation_name": { + "name": "result_automation_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "result_priority": { + "name": "result_priority", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "result_user_id": { + "name": "result_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "result_visibility": { + "name": "result_visibility", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "work_items_source_task_idx": { + "name": "work_items_source_task_idx", + "columns": [ + { + "expression": "source_task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "work_items_kind_status_idx": { + "name": "work_items_kind_status_idx", + "columns": [ + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "work_items_automation_key_fingerprint_idx": { + "name": "work_items_automation_key_fingerprint_idx", + "columns": [ + { + "expression": "automation_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "fingerprint", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "work_items_fingerprint_idx": { + "name": "work_items_fingerprint_idx", + "columns": [ + { + "expression": "fingerprint", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "work_items_launched_task_id_idx": { + "name": "work_items_launched_task_id_idx", + "columns": [ + { + "expression": "launched_task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "work_items_source_task_kind_sort_order_unique": { + "name": "work_items_source_task_kind_sort_order_unique", + "columns": [ + { + "expression": "source_task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "work_items_automation_key_automations_key_fk": { + "name": "work_items_automation_key_automations_key_fk", + "tableFrom": "work_items", + "tableTo": "automations", + "columnsFrom": ["automation_key"], + "columnsTo": ["key"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "work_items_source_task_id_tasks_id_fk": { + "name": "work_items_source_task_id_tasks_id_fk", + "tableFrom": "work_items", + "tableTo": "tasks", + "columnsFrom": ["source_task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "work_items_selected_by_user_id_users_id_fk": { + "name": "work_items_selected_by_user_id_users_id_fk", + "tableFrom": "work_items", + "tableTo": "users", + "columnsFrom": ["selected_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "work_items_source_work_item_id_work_items_id_fk": { + "name": "work_items_source_work_item_id_work_items_id_fk", + "tableFrom": "work_items", + "tableTo": "work_items", + "columnsFrom": ["source_work_item_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "work_items_target_environment_id_environments_id_fk": { + "name": "work_items_target_environment_id_environments_id_fk", + "tableFrom": "work_items", + "tableTo": "environments", + "columnsFrom": ["target_environment_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "work_items_launched_task_id_tasks_id_fk": { + "name": "work_items_launched_task_id_tasks_id_fk", + "tableFrom": "work_items", + "tableTo": "tasks", + "columnsFrom": ["launched_task_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "work_items_result_user_id_users_id_fk": { + "name": "work_items_result_user_id_users_id_fk", + "tableFrom": "work_items", + "tableTo": "users", + "columnsFrom": ["result_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index 784390a309..0f104a1451 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -960,6 +960,13 @@ "when": 1792699448858, "tag": "0136_environment_snapshot_worker_version", "breakpoints": true + }, + { + "idx": 137, + "version": "7", + "when": 1793704059777, + "tag": "0137_colorful_nightcrawler", + "breakpoints": true } ] } diff --git a/packages/db/src/lib/__tests__/agent-safety.test.ts b/packages/db/src/lib/__tests__/agent-safety.test.ts new file mode 100644 index 0000000000..5b5057a397 --- /dev/null +++ b/packages/db/src/lib/__tests__/agent-safety.test.ts @@ -0,0 +1,106 @@ +import { + admitTaskInferenceRequest, + stopTaskForAgentSafety, + db, + eq, + taskFactory, + runFactory, + tasks, + taskMessages, + fastAgentConversations, + fastAgentMessages, + userFactory, +} from '../../server'; + +const taskIds: string[] = []; +const conversationIds: string[] = []; +afterEach(async () => { + for (const id of taskIds.splice(0)) + await db.delete(tasks).where(eq(tasks.id, id)); + for (const id of conversationIds.splice(0)) + await db + .delete(fastAgentConversations) + .where(eq(fastAgentConversations.id, id)); +}); +async function seed(limit = 5) { + const task = await taskFactory.create({ inferenceRequestLimit: limit }); + taskIds.push(task.id); + const run = await runFactory.create({ taskId: task.id }); + return { task, run }; +} + +it('serializes concurrent admissions across children and resumed runs, with no cost data', async () => { + const { task, run } = await seed(); + const resumed = await runFactory.create({ taskId: task.id, kind: 'resume' }); + const results = await Promise.all( + Array.from({ length: 30 }, (_, i) => + admitTaskInferenceRequest(task.id, i % 2 ? run.id : resumed.id), + ), + ); + expect(results.filter(Boolean)).toHaveLength(5); + const row = await db.query.tasks.findFirst({ where: eq(tasks.id, task.id) }); + expect(row).toMatchObject({ + inferenceRequests: 5, + safetyStopReason: 'task_request_limit', + }); + expect(row?.safetyStoppedAt).toBeInstanceOf(Date); + expect(await admitTaskInferenceRequest(task.id, resumed.id)).toBe(false); + const notices = await db.query.taskMessages.findMany({ + where: eq(taskMessages.taskId, task.id), + }); + expect(notices).toHaveLength(1); +}); + +it('persists exactly one parent notice and stop latch together, independent of inference and later runs', async () => { + const owner = await userFactory.create(); + const [conversation] = await db + .insert(fastAgentConversations) + .values({ + userId: owner.id, + surface: 'web', + workspaceId: owner.id, + conversationId: crypto.randomUUID(), + }) + .returning(); + conversationIds.push(conversation!.id); + const { task, run } = await seed(); + // The parent binding is trusted run payload, never supplied by a tool argument. + const { taskRuns } = await import('../../server'); + await db + .update(taskRuns) + .set({ + payload: { + ...run.payload, + fastAgentParent: { + sessionId: conversation!.id, + conversation: { + surface: 'web', + workspaceId: owner.id, + conversationId: conversation!.conversationId, + }, + }, + }, + }) + .where(eq(taskRuns.id, run.id)); + await Promise.all( + Array.from({ length: 10 }, () => + stopTaskForAgentSafety({ + taskId: task.id, + runId: run.id, + reason: 'identical_tool_loop', + }), + ), + ); + expect( + await db.query.taskMessages.findMany({ + where: eq(taskMessages.taskId, task.id), + }), + ).toHaveLength(1); + expect( + await db.query.fastAgentMessages.findMany({ + where: eq(fastAgentMessages.conversationId, conversation!.id), + }), + ).toHaveLength(1); + const restarted = await runFactory.create({ taskId: task.id }); + expect(await admitTaskInferenceRequest(task.id, restarted.id)).toBe(false); +}); diff --git a/packages/db/src/lib/agent-safety.ts b/packages/db/src/lib/agent-safety.ts new file mode 100644 index 0000000000..e064aee89f --- /dev/null +++ b/packages/db/src/lib/agent-safety.ts @@ -0,0 +1,144 @@ +import { and, desc, eq } from 'drizzle-orm'; +import { + AGENT_SAFETY_STOP_TEXT, + ACP_ENVELOPE_EVENT_TYPES, + getFastAgentParentFromPayload, + ROOMOTE_RUNTIME_TASK_MESSAGE_PROTOCOL, + type AgentSafetyReason, + type AgentSafetyStopDetails, +} from '@roomote/types'; +import { db } from '../db'; +import { + tasks, + taskRuns, + taskMessages, + fastAgentMessages, + fastAgentConversations, +} from '../schema'; + +type Transaction = Parameters[0]>[0]; + +async function stopInTransaction( + tx: Transaction, + taskId: string, + reason: AgentSafetyReason, + runId?: number, + details?: AgentSafetyStopDetails, +) { + const [task] = await tx + .select() + .from(tasks) + .where(eq(tasks.id, taskId)) + .for('update'); + if (!task) throw new Error('Task not found for inference admission'); + if (task.safetyStoppedAt) return; + const stoppedAt = new Date(); + await tx + .update(tasks) + .set({ safetyStoppedAt: stoppedAt, safetyStopReason: reason }) + .where(eq(tasks.id, taskId)); + const [run] = await tx + .select() + .from(taskRuns) + .where( + and( + eq(taskRuns.taskId, taskId), + ...(runId === undefined ? [] : [eq(taskRuns.id, runId)]), + ), + ) + .orderBy(desc(taskRuns.id)) + .limit(1); + if (!run) throw new Error('Safety stop requires a persisted task run'); + const passText = details + ? ` Pass: ${details.sessionId ?? 'helper'}; steps: ${details.steps ?? 0}; completed tools: ${details.completedTools ?? 0}; identical completions: ${details.identicalCompletions ?? 0}; elapsed: ${Math.round((details.elapsedMs ?? 0) / 1000)}s.` + : ''; + const text = `${AGENT_SAFETY_STOP_TEXT}\n\nReason: ${reason}.${passText} Provider requests admitted: ${task.inferenceRequests}/${task.inferenceRequestLimit}. Partial results are retained; an interrupted review is not a clean review.`; + const ts = stoppedAt.getTime(); + const contentBlocks = [{ type: 'text' as const, text }]; + const metadata = { source: 'agent_safety_stop', visibleInTranscript: true }; + await tx.insert(taskMessages).values({ + taskId, + runId: run.id, + ts, + protocol: ROOMOTE_RUNTIME_TASK_MESSAGE_PROTOCOL, + eventType: ACP_ENVELOPE_EVENT_TYPES.AgentSafetyStop, + role: 'assistant', + contentBlocks, + metadata, + payload: { text, safetyStop: { reason } }, + }); + const parent = getFastAgentParentFromPayload(run.payload); + // A deleted parent must not prevent the task latch/notice from committing. + const [parentConversation] = parent + ? await tx + .select({ id: fastAgentConversations.id }) + .from(fastAgentConversations) + .where(eq(fastAgentConversations.id, parent.sessionId)) + .for('key share') + : []; + if (parentConversation) { + await tx + .insert(fastAgentMessages) + .values({ + conversationId: parentConversation.id, + eventId: `agent-safety:${taskId}`, + turnId: `agent-safety:${taskId}`, + turnSeq: 0, + ts, + eventType: ACP_ENVELOPE_EVENT_TYPES.AgentSafetyStop, + role: 'assistant', + contentBlocks: [{ type: 'text', text: `Task ${taskId}: ${text}` }], + metadata, + payload: { text, taskId, safetyStop: { reason } }, + source: 'agent_safety_stop', + }) + .onConflictDoNothing(); + } +} + +/** Latch and notices commit together, without a model call or volatile queue. */ +export async function stopTaskForAgentSafety(input: { + taskId: string; + reason: AgentSafetyReason; + runId?: number; + details?: AgentSafetyStopDetails; +}): Promise { + await db.transaction((tx) => + stopInTransaction( + tx, + input.taskId, + input.reason, + input.runId, + input.details, + ), + ); +} + +/** Serialize all providers/children/runs on the same task row. Never refund. */ +export async function admitTaskInferenceRequest( + taskId: string, + runId?: number, +): Promise { + return db.transaction(async (tx) => { + const [task] = await tx + .select({ + requests: tasks.inferenceRequests, + limit: tasks.inferenceRequestLimit, + stopped: tasks.safetyStoppedAt, + }) + .from(tasks) + .where(eq(tasks.id, taskId)) + .for('update'); + if (!task) throw new Error('Task not found for inference admission'); + if (task.stopped) return false; + if (task.requests >= task.limit) { + await stopInTransaction(tx, taskId, 'task_request_limit', runId); + return false; + } + await tx + .update(tasks) + .set({ inferenceRequests: task.requests + 1 }) + .where(eq(tasks.id, taskId)); + return true; + }); +} diff --git a/packages/db/src/schema.ts b/packages/db/src/schema.ts index 0fff50fe9a..437390d1ea 100644 --- a/packages/db/src/schema.ts +++ b/packages/db/src/schema.ts @@ -944,6 +944,14 @@ export const tasks = pgTable( harnessSessionId: text('harness_session_id'), // Assigned by Harness. + // Lifetime admission state, deliberately not reset by a new run/resume. + inferenceRequestLimit: integer('inference_request_limit') + .notNull() + .default(1000), + inferenceRequests: integer('inference_requests').notNull().default(0), + safetyStoppedAt: timestamp('safety_stopped_at'), + safetyStopReason: text('safety_stop_reason'), + // Inference provider that served this task's LLM, paired with `model`. // Renamed from the ambiguous `provider` (this deployment also has // source-control, communication, and compute providers). diff --git a/packages/db/src/server.ts b/packages/db/src/server.ts index fd051a2512..40accf6838 100644 --- a/packages/db/src/server.ts +++ b/packages/db/src/server.ts @@ -41,6 +41,7 @@ export * from './lib/artifacts'; export * from './lib/map-raw-row'; export * from './lib/legacy-task-inference-usage'; export * from './lib/llm-usage'; +export * from './lib/agent-safety'; export * from './lib/deployment-auth-keypairs'; export * from './lib/reencrypt-secrets'; export { runReencryptSecretsCli } from './lib/reencrypt-secrets-cli'; diff --git a/packages/sdk/src/server/lib/task-runs/__tests__/notify-fast-agent-parent-on-settle.test.ts b/packages/sdk/src/server/lib/task-runs/__tests__/notify-fast-agent-parent-on-settle.test.ts index ff34ae1950..6fe95cf529 100644 --- a/packages/sdk/src/server/lib/task-runs/__tests__/notify-fast-agent-parent-on-settle.test.ts +++ b/packages/sdk/src/server/lib/task-runs/__tests__/notify-fast-agent-parent-on-settle.test.ts @@ -10,11 +10,15 @@ const mocks = vi.hoisted(() => ({ getTaskUrl: vi.fn(() => 'https://roomote.example/task/child-task'), canRetryFailedStart: vi.fn(), findRun: vi.fn(), + findTaskSafety: vi.fn(), })); vi.mock('@roomote/db/server', () => ({ db: { - query: { taskRuns: { findFirst: mocks.findRun } }, + query: { + taskRuns: { findFirst: mocks.findRun }, + tasks: { findFirst: mocks.findTaskSafety }, + }, update: vi.fn(() => ({ set: vi.fn((values: unknown) => { mocks.updateSet(values); @@ -32,6 +36,7 @@ vi.mock('@roomote/db/server', () => ({ values, })), taskRuns: { id: 'task_runs.id', result: 'task_runs.result' }, + tasks: { id: 'tasks.id' }, })); vi.mock('@roomote/cloud-agents/server', () => ({ @@ -79,6 +84,7 @@ function makeRun( describe('notifyFastAgentParentOnSettle', () => { beforeEach(() => { vi.clearAllMocks(); + mocks.findTaskSafety.mockResolvedValue({ safetyStoppedAt: null }); mocks.claimReturning.mockResolvedValue([{ id: 200 }]); mocks.enqueueParentEvent.mockResolvedValue({ queued: true }); mocks.listPullRequests.mockResolvedValue([]); @@ -104,6 +110,18 @@ describe('notifyFastAgentParentOnSettle', () => { expect(mocks.updateSet).not.toHaveBeenCalled(); }); + it('does not wake parent inference or offer a retry for a durably safety-stopped task', async () => { + mocks.findTaskSafety.mockResolvedValue({ safetyStoppedAt: new Date() }); + expect( + await notifyFastAgentParentOnSettle( + makeRun({ fastAgentParent: fastParent }), + RunStatus.Failed, + ), + ).toBe('already_notified'); + expect(mocks.enqueueParentEvent).not.toHaveBeenCalled(); + expect(mocks.canRetryFailedStart).not.toHaveBeenCalled(); + }); + it('stays quiet for a successful session-requested review settle', async () => { // The PR feedback relay is the session's single carrier for the outcome. await notifyFastAgentParentOnSettle( diff --git a/packages/sdk/src/server/lib/task-runs/__tests__/notify-source-thread-provider-error.test.ts b/packages/sdk/src/server/lib/task-runs/__tests__/notify-source-thread-provider-error.test.ts index 06349dc099..ebbe7f29f7 100644 --- a/packages/sdk/src/server/lib/task-runs/__tests__/notify-source-thread-provider-error.test.ts +++ b/packages/sdk/src/server/lib/task-runs/__tests__/notify-source-thread-provider-error.test.ts @@ -1,4 +1,8 @@ -import { TaskPayloadKind, RunStatus } from '@roomote/types'; +import { + TaskPayloadKind, + RunStatus, + AGENT_SAFETY_STOP_TEXT, +} from '@roomote/types'; import type { Task, TaskRun } from '@roomote/db/server'; // ── Mocks ──────────────────────────────────────────────────────────────────── @@ -234,6 +238,24 @@ function notify(envelope: ReturnType): Promise { // ── Tests ──────────────────────────────────────────────────────────────────── describe('maybeNotifySourceThreadOfTerminalProviderError', () => { + it('does not wake a parent model to explain an already-persisted safety stop', async () => { + mockFindFirstRun.mockResolvedValue( + makeRun({ + payload: payload({ + fastAgentParent: { + sessionId: '11111111-1111-4111-8111-111111111111', + conversation: { + surface: 'web', + workspaceId: 'web', + conversationId: 'parent', + }, + }, + }), + }), + ); + await notify(makeEnvelope({ errorSummary: AGENT_SAFETY_STOP_TEXT })); + expect(mockEnqueueParentEvent).not.toHaveBeenCalled(); + }); beforeEach(() => { vi.clearAllMocks(); mockRedisSet.mockResolvedValue('OK'); diff --git a/packages/sdk/src/server/lib/task-runs/notify-fast-agent-parent-on-settle.ts b/packages/sdk/src/server/lib/task-runs/notify-fast-agent-parent-on-settle.ts index 949213ed1c..f7c1747857 100644 --- a/packages/sdk/src/server/lib/task-runs/notify-fast-agent-parent-on-settle.ts +++ b/packages/sdk/src/server/lib/task-runs/notify-fast-agent-parent-on-settle.ts @@ -13,6 +13,7 @@ import { recordTaskRunLifecycleEvent, sql, taskRuns, + tasks, } from '@roomote/db/server'; import { listFastAgentPullRequestContexts } from '../fast-agent-parent-event'; import { enqueueFastAgentParentEvent } from '../fast-agent-parent-event-queue'; @@ -61,6 +62,11 @@ export async function notifyFastAgentParentOnSettle( if (!parent) { return 'not_applicable'; } + const taskSafety = await db.query.tasks.findFirst({ + where: eq(tasks.id, run.taskId), + columns: { safetyStoppedAt: true }, + }); + if (taskSafety?.safetyStoppedAt) return 'already_notified'; // A review child's outcome reaches the session through exactly one pipe, // the PR feedback relay built from its summary comment. That holds for diff --git a/packages/sdk/src/server/lib/task-runs/notify-source-thread-provider-error.ts b/packages/sdk/src/server/lib/task-runs/notify-source-thread-provider-error.ts index a9af7cf825..1b1b3dabad 100644 --- a/packages/sdk/src/server/lib/task-runs/notify-source-thread-provider-error.ts +++ b/packages/sdk/src/server/lib/task-runs/notify-source-thread-provider-error.ts @@ -6,6 +6,7 @@ import { redactSecrets } from '@roomote/communication/redact-secrets'; import { type AcpPersistedEnvelope, asRecord, + isAgentSafetyStop, getCommunicationChannelFromTaskPayload, getCommunicationMessageIdFromTaskPayload, getCommunicationProviderFromTaskPayload, @@ -308,6 +309,9 @@ async function notifySourceThreadOfTerminalProviderError(input: { const parent = getFastAgentParentFromPayload(run.payload); if (parent) { + // Safety notices are already persisted directly with the durable latch. + // Do not wake inference to explain a stop or launch a replacement pass. + if (isAgentSafetyStop(input.errorSummary)) return; if (input.preformatted) return; const error = redactSecrets(input.errorSummary).trim(); if (!error) return; diff --git a/packages/sdk/src/server/routers/task-runs.test.ts b/packages/sdk/src/server/routers/task-runs.test.ts index a33eee19f6..11488615aa 100644 --- a/packages/sdk/src/server/routers/task-runs.test.ts +++ b/packages/sdk/src/server/routers/task-runs.test.ts @@ -5,6 +5,7 @@ const jevgrepMocks = vi.hoisted(() => ({ const judgeFileMocks = vi.hoisted(() => ({ evaluate: vi.fn(), repository: vi.fn(), + findRunForInference: vi.fn(), })); vi.mock('@roomote/cloud-agents/server/typesafe-judgment', () => ({ resolveJudgmentBackend: jevgrepMocks.backend, @@ -13,10 +14,23 @@ vi.mock('@roomote/cloud-agents/server/judge-file', () => ({ evaluateJudgeFileCriteria: judgeFileMocks.evaluate, evaluateRepositoryJudgement: judgeFileMocks.repository, })); -vi.mock('@roomote/db/server', async (original) => ({ - ...(await original()), - isDeploymentExperimentEnabled: jevgrepMocks.experiment, -})); +vi.mock('@roomote/db/server', async (original) => { + const actual = await original(); + return { + ...actual, + db: { + ...actual.db, + query: { + ...actual.db.query, + taskRuns: { + ...actual.db.query.taskRuns, + findFirst: judgeFileMocks.findRunForInference, + }, + }, + }, + isDeploymentExperimentEnabled: jevgrepMocks.experiment, + }; +}); import { z } from 'zod'; @@ -208,6 +222,7 @@ function createRunCaller() { describe('taskRunsRouter queue message guards', () => { beforeEach(() => { vi.clearAllMocks(); + judgeFileMocks.findRunForInference.mockResolvedValue({ taskId: 'task-42' }); mockEnqueueTask.mockResolvedValue({ id: 99, taskId: 'task-99' }); mockFindTaskRun.mockResolvedValue({ id: 42 }); mockFindTaskRunForAccess.mockResolvedValue({ id: 42 }); @@ -326,7 +341,7 @@ describe('taskRunsRouter queue message guards', () => { kind: 'answered', answer: { outcome: 'pass', confidence: 0.98 }, }); - expect(judgeFileMocks.repository).toHaveBeenCalledWith(request); + expect(judgeFileMocks.repository).toHaveBeenCalledWith(request, 'task-42'); judgeFileMocks.repository.mockClear(); await expect( createAuthCaller().evaluateRepositoryJudgement({ runId: 42, request }), @@ -399,11 +414,44 @@ describe('taskRunsRouter queue message guards', () => { }); expect(judgeFileMocks.evaluate).toHaveBeenCalledWith( expect.objectContaining({ + taskId: 'task-42', state: expect.objectContaining({ path: 'Example.tsx' }), }), ); }); + it('does not dispatch repository judgments without a persisted task binding', async () => { + judgeFileMocks.findRunForInference.mockResolvedValue(undefined); + await expect( + createRunCaller().evaluateRepositoryJudgement({ + runId: 42, + request: { + kind: 'judge', + rule: 'Use sentence case', + evidence: [], + focusPaths: [], + complete: true, + unresolved: [], + }, + }), + ).resolves.toEqual({ kind: 'error' }); + await expect( + createRunCaller().evaluateJudgeFileCriteria({ + runId: 42, + state: { + path: 'Example.tsx', + patch: '+changed', + patchTruncated: false, + finalContent: 'changed', + finalContentTruncated: false, + }, + criteria: [{ id: 'criterion_0', rule: 'Use sentence case.' }], + }), + ).resolves.toEqual({ kind: 'error' }); + expect(judgeFileMocks.repository).not.toHaveBeenCalled(); + expect(judgeFileMocks.evaluate).not.toHaveBeenCalled(); + }); + it('strips actingUserId from run-token update input (confused-deputy guard)', async () => { // A run token is held by the sandbox runtime. Allowing it to write // actingUserId would let a compromised sandbox reassign the run's acting diff --git a/packages/sdk/src/server/routers/task-runs.ts b/packages/sdk/src/server/routers/task-runs.ts index dde4915b83..2e06511dd9 100644 --- a/packages/sdk/src/server/routers/task-runs.ts +++ b/packages/sdk/src/server/routers/task-runs.ts @@ -14,6 +14,8 @@ import { isDeploymentExperimentEnabled, slackInstallations, recordVulnerabilityAssessment, + stopTaskForAgentSafety, + taskRuns, } from '@roomote/db/server'; import { @@ -651,6 +653,35 @@ export const taskRunsRouter = router({ }), 'runId', ).mutation(({ input }) => setTaskHarnessSessionId(input)), + stopForAgentSafety: runScoped( + z.object({ + runId: z.number(), + reason: z.enum([ + 'identical_tool_loop', + 'pass_step_limit', + 'pass_tool_limit', + 'pass_time_limit', + 'task_request_limit', + ]), + details: z + .object({ + sessionId: z.string().max(200).optional(), + steps: z.number().int().nonnegative().optional(), + completedTools: z.number().int().nonnegative().optional(), + identicalCompletions: z.number().int().nonnegative().optional(), + elapsedMs: z.number().nonnegative().optional(), + }) + .optional(), + }), + 'runId', + ).mutation(async ({ input }) => { + const run = await db.query.taskRuns.findFirst({ + where: eq(taskRuns.id, input.runId), + columns: { taskId: true }, + }); + if (!run?.taskId) throw new TRPCError({ code: 'NOT_FOUND' }); + await stopTaskForAgentSafety({ taskId: run.taskId, ...input }); + }), createSnapshot: runScoped( z.object({ runId: z.number(), @@ -1223,7 +1254,15 @@ export const taskRunsRouter = router({ 'runId', ).mutation(async ({ input }) => { try { - const answer = await evaluateRepositoryJudgement(input.request); + const run = await db.query.taskRuns.findFirst({ + where: eq(taskRuns.id, input.runId), + columns: { taskId: true }, + }); + if (!run?.taskId) throw new TRPCError({ code: 'NOT_FOUND' }); + const answer = await evaluateRepositoryJudgement( + input.request, + run.taskId, + ); return answer ? { kind: 'answered' as const, answer } : { kind: 'unavailable' as const }; @@ -1238,7 +1277,13 @@ export const taskRunsRouter = router({ 'runId', ).mutation(async ({ input }) => { try { + const run = await db.query.taskRuns.findFirst({ + where: eq(taskRuns.id, input.runId), + columns: { taskId: true }, + }); + if (!run?.taskId) throw new TRPCError({ code: 'NOT_FOUND' }); const evaluations = await evaluateJudgeFileCriteria({ + taskId: run.taskId, state: input.state, criteria: input.criteria, }); diff --git a/packages/sdk/src/task-runs.ts b/packages/sdk/src/task-runs.ts index c8527f3d93..e789e42a9e 100644 --- a/packages/sdk/src/task-runs.ts +++ b/packages/sdk/src/task-runs.ts @@ -8,6 +8,11 @@ import { } from './client'; import { hasBootstrapFailureSignal } from './bootstrap-failure-signal'; +export const stopForAgentSafety = ( + input: AppRouterInput['taskRuns']['stopForAgentSafety'], + options?: { signal?: AbortSignal }, +) => client.taskRuns.stopForAgentSafety.mutate(input, options); + export type TaskRun = NonNullable; export type DequeuedTaskRun = NonNullable< diff --git a/packages/types/src/__tests__/agent-safety.test.ts b/packages/types/src/__tests__/agent-safety.test.ts new file mode 100644 index 0000000000..f948df99c1 --- /dev/null +++ b/packages/types/src/__tests__/agent-safety.test.ts @@ -0,0 +1,94 @@ +import { createHash } from 'node:crypto'; +import { + AGENT_SAFETY, + AGENT_SAFETY_STOP_CODE, + AgentSafetyPass, + canonicalSafetyJson, + isAgentSafetyStop, +} from '../agent-safety'; +import { classifyModelFallbackTrigger } from '../model-fallbacks'; + +const pass = () => + new AgentSafetyPass( + (text) => createHash('sha256').update(text).digest('hex'), + 0, + ); +const call = (id: number, result: unknown = '') => ({ + id: String(id), + name: 'grep', + args: { pattern: 'missing snapshot', path: 'test' }, + result, +}); + +describe('agent safety pass', () => { + it('stops the original thousand-empty-search loop at the fifth unique completion', () => { + const guard = pass(); + for (let id = 0; id < 1_000; id++) + expect(guard.completed(call(id))).toBe( + id < 4 ? undefined : 'identical_tool_loop', + ); + }); + it('canonicalizes arguments and deduplicates repeated/out-of-order events', () => { + const guard = pass(); + for (let index = 0; index < 1_000; index++) + expect(guard.completed(call(1))).toBeUndefined(); + for (let id = 2; id < 5; id++) { + expect( + guard.completed({ + ...call(id), + args: { path: 'test', pattern: 'missing snapshot' }, + }), + ).toBeUndefined(); + expect(guard.completed(call(1))).toBeUndefined(); + } + expect(guard.completed(call(5))).toBe('identical_tool_loop'); + expect(canonicalSafetyJson({ a: 1, b: 2 })).toBe( + canonicalSafetyJson({ b: 2, a: 1 }), + ); + }); + it('resets repetition on changed results or arguments, but still caps the pass', () => { + const guard = pass(); + for (let id = 0; id < AGENT_SAFETY.passTools; id++) + expect(guard.completed(call(id, { value: id }))).toBe( + id === AGENT_SAFETY.passTools - 1 ? 'pass_tool_limit' : undefined, + ); + }); + it('permits bounded status polling, never arbitrary search or shell exemptions', () => { + const guard = pass(); + for (let id = 0; id < 20; id++) + expect( + guard.completed({ + id: String(id), + name: 'roomote_manage_tasks', + args: { action: 'get_updates' }, + result: [], + }), + ).toBe(id === 19 ? 'identical_tool_loop' : undefined); + }); + it('counts unique model steps and has an activity-independent deadline', () => { + const guard = pass(); + for (let id = 0; id < 100; id++) { + const expected = id === 99 ? 'pass_step_limit' : undefined; + expect(guard.step(String(id))).toBe(expected); + expect(guard.step(String(id))).toBe(expected); + } + expect(pass().checkTime(AGENT_SAFETY.passTimeoutMs)).toBe( + 'pass_time_limit', + ); + }); + it('never selects provider fallback for safety errors, even if wrapped as retryable', () => { + const error = { + data: { + isRetryable: true, + statusCode: 503, + responseBody: JSON.stringify({ + error: { code: AGENT_SAFETY_STOP_CODE }, + }), + }, + }; + expect(isAgentSafetyStop(error)).toBe(true); + expect( + classifyModelFallbackTrigger(error, { retriesUsed: 100 }), + ).toBeNull(); + }); +}); diff --git a/packages/types/src/acp.ts b/packages/types/src/acp.ts index e2b2b03e4f..b9800619d3 100644 --- a/packages/types/src/acp.ts +++ b/packages/types/src/acp.ts @@ -23,6 +23,7 @@ export const ACP_ENVELOPE_EVENT_TYPES = { AssistantThought: 'roomote_runtime.assistant_thought', AssistantThoughtChunk: 'roomote_runtime.assistant_thought_chunk', AssistantMessage: 'roomote_runtime.assistant_message', + AgentSafetyStop: 'roomote_runtime.agent_safety_stop', AssistantMessageChunk: 'roomote_runtime.assistant_message_chunk', Plan: 'roomote_runtime.plan', ToolCall: 'roomote_runtime.tool_call', @@ -861,6 +862,7 @@ export function inferAcpMessageKind( switch (eventType) { case ACP_ENVELOPE_EVENT_TYPES.UserPrompt: case ACP_ENVELOPE_EVENT_TYPES.AssistantMessage: + case ACP_ENVELOPE_EVENT_TYPES.AgentSafetyStop: case ACP_ENVELOPE_EVENT_TYPES.AssistantMessageChunk: return 'text'; case ACP_ENVELOPE_EVENT_TYPES.AssistantThought: diff --git a/packages/types/src/agent-safety.ts b/packages/types/src/agent-safety.ts new file mode 100644 index 0000000000..3dc41c8156 --- /dev/null +++ b/packages/types/src/agent-safety.ts @@ -0,0 +1,129 @@ +/** Finite platform defaults; these are safety bounds, not dollar budgets. */ +export const AGENT_SAFETY = { + identicalCompletions: 5, + pollingCompletions: 20, + passSteps: 100, + passTools: 200, + passTimeoutMs: 20 * 60_000, + taskRequests: 1_000, +} as const; + +export type AgentSafetyReason = + | 'identical_tool_loop' + | 'pass_step_limit' + | 'pass_tool_limit' + | 'pass_time_limit' + | 'task_request_limit'; + +export interface AgentSafetyStopDetails { + sessionId?: string; + steps?: number; + completedTools?: number; + identicalCompletions?: number; + elapsedMs?: number; +} + +export const AGENT_SAFETY_STOP_CODE = 'roomote_agent_safety_stop'; +export const AGENT_SAFETY_STOP_TEXT = + 'Roomote stopped this task at a safety limit. Automatic retries are disabled. Review the partial work and safety notice before starting a new task.'; + +export function isAgentSafetyStop(error: unknown): boolean { + // SDK/provider envelopes may stringify nested response bodies. + const text = + error instanceof Error + ? `${error.message} ${JSON.stringify(error.cause ?? '')}` + : typeof error === 'string' + ? error + : JSON.stringify(error ?? ''); + return ( + text.includes(AGENT_SAFETY_STOP_CODE) || + text.includes(AGENT_SAFETY_STOP_TEXT) + ); +} + +export function canonicalSafetyJson(value: unknown): string { + if (Array.isArray(value)) + return `[${value.map(canonicalSafetyJson).join(',')}]`; + if (value && typeof value === 'object') { + return `{${Object.entries(value) + .sort(([a], [b]) => a.localeCompare(b)) + .map( + ([key, item]) => `${JSON.stringify(key)}:${canonicalSafetyJson(item)}`, + ) + .join(',')}}`; + } + return JSON.stringify(value) ?? 'null'; +} + +/** One execution pass. Only digests and invocation IDs are retained. */ +export class AgentSafetyPass { + readonly startedAtMs: number; + private readonly completedCalls = new Set(); + private readonly steps = new Set(); + private lastFingerprint?: string; + private identical = 0; + private stopped?: AgentSafetyReason; + + constructor( + private readonly digest: (value: string) => string, + now = Date.now(), + ) { + this.startedAtMs = now; + } + + checkTime(now = Date.now()): AgentSafetyReason | undefined { + if (now - this.startedAtMs >= AGENT_SAFETY.passTimeoutMs) + this.stopped ??= 'pass_time_limit'; + return this.stopped; + } + + snapshot(now = Date.now()): AgentSafetyStopDetails { + return { + steps: this.steps.size, + completedTools: this.completedCalls.size, + identicalCompletions: this.identical, + elapsedMs: Math.max(0, now - this.startedAtMs), + }; + } + + step(id: string): AgentSafetyReason | undefined { + if (this.stopped) return this.stopped; + this.steps.add(id); + if (this.steps.size >= AGENT_SAFETY.passSteps) + this.stopped ??= 'pass_step_limit'; + return this.stopped; + } + + completed(input: { + id: string; + name: string; + args: unknown; + result: unknown; + }): AgentSafetyReason | undefined { + if (this.stopped || this.completedCalls.has(input.id)) return this.stopped; + this.completedCalls.add(input.id); + const fingerprint = this.digest( + canonicalSafetyJson([input.name, input.args, input.result]), + ); + this.identical = + fingerprint === this.lastFingerprint ? this.identical + 1 : 1; + this.lastFingerprint = fingerprint; + // Only explicit read-only status APIs get a larger, still finite allowance. + // bash/execute/search are never exempt, even if their text mentions polling. + const args = input.args as { action?: unknown } | undefined; + const polling = + ['roomote_manage_tasks', 'manage_tasks'].some( + (name) => input.name === name || input.name.endsWith(`_${name}`), + ) && args?.action === 'get_updates'; + if ( + this.identical >= + (polling + ? AGENT_SAFETY.pollingCompletions + : AGENT_SAFETY.identicalCompletions) + ) + this.stopped = 'identical_tool_loop'; + if (this.completedCalls.size >= AGENT_SAFETY.passTools) + this.stopped ??= 'pass_tool_limit'; + return this.stopped; + } +} diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 875611dbb5..8af27a4bea 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -130,3 +130,4 @@ export * from './secret-redaction'; export * from './credential-egress'; export * from './public-url-fetch'; export * from './vulnerability-watch'; +export * from './agent-safety'; diff --git a/packages/types/src/model-fallbacks.ts b/packages/types/src/model-fallbacks.ts index 63a04e48e3..790bc8a559 100644 --- a/packages/types/src/model-fallbacks.ts +++ b/packages/types/src/model-fallbacks.ts @@ -149,6 +149,7 @@ export function classifyModelFallbackTrigger( error: unknown, { retriesUsed }: { retriesUsed: number }, ): ModelFallbackTrigger | null { + if (isAgentSafetyStop(error)) return null; if (isInferenceCreditsExhaustedError(error)) return 'immediate'; const values = collectProviderErrorValues(error); const records = values.flatMap((value) => { @@ -202,3 +203,4 @@ export function classifyModelFallbackTrigger( ? 'after_retries' : null; } +import { isAgentSafetyStop } from './agent-safety';