diff --git a/apps/sim/.env.example b/apps/sim/.env.example index 08003939323..09e555043f6 100644 --- a/apps/sim/.env.example +++ b/apps/sim/.env.example @@ -64,6 +64,8 @@ API_ENCRYPTION_KEY=your_api_encryption_key # Use `openssl rand -hex 32` to gener # LITELLM_API_KEY= # Optional bearer token if your LiteLLM proxy requires auth # FIREWORKS_API_KEY= # Optional Fireworks AI API key for model listing # NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS=true # Set when using AWS default credential chain (IAM roles, ECS task roles, IRSA). Hides credential fields in Agent block UI. +# MANAGED_AGENT_SELF_HOSTED_DEFAULTS='{"SOURCE_TYPE":"git","SOURCE_REF":"main"}' # Server-only JSON object of default session-metadata rows seeded into fresh Claude Managed Agents (self-hosted) blocks. Deployment-specific; keys map to whatever env vars your self-hosted agent sandbox reads. Absent = empty table. Values are served via GET /api/managed-agent-defaults and never inlined into the client bundle — safe to include values that should not leak to the browser. +# NEXT_PUBLIC_MANAGED_AGENT_SELF_HOSTED_MEMORY_ENABLED=true # Reveal Memory Store + Memory Access fields on the Claude Managed Agents (self-hosted) block. Off by default: Claude self-hosted environments do not currently support the memory-store resource attach on the session API. Enable only if your self-hosted agent sandbox implements memory attach on its side. # AZURE_OPENAI_ENDPOINT= # Azure OpenAI endpoint (hides field in UI when set alongside NEXT_PUBLIC_AZURE_CONFIGURED) # AZURE_OPENAI_API_KEY= # Azure OpenAI API key # AZURE_OPENAI_API_VERSION= # Azure OpenAI API version diff --git a/apps/sim/app/api/managed-agent-connections/[id]/agents/route.ts b/apps/sim/app/api/managed-agent-connections/[id]/agents/route.ts new file mode 100644 index 00000000000..117904b6e66 --- /dev/null +++ b/apps/sim/app/api/managed-agent-connections/[id]/agents/route.ts @@ -0,0 +1,89 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { type NextRequest, NextResponse } from 'next/server' +import { + type ManagedAgentAgent, + managedAgentProxyParamsSchema, + managedAgentProxyQuerySchema, +} from '@/lib/api/contracts' +import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' +import { generateRequestId } from '@/lib/core/utils/request' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { getDecryptedApiKey } from '@/lib/managed-agents/connections' +import { + type AnthropicListPage, + apiKeyFailureResponse, + ManagedAgentProxyError, + proxyManagedAgentsGet, +} from '@/lib/managed-agents/proxy' +import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils' + +const logger = createLogger('ManagedAgentAgentsAPI') + +interface AnthropicAgent { + id: string + name?: string + description?: string + latest_version?: number | string + version?: number | string +} + +interface RouteContext { + params: Promise<{ id: string }> +} + +export const GET = withRouteHandler(async (request: NextRequest, context: RouteContext) => { + const requestId = generateRequestId() + try { + const authResult = await checkSessionOrInternalAuth(request, { requireWorkflowId: false }) + if (!authResult.success || !authResult.userId) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const userId = authResult.userId + + const rawParams = await context.params + const paramsValidation = managedAgentProxyParamsSchema.safeParse(rawParams) + const queryValidation = managedAgentProxyQuerySchema.safeParse( + Object.fromEntries(request.nextUrl.searchParams.entries()) + ) + if (!paramsValidation.success || !queryValidation.success) { + return NextResponse.json({ error: 'Invalid request data' }, { status: 400 }) + } + const { id } = paramsValidation.data + const { workspaceId } = queryValidation.data + + const userPermission = await getUserEntityPermissions(userId, 'workspace', workspaceId) + if (!userPermission) { + return NextResponse.json({ error: 'Access denied' }, { status: 403 }) + } + + const keyResult = await getDecryptedApiKey({ id, workspaceId }) + if (!keyResult.ok) return apiKeyFailureResponse(keyResult) + const apiKey = keyResult.apiKey + + try { + const body = await proxyManagedAgentsGet>( + apiKey, + '/v1/agents?limit=100' + ) + const data: ManagedAgentAgent[] = (body.data ?? []).map((row) => ({ + id: row.id, + name: row.name ?? null, + description: row.description ?? null, + version: row.latest_version ?? row.version ?? null, + })) + return NextResponse.json({ data }) + } catch (error) { + if (error instanceof ManagedAgentProxyError) { + return NextResponse.json({ error: error.message }, { status: 502 }) + } + throw error + } + } catch (error) { + logger.error(`[${requestId}] Failed to list agents`, error) + return NextResponse.json( + { error: getErrorMessage(error, 'Failed to list agents') }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/managed-agent-connections/[id]/environments/[envId]/route.ts b/apps/sim/app/api/managed-agent-connections/[id]/environments/[envId]/route.ts new file mode 100644 index 00000000000..0f49cae4cc1 --- /dev/null +++ b/apps/sim/app/api/managed-agent-connections/[id]/environments/[envId]/route.ts @@ -0,0 +1,102 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { type NextRequest, NextResponse } from 'next/server' +import { + type ManagedAgentEnvironment, + managedAgentEnvironmentDetailParamsSchema, + managedAgentProxyQuerySchema, +} from '@/lib/api/contracts' +import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' +import { generateRequestId } from '@/lib/core/utils/request' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { getDecryptedApiKey } from '@/lib/managed-agents/connections' +import { + apiKeyFailureResponse, + ManagedAgentProxyError, + proxyManagedAgentsGet, +} from '@/lib/managed-agents/proxy' +import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils' + +const logger = createLogger('ManagedAgentEnvironmentAPI') + +interface AnthropicEnvironment { + id: string + name?: string + description?: string + scope?: 'organization' | 'account' | null + config?: { type?: 'cloud' | 'self_hosted' } +} + +interface RouteContext { + params: Promise<{ id: string; envId: string }> +} + +/** + * GET /api/managed-agent-connections/[id]/environments/[envId] — used by + * the workflow-block tool at run time to resolve `envType` before + * building the session-create payload. + */ +export const GET = withRouteHandler(async (request: NextRequest, context: RouteContext) => { + const requestId = generateRequestId() + try { + const authResult = await checkSessionOrInternalAuth(request, { requireWorkflowId: false }) + if (!authResult.success || !authResult.userId) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const userId = authResult.userId + + const rawParams = await context.params + const paramsValidation = managedAgentEnvironmentDetailParamsSchema.safeParse(rawParams) + const queryValidation = managedAgentProxyQuerySchema.safeParse( + Object.fromEntries(request.nextUrl.searchParams.entries()) + ) + if (!paramsValidation.success || !queryValidation.success) { + return NextResponse.json({ error: 'Invalid request data' }, { status: 400 }) + } + const { id, envId } = paramsValidation.data + const { workspaceId } = queryValidation.data + + const userPermission = await getUserEntityPermissions(userId, 'workspace', workspaceId) + if (!userPermission) { + return NextResponse.json({ error: 'Access denied' }, { status: 403 }) + } + + const keyResult = await getDecryptedApiKey({ id, workspaceId }) + if (!keyResult.ok) return apiKeyFailureResponse(keyResult) + const apiKey = keyResult.apiKey + + try { + const body = await proxyManagedAgentsGet( + apiKey, + `/v1/environments/${encodeURIComponent(envId)}` + ) + const envType = body.config?.type + if (envType !== 'cloud' && envType !== 'self_hosted') { + return NextResponse.json( + { error: 'Environment returned an unrecognised config.type' }, + { status: 502 } + ) + } + const data: ManagedAgentEnvironment = { + id: body.id, + name: body.name ?? null, + description: body.description ?? null, + envType, + scope: body.scope ?? null, + } + return NextResponse.json({ data }) + } catch (error) { + if (error instanceof ManagedAgentProxyError) { + const status = error.status === 404 ? 404 : 502 + return NextResponse.json({ error: error.message }, { status }) + } + throw error + } + } catch (error) { + logger.error(`[${requestId}] Failed to fetch environment`, error) + return NextResponse.json( + { error: getErrorMessage(error, 'Failed to fetch environment') }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/managed-agent-connections/[id]/environments/route.ts b/apps/sim/app/api/managed-agent-connections/[id]/environments/route.ts new file mode 100644 index 00000000000..7d4e2330d02 --- /dev/null +++ b/apps/sim/app/api/managed-agent-connections/[id]/environments/route.ts @@ -0,0 +1,96 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { type NextRequest, NextResponse } from 'next/server' +import { + type ManagedAgentEnvironment, + managedAgentProxyParamsSchema, + managedAgentProxyQuerySchema, +} from '@/lib/api/contracts' +import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' +import { generateRequestId } from '@/lib/core/utils/request' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { getDecryptedApiKey } from '@/lib/managed-agents/connections' +import { + type AnthropicListPage, + apiKeyFailureResponse, + ManagedAgentProxyError, + proxyManagedAgentsGet, +} from '@/lib/managed-agents/proxy' +import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils' + +const logger = createLogger('ManagedAgentEnvironmentsAPI') + +interface AnthropicEnvironment { + id: string + name?: string + description?: string + scope?: 'organization' | 'account' | null + config?: { type?: 'cloud' | 'self_hosted' } +} + +interface RouteContext { + params: Promise<{ id: string }> +} + +export const GET = withRouteHandler(async (request: NextRequest, context: RouteContext) => { + const requestId = generateRequestId() + try { + const authResult = await checkSessionOrInternalAuth(request, { requireWorkflowId: false }) + if (!authResult.success || !authResult.userId) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const userId = authResult.userId + + const rawParams = await context.params + const paramsValidation = managedAgentProxyParamsSchema.safeParse(rawParams) + const queryValidation = managedAgentProxyQuerySchema.safeParse( + Object.fromEntries(request.nextUrl.searchParams.entries()) + ) + if (!paramsValidation.success || !queryValidation.success) { + return NextResponse.json({ error: 'Invalid request data' }, { status: 400 }) + } + const { id } = paramsValidation.data + const { workspaceId } = queryValidation.data + + const userPermission = await getUserEntityPermissions(userId, 'workspace', workspaceId) + if (!userPermission) { + return NextResponse.json({ error: 'Access denied' }, { status: 403 }) + } + + const keyResult = await getDecryptedApiKey({ id, workspaceId }) + if (!keyResult.ok) return apiKeyFailureResponse(keyResult) + const apiKey = keyResult.apiKey + + try { + const body = await proxyManagedAgentsGet>( + apiKey, + '/v1/environments?limit=100' + ) + const data: ManagedAgentEnvironment[] = (body.data ?? []) + .map((row) => { + const envType = row.config?.type + if (envType !== 'cloud' && envType !== 'self_hosted') return null + return { + id: row.id, + name: row.name ?? null, + description: row.description ?? null, + envType, + scope: row.scope ?? null, + } + }) + .filter((row): row is ManagedAgentEnvironment => row !== null) + return NextResponse.json({ data }) + } catch (error) { + if (error instanceof ManagedAgentProxyError) { + return NextResponse.json({ error: error.message }, { status: 502 }) + } + throw error + } + } catch (error) { + logger.error(`[${requestId}] Failed to list environments`, error) + return NextResponse.json( + { error: getErrorMessage(error, 'Failed to list environments') }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/managed-agent-connections/[id]/memory-stores/route.ts b/apps/sim/app/api/managed-agent-connections/[id]/memory-stores/route.ts new file mode 100644 index 00000000000..b7c011e397b --- /dev/null +++ b/apps/sim/app/api/managed-agent-connections/[id]/memory-stores/route.ts @@ -0,0 +1,108 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { type NextRequest, NextResponse } from 'next/server' +import { + type ManagedAgentMemoryStore, + managedAgentProxyParamsSchema, + managedAgentProxyQuerySchema, +} from '@/lib/api/contracts' +import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' +import { generateRequestId } from '@/lib/core/utils/request' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { getDecryptedApiKey } from '@/lib/managed-agents/connections' +import { + apiKeyFailureResponse, + ManagedAgentProxyError, + proxyManagedAgentsGet, +} from '@/lib/managed-agents/proxy' +import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils' + +const logger = createLogger('ManagedAgentMemoryStoresAPI') + +interface AnthropicMemoryStore { + id: string + name?: string + description?: string + archived_at?: string | null + type?: 'memory_store' +} + +interface AnthropicMemoryStorePage { + data?: AnthropicMemoryStore[] + next_page?: string | null +} + +interface RouteContext { + params: Promise<{ id: string }> +} + +/** + * GET /api/managed-agent-connections/[id]/memory-stores — proxies to + * Anthropic's `GET /v1/memory_stores` using the connection's stored API + * key. Powers the Memory Store combobox on the Managed Agent block. + * + * Archived stores are excluded (Anthropic's `include_archived` defaults + * to false, and we don't surface them to workflow authors — a stale + * memory store would just fail at session-create time). + */ +export const GET = withRouteHandler(async (request: NextRequest, context: RouteContext) => { + const requestId = generateRequestId() + try { + const authResult = await checkSessionOrInternalAuth(request, { requireWorkflowId: false }) + if (!authResult.success || !authResult.userId) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const userId = authResult.userId + + const rawParams = await context.params + const paramsValidation = managedAgentProxyParamsSchema.safeParse(rawParams) + const queryValidation = managedAgentProxyQuerySchema.safeParse( + Object.fromEntries(request.nextUrl.searchParams.entries()) + ) + if (!paramsValidation.success || !queryValidation.success) { + return NextResponse.json({ error: 'Invalid request data' }, { status: 400 }) + } + const { id } = paramsValidation.data + const { workspaceId } = queryValidation.data + + const userPermission = await getUserEntityPermissions(userId, 'workspace', workspaceId) + if (!userPermission) { + return NextResponse.json({ error: 'Access denied' }, { status: 403 }) + } + + const keyResult = await getDecryptedApiKey({ id, workspaceId }) + if (!keyResult.ok) return apiKeyFailureResponse(keyResult) + const apiKey = keyResult.apiKey + + try { + const body = await proxyManagedAgentsGet( + apiKey, + '/v1/memory_stores?limit=100' + ) + const data: ManagedAgentMemoryStore[] = (body.data ?? []) + .filter((row) => row.archived_at == null) + .map((row) => ({ + id: row.id, + name: row.name ?? null, + description: row.description ?? null, + archivedAt: row.archived_at ?? null, + })) + return NextResponse.json({ data }) + } catch (error) { + if (error instanceof ManagedAgentProxyError) { + // 404 = feature not enabled on this workspace / beta not granted. + // Return empty so the Memory Store field shows "no options" instead + // of blocking the whole editor. + if (error.status === 404) return NextResponse.json({ data: [] }) + return NextResponse.json({ error: error.message }, { status: 502 }) + } + throw error + } + } catch (error) { + logger.error(`[${requestId}] Failed to list memory stores`, error) + return NextResponse.json( + { error: getErrorMessage(error, 'Failed to list memory stores') }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/managed-agent-connections/[id]/route.ts b/apps/sim/app/api/managed-agent-connections/[id]/route.ts new file mode 100644 index 00000000000..b0069b157fb --- /dev/null +++ b/apps/sim/app/api/managed-agent-connections/[id]/route.ts @@ -0,0 +1,69 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { type NextRequest, NextResponse } from 'next/server' +import { rotateManagedAgentConnectionContract } from '@/lib/api/contracts' +import { parseRequest } from '@/lib/api/server' +import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' +import { generateRequestId } from '@/lib/core/utils/request' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { verifyAnthropicApiKey } from '@/lib/managed-agents/anthropic-verify' +import { rotateConnectionKey } from '@/lib/managed-agents/connections' +import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils' + +const logger = createLogger('ManagedAgentConnectionAPI') + +interface RouteContext { + params: Promise<{ id: string }> +} + +/** PATCH - Rotate a connection's API key. Verifies new key before writing. */ +export const PATCH = withRouteHandler(async (req: NextRequest, context: RouteContext) => { + const requestId = generateRequestId() + try { + const authResult = await checkSessionOrInternalAuth(req, { requireWorkflowId: false }) + if (!authResult.success || !authResult.userId) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const userId = authResult.userId + + const parsed = await parseRequest(rotateManagedAgentConnectionContract, req, context) + if (!parsed.success) return parsed.response + + const { id } = parsed.data.params + const { workspaceId, apiKey } = parsed.data.body + + const userPermission = await getUserEntityPermissions(userId, 'workspace', workspaceId) + if (!userPermission || (userPermission !== 'admin' && userPermission !== 'write')) { + return NextResponse.json({ error: 'Write permission required' }, { status: 403 }) + } + + try { + const rotated = await rotateConnectionKey({ + id, + workspaceId, + apiKey, + verify: (key) => verifyAnthropicApiKey(key), + }) + if (!rotated) { + return NextResponse.json({ error: 'Connection not found' }, { status: 404 }) + } + logger.info(`[${requestId}] Rotated managed-agent connection ${id}`) + return NextResponse.json({ + success: true, + data: { + ...rotated, + lastVerifiedAt: rotated.lastVerifiedAt ? rotated.lastVerifiedAt.toISOString() : null, + createdAt: rotated.createdAt.toISOString(), + updatedAt: rotated.updatedAt.toISOString(), + }, + }) + } catch (error) { + const message = getErrorMessage(error, 'Failed to rotate key') + logger.warn(`[${requestId}] Rotate failed: ${message}`) + return NextResponse.json({ error: message }, { status: 400 }) + } + } catch (error) { + logger.error(`[${requestId}] Failed to rotate connection key`, error) + return NextResponse.json({ error: 'Failed to rotate connection key' }, { status: 500 }) + } +}) diff --git a/apps/sim/app/api/managed-agent-connections/[id]/vaults/route.ts b/apps/sim/app/api/managed-agent-connections/[id]/vaults/route.ts new file mode 100644 index 00000000000..431947fe524 --- /dev/null +++ b/apps/sim/app/api/managed-agent-connections/[id]/vaults/route.ts @@ -0,0 +1,90 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { type NextRequest, NextResponse } from 'next/server' +import { + type ManagedAgentVault, + managedAgentProxyParamsSchema, + managedAgentProxyQuerySchema, +} from '@/lib/api/contracts' +import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' +import { generateRequestId } from '@/lib/core/utils/request' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { getDecryptedApiKey } from '@/lib/managed-agents/connections' +import { + type AnthropicListPage, + apiKeyFailureResponse, + ManagedAgentProxyError, + proxyManagedAgentsGet, +} from '@/lib/managed-agents/proxy' +import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils' + +const logger = createLogger('ManagedAgentVaultsAPI') + +interface AnthropicVault { + id: string + name?: string + description?: string +} + +interface RouteContext { + params: Promise<{ id: string }> +} + +export const GET = withRouteHandler(async (request: NextRequest, context: RouteContext) => { + const requestId = generateRequestId() + try { + const authResult = await checkSessionOrInternalAuth(request, { requireWorkflowId: false }) + if (!authResult.success || !authResult.userId) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const userId = authResult.userId + + const rawParams = await context.params + const paramsValidation = managedAgentProxyParamsSchema.safeParse(rawParams) + const queryValidation = managedAgentProxyQuerySchema.safeParse( + Object.fromEntries(request.nextUrl.searchParams.entries()) + ) + if (!paramsValidation.success || !queryValidation.success) { + return NextResponse.json({ error: 'Invalid request data' }, { status: 400 }) + } + const { id } = paramsValidation.data + const { workspaceId } = queryValidation.data + + const userPermission = await getUserEntityPermissions(userId, 'workspace', workspaceId) + if (!userPermission) { + return NextResponse.json({ error: 'Access denied' }, { status: 403 }) + } + + const keyResult = await getDecryptedApiKey({ id, workspaceId }) + if (!keyResult.ok) return apiKeyFailureResponse(keyResult) + const apiKey = keyResult.apiKey + + try { + const body = await proxyManagedAgentsGet>( + apiKey, + '/v1/vaults?limit=100' + ) + const data: ManagedAgentVault[] = (body.data ?? []).map((row) => ({ + id: row.id, + name: row.name ?? null, + description: row.description ?? null, + })) + return NextResponse.json({ data }) + } catch (error) { + if (error instanceof ManagedAgentProxyError) { + // 404 on /v1/vaults could mean this beta doesn't expose vaults yet. + // Return an empty list so the block's Vault dropdown just stays empty + // instead of blocking the whole flow. + if (error.status === 404) return NextResponse.json({ data: [] }) + return NextResponse.json({ error: error.message }, { status: 502 }) + } + throw error + } + } catch (error) { + logger.error(`[${requestId}] Failed to list vaults`, error) + return NextResponse.json( + { error: getErrorMessage(error, 'Failed to list vaults') }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/managed-agent-connections/route.test.ts b/apps/sim/app/api/managed-agent-connections/route.test.ts new file mode 100644 index 00000000000..c5ec67cd9a9 --- /dev/null +++ b/apps/sim/app/api/managed-agent-connections/route.test.ts @@ -0,0 +1,275 @@ +/** + * Tests for the Managed Agent connections API route — permission gates. + * + * @vitest-environment node + */ +import { createMockRequest, permissionsMock, permissionsMockFns } from '@sim/testing' +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const { mockCheckSessionOrInternalAuth, mockListConnections, mockCreateConnection, mockDeleteConnection, mockVerifyAnthropicApiKey } = + vi.hoisted(() => ({ + mockCheckSessionOrInternalAuth: vi.fn(), + mockListConnections: vi.fn(), + mockCreateConnection: vi.fn(), + mockDeleteConnection: vi.fn(), + mockVerifyAnthropicApiKey: vi.fn(), + })) + +vi.mock('@/lib/auth/hybrid', () => ({ + checkSessionOrInternalAuth: mockCheckSessionOrInternalAuth, +})) + +vi.mock('@/lib/managed-agents/connections', () => ({ + createConnection: mockCreateConnection, + deleteConnection: mockDeleteConnection, + listConnections: mockListConnections, +})) + +vi.mock('@/lib/managed-agents/anthropic-verify', () => ({ + verifyAnthropicApiKey: mockVerifyAnthropicApiKey, +})) + +vi.mock('@/lib/workspaces/permissions/utils', () => permissionsMock) + +import { DELETE, GET, POST } from '@/app/api/managed-agent-connections/route' + +const now = new Date('2026-07-19T00:00:00.000Z') +const connectionRow = { + id: 'conn_1', + workspaceId: 'ws_A', + userId: 'user_1', + name: 'prod', + maskedApiKey: 'sk-ant-a…wxyz', + lastVerifiedAt: now, + lastVerificationError: null, + createdAt: now, + updatedAt: now, +} + +describe('GET /api/managed-agent-connections', () => { + beforeEach(() => { + vi.clearAllMocks() + mockCheckSessionOrInternalAuth.mockResolvedValue({ success: true, userId: 'user_1' }) + permissionsMockFns.mockGetUserEntityPermissions.mockResolvedValue('read') + mockListConnections.mockResolvedValue([connectionRow]) + }) + + it('returns 401 when not authenticated', async () => { + mockCheckSessionOrInternalAuth.mockResolvedValue({ success: false }) + const req = createMockRequest( + 'GET', + undefined, + {}, + 'http://localhost:3000/api/managed-agent-connections?workspaceId=ws_A' + ) + const res = await GET(req) + expect(res.status).toBe(401) + }) + + it('returns 400 when workspaceId is missing', async () => { + const req = createMockRequest( + 'GET', + undefined, + {}, + 'http://localhost:3000/api/managed-agent-connections' + ) + const res = await GET(req) + expect(res.status).toBe(400) + }) + + it('returns 403 when the user has no permission on the workspace', async () => { + permissionsMockFns.mockGetUserEntityPermissions.mockResolvedValue(null) + const req = createMockRequest( + 'GET', + undefined, + {}, + 'http://localhost:3000/api/managed-agent-connections?workspaceId=ws_A' + ) + const res = await GET(req) + expect(res.status).toBe(403) + expect(mockListConnections).not.toHaveBeenCalled() + }) + + it('allows read-tier members to list', async () => { + permissionsMockFns.mockGetUserEntityPermissions.mockResolvedValue('read') + const req = createMockRequest( + 'GET', + undefined, + {}, + 'http://localhost:3000/api/managed-agent-connections?workspaceId=ws_A' + ) + const res = await GET(req) + expect(res.status).toBe(200) + expect(mockListConnections).toHaveBeenCalledWith({ workspaceId: 'ws_A' }) + }) + + it('serializes dates as ISO strings', async () => { + const req = createMockRequest( + 'GET', + undefined, + {}, + 'http://localhost:3000/api/managed-agent-connections?workspaceId=ws_A' + ) + const res = await GET(req) + const body = await res.json() + expect(body.data[0].createdAt).toBe(now.toISOString()) + expect(body.data[0].lastVerifiedAt).toBe(now.toISOString()) + }) + + it('emits null for lastVerifiedAt when the row has never been verified', async () => { + mockListConnections.mockResolvedValue([{ ...connectionRow, lastVerifiedAt: null }]) + const req = createMockRequest( + 'GET', + undefined, + {}, + 'http://localhost:3000/api/managed-agent-connections?workspaceId=ws_A' + ) + const body = await (await GET(req)).json() + expect(body.data[0].lastVerifiedAt).toBeNull() + }) +}) + +describe('POST /api/managed-agent-connections', () => { + beforeEach(() => { + vi.clearAllMocks() + mockCheckSessionOrInternalAuth.mockResolvedValue({ success: true, userId: 'user_1' }) + permissionsMockFns.mockGetUserEntityPermissions.mockResolvedValue('write') + mockVerifyAnthropicApiKey.mockResolvedValue({ ok: true }) + mockCreateConnection.mockResolvedValue(connectionRow) + }) + + it('returns 401 when not authenticated', async () => { + mockCheckSessionOrInternalAuth.mockResolvedValue({ success: false }) + const req = createMockRequest('POST', { + workspaceId: 'ws_A', + name: 'prod', + apiKey: 'sk-ant-plaintext', + }) + const res = await POST(req) + expect(res.status).toBe(401) + }) + + it('returns 403 when the caller only has read permission', async () => { + permissionsMockFns.mockGetUserEntityPermissions.mockResolvedValue('read') + const req = createMockRequest('POST', { + workspaceId: 'ws_A', + name: 'prod', + apiKey: 'sk-ant-plaintext', + }) + const res = await POST(req) + expect(res.status).toBe(403) + expect(mockCreateConnection).not.toHaveBeenCalled() + }) + + it('allows write and admin to create', async () => { + for (const perm of ['write', 'admin'] as const) { + permissionsMockFns.mockGetUserEntityPermissions.mockResolvedValue(perm) + mockCreateConnection.mockClear() + const req = createMockRequest('POST', { + workspaceId: 'ws_A', + name: 'prod', + apiKey: 'sk-ant-plaintext', + }) + const res = await POST(req) + expect(res.status).toBe(200) + expect(mockCreateConnection).toHaveBeenCalledTimes(1) + } + }) + + it('surfaces the verify error message when createConnection rejects', async () => { + mockCreateConnection.mockRejectedValue(new Error('Anthropic rejected the key')) + const req = createMockRequest('POST', { + workspaceId: 'ws_A', + name: 'prod', + apiKey: 'sk-ant-bad', + }) + const res = await POST(req) + expect(res.status).toBe(400) + const body = await res.json() + expect(body.error).toBe('Anthropic rejected the key') + }) + + it('never returns the plaintext api key in the response', async () => { + const req = createMockRequest('POST', { + workspaceId: 'ws_A', + name: 'prod', + apiKey: 'sk-ant-plaintext-abcd', + }) + const res = await POST(req) + const body = await res.text() + expect(body).not.toContain('sk-ant-plaintext-abcd') + }) +}) + +describe('DELETE /api/managed-agent-connections', () => { + beforeEach(() => { + vi.clearAllMocks() + mockCheckSessionOrInternalAuth.mockResolvedValue({ success: true, userId: 'user_1' }) + permissionsMockFns.mockGetUserEntityPermissions.mockResolvedValue('write') + mockDeleteConnection.mockResolvedValue(true) + }) + + it('returns 401 when not authenticated', async () => { + mockCheckSessionOrInternalAuth.mockResolvedValue({ success: false }) + const req = createMockRequest( + 'DELETE', + undefined, + {}, + 'http://localhost:3000/api/managed-agent-connections?id=conn_1&workspaceId=ws_A' + ) + const res = await DELETE(req) + expect(res.status).toBe(401) + }) + + it('returns 400 when id or workspaceId is missing', async () => { + const req = createMockRequest( + 'DELETE', + undefined, + {}, + 'http://localhost:3000/api/managed-agent-connections?workspaceId=ws_A' + ) + const res = await DELETE(req) + expect(res.status).toBe(400) + }) + + it('returns 403 when the caller only has read permission', async () => { + permissionsMockFns.mockGetUserEntityPermissions.mockResolvedValue('read') + const req = createMockRequest( + 'DELETE', + undefined, + {}, + 'http://localhost:3000/api/managed-agent-connections?id=conn_1&workspaceId=ws_A' + ) + const res = await DELETE(req) + expect(res.status).toBe(403) + expect(mockDeleteConnection).not.toHaveBeenCalled() + }) + + it('returns 404 when the connection does not exist for that workspace', async () => { + mockDeleteConnection.mockResolvedValue(false) + const req = createMockRequest( + 'DELETE', + undefined, + {}, + 'http://localhost:3000/api/managed-agent-connections?id=conn_missing&workspaceId=ws_A' + ) + const res = await DELETE(req) + expect(res.status).toBe(404) + }) + + it('allows write and admin to delete', async () => { + for (const perm of ['write', 'admin'] as const) { + permissionsMockFns.mockGetUserEntityPermissions.mockResolvedValue(perm) + mockDeleteConnection.mockClear().mockResolvedValue(true) + const req = createMockRequest( + 'DELETE', + undefined, + {}, + 'http://localhost:3000/api/managed-agent-connections?id=conn_1&workspaceId=ws_A' + ) + const res = await DELETE(req) + expect(res.status).toBe(200) + expect(mockDeleteConnection).toHaveBeenCalledWith({ id: 'conn_1', workspaceId: 'ws_A' }) + } + }) +}) diff --git a/apps/sim/app/api/managed-agent-connections/route.ts b/apps/sim/app/api/managed-agent-connections/route.ts new file mode 100644 index 00000000000..ab10d61b6ea --- /dev/null +++ b/apps/sim/app/api/managed-agent-connections/route.ts @@ -0,0 +1,163 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { type NextRequest, NextResponse } from 'next/server' +import { + createManagedAgentConnectionContract, + deleteManagedAgentConnectionQuerySchema, + listManagedAgentConnectionsQuerySchema, +} from '@/lib/api/contracts' +import { parseRequest } from '@/lib/api/server' +import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' +import { generateRequestId } from '@/lib/core/utils/request' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { verifyAnthropicApiKey } from '@/lib/managed-agents/anthropic-verify' +import { + createConnection, + deleteConnection, + listConnections, +} from '@/lib/managed-agents/connections' +import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils' + +const logger = createLogger('ManagedAgentConnectionsAPI') + +function serialize< + T extends { + lastVerifiedAt: Date | null + createdAt: Date + updatedAt: Date + }, +>(row: T) { + return { + ...row, + lastVerifiedAt: row.lastVerifiedAt ? row.lastVerifiedAt.toISOString() : null, + createdAt: row.createdAt.toISOString(), + updatedAt: row.updatedAt.toISOString(), + } +} + +/** GET - List Managed Agent connections in a workspace */ +export const GET = withRouteHandler(async (request: NextRequest) => { + const requestId = generateRequestId() + try { + const authResult = await checkSessionOrInternalAuth(request, { requireWorkflowId: false }) + if (!authResult.success || !authResult.userId) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const userId = authResult.userId + + const query = listManagedAgentConnectionsQuerySchema.safeParse( + Object.fromEntries(request.nextUrl.searchParams.entries()) + ) + if (!query.success) { + return NextResponse.json( + { error: 'Invalid request data', details: query.error.issues }, + { status: 400 } + ) + } + const { workspaceId } = query.data + + const userPermission = await getUserEntityPermissions(userId, 'workspace', workspaceId) + if (!userPermission) { + return NextResponse.json({ error: 'Access denied' }, { status: 403 }) + } + + const rows = await listConnections({ workspaceId }) + return NextResponse.json({ data: rows.map(serialize) }, { status: 200 }) + } catch (error) { + logger.error(`[${requestId}] Failed to list connections`, error) + return NextResponse.json( + { error: 'Failed to list managed-agent connections' }, + { status: 500 } + ) + } +}) + +/** + * POST - Register a new Managed Agent connection. + * + * Body: `{workspaceId, name, apiKey}`. The key is verified against + * `GET /v1/agents` before we persist the row; a failed verify never + * writes. + */ +export const POST = withRouteHandler(async (req: NextRequest) => { + const requestId = generateRequestId() + try { + const authResult = await checkSessionOrInternalAuth(req, { requireWorkflowId: false }) + if (!authResult.success || !authResult.userId) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const userId = authResult.userId + + const parsed = await parseRequest(createManagedAgentConnectionContract, req, {}) + if (!parsed.success) return parsed.response + const { workspaceId, name, apiKey } = parsed.data.body + + const userPermission = await getUserEntityPermissions(userId, 'workspace', workspaceId) + if (!userPermission || (userPermission !== 'admin' && userPermission !== 'write')) { + return NextResponse.json({ error: 'Write permission required' }, { status: 403 }) + } + + try { + const created = await createConnection({ + workspaceId, + userId, + name, + apiKey, + verify: (key) => verifyAnthropicApiKey(key), + }) + logger.info(`[${requestId}] Created managed-agent connection ${created.id}`) + return NextResponse.json({ success: true, data: serialize(created) }) + } catch (error) { + const message = getErrorMessage(error, 'Failed to create connection') + logger.warn(`[${requestId}] Create failed: ${message}`) + return NextResponse.json({ error: message }, { status: 400 }) + } + } catch (error) { + logger.error(`[${requestId}] Failed to create connection`, error) + return NextResponse.json( + { error: 'Failed to create managed-agent connection' }, + { status: 500 } + ) + } +}) + +/** DELETE - Remove a Managed Agent connection */ +export const DELETE = withRouteHandler(async (request: NextRequest) => { + const requestId = generateRequestId() + try { + const authResult = await checkSessionOrInternalAuth(request, { requireWorkflowId: false }) + if (!authResult.success || !authResult.userId) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const userId = authResult.userId + + const query = deleteManagedAgentConnectionQuerySchema.safeParse( + Object.fromEntries(request.nextUrl.searchParams.entries()) + ) + if (!query.success) { + return NextResponse.json( + { error: 'Invalid request data', details: query.error.issues }, + { status: 400 } + ) + } + const { id, workspaceId } = query.data + + const userPermission = await getUserEntityPermissions(userId, 'workspace', workspaceId) + if (!userPermission || (userPermission !== 'admin' && userPermission !== 'write')) { + return NextResponse.json({ error: 'Write permission required' }, { status: 403 }) + } + + const deleted = await deleteConnection({ id, workspaceId }) + if (!deleted) { + return NextResponse.json({ error: 'Connection not found' }, { status: 404 }) + } + logger.info(`[${requestId}] Deleted managed-agent connection ${id}`) + return NextResponse.json({ success: true }) + } catch (error) { + logger.error(`[${requestId}] Failed to delete connection`, error) + return NextResponse.json( + { error: 'Failed to delete managed-agent connection' }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx b/apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx index 1f6fe23b076..c020784304d 100644 --- a/apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx +++ b/apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx @@ -43,6 +43,11 @@ const Inbox = dynamic(() => const MCP = dynamic(() => import('@/app/workspace/[workspaceId]/settings/components/mcp/mcp').then((m) => m.MCP) ) +const ManagedAgents = dynamic(() => + import( + '@/app/workspace/[workspaceId]/settings/components/managed-agents' + ).then((m) => m.ManagedAgents) +) const Mothership = dynamic(() => import('@/app/workspace/[workspaceId]/settings/components/mothership/mothership').then( (m) => m.Mothership @@ -170,6 +175,7 @@ export function SettingsPage({ section }: SettingsPageProps) { {effectiveSection === 'byok' && } {effectiveSection === 'copilot' && } {effectiveSection === 'mcp' && } + {effectiveSection === 'managed-agents' && } {effectiveSection === 'forks' && } {effectiveSection === 'custom-tools' && } {effectiveSection === 'workflow-mcp-servers' && } diff --git a/apps/sim/app/workspace/[workspaceId]/settings/components/managed-agents/connection-form-modal.tsx b/apps/sim/app/workspace/[workspaceId]/settings/components/managed-agents/connection-form-modal.tsx new file mode 100644 index 00000000000..11ef81abadd --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/settings/components/managed-agents/connection-form-modal.tsx @@ -0,0 +1,121 @@ +'use client' + +import { useState } from 'react' +import { + ChipModal, + ChipModalBody, + ChipModalError, + ChipModalField, + ChipModalFooter, + ChipModalHeader, +} from '@sim/emcn' +import { getErrorMessage } from '@sim/utils/errors' + +export interface ConnectionFormValues { + name: string + apiKey: string +} + +interface ConnectionFormModalProps { + open: boolean + onOpenChange: (open: boolean) => void + onSubmit: (values: ConnectionFormValues) => Promise +} + +/** + * "Link Claude workspace" dialog. User enters a display name + an + * Anthropic API key. Submission triggers a verify-then-save flow on the + * server; the modal keeps the dialog open until the request resolves so + * verification errors surface inline. + */ +export function ConnectionFormModal({ + open, + onOpenChange, + onSubmit, +}: ConnectionFormModalProps) { + const [name, setName] = useState('') + const [apiKey, setApiKey] = useState('') + const [submitting, setSubmitting] = useState(false) + const [error, setError] = useState(null) + const [prevOpen, setPrevOpen] = useState(false) + + if (open !== prevOpen) { + setPrevOpen(open) + if (open) { + setName('') + setApiKey('') + setError(null) + setSubmitting(false) + } + } + + const handleSubmit = async () => { + const trimmedName = name.trim() + const trimmedKey = apiKey.trim() + if (!trimmedName) { + setError('Give this connection a name (e.g. "prod", "staging").') + return + } + if (!trimmedKey) { + setError('Anthropic API key is required.') + return + } + setSubmitting(true) + setError(null) + try { + await onSubmit({ name: trimmedName, apiKey: trimmedKey }) + onOpenChange(false) + } catch (err) { + setError(getErrorMessage(err, 'Failed to link the Claude workspace.')) + } finally { + setSubmitting(false) + } + } + + return ( + + onOpenChange(false)}>Link Claude workspace + + + { + setName(value) + if (error) setError(null) + }} + placeholder='prod, staging, my-team, …' + required + hint='A label you’ll see when picking connections from a workflow block.' + /> + + { + setApiKey(value) + if (error) setError(null) + }} + placeholder='sk-ant-…' + password + required + hint='The workspace key from Claude Platform. Verified against /v1/agents before saving.' + /> + + {error ?? undefined} + + + onOpenChange(false)} + cancelDisabled={submitting} + primaryAction={{ + label: submitting ? 'Verifying…' : 'Link & save', + onClick: handleSubmit, + disabled: submitting || !name.trim() || !apiKey.trim(), + }} + /> + + ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/settings/components/managed-agents/index.ts b/apps/sim/app/workspace/[workspaceId]/settings/components/managed-agents/index.ts new file mode 100644 index 00000000000..71fafe65b5e --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/settings/components/managed-agents/index.ts @@ -0,0 +1 @@ +export { ManagedAgents } from './managed-agents' diff --git a/apps/sim/app/workspace/[workspaceId]/settings/components/managed-agents/managed-agents.tsx b/apps/sim/app/workspace/[workspaceId]/settings/components/managed-agents/managed-agents.tsx new file mode 100644 index 00000000000..951bf6bbe02 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/settings/components/managed-agents/managed-agents.tsx @@ -0,0 +1,233 @@ +'use client' + +import { useState } from 'react' +import { ChipConfirmModal, toast } from '@sim/emcn' +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { Plus } from 'lucide-react' +import { useParams } from 'next/navigation' +import { canMutateWorkspaceSettingsSection } from '@/components/settings/navigation' +import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider' +import { RowActionsMenu } from '@/app/workspace/[workspaceId]/settings/components/row-actions-menu' +import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' +import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components/settings-panel' +import { useSettingsSearch } from '@/app/workspace/[workspaceId]/settings/components/use-settings-search' +import { ConnectionFormModal } from '@/app/workspace/[workspaceId]/settings/components/managed-agents/connection-form-modal' +import { RotateKeyModal } from '@/app/workspace/[workspaceId]/settings/components/managed-agents/rotate-key-modal' +import { + useCreateManagedAgentConnection, + useDeleteManagedAgentConnection, + useManagedAgentConnections, + useRotateManagedAgentConnection, +} from '@/hooks/queries/managed-agent-connections' + +const logger = createLogger('ManagedAgentsSettings') + +export function ManagedAgents() { + const params = useParams() + const workspaceId = params.workspaceId as string + const workspacePermissions = useUserPermissionsContext() + const canEdit = canMutateWorkspaceSettingsSection('managed-agents', workspacePermissions) + + const { + data: connections = [], + isLoading, + error: listError, + } = useManagedAgentConnections(workspaceId) + const createConnection = useCreateManagedAgentConnection() + const deleteConnection = useDeleteManagedAgentConnection() + const rotateConnection = useRotateManagedAgentConnection() + + const [searchTerm, setSearchTerm] = useSettingsSearch() + const [showAddModal, setShowAddModal] = useState(false) + const [connectionToDeleteId, setConnectionToDeleteId] = useState(null) + const [connectionToRotate, setConnectionToRotate] = useState<{ + id: string + name: string + } | null>(null) + + const filtered = connections.filter((c) => { + if (!searchTerm.trim()) return true + return c.name.toLowerCase().includes(searchTerm.toLowerCase()) + }) + + const handleCreate = async (values: { name: string; apiKey: string }) => { + await createConnection.mutateAsync({ + workspaceId, + name: values.name, + apiKey: values.apiKey, + }) + toast.success('Claude workspace linked') + } + + const confirmDelete = async () => { + if (!connectionToDeleteId) return + const id = connectionToDeleteId + setConnectionToDeleteId(null) + try { + await deleteConnection.mutateAsync({ workspaceId, id }) + toast.success('Connection removed') + } catch (error) { + logger.error('Failed to delete connection:', error) + toast.error('Failed to remove connection', { + description: getErrorMessage(error), + }) + } + } + + const handleRotate = async (apiKey: string) => { + if (!connectionToRotate) return + await rotateConnection.mutateAsync({ + workspaceId, + id: connectionToRotate.id, + apiKey, + }) + toast.success('API key rotated') + } + + const hasConnections = connections.length > 0 + const showNoResults = searchTerm.trim() && filtered.length === 0 && hasConnections + + return ( + <> + setShowAddModal(true), + disabled: isLoading, + }, + ] + : [] + } + > + {listError ? ( +
+

+ {getErrorMessage(listError, 'Failed to load connections')} +

+
+ ) : isLoading ? null : !hasConnections ? ( + + {canEdit + ? 'Click "Link Claude workspace" above to connect an Anthropic workspace.' + : 'No Managed Agent connections configured.'} + + ) : ( +
+ {filtered.map((c) => { + const subtitle = formatSubtitle(c) + return ( +
+
+
+ + {c.name} + + + {c.maskedApiKey} + +
+

+ {subtitle.text} +

+
+
+ + setConnectionToRotate({ id: c.id, name: c.name }), + }, + { + label: 'Remove', + destructive: true, + onSelect: () => setConnectionToDeleteId(c.id), + }, + ] + : []), + ]} + /> +
+
+ ) + })} + {showNoResults && ( + + No connections found matching "{searchTerm}" + + )} +
+ )} +
+ + {canEdit && ( + + )} + + {canEdit && ( + { + if (!open) setConnectionToDeleteId(null) + }} + srTitle='Remove connection' + title='Remove Managed Agent connection' + text={[ + 'Any workflows that reference this connection will fail at run time until you re-link the workspace. This action cannot be undone.', + ]} + confirm={{ label: 'Remove', onClick: confirmDelete }} + /> + )} + + {canEdit && ( + { + if (!open) setConnectionToRotate(null) + }} + onSubmit={handleRotate} + /> + )} + + ) +} + +function formatSubtitle(row: { + lastVerifiedAt: string | null + lastVerificationError: string | null +}): { text: string; isError: boolean } { + if (row.lastVerificationError) { + return { text: row.lastVerificationError, isError: true } + } + if (row.lastVerifiedAt) { + const when = new Date(row.lastVerifiedAt).toLocaleString() + return { text: `Verified ${when}`, isError: false } + } + return { text: 'Not verified', isError: false } +} diff --git a/apps/sim/app/workspace/[workspaceId]/settings/components/managed-agents/rotate-key-modal.tsx b/apps/sim/app/workspace/[workspaceId]/settings/components/managed-agents/rotate-key-modal.tsx new file mode 100644 index 00000000000..473f626a120 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/settings/components/managed-agents/rotate-key-modal.tsx @@ -0,0 +1,100 @@ +'use client' + +import { useState } from 'react' +import { + ChipModal, + ChipModalBody, + ChipModalError, + ChipModalField, + ChipModalFooter, + ChipModalHeader, +} from '@sim/emcn' +import { getErrorMessage } from '@sim/utils/errors' + +interface RotateKeyModalProps { + open: boolean + connectionName: string | null + onOpenChange: (open: boolean) => void + onSubmit: (apiKey: string) => Promise +} + +/** + * "Rotate API key" dialog. Same verify-then-save flow as the initial + * link modal, but only the key field is editable — the connection name + * stays put. Kept separate from the create modal so the wording and the + * required fields match the operation the user is doing. + */ +export function RotateKeyModal({ + open, + connectionName, + onOpenChange, + onSubmit, +}: RotateKeyModalProps) { + const [apiKey, setApiKey] = useState('') + const [submitting, setSubmitting] = useState(false) + const [error, setError] = useState(null) + const [prevOpen, setPrevOpen] = useState(false) + + if (open !== prevOpen) { + setPrevOpen(open) + if (open) { + setApiKey('') + setError(null) + setSubmitting(false) + } + } + + const handleSubmit = async () => { + const trimmedKey = apiKey.trim() + if (!trimmedKey) { + setError('Anthropic API key is required.') + return + } + setSubmitting(true) + setError(null) + try { + await onSubmit(trimmedKey) + onOpenChange(false) + } catch (err) { + setError(getErrorMessage(err, 'Failed to rotate the API key.')) + } finally { + setSubmitting(false) + } + } + + const title = connectionName ? `Rotate key — ${connectionName}` : 'Rotate API key' + + return ( + + onOpenChange(false)}>{title} + + + { + setApiKey(value) + if (error) setError(null) + }} + placeholder='sk-ant-…' + password + required + hint='Verified against /v1/agents before saving. The old key is overwritten on success — existing workflows immediately use the new one.' + /> + + {error ?? undefined} + + + onOpenChange(false)} + cancelDisabled={submitting} + primaryAction={{ + label: submitting ? 'Verifying…' : 'Rotate & save', + onClick: handleSubmit, + disabled: submitting || !apiKey.trim(), + }} + /> + + ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx index 3e63939ba9e..986ecdc4826 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx @@ -50,6 +50,13 @@ import { getDependsOnFields } from '@/blocks/utils' import { useKnowledgeBase } from '@/hooks/kb/use-knowledge' import { useCustomTools } from '@/hooks/queries/custom-tools' import { useDeployWorkflow } from '@/hooks/queries/deployments' +import { + useManagedAgentAgents, + useManagedAgentConnections, + useManagedAgentEnvironments, + useManagedAgentMemoryStores, + useManagedAgentVaults, +} from '@/hooks/queries/managed-agent-connections' import { useMcpServers, useMcpToolsQuery } from '@/hooks/queries/mcp' import { useCredentialName } from '@/hooks/queries/oauth/oauth-credentials' import { useReactivateSchedule, useScheduleInfo } from '@/hooks/queries/schedules' @@ -80,6 +87,7 @@ interface SubBlockRowProps { workspaceId?: string workflowId?: string blockId?: string + blockType?: string allSubBlockValues?: Record displayAdvancedOptions?: boolean canonicalIndex?: ReturnType @@ -98,6 +106,18 @@ const areSubBlockRowPropsEqual = ( const nextValue = subBlockId ? nextProps.allSubBlockValues?.[subBlockId]?.value : undefined const valueEqual = prevValue === nextValue || isEqual(prevValue, nextValue) + // Some subblocks resolve their friendly-name label using SIBLING values + // (e.g. managed-agent rows key off the selected `connection` id). If a + // sibling changes but this row's own value doesn't, the memo would keep + // showing a label tied to the previous sibling. Compare a small set of + // known dependency keys explicitly so hydration stays fresh. + const depFields = ['connection', 'oauthCredential', 'credential'] as const + const depsEqual = depFields.every((field) => { + const prev = prevProps.allSubBlockValues?.[field]?.value + const next = nextProps.allSubBlockValues?.[field]?.value + return prev === next || isEqual(prev, next) + }) + return ( prevProps.title === nextProps.title && prevProps.value === nextProps.value && @@ -106,7 +126,9 @@ const areSubBlockRowPropsEqual = ( prevProps.workspaceId === nextProps.workspaceId && prevProps.workflowId === nextProps.workflowId && prevProps.blockId === nextProps.blockId && + prevProps.blockType === nextProps.blockType && valueEqual && + depsEqual && prevProps.displayAdvancedOptions === nextProps.displayAdvancedOptions && prevProps.canonicalIndex === nextProps.canonicalIndex && prevProps.canonicalModeOverrides === nextProps.canonicalModeOverrides @@ -126,6 +148,7 @@ const SubBlockRow = memo(function SubBlockRow({ workspaceId, workflowId, blockId, + blockType, allSubBlockValues, displayAdvancedOptions, canonicalIndex, @@ -356,6 +379,83 @@ const SubBlockRow = memo(function SubBlockRow({ [subBlock, rawValue] ) + /** + * Hydrates managed-agent selectors (connection, agent, environment, + * vaults, memory store) on the Claude Managed Agents blocks. Anthropic + * IDs (`agent_01...`, `env_01...`, `vlt_...`) are meaningless in a + * collapsed row; look up the label from the React Query cache the + * combobox already populates when the editor picker opens. + */ + const isManagedAgentBlock = + typeof blockType === 'string' && blockType.startsWith('managed_agent_') + const managedAgentConnectionId = + isManagedAgentBlock && subBlock?.id !== 'connection' + ? (allSubBlockValues?.connection?.value as string | undefined) + : undefined + const { data: managedAgentConnections = [] } = useManagedAgentConnections( + isManagedAgentBlock && subBlock?.id === 'connection' && workspaceId ? workspaceId : '' + ) + const { data: managedAgentAgents = [] } = useManagedAgentAgents( + isManagedAgentBlock && subBlock?.id === 'agent' ? managedAgentConnectionId ?? null : null, + workspaceId ?? '' + ) + const { data: managedAgentEnvironments = [] } = useManagedAgentEnvironments( + isManagedAgentBlock && subBlock?.id === 'environment' + ? managedAgentConnectionId ?? null + : null, + workspaceId ?? '' + ) + const { data: managedAgentVaultOptions = [] } = useManagedAgentVaults( + isManagedAgentBlock && subBlock?.id === 'vaults' ? managedAgentConnectionId ?? null : null, + workspaceId ?? '' + ) + const { data: managedAgentMemoryStoreOptions = [] } = useManagedAgentMemoryStores( + isManagedAgentBlock && subBlock?.id === 'memoryStoreId' + ? managedAgentConnectionId ?? null + : null, + workspaceId ?? '' + ) + const managedAgentDisplayName = useMemo(() => { + if (!isManagedAgentBlock || !subBlock) return null + if (subBlock.id === 'connection' && typeof rawValue === 'string' && rawValue.length > 0) { + return managedAgentConnections.find((c) => c.id === rawValue)?.name ?? null + } + if (subBlock.id === 'agent' && typeof rawValue === 'string' && rawValue.length > 0) { + return managedAgentAgents.find((a) => a.id === rawValue)?.name ?? null + } + if (subBlock.id === 'environment' && typeof rawValue === 'string' && rawValue.length > 0) { + return managedAgentEnvironments.find((e) => e.id === rawValue)?.name ?? null + } + if (subBlock.id === 'memoryStoreId' && typeof rawValue === 'string' && rawValue.length > 0) { + return managedAgentMemoryStoreOptions.find((m) => m.id === rawValue)?.name ?? null + } + if (subBlock.id === 'vaults') { + const ids = Array.isArray(rawValue) + ? (rawValue as unknown[]).filter( + (v): v is string => typeof v === 'string' && v.length > 0 + ) + : typeof rawValue === 'string' && rawValue.length > 0 + ? [rawValue] + : [] + if (ids.length === 0) return null + const names = ids.map( + (id) => managedAgentVaultOptions.find((v) => v.id === id)?.name ?? id + ) + if (names.length === 1) return names[0] + return `${names[0]} +${names.length - 1}` + } + return null + }, [ + isManagedAgentBlock, + subBlock, + rawValue, + managedAgentConnections, + managedAgentAgents, + managedAgentEnvironments, + managedAgentVaultOptions, + managedAgentMemoryStoreOptions, + ]) + /** Hydrates skill references to display names. */ const { data: workspaceSkills = [] } = useSkills(workspaceId || '') const skillsDisplayValue = useMemo( @@ -381,6 +481,7 @@ const SubBlockRow = memo(function SubBlockRow({ mcpToolDisplayName || tableDisplayName || webhookUrlDisplayValue || + managedAgentDisplayName || selectorDisplayName const displayValue = maskedValue || hydratedName || (isSelectorType && value ? '-' : value) @@ -687,6 +788,7 @@ export const WorkflowBlock = memo(function WorkflowBlock({ visibleSubBlockCount: totalRenderedRowCount, conditionRowCount: conditionRows.length, routerRowCount: routerRows.length, + nodeWidth: config.nodeWidth, }) }, dependencies: [ @@ -697,6 +799,7 @@ export const WorkflowBlock = memo(function WorkflowBlock({ conditionRows.length, routerRows.length, horizontalHandles, + config.nodeWidth, ], }) @@ -756,6 +859,7 @@ export const WorkflowBlock = memo(function WorkflowBlock({ workspaceId={workspaceId} workflowId={currentWorkflowId} blockId={id} + blockType={type} allSubBlockValues={subBlockState} displayAdvancedOptions={effectiveAdvanced} canonicalIndex={canonicalIndex} diff --git a/apps/sim/blocks/blocks/managed_agent_cloud.ts b/apps/sim/blocks/blocks/managed_agent_cloud.ts new file mode 100644 index 00000000000..5357a10a84e --- /dev/null +++ b/apps/sim/blocks/blocks/managed_agent_cloud.ts @@ -0,0 +1,231 @@ +import { ClaudeIcon } from '@/components/icons' +import { + fetchManagedAgentAgentOptions, + fetchManagedAgentCloudEnvironmentOptions, + fetchManagedAgentConnectionOptions, + fetchManagedAgentMemoryStoreOptions, + fetchManagedAgentVaultOptions, +} from '@/lib/managed-agents/subblock-options' +import type { BlockConfig, BlockMeta } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' + +/** + * Claude Managed Agents block — cloud (Anthropic-managed) environments. + * + * Supports the full `POST /v1/sessions` shape: + * - `agent`, `environment_id`, `vault_ids` + * - `resources: [{type: 'memory_store', ...}, {type: 'file', ...}]` + * - `metadata: {...}` (arbitrary key/value tags) + * + * The environment picker is filtered to `config.type === 'cloud'` so this + * block only lists cloud envs. Self-hosted envs live on the sibling + * `managed_agent_self_hosted` block. + */ +export const ManagedAgentCloudBlock: BlockConfig = { + type: 'managed_agent_cloud', + name: 'Claude Managed Agents', + description: 'Run a Claude Platform Managed Agent (cloud environments)', + authMode: AuthMode.ApiKey, + longDescription: + "Invoke a Claude Platform Managed Agent running in an Anthropic-managed cloud sandbox. Pick a linked Claude workspace, agent, and cloud environment. Attach vaults, a memory store, and files via the session resources array. Add opaque metadata tags if needed. The block returns the assistant's final text.", + category: 'tools', + integrationType: IntegrationType.AI, + docsLink: 'https://docs.sim.ai/integrations/managed-agent', + bgColor: '#DA7756', + icon: ClaudeIcon, + nodeWidth: 400, + subBlocks: [ + { + id: 'connection', + title: 'Claude Workspace', + type: 'combobox', + required: true, + placeholder: 'Select a linked Claude workspace…', + commandSearchable: true, + options: [], + fetchOptions: fetchManagedAgentConnectionOptions, + }, + { + id: 'environment', + title: 'Cloud Environment', + type: 'combobox', + required: true, + placeholder: 'Select a cloud environment…', + commandSearchable: true, + options: [], + dependsOn: ['connection'], + fetchOptions: fetchManagedAgentCloudEnvironmentOptions, + }, + { + // Constant — cloud block only ever runs against cloud envs, so the + // session-client builds the cloud-shaped payload (resources + + // metadata, no session_parameters routing). + id: 'environmentType', + title: 'Environment Type', + type: 'short-input', + value: () => 'cloud', + hidden: true, + }, + { + id: 'vaults', + title: 'Credential vaults', + type: 'combobox', + required: false, + placeholder: 'Optional — pick zero or more OAuth vaults', + commandSearchable: true, + multiSelect: true, + options: [], + dependsOn: ['connection'], + fetchOptions: fetchManagedAgentVaultOptions, + }, + { + // Security ack — enforced at execution time when at least one vault + // is selected. Rendered as a plain switch (with the same wording as + // the design spec) rather than a bespoke amber banner, to stay + // consistent with the rest of Sim's sub-block styling. The tool + // rejects execution with an actionable error if `vaults` is + // non-empty but this is false. + id: 'vaultsAck', + title: + 'I own or am authorized to use these vaults. I understand this means this agent can assume the identity granted by them.', + type: 'switch', + required: false, + description: 'Required when at least one vault is selected above.', + }, + { + // Memory store — attached as a `memory_store` resource entry. + id: 'memoryStoreId', + title: 'Memory Store', + type: 'combobox', + required: false, + placeholder: 'Optional — pick a memory store or leave empty', + commandSearchable: true, + options: [], + dependsOn: ['connection'], + fetchOptions: fetchManagedAgentMemoryStoreOptions, + }, + { + id: 'memoryAccess', + title: 'Memory Access', + type: 'dropdown', + required: false, + options: [ + { label: 'Read + write (default)', id: 'read_write' }, + { label: 'Read only', id: 'read_only' }, + ], + value: () => 'read_write', + dependsOn: ['memoryStoreId'], + condition: { field: 'memoryStoreId', value: '', not: true }, + description: + 'read_write pushes changes back on session exit. read_only pulls only and never writes.', + }, + { + id: 'agent', + title: 'Agent', + type: 'combobox', + required: true, + placeholder: 'Select an agent from this workspace…', + commandSearchable: true, + options: [], + dependsOn: ['connection'], + fetchOptions: fetchManagedAgentAgentOptions, + }, + { + id: 'userMessage', + title: 'User message', + type: 'long-input', + required: true, + placeholder: 'Ask the Managed Agent to do something…', + }, + { + // Free-form session metadata. Cloud envs store these as opaque + // tags; use for downstream analytics or your own bookkeeping. + id: 'sessionParameters', + title: 'Metadata', + type: 'table', + required: false, + columns: ['Key', 'Value'], + description: + 'Optional key/value metadata forwarded on the session (top-level `metadata` field).', + }, + { + // File attachments — each row is a Files-API `file_...` id plus + // an optional mount path. Anthropic mounts each file into the + // session container so the agent can read it. + id: 'files', + title: 'Files', + type: 'table', + required: false, + columns: ['File ID', 'Mount path'], + description: + 'Files-API file ids (file_...) to mount into the session. Mount path is optional; Anthropic picks a default when omitted.', + }, + ], + tools: { + access: ['managed_agent_run_session'], + }, + inputs: { + connection: { type: 'string', description: 'Managed Agent connection id.' }, + agent: { type: 'string', description: 'Managed-agent id inside the linked Claude workspace.' }, + environment: { type: 'string', description: 'Cloud environment id.' }, + environmentType: { type: 'string', description: 'Always "cloud" for this block.' }, + vaults: { type: 'json', description: 'Vault ids for MCP auth (array of strings).' }, + vaultsAck: { + type: 'boolean', + description: + 'Workflow-author acknowledgement that they are authorized to use the attached vaults. Required when `vaults` is non-empty.', + }, + memoryStoreId: { type: 'string', description: 'Optional Agent Memory Store id.' }, + memoryAccess: { + type: 'string', + description: "Memory store access mode — 'read_write' (default) or 'read_only'.", + }, + files: { type: 'json', description: 'File attachments — [{fileId, mountPath?}].' }, + sessionParameters: { + type: 'json', + description: 'Session metadata (top-level `metadata` field on the session).', + }, + userMessage: { type: 'string', description: 'The user message to send to the agent.' }, + }, + outputs: { + content: { type: 'string', description: "The Managed Agent's final assistant text." }, + sessionId: { + type: 'string', + description: 'Anthropic session id — logged so downstream steps can link to the run.', + }, + }, +} + +export const ManagedAgentCloudBlockMeta = { + tags: ['agent', 'anthropic', 'claude', 'session', 'managed-agent', 'cloud'], + url: 'https://platform.claude.com/', + templates: [ + { + icon: ClaudeIcon, + title: 'Delegate an analysis task to a cloud Managed Agent', + prompt: + "Build a workflow that opens a Managed Agent session in an Anthropic-managed cloud sandbox, attaches a memory store and any relevant files, and captures the agent's response.", + modules: ['agent', 'workflows'], + category: 'engineering', + tags: ['automation', 'analysis'], + }, + { + icon: ClaudeIcon, + title: 'Route a customer request to a vault-backed cloud agent', + prompt: + "Read a customer request from a webhook, invoke a cloud Managed Agent bound to an OAuth vault for MCP tool access, and return the agent's response as a chat reply.", + modules: ['agent', 'workflows'], + category: 'support', + tags: ['automation', 'customer-support'], + }, + ], + skills: [ + { + name: 'run-cloud-managed-agent', + description: + 'Delegate a task to a cloud Claude Platform Managed Agent — optionally attaching a memory store and files as session resources.', + content: + "# Run Cloud Managed Agent\n\nInvoke a Managed Agent running in Anthropic's cloud sandbox from a Sim workflow.\n\n## Steps\n1. Pick the connection (linked Claude workspace).\n2. Pick the cloud agent and environment.\n3. Optionally attach vaults, a memory store (with access mode), and files.\n4. Optionally add metadata tags for bookkeeping.\n5. Write the user message; `` references resolve at run time.\n\n## Output\nThe block returns the assistant's final text as `content`. Chain downstream blocks as needed.", + }, + ], +} as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/managed_agent_self_hosted.test.ts b/apps/sim/blocks/blocks/managed_agent_self_hosted.test.ts new file mode 100644 index 00000000000..89b14716605 --- /dev/null +++ b/apps/sim/blocks/blocks/managed_agent_self_hosted.test.ts @@ -0,0 +1,56 @@ +/** + * @vitest-environment node + */ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const { envState } = vi.hoisted(() => ({ + envState: { + NEXT_PUBLIC_MANAGED_AGENT_SELF_HOSTED_MEMORY_ENABLED: undefined as string | undefined, + }, +})) + +vi.mock('@/lib/core/config/env', () => ({ + env: new Proxy({} as Record, { + get: (_target, key) => (envState as Record)[key as string], + }), +})) + +vi.mock('@/lib/managed-agents/subblock-options', () => ({ + fetchManagedAgentAgentOptions: vi.fn(), + fetchManagedAgentConnectionOptions: vi.fn(), + fetchManagedAgentMemoryStoreOptions: vi.fn(), + fetchManagedAgentSelfHostedEnvironmentOptions: vi.fn(), + fetchManagedAgentVaultOptions: vi.fn(), +})) + +import { isSelfHostedMemoryEnabled } from '@/blocks/blocks/managed_agent_self_hosted' + +describe('isSelfHostedMemoryEnabled', () => { + beforeEach(() => { + envState.NEXT_PUBLIC_MANAGED_AGENT_SELF_HOSTED_MEMORY_ENABLED = undefined + }) + + it('defaults to false when the env var is unset', () => { + envState.NEXT_PUBLIC_MANAGED_AGENT_SELF_HOSTED_MEMORY_ENABLED = undefined + expect(isSelfHostedMemoryEnabled()).toBe(false) + }) + + it('is true only for truthy string forms', () => { + for (const on of ['1', 'true', 'True', 'YES', 'yes']) { + envState.NEXT_PUBLIC_MANAGED_AGENT_SELF_HOSTED_MEMORY_ENABLED = on + expect(isSelfHostedMemoryEnabled()).toBe(true) + } + }) + + it('is false for other strings', () => { + for (const off of ['0', 'false', 'no', 'off', 'random']) { + envState.NEXT_PUBLIC_MANAGED_AGENT_SELF_HOSTED_MEMORY_ENABLED = off + expect(isSelfHostedMemoryEnabled()).toBe(false) + } + }) + + it('trims surrounding whitespace before comparing', () => { + envState.NEXT_PUBLIC_MANAGED_AGENT_SELF_HOSTED_MEMORY_ENABLED = ' true ' + expect(isSelfHostedMemoryEnabled()).toBe(true) + }) +}) diff --git a/apps/sim/blocks/blocks/managed_agent_self_hosted.ts b/apps/sim/blocks/blocks/managed_agent_self_hosted.ts new file mode 100644 index 00000000000..bf51e39924e --- /dev/null +++ b/apps/sim/blocks/blocks/managed_agent_self_hosted.ts @@ -0,0 +1,243 @@ +import { ClaudeIcon } from '@/components/icons' +import { env } from '@/lib/core/config/env' +import { + fetchManagedAgentAgentOptions, + fetchManagedAgentConnectionOptions, + fetchManagedAgentMemoryStoreOptions, + fetchManagedAgentSelfHostedEnvironmentOptions, + fetchManagedAgentVaultOptions, +} from '@/lib/managed-agents/subblock-options' +import type { BlockConfig, BlockMeta, SubBlockConfig } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' + +/** + * Feature-flag gate for the memory-store + memory-access fields on the + * self-hosted variant. Off by default: Claude self-hosted environments + * do not currently support the memory-store resource attach on the + * session API. Deployers whose self-hosted agent sandbox has a custom + * memory-mount path can flip this on to expose the fields, and the + * key/value pair still ends up on the session's `metadata` for the + * sandbox to pick up. + */ +export function isSelfHostedMemoryEnabled(): boolean { + const raw = env.NEXT_PUBLIC_MANAGED_AGENT_SELF_HOSTED_MEMORY_ENABLED + if (typeof raw !== 'string') return false + const normalized = raw.trim().toLowerCase() + return normalized === '1' || normalized === 'true' || normalized === 'yes' +} + +const memorySubBlocks: SubBlockConfig[] = isSelfHostedMemoryEnabled() + ? [ + { + id: 'memoryStoreId', + title: 'Memory Store', + type: 'combobox', + required: false, + placeholder: 'Optional — pick a memory store or leave empty', + commandSearchable: true, + options: [], + dependsOn: ['connection'], + fetchOptions: fetchManagedAgentMemoryStoreOptions, + }, + { + id: 'memoryAccess', + title: 'Memory Access', + type: 'dropdown', + required: false, + options: [ + { label: 'Read + write (default)', id: 'read_write' }, + { label: 'Read only', id: 'read_only' }, + ], + value: () => 'read_write', + dependsOn: ['memoryStoreId'], + condition: { field: 'memoryStoreId', value: '', not: true }, + description: + 'read_write pushes changes back on session exit. read_only pulls only and never writes.', + }, + ] + : [] + +/** + * Claude Managed Agents block — self-hosted variant. + * + * Same session-create shape as the cloud block **without** the + * `resources` array. Session metadata (top-level `metadata` field) is + * exposed to the self-hosted agent sandbox as env vars, so this + * block's Session parameters table is where you set the keys your + * deployment reads. The set of supported keys is deployment-specific. + * + * The environment picker is filtered to `config.type === 'self_hosted'`. + * Icon renders black-on-white to visually differentiate from the cloud + * block's warm-orange tile. + */ +export const ManagedAgentSelfHostedBlock: BlockConfig = { + type: 'managed_agent_self_hosted', + name: 'Claude Managed Agents (self-hosted)', + description: 'Run a Claude Platform Managed Agent (self-hosted environments)', + authMode: AuthMode.ApiKey, + longDescription: + "Invoke a Claude Platform Managed Agent running in a self-hosted sandbox on your own infrastructure. Pick a linked Claude workspace, agent, and self-hosted environment. Attach vaults. Set metadata keys the self-hosted agent sandbox forwards to the container as env vars (keys are deployment-specific). The block returns the assistant's final text.", + category: 'tools', + integrationType: IntegrationType.AI, + docsLink: 'https://docs.sim.ai/integrations/managed-agent', + bgColor: '#000000', + icon: ClaudeIcon, + nodeWidth: 400, + subBlocks: [ + { + id: 'connection', + title: 'Claude Workspace', + type: 'combobox', + required: true, + placeholder: 'Select a linked Claude workspace…', + commandSearchable: true, + options: [], + fetchOptions: fetchManagedAgentConnectionOptions, + }, + { + id: 'environment', + title: 'Self-hosted Environment', + type: 'combobox', + required: true, + placeholder: 'Select a self-hosted environment…', + commandSearchable: true, + options: [], + dependsOn: ['connection'], + fetchOptions: fetchManagedAgentSelfHostedEnvironmentOptions, + }, + { + // Constant — self-hosted block only runs against self-hosted envs. + // The session-client uses this to build the metadata-shaped payload + // (no top-level `resources`, memory folded into metadata). + id: 'environmentType', + title: 'Environment Type', + type: 'short-input', + value: () => 'self_hosted', + hidden: true, + }, + { + id: 'vaults', + title: 'Credential vaults', + type: 'combobox', + required: false, + placeholder: 'Optional — pick zero or more OAuth vaults', + commandSearchable: true, + multiSelect: true, + options: [], + dependsOn: ['connection'], + fetchOptions: fetchManagedAgentVaultOptions, + }, + { + // Security ack — enforced at execution time when at least one vault + // is selected. See the sibling comment on `managed_agent_cloud.ts`. + id: 'vaultsAck', + title: + 'I own or am authorized to use these vaults. I understand this means this agent can assume the identity granted by them.', + type: 'switch', + required: false, + description: 'Required when at least one vault is selected above.', + }, + ...memorySubBlocks, + { + id: 'agent', + title: 'Agent', + type: 'combobox', + required: true, + placeholder: 'Select an agent from this workspace…', + commandSearchable: true, + options: [], + dependsOn: ['connection'], + fetchOptions: fetchManagedAgentAgentOptions, + }, + { + id: 'userMessage', + title: 'User message', + type: 'long-input', + required: true, + placeholder: 'Ask the Managed Agent to do something…', + }, + { + // Session metadata forwarded to the self-hosted agent sandbox as + // env vars. The set of supported keys is deployment-specific and + // lives with the deployer, not in this repo. + id: 'sessionParameters', + title: 'Session parameters', + type: 'table', + required: false, + columns: ['Key', 'Value'], + description: + 'Key/value pairs forwarded to the self-hosted agent sandbox as environment variables. Supported keys depend on your deployment — consult your deployment docs. Value cells support / references.', + }, + ], + tools: { + access: ['managed_agent_run_session'], + }, + inputs: { + connection: { type: 'string', description: 'Managed Agent connection id.' }, + agent: { type: 'string', description: 'Managed-agent id inside the linked Claude workspace.' }, + environment: { type: 'string', description: 'Self-hosted environment id.' }, + environmentType: { type: 'string', description: 'Always "self_hosted" for this block.' }, + vaults: { type: 'json', description: 'Vault ids for MCP auth (array of strings).' }, + vaultsAck: { + type: 'boolean', + description: + 'Workflow-author acknowledgement that they are authorized to use the attached vaults. Required when `vaults` is non-empty.', + }, + memoryStoreId: { + type: 'string', + description: + "Optional Agent Memory Store id. Only exposed when NEXT_PUBLIC_MANAGED_AGENT_SELF_HOSTED_MEMORY_ENABLED is truthy; forwarded on the session's `metadata` for the self-hosted agent sandbox to consume.", + }, + memoryAccess: { + type: 'string', + description: "Memory store access mode — 'read_write' (default) or 'read_only'.", + }, + sessionParameters: { + type: 'json', + description: + 'Session parameters (key/value) forwarded to the self-hosted agent sandbox as env vars.', + }, + userMessage: { type: 'string', description: 'The user message to send to the agent.' }, + }, + outputs: { + content: { type: 'string', description: "The Managed Agent's final assistant text." }, + sessionId: { + type: 'string', + description: 'Anthropic session id — logged so downstream steps can link to the run.', + }, + }, +} + +export const ManagedAgentSelfHostedBlockMeta = { + tags: ['agent', 'anthropic', 'claude', 'session', 'managed-agent', 'self-hosted'], + url: 'https://platform.claude.com/', + templates: [ + { + icon: ClaudeIcon, + title: 'Delegate a repo-scoped code review to a self-hosted Managed Agent', + prompt: + 'Build a workflow that receives a repo URL and ref, invokes a Claude Platform Managed Agent in a self-hosted environment with SOURCE_TYPE=git session parameters, and captures the review as a summary comment.', + modules: ['agent', 'workflows'], + category: 'engineering', + tags: ['automation', 'code-review'], + }, + { + icon: ClaudeIcon, + title: 'Trigger a scheduled analysis on a git-repo-mounted agent', + prompt: + "Create a scheduled workflow that opens a Managed Agent session against a self-hosted environment, mounts a repository via git-repo manifest session parameters (SOURCE_TYPE=repo), and stores the agent's analysis in a tables block.", + modules: ['scheduled', 'agent', 'tables', 'workflows'], + category: 'engineering', + tags: ['automation', 'analysis'], + }, + ], + skills: [ + { + name: 'run-self-hosted-managed-agent', + description: + 'Delegate a repo-scoped task to a self-hosted Managed Agent that mounts the repo via session parameters.', + content: + "# Run Self-Hosted Managed Agent\n\nWhen a Managed Agent needs to reason about deployment-specific context (e.g. a repo checkout), configure it via session parameters — the self-hosted agent sandbox reads each key/value pair as an env var.\n\n## Steps\n1. Pick a self-hosted environment.\n2. Set the session-parameter keys your deployment defines.\n3. Write the user message referring to whatever the session parameters set up.\n\n## Output\nThe block returns the agent's final text.", + }, + ], +} as const satisfies BlockMeta diff --git a/apps/sim/blocks/registry-maps.ts b/apps/sim/blocks/registry-maps.ts index 65a48b4c310..d855839c6c6 100644 --- a/apps/sim/blocks/registry-maps.ts +++ b/apps/sim/blocks/registry-maps.ts @@ -183,6 +183,14 @@ import { LoopsBlock, LoopsBlockMeta } from '@/blocks/blocks/loops' import { LumaBlock, LumaBlockMeta } from '@/blocks/blocks/luma' import { MailchimpBlock, MailchimpBlockMeta } from '@/blocks/blocks/mailchimp' import { MailgunBlock, MailgunBlockMeta } from '@/blocks/blocks/mailgun' +import { + ManagedAgentCloudBlock, + ManagedAgentCloudBlockMeta, +} from '@/blocks/blocks/managed_agent_cloud' +import { + ManagedAgentSelfHostedBlock, + ManagedAgentSelfHostedBlockMeta, +} from '@/blocks/blocks/managed_agent_self_hosted' import { ManualTriggerBlock } from '@/blocks/blocks/manual_trigger' import { McpBlock } from '@/blocks/blocks/mcp' import { Mem0Block, Mem0BlockMeta } from '@/blocks/blocks/mem0' @@ -510,6 +518,8 @@ export const BLOCK_REGISTRY: Record = { luma: LumaBlock, mailchimp: MailchimpBlock, mailgun: MailgunBlock, + managed_agent_cloud: ManagedAgentCloudBlock, + managed_agent_self_hosted: ManagedAgentSelfHostedBlock, manual_trigger: ManualTriggerBlock, mcp: McpBlock, mem0: Mem0Block, @@ -807,6 +817,8 @@ export const BLOCK_META_REGISTRY: Record = { luma: LumaBlockMeta, mailchimp: MailchimpBlockMeta, mailgun: MailgunBlockMeta, + managed_agent_cloud: ManagedAgentCloudBlockMeta, + managed_agent_self_hosted: ManagedAgentSelfHostedBlockMeta, mem0: Mem0BlockMeta, microsoft_ad: MicrosoftAdBlockMeta, microsoft_dataverse: MicrosoftDataverseBlockMeta, diff --git a/apps/sim/blocks/types.ts b/apps/sim/blocks/types.ts index 9024e44cb88..842654e94b0 100644 --- a/apps/sim/blocks/types.ts +++ b/apps/sim/blocks/types.ts @@ -500,6 +500,13 @@ export interface BlockConfig { enabled: boolean available: string[] // List of trigger IDs this block supports } + /** + * Override the canvas-node width (px) for this block. Defaults to + * `BLOCK_DIMENSIONS.FIXED_WIDTH` (250). Use only when the block's rows + * carry unavoidably long identifiers (e.g. Anthropic session ids) and a + * standard-width tile would truncate them into meaningless ellipses. + */ + nodeWidth?: number } interface OutputConfig { diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 9ac49e147a7..3c49c0a2dfc 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -3683,6 +3683,27 @@ export const AnthropicIcon = (props: SVGProps) => ( ) +/** + * Claude AI symbol — the orbital "burst" mark used on claude.com. Sourced + * from Wikimedia Commons (Claude_AI_symbol.svg, CC0 1.0 Public Domain + * Dedication). Rendered with `currentColor` so the block tile can drive + * contrast; `iconColor: '#DA7756'` on the block config keeps the Claude + * warm-orange even when rendered bare. + */ +export const ClaudeIcon = (props: SVGProps) => ( + + Claude + + +) + export function AzureIcon(props: SVGProps) { const id = useId() const gradient0 = `azure_paint0_${id}` diff --git a/apps/sim/components/settings/navigation.ts b/apps/sim/components/settings/navigation.ts index c03e332de9e..f40fc61ebdf 100644 --- a/apps/sim/components/settings/navigation.ts +++ b/apps/sim/components/settings/navigation.ts @@ -51,6 +51,7 @@ export type WorkspaceSettingsSection = | 'byok' | 'custom-tools' | 'mcp' + | 'managed-agents' | 'workflow-mcp-servers' | 'api-keys' | 'inbox' @@ -91,6 +92,7 @@ export type UnifiedSettingsSection = | 'forks' | 'mcp' | 'custom-tools' + | 'managed-agents' | 'workflow-mcp-servers' | 'inbox' | 'admin' @@ -432,6 +434,18 @@ export const SETTINGS_SECTION_REGISTRY: readonly SettingsSectionRegistryEntry[] workspace: { id: 'mcp', group: 'tools', order: 4 }, }, }, + { + label: 'Managed Agents', + icon: HexSimple, + unified: { + id: 'managed-agents', + description: 'Link Claude Platform workspaces and pick agents from workflows.', + group: 'tools', + }, + planes: { + workspace: { id: 'managed-agents', group: 'tools', order: 5 }, + }, + }, { label: 'Sim API keys', icon: TerminalWindow, @@ -464,7 +478,7 @@ export const SETTINGS_SECTION_REGISTRY: readonly SettingsSectionRegistryEntry[] group: 'system', }, planes: { - workspace: { id: 'workflow-mcp-servers', group: 'tools', order: 5 }, + workspace: { id: 'workflow-mcp-servers', group: 'tools', order: 6 }, }, }, { @@ -773,6 +787,7 @@ const WORKSPACE_MUTATION_PERMISSION: Record [...managedAgentConnectionsKeys.all, 'list'] as const, + list: (workspaceId: string) => + [...managedAgentConnectionsKeys.lists(), workspaceId] as const, + agents: (connectionId: string, workspaceId: string) => + [...managedAgentConnectionsKeys.all, 'agents', workspaceId, connectionId] as const, + environments: (connectionId: string, workspaceId: string) => + [ + ...managedAgentConnectionsKeys.all, + 'environments', + workspaceId, + connectionId, + ] as const, + vaults: (connectionId: string, workspaceId: string) => + [...managedAgentConnectionsKeys.all, 'vaults', workspaceId, connectionId] as const, + memoryStores: (connectionId: string, workspaceId: string) => + [ + ...managedAgentConnectionsKeys.all, + 'memory-stores', + workspaceId, + connectionId, + ] as const, +} + +async function fetchConnections( + workspaceId: string, + signal?: AbortSignal +): Promise { + const { data } = await requestJson(listManagedAgentConnectionsContract, { + query: { workspaceId }, + signal, + }) + return data +} + +export function useManagedAgentConnections(workspaceId: string) { + return useQuery({ + queryKey: managedAgentConnectionsKeys.list(workspaceId), + queryFn: ({ signal }) => fetchConnections(workspaceId, signal), + enabled: !!workspaceId, + staleTime: MANAGED_AGENT_CONNECTION_LIST_STALE_TIME, + placeholderData: keepPreviousData, + }) +} + +interface CreateConnectionParams { + workspaceId: string + name: string + apiKey: string +} + +export function useCreateManagedAgentConnection() { + const queryClient = useQueryClient() + return useMutation({ + mutationFn: async ({ workspaceId, name, apiKey }: CreateConnectionParams) => { + logger.info(`Creating managed-agent connection: ${name}`) + const { data } = await requestJson(createManagedAgentConnectionContract, { + body: { workspaceId, name, apiKey }, + }) + return data + }, + onSuccess: (_data, variables) => { + queryClient.invalidateQueries({ + queryKey: managedAgentConnectionsKeys.list(variables.workspaceId), + }) + }, + }) +} + +interface DeleteConnectionParams { + workspaceId: string + id: string +} + +export function useDeleteManagedAgentConnection() { + const queryClient = useQueryClient() + return useMutation({ + mutationFn: async ({ workspaceId, id }: DeleteConnectionParams) => { + logger.info(`Deleting managed-agent connection ${id}`) + const data = await requestJson(deleteManagedAgentConnectionContract, { + query: { id, workspaceId }, + }) + return data + }, + onSuccess: (_data, variables) => { + queryClient.invalidateQueries({ + queryKey: managedAgentConnectionsKeys.list(variables.workspaceId), + }) + }, + }) +} + +interface RotateKeyParams { + workspaceId: string + id: string + apiKey: string +} + +export function useRotateManagedAgentConnection() { + const queryClient = useQueryClient() + return useMutation({ + mutationFn: async ({ workspaceId, id, apiKey }: RotateKeyParams) => { + logger.info(`Rotating managed-agent connection ${id}`) + const { data } = await requestJson(rotateManagedAgentConnectionContract, { + params: { id }, + body: { workspaceId, apiKey }, + }) + return data + }, + onSuccess: (_data, variables) => { + queryClient.invalidateQueries({ + queryKey: managedAgentConnectionsKeys.list(variables.workspaceId), + }) + }, + }) +} + +async function fetchAgents( + connectionId: string, + workspaceId: string, + signal?: AbortSignal +): Promise { + const { data } = await requestJson(listManagedAgentAgentsContract, { + params: { id: connectionId }, + query: { workspaceId }, + signal, + }) + return data +} + +/** + * Loads agents from the linked Claude workspace tied to `connectionId`. + * Empty `connectionId` disables the query so the block editor doesn't + * fire a bad request while the user hasn't picked a connection yet. + */ +export function useManagedAgentAgents(connectionId: string | null, workspaceId: string) { + return useQuery({ + queryKey: managedAgentConnectionsKeys.agents(connectionId ?? '', workspaceId), + queryFn: ({ signal }) => fetchAgents(connectionId as string, workspaceId, signal), + enabled: !!connectionId && !!workspaceId, + staleTime: MANAGED_AGENT_RESOURCE_STALE_TIME, + }) +} + +async function fetchEnvironments( + connectionId: string, + workspaceId: string, + signal?: AbortSignal +): Promise { + const { data } = await requestJson(listManagedAgentEnvironmentsContract, { + params: { id: connectionId }, + query: { workspaceId }, + signal, + }) + return data +} + +export function useManagedAgentEnvironments( + connectionId: string | null, + workspaceId: string +) { + return useQuery({ + queryKey: managedAgentConnectionsKeys.environments(connectionId ?? '', workspaceId), + queryFn: ({ signal }) => fetchEnvironments(connectionId as string, workspaceId, signal), + enabled: !!connectionId && !!workspaceId, + staleTime: MANAGED_AGENT_RESOURCE_STALE_TIME, + }) +} + +async function fetchVaults( + connectionId: string, + workspaceId: string, + signal?: AbortSignal +): Promise { + const { data } = await requestJson(listManagedAgentVaultsContract, { + params: { id: connectionId }, + query: { workspaceId }, + signal, + }) + return data +} + +export function useManagedAgentVaults(connectionId: string | null, workspaceId: string) { + return useQuery({ + queryKey: managedAgentConnectionsKeys.vaults(connectionId ?? '', workspaceId), + queryFn: ({ signal }) => fetchVaults(connectionId as string, workspaceId, signal), + enabled: !!connectionId && !!workspaceId, + staleTime: MANAGED_AGENT_RESOURCE_STALE_TIME, + }) +} + +async function fetchMemoryStores( + connectionId: string, + workspaceId: string, + signal?: AbortSignal +): Promise { + const { data } = await requestJson(listManagedAgentMemoryStoresContract, { + params: { id: connectionId }, + query: { workspaceId }, + signal, + }) + return data +} + +export function useManagedAgentMemoryStores( + connectionId: string | null, + workspaceId: string +) { + return useQuery({ + queryKey: managedAgentConnectionsKeys.memoryStores(connectionId ?? '', workspaceId), + queryFn: ({ signal }) => fetchMemoryStores(connectionId as string, workspaceId, signal), + enabled: !!connectionId && !!workspaceId, + staleTime: MANAGED_AGENT_RESOURCE_STALE_TIME, + }) +} diff --git a/apps/sim/lib/api/contracts/index.ts b/apps/sim/lib/api/contracts/index.ts index ef339965c5b..7c16a0a9024 100644 --- a/apps/sim/lib/api/contracts/index.ts +++ b/apps/sim/lib/api/contracts/index.ts @@ -16,6 +16,7 @@ export * from './inbox' export * from './media' export * from './permission-groups' export * from './primitives' +export * from './managed-agent-connections' export * from './selectors' export * from './skills' export * from './storage-transfer' diff --git a/apps/sim/lib/api/contracts/managed-agent-connections.ts b/apps/sim/lib/api/contracts/managed-agent-connections.ts new file mode 100644 index 00000000000..d9f40ecbcd8 --- /dev/null +++ b/apps/sim/lib/api/contracts/managed-agent-connections.ts @@ -0,0 +1,206 @@ +import { z } from 'zod' +import { defineRouteContract } from '@/lib/api/contracts/types' + +export const managedAgentConnectionSchema = z.object({ + id: z.string(), + workspaceId: z.string(), + userId: z.string().nullable(), + name: z.string(), + /** First 8 chars + '…' + last 4. Never plaintext. */ + maskedApiKey: z.string(), + lastVerifiedAt: z.string().nullable(), + lastVerificationError: z.string().nullable(), + createdAt: z.string(), + updatedAt: z.string(), +}) + +export type ManagedAgentConnection = z.output + +export const listManagedAgentConnectionsQuerySchema = z.object({ + workspaceId: z.string().min(1), +}) + +export const createManagedAgentConnectionBodySchema = z.object({ + workspaceId: z.string().min(1), + name: z + .string() + .trim() + .min(1, 'Name is required') + .max(64, 'Name must be 64 characters or fewer'), + apiKey: z + .string() + .trim() + .min(1, 'API key is required') + .max(2048, 'API key looks too long — check for stray whitespace'), +}) + +export const deleteManagedAgentConnectionQuerySchema = z.object({ + id: z.string().min(1), + workspaceId: z.string().min(1), +}) + +export const rotateManagedAgentConnectionParamsSchema = z.object({ + id: z.string().min(1), +}) +export const rotateManagedAgentConnectionBodySchema = z.object({ + workspaceId: z.string().min(1), + apiKey: z.string().trim().min(1).max(2048), +}) + +export const managedAgentProxyParamsSchema = z.object({ + id: z.string().min(1), +}) +export const managedAgentProxyQuerySchema = z.object({ + workspaceId: z.string().min(1), +}) + +export const managedAgentAgentSchema = z.object({ + id: z.string(), + name: z.string().nullable().optional(), + description: z.string().nullable().optional(), + version: z.union([z.string(), z.number()]).nullable().optional(), +}) +export type ManagedAgentAgent = z.output + +export const managedAgentEnvironmentSchema = z.object({ + id: z.string(), + name: z.string().nullable().optional(), + description: z.string().nullable().optional(), + envType: z.enum(['cloud', 'self_hosted']), + scope: z.enum(['organization', 'account']).nullable().optional(), +}) +export type ManagedAgentEnvironment = z.output + +export const managedAgentVaultSchema = z.object({ + id: z.string(), + name: z.string().nullable().optional(), + description: z.string().nullable().optional(), +}) +export type ManagedAgentVault = z.output + +export const managedAgentMemoryStoreSchema = z.object({ + id: z.string(), + name: z.string().nullable().optional(), + description: z.string().nullable().optional(), + archivedAt: z.string().nullable().optional(), +}) +export type ManagedAgentMemoryStore = z.output + +export const managedAgentEnvironmentDetailParamsSchema = z.object({ + id: z.string().min(1), + envId: z.string().min(1), +}) + +export const listManagedAgentConnectionsContract = defineRouteContract({ + method: 'GET', + path: '/api/managed-agent-connections', + query: listManagedAgentConnectionsQuerySchema, + response: { + mode: 'json', + schema: z.object({ + data: z.array(managedAgentConnectionSchema), + }), + }, +}) + +export const createManagedAgentConnectionContract = defineRouteContract({ + method: 'POST', + path: '/api/managed-agent-connections', + body: createManagedAgentConnectionBodySchema, + response: { + mode: 'json', + schema: z.object({ + success: z.literal(true), + data: managedAgentConnectionSchema, + }), + }, +}) + +export const deleteManagedAgentConnectionContract = defineRouteContract({ + method: 'DELETE', + path: '/api/managed-agent-connections', + query: deleteManagedAgentConnectionQuerySchema, + response: { + mode: 'json', + schema: z.object({ success: z.literal(true) }), + }, +}) + +export const rotateManagedAgentConnectionContract = defineRouteContract({ + method: 'PATCH', + path: '/api/managed-agent-connections/[id]', + params: rotateManagedAgentConnectionParamsSchema, + body: rotateManagedAgentConnectionBodySchema, + response: { + mode: 'json', + schema: z.object({ + success: z.literal(true), + data: managedAgentConnectionSchema, + }), + }, +}) + +export const listManagedAgentAgentsContract = defineRouteContract({ + method: 'GET', + path: '/api/managed-agent-connections/[id]/agents', + params: managedAgentProxyParamsSchema, + query: managedAgentProxyQuerySchema, + response: { + mode: 'json', + schema: z.object({ + data: z.array(managedAgentAgentSchema), + }), + }, +}) + +export const listManagedAgentEnvironmentsContract = defineRouteContract({ + method: 'GET', + path: '/api/managed-agent-connections/[id]/environments', + params: managedAgentProxyParamsSchema, + query: managedAgentProxyQuerySchema, + response: { + mode: 'json', + schema: z.object({ + data: z.array(managedAgentEnvironmentSchema), + }), + }, +}) + +export const getManagedAgentEnvironmentContract = defineRouteContract({ + method: 'GET', + path: '/api/managed-agent-connections/[id]/environments/[envId]', + params: managedAgentEnvironmentDetailParamsSchema, + query: managedAgentProxyQuerySchema, + response: { + mode: 'json', + schema: z.object({ + data: managedAgentEnvironmentSchema, + }), + }, +}) + +export const listManagedAgentVaultsContract = defineRouteContract({ + method: 'GET', + path: '/api/managed-agent-connections/[id]/vaults', + params: managedAgentProxyParamsSchema, + query: managedAgentProxyQuerySchema, + response: { + mode: 'json', + schema: z.object({ + data: z.array(managedAgentVaultSchema), + }), + }, +}) + +export const listManagedAgentMemoryStoresContract = defineRouteContract({ + method: 'GET', + path: '/api/managed-agent-connections/[id]/memory-stores', + params: managedAgentProxyParamsSchema, + query: managedAgentProxyQuerySchema, + response: { + mode: 'json', + schema: z.object({ + data: z.array(managedAgentMemoryStoreSchema), + }), + }, +}) diff --git a/apps/sim/lib/core/config/env.ts b/apps/sim/lib/core/config/env.ts index c86eb9e7ff4..89b7b35b64c 100644 --- a/apps/sim/lib/core/config/env.ts +++ b/apps/sim/lib/core/config/env.ts @@ -148,6 +148,7 @@ export const env = createEnv({ OPENAI_API_KEY_2: z.string().min(1).optional(), // Additional OpenAI API key for load balancing OPENAI_API_KEY_3: z.string().min(1).optional(), // Additional OpenAI API key for load balancing MISTRAL_API_KEY: z.string().min(1).optional(), // Mistral AI API key + MANAGED_AGENT_DEBUG_PAYLOAD: z.string().optional(), // When "1" | "true" | "yes", the Managed Agent workflow-block tool logs the full session-create payload (never includes the api key) so you can inspect memory / vault / metadata routing ANTHROPIC_API_KEY_1: z.string().min(1).optional(), // Primary Anthropic Claude API key ANTHROPIC_API_KEY_2: z.string().min(1).optional(), // Additional Anthropic API key for load balancing ANTHROPIC_API_KEY_3: z.string().min(1).optional(), // Additional Anthropic API key for load balancing @@ -537,6 +538,7 @@ export const env = createEnv({ NEXT_PUBLIC_SUPPORT_EMAIL: z.string().email().optional(), // Custom support email NEXT_PUBLIC_E2B_ENABLED: z.string().optional(), + NEXT_PUBLIC_MANAGED_AGENT_SELF_HOSTED_MEMORY_ENABLED: z.string().optional(), // When "1"|"true"|"yes", reveal the Memory Store + Memory Access fields on the Claude Managed Agents (self-hosted) block. Off by default because Claude self-hosted environments do not currently support memory-store attach. NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS: z.string().optional(), // Hide Bedrock credential fields when deployment uses AWS default credential chain (IAM roles, instance profiles, ECS task roles, IRSA) NEXT_PUBLIC_AZURE_CONFIGURED: z.string().optional(), // Hide Azure credential fields when endpoint/key/version are pre-configured server-side NEXT_PUBLIC_COHERE_CONFIGURED: z.string().optional(), // Hide Cohere API key field on Knowledge block when COHERE_API_KEY is pre-configured server-side @@ -610,6 +612,7 @@ export const env = createEnv({ NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED: process.env.NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED, NEXT_PUBLIC_TURNSTILE_SITE_KEY: process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY, NEXT_PUBLIC_E2B_ENABLED: process.env.NEXT_PUBLIC_E2B_ENABLED, + NEXT_PUBLIC_MANAGED_AGENT_SELF_HOSTED_MEMORY_ENABLED: process.env.NEXT_PUBLIC_MANAGED_AGENT_SELF_HOSTED_MEMORY_ENABLED, NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS: process.env.NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS, NEXT_PUBLIC_AZURE_CONFIGURED: process.env.NEXT_PUBLIC_AZURE_CONFIGURED, NEXT_PUBLIC_COHERE_CONFIGURED: process.env.NEXT_PUBLIC_COHERE_CONFIGURED, diff --git a/apps/sim/lib/managed-agents/anthropic-verify.ts b/apps/sim/lib/managed-agents/anthropic-verify.ts new file mode 100644 index 00000000000..91fdba27c52 --- /dev/null +++ b/apps/sim/lib/managed-agents/anthropic-verify.ts @@ -0,0 +1,35 @@ +import { + ANTHROPIC_API_BASE, + ANTHROPIC_VERSION, + MANAGED_AGENTS_BETA, +} from '@/lib/managed-agents/session-client' + +/** + * Probes `GET /v1/agents` with the given key to prove the key is valid and + * scoped to a real Claude Platform workspace. On success we don't care about + * the response body — a 2xx is proof enough. On failure the body is trimmed + * to 200 chars and surfaced so the "Verify" button can render Anthropic's + * actual message. + */ +export async function verifyAnthropicApiKey( + apiKey: string, + signal?: AbortSignal +): Promise<{ ok: true } | { ok: false; error: string }> { + const resp = await fetch(`${ANTHROPIC_API_BASE}/v1/agents?limit=1`, { + method: 'GET', + headers: { + 'x-api-key': apiKey, + 'anthropic-version': ANTHROPIC_VERSION, + 'anthropic-beta': MANAGED_AGENTS_BETA, + }, + signal, + }) + if (resp.ok) return { ok: true } + const detail = await resp.text().catch(() => '') + const status = resp.status + const message = + status === 401 || status === 403 + ? 'Anthropic rejected the API key. Check that the key belongs to a Managed Agents-enabled workspace.' + : `Anthropic verify failed (HTTP ${status}). ${detail.slice(0, 200)}` + return { ok: false, error: message } +} diff --git a/apps/sim/lib/managed-agents/connections.test.ts b/apps/sim/lib/managed-agents/connections.test.ts new file mode 100644 index 00000000000..58414a7efd5 --- /dev/null +++ b/apps/sim/lib/managed-agents/connections.test.ts @@ -0,0 +1,377 @@ +/** + * @vitest-environment node + */ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const { dbState, mockEncryptSecret, mockDecryptSecret, mockGenerateShortId } = vi.hoisted( + () => ({ + dbState: { + selectResults: [] as any[][], + insertRows: [] as any[], + updateArgs: [] as any[], + deleteArgs: [] as any[], + whereCalls: [] as any[], + }, + // Opaque encryption mock: the ciphertext never contains the plaintext, + // so tests can assert that the raw key does not leak into the row. + mockEncryptSecret: vi.fn(async (value: string) => ({ + encrypted: Buffer.from(value).toString('base64'), + iv: 'iv', + })), + mockDecryptSecret: vi.fn(async (value: string) => ({ + decrypted: Buffer.from(value, 'base64').toString('utf8'), + })), + mockGenerateShortId: vi.fn(() => 'gen-id-123'), + }) +) + +function makeSelectChain() { + const chain: any = {} + chain.from = vi.fn(() => chain) + chain.where = vi.fn((...args: any[]) => { + dbState.whereCalls.push(args) + return chain + }) + chain.orderBy = vi.fn(() => Promise.resolve(dbState.selectResults.shift() ?? [])) + chain.limit = vi.fn(() => Promise.resolve(dbState.selectResults.shift() ?? [])) + return chain +} + +function makeInsertChain() { + const chain: any = {} + chain.values = vi.fn((row: any) => { + dbState.insertRows.push(row) + return Promise.resolve(undefined) + }) + return chain +} + +function makeUpdateChain() { + const chain: any = {} + const capture: any = {} + chain.set = vi.fn((row: any) => { + capture.set = row + return chain + }) + chain.where = vi.fn((...args: any[]) => { + capture.where = args + dbState.updateArgs.push(capture) + return Promise.resolve(undefined) + }) + return chain +} + +function makeDeleteChain() { + const chain: any = {} + const capture: any = {} + chain.where = vi.fn((...args: any[]) => { + capture.where = args + dbState.deleteArgs.push(capture) + return Promise.resolve(undefined) + }) + return chain +} + +vi.mock('@sim/db', () => ({ + db: { + select: vi.fn(() => makeSelectChain()), + insert: vi.fn(() => makeInsertChain()), + update: vi.fn(() => makeUpdateChain()), + delete: vi.fn(() => makeDeleteChain()), + }, +})) + +vi.mock('@sim/db/schema', () => ({ + managedAgentConnection: { + id: 'managed_agent_connection.id', + workspaceId: 'managed_agent_connection.workspaceId', + createdAt: 'managed_agent_connection.createdAt', + }, +})) + +vi.mock('drizzle-orm', () => ({ + and: vi.fn((...args: unknown[]) => ({ and: args })), + eq: vi.fn((a: unknown, b: unknown) => ({ eq: [a, b] })), +})) + +vi.mock('@/lib/core/security/encryption', () => ({ + encryptSecret: mockEncryptSecret, + decryptSecret: mockDecryptSecret, +})) + +vi.mock('@sim/utils/id', () => ({ + generateShortId: mockGenerateShortId, +})) + +import { + createConnection, + deleteConnection, + getDecryptedApiKey, + listConnections, + markVerificationResult, + rotateConnectionKey, +} from '@/lib/managed-agents/connections' + +const now = new Date('2026-07-19T00:00:00.000Z') +const PLAINTEXT_KEY = 'sk-ant-secret-key-1234567890abcdef' +const CIPHERTEXT_KEY = Buffer.from(PLAINTEXT_KEY).toString('base64') +const baseRow = { + id: 'conn_1', + workspaceId: 'ws_A', + userId: 'user_1', + name: 'prod', + encryptedApiKey: CIPHERTEXT_KEY, + lastVerifiedAt: now, + lastVerificationError: null, + createdAt: now, + updatedAt: now, +} + +describe('listConnections', () => { + beforeEach(() => { + vi.clearAllMocks() + dbState.selectResults = [] + dbState.insertRows = [] + dbState.updateArgs = [] + dbState.deleteArgs = [] + dbState.whereCalls = [] + }) + + it('returns a masked preview of each connection and never exposes the plaintext', async () => { + dbState.selectResults = [[baseRow]] + const results = await listConnections({ workspaceId: 'ws_A' }) + expect(results).toHaveLength(1) + expect(results[0]).not.toHaveProperty('encryptedApiKey') + // 8-char prefix + `…` + 4-char suffix. + expect(results[0].maskedApiKey).toBe('sk-ant-s…cdef') + }) + + it('falls back to a solid bullet mask when a row cannot be decrypted', async () => { + dbState.selectResults = [[baseRow]] + mockDecryptSecret.mockRejectedValueOnce(new Error('bad tag')) + const results = await listConnections({ workspaceId: 'ws_A' }) + expect(results[0].maskedApiKey).toBe('••••••••') + }) + + it('scopes the query to the requested workspaceId', async () => { + dbState.selectResults = [[]] + await listConnections({ workspaceId: 'ws_A' }) + expect(dbState.whereCalls).toHaveLength(1) + // The where argument must reference the workspaceId column and value. + expect(JSON.stringify(dbState.whereCalls[0])).toContain('ws_A') + }) +}) + +describe('getDecryptedApiKey', () => { + beforeEach(() => { + vi.clearAllMocks() + dbState.selectResults = [] + dbState.whereCalls = [] + }) + + it('returns {ok:true, apiKey} when the connection exists', async () => { + dbState.selectResults = [[baseRow]] + const result = await getDecryptedApiKey({ id: 'conn_1', workspaceId: 'ws_A' }) + expect(result).toEqual({ ok: true, apiKey: PLAINTEXT_KEY }) + // The DB lookup must include BOTH id and workspaceId (no cross-workspace read). + expect(JSON.stringify(dbState.whereCalls[0])).toContain('conn_1') + expect(JSON.stringify(dbState.whereCalls[0])).toContain('ws_A') + }) + + it('returns {ok:false, reason:"not_found"} when the connection does not exist', async () => { + dbState.selectResults = [[]] + const result = await getDecryptedApiKey({ id: 'conn_1', workspaceId: 'ws_A' }) + expect(result).toEqual({ ok: false, reason: 'not_found' }) + }) + + it('returns {ok:false, reason:"decrypt_failed"} when the ciphertext cannot be decrypted', async () => { + // Simulates the post-ENCRYPTION_KEY-rotation case: row exists but the + // stored blob no longer decrypts. Callers must render this as an + // actionable 502 rather than a 500. + dbState.selectResults = [[baseRow]] + mockDecryptSecret.mockRejectedValueOnce(new Error('bad auth tag')) + const result = await getDecryptedApiKey({ id: 'conn_1', workspaceId: 'ws_A' }) + expect(result).toEqual({ ok: false, reason: 'decrypt_failed' }) + }) +}) + +describe('createConnection', () => { + beforeEach(() => { + vi.clearAllMocks() + dbState.selectResults = [] + dbState.insertRows = [] + dbState.whereCalls = [] + mockGenerateShortId.mockReturnValue('gen-id-123') + }) + + it('encrypts the api key before persisting and never writes plaintext', async () => { + const plaintext = 'sk-ant-plaintext-secret-9999' + const expectedCiphertext = Buffer.from(plaintext).toString('base64') + dbState.selectResults = [[{ ...baseRow, id: 'gen-id-123' }]] // getConnection after insert + await createConnection({ + workspaceId: 'ws_A', + userId: 'user_1', + name: 'prod', + apiKey: plaintext, + }) + expect(mockEncryptSecret).toHaveBeenCalledWith(plaintext) + const inserted = dbState.insertRows[0] + expect(inserted.encryptedApiKey).toBe(expectedCiphertext) + // The raw key MUST NOT appear anywhere in the persisted row. + expect(JSON.stringify(inserted)).not.toContain(plaintext) + }) + + it('persists the connection under the provided workspaceId', async () => { + dbState.selectResults = [[{ ...baseRow, id: 'gen-id-123', workspaceId: 'ws_A' }]] + await createConnection({ + workspaceId: 'ws_A', + userId: 'user_1', + name: 'prod', + apiKey: 'sk-ant-plaintext', + }) + expect(dbState.insertRows[0].workspaceId).toBe('ws_A') + }) + + it('runs `verify` before writing and aborts on failure', async () => { + const verify = vi + .fn() + .mockResolvedValueOnce({ ok: false, error: 'Anthropic rejected the key' }) + await expect( + createConnection({ + workspaceId: 'ws_A', + userId: 'user_1', + name: 'prod', + apiKey: 'sk-ant-bad', + verify, + }) + ).rejects.toThrow('Anthropic rejected the key') + expect(dbState.insertRows).toHaveLength(0) + expect(mockEncryptSecret).not.toHaveBeenCalled() + }) + + it('sets lastVerifiedAt when verify passes, null otherwise', async () => { + dbState.selectResults = [[{ ...baseRow, id: 'gen-id-123' }]] + await createConnection({ + workspaceId: 'ws_A', + userId: 'user_1', + name: 'prod', + apiKey: 'sk-ant-plaintext', + verify: async () => ({ ok: true }), + }) + expect(dbState.insertRows[0].lastVerifiedAt).toBeInstanceOf(Date) + + dbState.selectResults = [[{ ...baseRow, id: 'gen-id-123' }]] + dbState.insertRows.length = 0 + await createConnection({ + workspaceId: 'ws_A', + userId: 'user_1', + name: 'prod', + apiKey: 'sk-ant-plaintext', + }) + expect(dbState.insertRows[0].lastVerifiedAt).toBeNull() + }) +}) + +describe('deleteConnection', () => { + beforeEach(() => { + vi.clearAllMocks() + dbState.selectResults = [] + dbState.deleteArgs = [] + }) + + it('returns false when the connection is not found', async () => { + dbState.selectResults = [[]] + const ok = await deleteConnection({ id: 'conn_missing', workspaceId: 'ws_A' }) + expect(ok).toBe(false) + expect(dbState.deleteArgs).toHaveLength(0) + }) + + it('returns true and issues a workspace-scoped delete when found', async () => { + dbState.selectResults = [[baseRow]] + const ok = await deleteConnection({ id: 'conn_1', workspaceId: 'ws_A' }) + expect(ok).toBe(true) + expect(dbState.deleteArgs).toHaveLength(1) + expect(JSON.stringify(dbState.deleteArgs[0].where)).toContain('conn_1') + expect(JSON.stringify(dbState.deleteArgs[0].where)).toContain('ws_A') + }) +}) + +describe('rotateConnectionKey', () => { + beforeEach(() => { + vi.clearAllMocks() + dbState.selectResults = [] + dbState.updateArgs = [] + }) + + it('returns null when the connection does not exist for that workspace', async () => { + dbState.selectResults = [[]] // getConnection returns empty + const result = await rotateConnectionKey({ + id: 'conn_missing', + workspaceId: 'ws_A', + apiKey: 'sk-ant-new', + }) + expect(result).toBeNull() + expect(dbState.updateArgs).toHaveLength(0) + }) + + it('encrypts the new key and updates the row workspace-scoped', async () => { + // Two select results: getConnection before update, getConnection after. + dbState.selectResults = [[baseRow], [baseRow]] + await rotateConnectionKey({ + id: 'conn_1', + workspaceId: 'ws_A', + apiKey: 'sk-ant-new', + }) + expect(mockEncryptSecret).toHaveBeenCalledWith('sk-ant-new') + expect(dbState.updateArgs).toHaveLength(1) + expect(dbState.updateArgs[0].set.encryptedApiKey).toBe( + Buffer.from('sk-ant-new').toString('base64') + ) + expect(JSON.stringify(dbState.updateArgs[0].where)).toContain('conn_1') + expect(JSON.stringify(dbState.updateArgs[0].where)).toContain('ws_A') + }) + + it('rejects when verify fails and never touches the row', async () => { + dbState.selectResults = [[baseRow]] + await expect( + rotateConnectionKey({ + id: 'conn_1', + workspaceId: 'ws_A', + apiKey: 'sk-ant-bad', + verify: async () => ({ ok: false, error: 'nope' }), + }) + ).rejects.toThrow('nope') + expect(dbState.updateArgs).toHaveLength(0) + expect(mockEncryptSecret).not.toHaveBeenCalled() + }) +}) + +describe('markVerificationResult', () => { + beforeEach(() => { + vi.clearAllMocks() + dbState.updateArgs = [] + }) + + it('records success as lastVerifiedAt=now, error=null', async () => { + await markVerificationResult({ id: 'conn_1', workspaceId: 'ws_A', ok: true }) + expect(dbState.updateArgs[0].set.lastVerifiedAt).toBeInstanceOf(Date) + expect(dbState.updateArgs[0].set.lastVerificationError).toBeNull() + }) + + it('records failure as lastVerifiedAt=null with a bounded error string', async () => { + const bigError = 'e'.repeat(1000) + await markVerificationResult({ + id: 'conn_1', + workspaceId: 'ws_A', + ok: false, + error: bigError, + }) + expect(dbState.updateArgs[0].set.lastVerifiedAt).toBeNull() + expect(dbState.updateArgs[0].set.lastVerificationError).toHaveLength(500) + }) + + it('scopes the update to the workspaceId', async () => { + await markVerificationResult({ id: 'conn_1', workspaceId: 'ws_A', ok: true }) + expect(JSON.stringify(dbState.updateArgs[0].where)).toContain('ws_A') + }) +}) diff --git a/apps/sim/lib/managed-agents/connections.ts b/apps/sim/lib/managed-agents/connections.ts new file mode 100644 index 00000000000..610f6cefab5 --- /dev/null +++ b/apps/sim/lib/managed-agents/connections.ts @@ -0,0 +1,238 @@ +import { db } from '@sim/db' +import { managedAgentConnection } from '@sim/db/schema' +import { createLogger } from '@sim/logger' +import { generateShortId } from '@sim/utils/id' +import { and, eq } from 'drizzle-orm' +import { decryptSecret, encryptSecret } from '@/lib/core/security/encryption' + +const logger = createLogger('ManagedAgentConnections') + +/** + * Row shape returned by list/get. `encryptedApiKey` is intentionally + * dropped and replaced with `maskedApiKey` — nothing on the wire ever + * carries the plaintext. + */ +export interface ManagedAgentConnectionSummary { + id: string + workspaceId: string + userId: string | null + name: string + maskedApiKey: string + lastVerifiedAt: Date | null + lastVerificationError: string | null + createdAt: Date + updatedAt: Date +} + +function toSummary( + row: typeof managedAgentConnection.$inferSelect, + apiKey: string | null +): ManagedAgentConnectionSummary { + return { + id: row.id, + workspaceId: row.workspaceId, + userId: row.userId, + name: row.name, + maskedApiKey: apiKey ? maskApiKey(apiKey) : '••••••••', + lastVerifiedAt: row.lastVerifiedAt, + lastVerificationError: row.lastVerificationError, + createdAt: row.createdAt, + updatedAt: row.updatedAt, + } +} + +function maskApiKey(apiKey: string): string { + if (apiKey.length <= 12) return '••••••••' + return `${apiKey.slice(0, 8)}…${apiKey.slice(-4)}` +} + +export async function listConnections(params: { + workspaceId: string +}): Promise { + const rows = await db + .select() + .from(managedAgentConnection) + .where(eq(managedAgentConnection.workspaceId, params.workspaceId)) + .orderBy(managedAgentConnection.createdAt) + // Decrypt only to compute the mask preview; failures fall back to a + // solid bullet string so a corrupt row can't take down the list. + const summaries: ManagedAgentConnectionSummary[] = [] + for (const row of rows) { + let apiKey: string | null = null + try { + apiKey = (await decryptSecret(row.encryptedApiKey)).decrypted + } catch (err) { + logger.warn(`Failed to decrypt api key for connection ${row.id}`, { error: err }) + } + summaries.push(toSummary(row, apiKey)) + } + return summaries +} + +export async function getConnection(params: { + id: string + workspaceId: string +}): Promise { + const rows = await db + .select() + .from(managedAgentConnection) + .where( + and( + eq(managedAgentConnection.id, params.id), + eq(managedAgentConnection.workspaceId, params.workspaceId) + ) + ) + .limit(1) + return rows[0] ?? null +} + +/** + * Result of {@link getDecryptedApiKey}. Callers must distinguish the two + * failure modes so they can surface the right message: + * - `not_found`: the row does not exist for this workspace — 404. + * - `decrypt_failed`: the row exists but its ciphertext cannot be + * decoded (typically after an `ENCRYPTION_KEY` rotation) — a + * controlled 502 with a "rotate the API key to re-encrypt" hint. + */ +export type DecryptedApiKeyResult = + | { ok: true; apiKey: string } + | { ok: false; reason: 'not_found' | 'decrypt_failed' } + +/** + * Decrypts the stored API key for a given connection. Server-side only — + * never expose the return value to the browser. Callers are proxy routes + * and the workflow-block tool. Returns a discriminated result rather + * than throwing so callers can respond with an actionable status code + * (404 vs 502) instead of leaking an unhandled 500. + */ +export async function getDecryptedApiKey(params: { + id: string + workspaceId: string +}): Promise { + const row = await getConnection(params) + if (!row) return { ok: false, reason: 'not_found' } + try { + const { decrypted } = await decryptSecret(row.encryptedApiKey) + return { ok: true, apiKey: decrypted } + } catch (err) { + logger.warn(`Failed to decrypt api key for connection ${params.id}`, { error: err }) + return { ok: false, reason: 'decrypt_failed' } + } +} + +export interface CreateConnectionInput { + workspaceId: string + userId: string + name: string + apiKey: string + /** + * Optional callback invoked with the decrypted key so the caller can + * verify it against `GET /v1/agents` before we commit the row. Return + * `{ ok: true }` to persist, `{ ok: false, error }` to reject. + */ + verify?: (apiKey: string) => Promise<{ ok: true } | { ok: false; error: string }> +} + +export async function createConnection( + input: CreateConnectionInput +): Promise { + if (input.verify) { + const outcome = await input.verify(input.apiKey) + if (!outcome.ok) { + throw new Error(outcome.error) + } + } + const now = new Date() + const { encrypted } = await encryptSecret(input.apiKey) + const id = generateShortId() + await db.insert(managedAgentConnection).values({ + id, + workspaceId: input.workspaceId, + userId: input.userId, + name: input.name, + encryptedApiKey: encrypted, + lastVerifiedAt: input.verify ? now : null, + lastVerificationError: null, + createdAt: now, + updatedAt: now, + }) + const created = await getConnection({ id, workspaceId: input.workspaceId }) + if (!created) throw new Error('Failed to load newly created managed-agent connection') + return toSummary(created, input.apiKey) +} + +export async function deleteConnection(params: { + id: string + workspaceId: string +}): Promise { + const existing = await getConnection(params) + if (!existing) return false + await db + .delete(managedAgentConnection) + .where( + and( + eq(managedAgentConnection.id, params.id), + eq(managedAgentConnection.workspaceId, params.workspaceId) + ) + ) + return true +} + +export interface RotateKeyInput { + id: string + workspaceId: string + apiKey: string + verify?: (apiKey: string) => Promise<{ ok: true } | { ok: false; error: string }> +} + +export async function rotateConnectionKey( + input: RotateKeyInput +): Promise { + const existing = await getConnection({ id: input.id, workspaceId: input.workspaceId }) + if (!existing) return null + if (input.verify) { + const outcome = await input.verify(input.apiKey) + if (!outcome.ok) throw new Error(outcome.error) + } + const { encrypted } = await encryptSecret(input.apiKey) + const now = new Date() + await db + .update(managedAgentConnection) + .set({ + encryptedApiKey: encrypted, + lastVerifiedAt: input.verify ? now : existing.lastVerifiedAt, + lastVerificationError: null, + updatedAt: now, + }) + .where( + and( + eq(managedAgentConnection.id, input.id), + eq(managedAgentConnection.workspaceId, input.workspaceId) + ) + ) + const refreshed = await getConnection({ id: input.id, workspaceId: input.workspaceId }) + if (!refreshed) return null + return toSummary(refreshed, input.apiKey) +} + +export async function markVerificationResult(params: { + id: string + workspaceId: string + ok: boolean + error?: string +}): Promise { + const now = new Date() + await db + .update(managedAgentConnection) + .set({ + lastVerifiedAt: params.ok ? now : null, + lastVerificationError: params.ok ? null : (params.error ?? 'Unknown error').slice(0, 500), + updatedAt: now, + }) + .where( + and( + eq(managedAgentConnection.id, params.id), + eq(managedAgentConnection.workspaceId, params.workspaceId) + ) + ) +} diff --git a/apps/sim/lib/managed-agents/proxy.ts b/apps/sim/lib/managed-agents/proxy.ts new file mode 100644 index 00000000000..005400d9e8c --- /dev/null +++ b/apps/sim/lib/managed-agents/proxy.ts @@ -0,0 +1,83 @@ +import { createLogger } from '@sim/logger' +import { NextResponse } from 'next/server' +import type { DecryptedApiKeyResult } from '@/lib/managed-agents/connections' +import { + ANTHROPIC_API_BASE, + ANTHROPIC_VERSION, + MANAGED_AGENTS_BETA, +} from '@/lib/managed-agents/session-client' + +const logger = createLogger('ManagedAgentProxy') + +/** + * Server-side proxy helper for the block-editor dropdowns + * (`GET /v1/agents`, `/v1/environments`, `/v1/environments/{id}`, + * `/v1/vaults`). Decrypted keys never touch the browser — the client + * always calls the workspace-scoped proxy route, which in turn calls + * Anthropic with the stored key. + */ +export async function proxyManagedAgentsGet( + apiKey: string, + pathAndQuery: string, + signal?: AbortSignal +): Promise { + const url = `${ANTHROPIC_API_BASE}${pathAndQuery}` + const resp = await fetch(url, { + method: 'GET', + headers: { + 'x-api-key': apiKey, + 'anthropic-version': ANTHROPIC_VERSION, + 'anthropic-beta': MANAGED_AGENTS_BETA, + }, + signal, + }) + if (!resp.ok) { + const detail = await resp.text().catch(() => '') + logger.warn('managed-agents proxy call failed', { + pathAndQuery, + status: resp.status, + detail: detail.slice(0, 200), + }) + throw new ManagedAgentProxyError(resp.status, detail.slice(0, 400)) + } + return (await resp.json()) as T +} + +export class ManagedAgentProxyError extends Error { + readonly status: number + readonly detail: string + constructor(status: number, detail: string) { + super(`Anthropic proxy call failed (HTTP ${status}): ${detail}`) + this.name = 'ManagedAgentProxyError' + this.status = status + this.detail = detail + } +} + +/** Normalise Anthropic's `data: []` + `has_more` list pages into a flat array. */ +export interface AnthropicListPage { + data?: T[] + has_more?: boolean + last_id?: string +} + +/** + * Map a {@link DecryptedApiKeyResult} failure to the correct HTTP + * response for a proxy route. Keeps the "not_found → 404" and + * "decrypt_failed → 502 + actionable message" mapping in one place so + * every proxy route surfaces the same UX for the same failure mode. + */ +export function apiKeyFailureResponse( + failure: Extract +): NextResponse { + if (failure.reason === 'decrypt_failed') { + return NextResponse.json( + { + error: + 'Managed Agent connection could not be decrypted — the workspace encryption key may have rotated. Rotate the API key in Settings → Managed Agents to re-encrypt.', + }, + { status: 502 } + ) + } + return NextResponse.json({ error: 'Connection not found' }, { status: 404 }) +} diff --git a/apps/sim/lib/managed-agents/session-client.test.ts b/apps/sim/lib/managed-agents/session-client.test.ts new file mode 100644 index 00000000000..960b82c624a --- /dev/null +++ b/apps/sim/lib/managed-agents/session-client.test.ts @@ -0,0 +1,201 @@ +/** + * @vitest-environment node + */ +import { describe, expect, it } from 'vitest' +import { buildSessionCreatePayload } from '@/lib/managed-agents/session-client' + +const BASE = { + apiKey: 'sk-ant-fake', + agentId: 'agent_01ABC', + environmentId: 'env_01XYZ', +} as const + +describe('buildSessionCreatePayload — always-on fields', () => { + it('emits `agent` and `environment_id` from the input', () => { + const payload = buildSessionCreatePayload({ ...BASE }) + expect(payload).toEqual({ agent: 'agent_01ABC', environment_id: 'env_01XYZ' }) + }) + + it('emits `title` when set', () => { + const payload = buildSessionCreatePayload({ ...BASE, title: 'my session' }) + expect(payload.title).toBe('my session') + }) + + it('emits `vault_ids` only when non-empty', () => { + const withNone = buildSessionCreatePayload({ ...BASE }) + expect(withNone.vault_ids).toBeUndefined() + + const withEmptyArray = buildSessionCreatePayload({ ...BASE, vaultIds: [] }) + expect(withEmptyArray.vault_ids).toBeUndefined() + + const withVaults = buildSessionCreatePayload({ + ...BASE, + vaultIds: ['vlt_1', 'vlt_2'], + }) + expect(withVaults.vault_ids).toEqual(['vlt_1', 'vlt_2']) + }) +}) + +describe('buildSessionCreatePayload — cloud env', () => { + it('attaches memory store as a `memory_store` resource with default access', () => { + const payload = buildSessionCreatePayload({ + ...BASE, + envType: 'cloud', + memoryStoreId: 'memstore_01', + }) + expect(payload.resources).toEqual([ + { type: 'memory_store', memory_store_id: 'memstore_01', access: 'read_write' }, + ]) + // Cloud must NOT fold memory into metadata. + expect(payload.metadata).toBeUndefined() + }) + + it('honors explicit read_only memory access', () => { + const payload = buildSessionCreatePayload({ + ...BASE, + envType: 'cloud', + memoryStoreId: 'memstore_01', + memoryAccess: 'read_only', + }) + expect(payload.resources).toEqual([ + { type: 'memory_store', memory_store_id: 'memstore_01', access: 'read_only' }, + ]) + }) + + it('attaches file resources with an optional mount_path', () => { + const payload = buildSessionCreatePayload({ + ...BASE, + envType: 'cloud', + files: [ + { fileId: 'file_1', mountPath: '/data/one' }, + { fileId: 'file_2' }, + ], + }) + expect(payload.resources).toEqual([ + { type: 'file', file_id: 'file_1', mount_path: '/data/one' }, + { type: 'file', file_id: 'file_2' }, + ]) + }) + + it('drops file entries missing a fileId', () => { + const payload = buildSessionCreatePayload({ + ...BASE, + envType: 'cloud', + files: [{ fileId: '' }, { fileId: 'file_ok' }], + }) + expect(payload.resources).toEqual([{ type: 'file', file_id: 'file_ok' }]) + }) + + it('emits `metadata` from sessionParameters as opaque tags', () => { + const payload = buildSessionCreatePayload({ + ...BASE, + envType: 'cloud', + sessionParameters: { foo: 'bar', baz: 'qux' }, + }) + expect(payload.metadata).toEqual({ foo: 'bar', baz: 'qux' }) + expect(payload.resources).toBeUndefined() + }) + + it('emits neither resources nor metadata when the caller supplies nothing', () => { + const payload = buildSessionCreatePayload({ ...BASE, envType: 'cloud' }) + expect(payload.resources).toBeUndefined() + expect(payload.metadata).toBeUndefined() + }) + + it('emits both resources[] and metadata when both are set', () => { + const payload = buildSessionCreatePayload({ + ...BASE, + envType: 'cloud', + memoryStoreId: 'memstore_01', + files: [{ fileId: 'file_1' }], + sessionParameters: { env: 'staging' }, + }) + expect(payload.resources).toEqual([ + { type: 'memory_store', memory_store_id: 'memstore_01', access: 'read_write' }, + { type: 'file', file_id: 'file_1' }, + ]) + expect(payload.metadata).toEqual({ env: 'staging' }) + }) +}) + +describe('buildSessionCreatePayload — self-hosted env', () => { + it('folds memory into metadata (never onto resources)', () => { + const payload = buildSessionCreatePayload({ + ...BASE, + envType: 'self_hosted', + memoryStoreId: 'memstore_01', + }) + expect(payload.resources).toBeUndefined() + expect(payload.metadata).toEqual({ + memory_store_ids: 'memstore_01', + memory_access: 'read_write', + }) + }) + + it('honors explicit read_only memory access when folded into metadata', () => { + const payload = buildSessionCreatePayload({ + ...BASE, + envType: 'self_hosted', + memoryStoreId: 'memstore_01', + memoryAccess: 'read_only', + }) + expect(payload.metadata).toEqual({ + memory_store_ids: 'memstore_01', + memory_access: 'read_only', + }) + }) + + it('merges user-supplied sessionParameters with memory metadata', () => { + const payload = buildSessionCreatePayload({ + ...BASE, + envType: 'self_hosted', + memoryStoreId: 'memstore_01', + sessionParameters: { SOURCE_URL: 'https://example/repo.git' }, + }) + expect(payload.metadata).toEqual({ + SOURCE_URL: 'https://example/repo.git', + memory_store_ids: 'memstore_01', + memory_access: 'read_write', + }) + }) + + it('does not overwrite a user-supplied memory_store_ids key', () => { + const payload = buildSessionCreatePayload({ + ...BASE, + envType: 'self_hosted', + memoryStoreId: 'memstore_A', + sessionParameters: { memory_store_ids: 'memstore_B' }, + }) + expect(payload.metadata).toEqual({ memory_store_ids: 'memstore_B' }) + }) + + it('never emits `resources` — even when files are supplied', () => { + const payload = buildSessionCreatePayload({ + ...BASE, + envType: 'self_hosted', + memoryStoreId: 'memstore_01', + files: [{ fileId: 'file_1', mountPath: '/dropped' }], + sessionParameters: { A: '1' }, + }) + expect(payload.resources).toBeUndefined() + }) + + it('omits metadata when nothing memory- or param-related is set', () => { + const payload = buildSessionCreatePayload({ ...BASE, envType: 'self_hosted' }) + expect(payload.metadata).toBeUndefined() + expect(payload.resources).toBeUndefined() + }) +}) + +describe('buildSessionCreatePayload — envType default (no route branch)', () => { + it('defaults to the cloud shape when envType is omitted', () => { + const payload = buildSessionCreatePayload({ + ...BASE, + memoryStoreId: 'memstore_01', + }) + expect(payload.resources).toEqual([ + { type: 'memory_store', memory_store_id: 'memstore_01', access: 'read_write' }, + ]) + expect(payload.metadata).toBeUndefined() + }) +}) diff --git a/apps/sim/lib/managed-agents/session-client.ts b/apps/sim/lib/managed-agents/session-client.ts new file mode 100644 index 00000000000..27accd2ba9a --- /dev/null +++ b/apps/sim/lib/managed-agents/session-client.ts @@ -0,0 +1,303 @@ +/** + * Provider-neutral HTTP client for the Claude Platform Managed Agents API. + * + * Two consumers today: + * 1. `apps/sim/lib/copilot/request/lifecycle/managed-agent-leg.ts` — the copilot + * home-chat integration; layers mothership-envelope translation, Sim tool + * dispatch, and Redis buffering on top of these primitives. + * 2. `apps/sim/tools/managed_agent/run_session.ts` (workflow-block tool) — calls + * these primitives directly and returns the accumulated assistant text as + * the block output. No envelope translation, no Sim-side tool dispatch. + * + * This module intentionally has NO Sim-domain dependencies (no `@sim/db`, no + * copilot buffer, no mothership stream types). It's a thin wrapper around + * `fetch` that speaks the Managed Agents beta. + */ + +import type { + AnthropicAgentCustomToolUseEvent, + AnthropicSessionEvent, +} from '@/lib/copilot/request/lifecycle/event-translator' + +export const ANTHROPIC_API_BASE = 'https://api.anthropic.com' +export const ANTHROPIC_VERSION = '2023-06-01' +export const MANAGED_AGENTS_BETA = 'managed-agents-2026-04-01' + +/** Environment `config.type` per `GET /v1/environments/{id}`. */ +export type ManagedAgentEnvType = 'cloud' | 'self_hosted' + +/** + * Shared inputs on every managed-agents call. `apiKey` is the caller's + * Claude Platform API key (an Anthropic workspace-scoped key); `signal` + * propagates cancellation into the outbound fetch. + */ +export interface SessionAuth { + apiKey: string + signal?: AbortSignal +} + +export interface CreateSessionInput extends SessionAuth { + agentId: string + environmentId: string + /** Optional session title stored on the Anthropic session. */ + title?: string + /** + * OAuth credential vaults the agent's MCP tools can reference. See + * https://platform.claude.com/docs/en/managed-agents/vaults. + */ + vaultIds?: string[] + /** + * Memory-store id (`memstore_...`). Routing depends on `envType`: + * - `cloud`: attached as a `memory_store` session resource + * (`resources: [{ type: 'memory_store', memory_store_id, access }]`). + * - `self_hosted`: forwarded via `metadata.memory_store_ids` so the + * self-hosted agent sandbox can expose it as an env var and + * mount the store on its side. + */ + memoryStoreId?: string + /** + * Access mode on the attached memory store — `read_write` (default) + * pushes changes back on session exit; `read_only` never writes. + * Cloud path: encoded on the resource entry. Self-hosted path: + * forwarded as `metadata.memory_access`. Ignored when `memoryStoreId` + * is unset. + */ + memoryAccess?: 'read_write' | 'read_only' + /** + * File attachments (cloud envs only — the Managed Agents `resources` + * array accepts entries of type `file`). Each mounts a Files-API + * file into the session container. `mountPath` is optional; Anthropic + * picks a default when omitted. Ignored for self-hosted envs. + */ + files?: Array<{ fileId: string; mountPath?: string }> + /** + * Arbitrary session metadata. Wire name: `metadata` (top-level on + * `POST /v1/sessions`). On self-hosted envs the self-hosted agent + * sandbox forwards each key to an env var; on cloud envs the keys + * are stored as opaque tags — safe to send from either block. + */ + sessionParameters?: Record + /** `cloud` or `self_hosted`. Routes memory + resources correctly. */ + envType?: ManagedAgentEnvType +} + +export interface CreateSessionResult { + id: string +} + +/** + * POST /v1/sessions — provisions a session sandbox. Does NOT start work; a + * subsequent `sendUserMessage` (or `sendSessionEvents`) is what causes the + * agent to run. This mirrors the docs' two-step lifecycle: + * https://platform.claude.com/docs/en/managed-agents/sessions#creating-a-session + */ +export async function createSession(input: CreateSessionInput): Promise { + const payload = buildSessionCreatePayload(input) + const resp = await fetch(`${ANTHROPIC_API_BASE}/v1/sessions`, { + method: 'POST', + headers: managedAgentsHeaders(input.apiKey, { json: true }), + body: JSON.stringify(payload), + signal: input.signal, + }) + if (!resp.ok) { + const detail = await resp.text().catch(() => '') + throw new Error(`Anthropic sessions.create failed (${resp.status}): ${detail.slice(0, 400)}`) + } + const body = (await resp.json()) as { id?: unknown } + if (typeof body.id !== 'string' || body.id.length === 0) { + throw new Error('Anthropic sessions.create returned no id') + } + return { id: body.id } +} + +/** + * Builds the request body for `POST /v1/sessions` from the caller's typed + * inputs. Keeps the env-type routing in ONE place so callers can't + * accidentally leak self-hosted-only fields onto a cloud session or vice + * versa. Any future rename of the session-parameters wire field is a + * one-line change here. + */ +export function buildSessionCreatePayload( + input: CreateSessionInput +): Record { + const payload: Record = { + agent: input.agentId, + environment_id: input.environmentId, + } + if (input.title) payload.title = input.title + if (input.vaultIds && input.vaultIds.length > 0) payload.vault_ids = input.vaultIds + + const isSelfHosted = input.envType === 'self_hosted' + const access = input.memoryAccess ?? 'read_write' + + if (isSelfHosted) { + // Self-hosted: memory + user-supplied metadata both live under + // top-level `metadata`. The self-hosted agent sandbox forwards + // keys to env vars. + const metadata: Record = { ...(input.sessionParameters ?? {}) } + if (input.memoryStoreId && !metadata.memory_store_ids) { + metadata.memory_store_ids = input.memoryStoreId + if (!metadata.memory_access) metadata.memory_access = access + } + if (Object.keys(metadata).length > 0) payload.metadata = metadata + // `files` and `resources` are intentionally NOT forwarded for + // self-hosted — the self-hosted agent sandbox owns any resource + // mounting on its side. + } else { + // Cloud: build resources[] (memory + file) and emit user metadata as + // opaque tags. Both are optional. + const resources: Array> = [] + if (input.memoryStoreId) { + resources.push({ + type: 'memory_store', + memory_store_id: input.memoryStoreId, + access, + }) + } + if (input.files && input.files.length > 0) { + for (const file of input.files) { + if (!file.fileId) continue + const entry: Record = { type: 'file', file_id: file.fileId } + if (file.mountPath) entry.mount_path = file.mountPath + resources.push(entry) + } + } + if (resources.length > 0) payload.resources = resources + if (input.sessionParameters && Object.keys(input.sessionParameters).length > 0) { + payload.metadata = { ...input.sessionParameters } + } + } + return payload +} + +interface UserMessageEvent { + type: 'user.message' + content: Array<{ type: 'text'; text: string }> +} + +interface UserCustomToolResultEvent { + type: 'user.custom_tool_result' + custom_tool_use_id: string + content: Array<{ type: 'text'; text: string }> + is_error: boolean +} + +export type OutboundSessionEvent = UserMessageEvent | UserCustomToolResultEvent + +/** POST /v1/sessions/{id}/events with a single `user.message`. */ +export async function sendUserMessage( + input: SessionAuth & { sessionId: string; text: string } +): Promise { + await sendSessionEvents({ + apiKey: input.apiKey, + signal: input.signal, + sessionId: input.sessionId, + events: [{ type: 'user.message', content: [{ type: 'text', text: input.text }] }], + }) +} + +/** Generic events-send used for both `user.message` and `user.custom_tool_result`. */ +export async function sendSessionEvents( + input: SessionAuth & { sessionId: string; events: OutboundSessionEvent[] } +): Promise { + if (input.events.length === 0) return + const resp = await fetch(`${ANTHROPIC_API_BASE}/v1/sessions/${input.sessionId}/events`, { + method: 'POST', + headers: managedAgentsHeaders(input.apiKey, { json: true }), + body: JSON.stringify({ events: input.events }), + signal: input.signal, + }) + if (!resp.ok) { + const detail = await resp.text().catch(() => '') + throw new Error(`Anthropic events.send failed (${resp.status}): ${detail.slice(0, 400)}`) + } +} + +/** GET /v1/sessions/{id}/events/stream — opens the SSE response. */ +export async function openSessionStream( + input: SessionAuth & { sessionId: string } +): Promise { + const resp = await fetch( + `${ANTHROPIC_API_BASE}/v1/sessions/${input.sessionId}/events/stream`, + { + method: 'GET', + headers: managedAgentsHeaders(input.apiKey, { accept: 'text/event-stream' }), + signal: input.signal, + } + ) + if (!resp.ok) { + const detail = await resp.text().catch(() => '') + throw new Error(`Anthropic events.stream failed (${resp.status}): ${detail.slice(0, 400)}`) + } + if (!resp.body) { + throw new Error('Anthropic events.stream returned no body') + } + return resp +} + +const DEFAULT_MAX_EVENTS_PER_CATCHUP = 500 + +/** + * Paginated pull of session events emitted after `afterId`, following + * `has_more` cursors up to `maxEvents` (default 500). Returns events in + * arrival order. Used by callers that want to reconcile after an SSE + * stream closes before a terminal state — the copilot leg's reconnect + * loop is the canonical consumer. + */ +export async function listEventsAfter( + input: SessionAuth & { + sessionId: string + afterId: string | null + maxEvents?: number + } +): Promise { + const collected: AnthropicSessionEvent[] = [] + const maxEvents = input.maxEvents ?? DEFAULT_MAX_EVENTS_PER_CATCHUP + let cursor: string | null = input.afterId + while (collected.length < maxEvents) { + const url = new URL(`${ANTHROPIC_API_BASE}/v1/sessions/${input.sessionId}/events`) + url.searchParams.set('limit', '100') + if (cursor) url.searchParams.set('after_id', cursor) + const resp = await fetch(url.toString(), { + method: 'GET', + headers: managedAgentsHeaders(input.apiKey), + signal: input.signal, + }) + if (!resp.ok) { + const detail = await resp.text().catch(() => '') + throw new Error(`Anthropic events.list failed (${resp.status}): ${detail.slice(0, 400)}`) + } + const body = (await resp.json()) as { + data?: AnthropicSessionEvent[] + has_more?: boolean + last_id?: string + } + const page = Array.isArray(body.data) ? body.data : [] + collected.push(...page) + if (!body.has_more || page.length === 0) break + cursor = body.last_id ?? page[page.length - 1]?.id ?? null + if (!cursor) break + } + return collected +} + +/** + * Standard header set for every Managed Agents call. Kept in one place so + * a beta-version bump (e.g. `managed-agents-2026-05-01`) is a single + * literal change. + */ +function managedAgentsHeaders( + apiKey: string, + options: { json?: boolean; accept?: string } = {} +): Record { + const headers: Record = { + 'x-api-key': apiKey, + 'anthropic-version': ANTHROPIC_VERSION, + 'anthropic-beta': MANAGED_AGENTS_BETA, + } + if (options.json) headers['content-type'] = 'application/json' + if (options.accept) headers.accept = options.accept + return headers +} + +export type { AnthropicSessionEvent, AnthropicAgentCustomToolUseEvent } diff --git a/apps/sim/lib/managed-agents/subblock-options.ts b/apps/sim/lib/managed-agents/subblock-options.ts new file mode 100644 index 00000000000..d753db8a014 --- /dev/null +++ b/apps/sim/lib/managed-agents/subblock-options.ts @@ -0,0 +1,178 @@ +import { requestJson } from '@/lib/api/client/request' +import { + listManagedAgentAgentsContract, + listManagedAgentConnectionsContract, + listManagedAgentEnvironmentsContract, + listManagedAgentMemoryStoresContract, + listManagedAgentVaultsContract, +} from '@/lib/api/contracts' +import { useSubBlockStore } from '@/stores/workflows/subblock/store' +import { useWorkflowRegistry } from '@/stores/workflows/registry/store' + +/** + * fetchOptions helpers for the Managed Agent workflow block's dropdowns. + * + * The subblock system passes only `blockId` to `fetchOptions`; each helper + * reads the sibling subblock values it depends on from the subblock store + * (`connection` → agents / environments / vaults). Same pattern the Agent + * block uses for its `reasoningEffort` / `verbosity` fetchers. + * + * All requests go through the workspace-scoped proxy routes, which decrypt + * the stored API key server-side and hit Claude Platform on our behalf — + * the API key never touches the browser. + */ + +interface SubBlockOption { + label: string + id: string +} + +function activeWorkspaceId(): string | null { + return useWorkflowRegistry.getState().hydration.workspaceId ?? null +} + +function connectionIdForBlock(blockId: string): string | null { + const activeWorkflowId = useWorkflowRegistry.getState().activeWorkflowId + if (!activeWorkflowId) return null + const workflowValues = useSubBlockStore.getState().workflowValues[activeWorkflowId] + const value = workflowValues?.[blockId]?.connection + return typeof value === 'string' && value.length > 0 ? value : null +} + +/** List Managed Agent connections in the current workspace. */ +export async function fetchManagedAgentConnectionOptions(): Promise { + const workspaceId = activeWorkspaceId() + if (!workspaceId) return [] + try { + const { data } = await requestJson(listManagedAgentConnectionsContract, { + query: { workspaceId }, + }) + return data.map((row) => ({ id: row.id, label: row.name || row.id })) + } catch { + return [] + } +} + +/** List agents inside the connection selected on `blockId`. */ +export async function fetchManagedAgentAgentOptions(blockId: string): Promise { + const workspaceId = activeWorkspaceId() + const connectionId = connectionIdForBlock(blockId) + if (!workspaceId || !connectionId) return [] + try { + const { data } = await requestJson(listManagedAgentAgentsContract, { + params: { id: connectionId }, + query: { workspaceId }, + }) + return data.map((row) => ({ + id: row.id, + label: row.name ? `${row.name} (${row.id})` : row.id, + })) + } catch { + return [] + } +} + +/** + * List environments inside the connection selected on `blockId`. Options + * carry the config type in the label (e.g. "prod (self-hosted)") so users + * can tell which env types they're picking without a second lookup. + */ +export async function fetchManagedAgentEnvironmentOptions( + blockId: string, + filterType?: 'cloud' | 'self_hosted' +): Promise { + const workspaceId = activeWorkspaceId() + const connectionId = connectionIdForBlock(blockId) + if (!workspaceId || !connectionId) return [] + try { + const { data } = await requestJson(listManagedAgentEnvironmentsContract, { + params: { id: connectionId }, + query: { workspaceId }, + }) + return data + .filter((row) => (filterType ? row.envType === filterType : true)) + .map((row) => ({ id: row.id, label: row.name ? `${row.name} (${row.id})` : row.id })) + } catch { + return [] + } +} + +/** + * Cloud-only environment picker. Bound directly to a block's + * `fetchOptions` (no wrapping) so the block signature matches the + * subblock system's expected `(blockId: string) => Promise`. + */ +export function fetchManagedAgentCloudEnvironmentOptions( + blockId: string +): Promise { + return fetchManagedAgentEnvironmentOptions(blockId, 'cloud') +} + +/** Self-hosted-only environment picker. */ +export function fetchManagedAgentSelfHostedEnvironmentOptions( + blockId: string +): Promise { + return fetchManagedAgentEnvironmentOptions(blockId, 'self_hosted') +} + +/** + * Fetches the environment's raw config for the block's `environmentType` + * companion field. Called after the user picks an environment so the + * `sessionParameters` subblock's `condition: environmentType==='self_hosted'` + * can gate correctly without a follow-up server round-trip at execute time. + */ +export async function fetchManagedAgentEnvironmentType( + blockId: string, + environmentId: string +): Promise<'cloud' | 'self_hosted' | null> { + const workspaceId = activeWorkspaceId() + const connectionId = connectionIdForBlock(blockId) + if (!workspaceId || !connectionId || !environmentId) return null + try { + const { data } = await requestJson(listManagedAgentEnvironmentsContract, { + params: { id: connectionId }, + query: { workspaceId }, + }) + const match = data.find((row) => row.id === environmentId) + return match?.envType ?? null + } catch { + return null + } +} + +/** List vaults for the connection selected on `blockId`. */ +export async function fetchManagedAgentVaultOptions(blockId: string): Promise { + const workspaceId = activeWorkspaceId() + const connectionId = connectionIdForBlock(blockId) + if (!workspaceId || !connectionId) return [] + try { + const { data } = await requestJson(listManagedAgentVaultsContract, { + params: { id: connectionId }, + query: { workspaceId }, + }) + return data.map((row) => ({ id: row.id, label: row.name || row.id })) + } catch { + return [] + } +} + +/** List memory stores for the connection selected on `blockId`. */ +export async function fetchManagedAgentMemoryStoreOptions( + blockId: string +): Promise { + const workspaceId = activeWorkspaceId() + const connectionId = connectionIdForBlock(blockId) + if (!workspaceId || !connectionId) return [] + try { + const { data } = await requestJson(listManagedAgentMemoryStoresContract, { + params: { id: connectionId }, + query: { workspaceId }, + }) + return data.map((row) => ({ + id: row.id, + label: row.name ? `${row.name} (${row.id})` : row.id, + })) + } catch { + return [] + } +} diff --git a/apps/sim/lib/workflows/autolayout/utils.ts b/apps/sim/lib/workflows/autolayout/utils.ts index cd8fc3ada11..370fc143b62 100644 --- a/apps/sim/lib/workflows/autolayout/utils.ts +++ b/apps/sim/lib/workflows/autolayout/utils.ts @@ -236,6 +236,7 @@ function estimateWorkflowBlockDimensions(block: BlockState): { width: number; he block.type === 'router_v2' ? getRouterRows(block.id, block.subBlocks?.routes?.value).length : 0, + nodeWidth: blockConfig.nodeWidth, }) } diff --git a/apps/sim/lib/workflows/blocks/deterministic-dimensions.ts b/apps/sim/lib/workflows/blocks/deterministic-dimensions.ts index b3d8145e91b..52b57b5ecae 100644 --- a/apps/sim/lib/workflows/blocks/deterministic-dimensions.ts +++ b/apps/sim/lib/workflows/blocks/deterministic-dimensions.ts @@ -8,6 +8,8 @@ interface WorkflowBlockDimensionsInput { visibleSubBlockCount: number conditionRowCount?: number routerRowCount?: number + /** Optional per-block width override from `BlockConfig.nodeWidth`. */ + nodeWidth?: number } export function calculateWorkflowBlockDimensions({ @@ -17,6 +19,7 @@ export function calculateWorkflowBlockDimensions({ visibleSubBlockCount, conditionRowCount = 0, routerRowCount = 0, + nodeWidth, }: WorkflowBlockDimensionsInput): { width: number; height: number } { const shouldShowDefaultHandles = category !== 'triggers' && blockType !== 'starter' && !displayTriggerMode @@ -41,7 +44,7 @@ export function calculateWorkflowBlockDimensions({ ) return { - width: BLOCK_DIMENSIONS.FIXED_WIDTH, + width: nodeWidth ?? BLOCK_DIMENSIONS.FIXED_WIDTH, height, } } diff --git a/apps/sim/tools/index.ts b/apps/sim/tools/index.ts index f4b9c3fc241..58d825c0e14 100644 --- a/apps/sim/tools/index.ts +++ b/apps/sim/tools/index.ts @@ -1,3 +1,8 @@ +// Server-only side-effect: registers the Managed Agent tool's actual +// execution on `globalThis`. Kept out of the client-safe `tools/registry.ts` +// so `@sim/db` / postgres / node builtins don't get pulled into the browser +// bundle. See `apps/sim/tools/managed_agent/run_session.ts` for the design. +import '@/tools/managed_agent/run_session.server' import { createLogger } from '@sim/logger' import { getErrorMessage, toError } from '@sim/utils/errors' import { sleep } from '@sim/utils/helpers' @@ -1240,7 +1245,20 @@ export async function executeTool( // Check for direct execution (no HTTP request needed) if (tool.directExecution) { logger.info(`[${requestId}] Using directExecution for ${toolId}`) - const result = await tool.directExecution(contextParams) + // Attach the workflow's abort signal to `_context.abortSignal` so + // direct-execution tools (Managed Agent session, etc.) can propagate + // cancellation into long-lived operations like SSE streams. Non-abort + // callers get the same context they had before. + const directExecutionParams = effectiveSignal + ? { + ...contextParams, + _context: { + ...(contextParams._context as Record | undefined), + abortSignal: effectiveSignal, + }, + } + : contextParams + const result = await tool.directExecution(directExecutionParams) // Apply post-processing if available and not skipped let finalResult = result diff --git a/apps/sim/tools/managed_agent/index.ts b/apps/sim/tools/managed_agent/index.ts new file mode 100644 index 00000000000..321e5cd977f --- /dev/null +++ b/apps/sim/tools/managed_agent/index.ts @@ -0,0 +1,2 @@ +export { managedAgentRunSessionTool } from './run_session' +export type { ManagedAgentRunSessionOutput, ManagedAgentRunSessionParams } from './types' diff --git a/apps/sim/tools/managed_agent/normalizers.test.ts b/apps/sim/tools/managed_agent/normalizers.test.ts new file mode 100644 index 00000000000..b8010a1ab75 --- /dev/null +++ b/apps/sim/tools/managed_agent/normalizers.test.ts @@ -0,0 +1,249 @@ +/** + * @vitest-environment node + */ +import { describe, expect, it } from 'vitest' +import { + isTruthyAck, + normalizeEnvType, + normalizeFiles, + normalizeMemoryAccess, + normalizeSessionParameters, + normalizeStringList, +} from '@/tools/managed_agent/normalizers' + +describe('normalizeEnvType', () => { + it('passes through cloud and self_hosted', () => { + expect(normalizeEnvType('cloud')).toBe('cloud') + expect(normalizeEnvType('self_hosted')).toBe('self_hosted') + }) + + it('returns undefined for anything else', () => { + expect(normalizeEnvType(undefined)).toBeUndefined() + expect(normalizeEnvType('')).toBeUndefined() + expect(normalizeEnvType('Cloud')).toBeUndefined() + expect(normalizeEnvType('other')).toBeUndefined() + }) +}) + +describe('normalizeMemoryAccess', () => { + it('passes through the two supported modes', () => { + expect(normalizeMemoryAccess('read_write')).toBe('read_write') + expect(normalizeMemoryAccess('read_only')).toBe('read_only') + }) + + it('returns undefined for anything else', () => { + expect(normalizeMemoryAccess(undefined)).toBeUndefined() + expect(normalizeMemoryAccess('')).toBeUndefined() + expect(normalizeMemoryAccess('write')).toBeUndefined() + expect(normalizeMemoryAccess('READ_WRITE')).toBeUndefined() + }) +}) + +describe('normalizeStringList', () => { + it('returns empty when the value is undefined / null / non-string non-array', () => { + expect(normalizeStringList(undefined)).toEqual([]) + expect(normalizeStringList(null)).toEqual([]) + expect(normalizeStringList(42)).toEqual([]) + expect(normalizeStringList({})).toEqual([]) + expect(normalizeStringList(true)).toEqual([]) + }) + + it('preserves array-of-string input and trims each entry', () => { + expect(normalizeStringList(['a', ' b ', 'c'])).toEqual(['a', 'b', 'c']) + }) + + it('drops non-string and blank entries from an array', () => { + expect(normalizeStringList(['a', '', ' ', null, 5, 'b'])).toEqual(['a', 'b']) + }) + + it('parses a JSON-encoded array string', () => { + expect(normalizeStringList('["vlt_1","vlt_2"]')).toEqual(['vlt_1', 'vlt_2']) + }) + + it('falls back to comma-split when the JSON array parse fails', () => { + // The leading `[` triggers the JSON attempt; broken JSON should not + // then silently vanish — the raw comma-split path is preferred. + // In practice broken JSON is not comma-separated, so the string is + // returned as a single entry after the trim. + expect(normalizeStringList('[not json')).toEqual(['[not json']) + }) + + it('splits comma-separated strings and trims each item', () => { + expect(normalizeStringList('vlt_1, vlt_2 ,vlt_3')).toEqual(['vlt_1', 'vlt_2', 'vlt_3']) + }) + + it('accepts a single-value string', () => { + expect(normalizeStringList('vlt_only')).toEqual(['vlt_only']) + }) + + it('returns empty for a whitespace-only string', () => { + expect(normalizeStringList(' ')).toEqual([]) + }) +}) + +describe('normalizeFiles', () => { + it('returns empty for non-array input', () => { + expect(normalizeFiles(undefined)).toEqual([]) + expect(normalizeFiles(null)).toEqual([]) + expect(normalizeFiles('file_id')).toEqual([]) + expect(normalizeFiles({})).toEqual([]) + }) + + it('accepts the flat {fileId, mountPath?} shape', () => { + expect( + normalizeFiles([ + { fileId: 'file_1', mountPath: '/data/one' }, + { fileId: 'file_2' }, + ]) + ).toEqual([ + { fileId: 'file_1', mountPath: '/data/one' }, + { fileId: 'file_2' }, + ]) + }) + + it('accepts the table-subblock {cells: {Key, Value}} shape', () => { + expect( + normalizeFiles([ + { id: 'r1', cells: { Key: 'file_1', Value: '/data/one' } }, + { id: 'r2', cells: { Key: 'file_2', Value: '' } }, + ]) + ).toEqual([ + { fileId: 'file_1', mountPath: '/data/one' }, + { fileId: 'file_2' }, + ]) + }) + + it("accepts the block's declared column names (`File ID` / `Mount path`)", () => { + // The cloud block declares `columns: ['File ID', 'Mount path']`, so + // the table subblock stores each row keyed by exactly those strings. + // Regression test — the previous normalizer only knew about + // `Key`/`Value` and silently dropped every row. + expect( + normalizeFiles([ + { id: 'r1', cells: { 'File ID': 'file_1', 'Mount path': '/data/one' } }, + { id: 'r2', cells: { 'File ID': 'file_2', 'Mount path': '' } }, + ]) + ).toEqual([ + { fileId: 'file_1', mountPath: '/data/one' }, + { fileId: 'file_2' }, + ]) + }) + + it('drops rows with no file id and rows that are not objects', () => { + expect( + normalizeFiles([ + { fileId: '' }, + { cells: { Key: ' ' } }, + null, + undefined, + 'garbage', + { cells: {} }, + { fileId: 'file_ok' }, + ]) + ).toEqual([{ fileId: 'file_ok' }]) + }) + + it('omits mountPath when it is blank / whitespace-only', () => { + expect( + normalizeFiles([ + { fileId: 'file_1', mountPath: ' ' }, + { fileId: 'file_2', mountPath: '/mount' }, + ]) + ).toEqual([{ fileId: 'file_1' }, { fileId: 'file_2', mountPath: '/mount' }]) + }) +}) + +describe('normalizeSessionParameters', () => { + it('returns undefined for empty / non-object / non-string values', () => { + expect(normalizeSessionParameters(undefined)).toBeUndefined() + expect(normalizeSessionParameters(null)).toBeUndefined() + expect(normalizeSessionParameters(42)).toBeUndefined() + expect(normalizeSessionParameters(true)).toBeUndefined() + expect(normalizeSessionParameters('')).toBeUndefined() + expect(normalizeSessionParameters(' ')).toBeUndefined() + }) + + it('collapses the table-row shape into a flat Record', () => { + // This is the shape the workflow `table` subblock stores — the bug the + // metadata: {} on the wire regression was caused by NOT handling this. + const rows = [ + { id: 'r1', cells: { Key: 'SOURCE_TYPE', Value: 'git' } }, + { id: 'r2', cells: { Key: 'SOURCE_URL', Value: 'https://example/repo.git' } }, + { id: 'r3', cells: { Key: 'DEST_DIR', Value: 'repo' } }, + ] + expect(normalizeSessionParameters(rows)).toEqual({ + SOURCE_TYPE: 'git', + SOURCE_URL: 'https://example/repo.git', + DEST_DIR: 'repo', + }) + }) + + it('accepts a JSON-encoded array-of-rows string', () => { + const encoded = JSON.stringify([ + { cells: { Key: 'K1', Value: 'V1' } }, + { cells: { Key: 'K2', Value: 'V2' } }, + ]) + expect(normalizeSessionParameters(encoded)).toEqual({ K1: 'V1', K2: 'V2' }) + }) + + it('accepts the flat Record shape', () => { + expect(normalizeSessionParameters({ A: '1', B: '2' })).toEqual({ A: '1', B: '2' }) + }) + + it('drops rows with a blank key', () => { + const rows = [ + { cells: { Key: '', Value: 'ignored' } }, + { cells: { Key: ' ', Value: 'also-ignored' } }, + { cells: { Key: 'KEEP', Value: 'yes' } }, + ] + expect(normalizeSessionParameters(rows)).toEqual({ KEEP: 'yes' }) + }) + + it('coerces non-string values to empty string but preserves the key', () => { + const rows = [ + { cells: { Key: 'A', Value: 'str' } }, + { cells: { Key: 'B', Value: 42 } }, + { cells: { Key: 'C', Value: null } }, + ] + expect(normalizeSessionParameters(rows)).toEqual({ A: 'str', B: '', C: '' }) + }) + + it('returns undefined when every row is dropped', () => { + expect( + normalizeSessionParameters([{ cells: { Key: '', Value: 'x' } }, { cells: {} }]) + ).toBeUndefined() + }) + + it('returns undefined for a non-parseable JSON string', () => { + // Non-`[`-prefixed strings are not parsed and not comma-split for + // metadata (unlike vault lists) — they cannot form a valid k/v map. + expect(normalizeSessionParameters('not json')).toBeUndefined() + expect(normalizeSessionParameters('[broken')).toBeUndefined() + }) +}) + +describe('isTruthyAck', () => { + it('accepts the real boolean true', () => { + expect(isTruthyAck(true)).toBe(true) + }) + + it('accepts common string checked-forms (case-insensitive, trimmed)', () => { + for (const on of ['true', 'True', 'TRUE', '1', 'yes', 'YES', ' true ']) { + expect(isTruthyAck(on)).toBe(true) + } + }) + + it('rejects false, empty, and every other string form', () => { + for (const off of [false, '', ' ', 'false', '0', 'no', 'off', 'random']) { + expect(isTruthyAck(off)).toBe(false) + } + }) + + it('rejects undefined / null / non-string non-boolean values', () => { + expect(isTruthyAck(undefined)).toBe(false) + expect(isTruthyAck(null)).toBe(false) + expect(isTruthyAck(1)).toBe(false) + expect(isTruthyAck({})).toBe(false) + expect(isTruthyAck([])).toBe(false) + }) +}) diff --git a/apps/sim/tools/managed_agent/normalizers.ts b/apps/sim/tools/managed_agent/normalizers.ts new file mode 100644 index 00000000000..4bffddfbcbf --- /dev/null +++ b/apps/sim/tools/managed_agent/normalizers.ts @@ -0,0 +1,180 @@ +/** + * Pure normalization helpers used by the Managed Agent workflow-block tool + * to shape user input from Sim's block subblocks (which store their values + * in several different runtime shapes) into the tidy typed values the + * Anthropic session-client expects. + * + * Kept in a client-safe module (no `import 'server-only'`, no DB, no `env`) + * so the tests can import each helper directly without loading the whole + * session runtime and its side-effect registration. + */ + +import type { ManagedAgentEnvType } from '@/lib/managed-agents/session-client' + +export function normalizeEnvType( + value: string | undefined +): ManagedAgentEnvType | undefined { + if (value === 'cloud' || value === 'self_hosted') return value + return undefined +} + +export function normalizeMemoryAccess( + value: string | undefined +): 'read_write' | 'read_only' | undefined { + if (value === 'read_write' || value === 'read_only') return value + return undefined +} + +/** + * A subblock's `switch` value may arrive as a real boolean or as a + * string (`"true"`, `"1"`, `"yes"`) depending on how the workflow was + * serialized. Treat every reasonable "checked" form as truthy; anything + * else — including `false`, empty string, `undefined`, non-string + * non-boolean values — as not-checked. + */ +export function isTruthyAck(value: unknown): boolean { + if (value === true) return true + if (typeof value !== 'string') return false + const normalized = value.trim().toLowerCase() + return normalized === 'true' || normalized === '1' || normalized === 'yes' +} + +/** + * Coerces the block's file table into the tidy shape the session-client + * expects. Silently drops rows missing a file id. + * + * The table subblock stores rows as `WorkflowTableRow[]` with `cells` + * keyed by the column-header STRINGS the block declared. The cloud + * Managed Agents block uses `columns: ['File ID', 'Mount path']`, so + * cells arrive as `{ 'File ID': '...', 'Mount path': '...' }`. We also + * accept the older `{Key, Value}` and the flat `{fileId, mountPath}` + * shapes so hand-authored or legacy stored values still resolve. + */ +export function normalizeFiles( + value: unknown +): Array<{ fileId: string; mountPath?: string }> { + if (!Array.isArray(value)) return [] + const out: Array<{ fileId: string; mountPath?: string }> = [] + for (const raw of value) { + if (!raw || typeof raw !== 'object') continue + const record = raw as Record + const cells = + record.cells && typeof record.cells === 'object' + ? (record.cells as Record) + : record + const readString = (key: string): string | undefined => + typeof cells[key] === 'string' ? (cells[key] as string) : undefined + const fileId = + readString('fileId') ?? + readString('File ID') ?? + readString('file_id') ?? + readString('Key') ?? + '' + if (!fileId.trim()) continue + const mountPath = + readString('mountPath') ?? + readString('Mount path') ?? + readString('mount_path') ?? + readString('Value') + out.push({ + fileId: fileId.trim(), + ...(mountPath && mountPath.trim() ? { mountPath: mountPath.trim() } : {}), + }) + } + return out +} + +/** + * Coerce whatever shape the multi-select combobox / json input ends up + * with — an array, a JSON-encoded array string, a comma-separated string, + * or a single string — into a trimmed `string[]`. Handles the case where + * a `type: 'json'` input isn't parsed for us (fresh workflows, stale + * serialization, block hydration). + */ +export function normalizeStringList(value: unknown): string[] { + if (Array.isArray(value)) { + return value + .filter((v): v is string => typeof v === 'string' && v.trim().length > 0) + .map((v) => v.trim()) + } + if (typeof value !== 'string') return [] + const trimmed = value.trim() + if (!trimmed) return [] + if (trimmed.startsWith('[')) { + try { + const parsed = JSON.parse(trimmed) + if (Array.isArray(parsed)) { + return parsed + .filter((v): v is string => typeof v === 'string' && v.trim().length > 0) + .map((v) => v.trim()) + } + } catch { + // fall through to comma-split + } + } + return trimmed + .split(',') + .map((v) => v.trim()) + .filter((v) => v.length > 0) +} + +/** + * Coerce the block's session-parameters value into a `Record` + * ready for the Anthropic session-create `metadata` field. + * + * The `table` subblock stores rows as `WorkflowTableRow[]` — an array of + * `{ id, cells: { Key: string, Value: string } }` — not a flat object. It + * may also arrive as a JSON-encoded array string (fresh workflows, some + * hydration paths) or the flat `Record` shape (older + * serializations). Handle all three; drop rows/pairs with a blank key. + */ +export function normalizeSessionParameters( + value: unknown +): Record | undefined { + const rows = coerceToRows(value) + if (rows === undefined) return undefined + const out: Record = {} + for (const row of rows) { + const key = typeof row.key === 'string' ? row.key.trim() : '' + if (!key) continue + const val = typeof row.value === 'string' ? row.value : '' + out[key] = val + } + return Object.keys(out).length > 0 ? out : undefined +} + +function coerceToRows( + value: unknown +): Array<{ key: unknown; value: unknown }> | undefined { + if (Array.isArray(value)) { + return value.map((row) => tableRowToPair(row)) + } + if (typeof value === 'string') { + const trimmed = value.trim() + if (!trimmed || !trimmed.startsWith('[')) return undefined + try { + const parsed = JSON.parse(trimmed) + if (Array.isArray(parsed)) return parsed.map((row) => tableRowToPair(row)) + } catch { + return undefined + } + return undefined + } + if (value && typeof value === 'object') { + return Object.entries(value as Record).map(([key, val]) => ({ + key, + value: val, + })) + } + return undefined +} + +function tableRowToPair(row: unknown): { key: unknown; value: unknown } { + if (!row || typeof row !== 'object') return { key: undefined, value: undefined } + const record = row as Record + const cells = + record.cells && typeof record.cells === 'object' + ? (record.cells as Record) + : record + return { key: cells.Key ?? cells.key, value: cells.Value ?? cells.value } +} diff --git a/apps/sim/tools/managed_agent/run_session.server.ts b/apps/sim/tools/managed_agent/run_session.server.ts new file mode 100644 index 00000000000..53a4a78da72 --- /dev/null +++ b/apps/sim/tools/managed_agent/run_session.server.ts @@ -0,0 +1,542 @@ +import 'server-only' + +import { db } from '@sim/db' +import { workflow as workflowTable, workspace as workspaceTable } from '@sim/db/schema' +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { sleep } from '@sim/utils/helpers' +import { eq } from 'drizzle-orm' +import { readSSEEvents } from '@/lib/core/utils/sse' +import { getDecryptedApiKey } from '@/lib/managed-agents/connections' +import { env } from '@/lib/core/config/env' +import { + type AnthropicSessionEvent, + buildSessionCreatePayload, + createSession, + listEventsAfter, + openSessionStream, + sendSessionEvents, + sendUserMessage, +} from '@/lib/managed-agents/session-client' +import { + isTruthyAck, + normalizeEnvType, + normalizeFiles, + normalizeMemoryAccess, + normalizeSessionParameters, + normalizeStringList, +} from '@/tools/managed_agent/normalizers' +import { + registerManagedAgentServerImpl, + type ManagedAgentServerImpl, +} from '@/tools/managed_agent/run_session' +import type { + ManagedAgentRunSessionOutput, + ManagedAgentRunSessionParams, +} from '@/tools/managed_agent/types' +import type { ToolResponse } from '@/tools/types' + +/** + * Server-only execution for the Managed Agent workflow-block tool. + * + * `import 'server-only'` fails the build if anything in the client + * graph reaches this file — matching the intent. The client tool + * skeleton (`./run_session.ts`) uses a `globalThis` lookup to reach + * this impl at runtime, so Turbopack finds no cross-boundary edge. + */ + +const logger = createLogger('ManagedAgentRunSessionServer') + +/** Upper bound on stream-close → catch-up → reopen cycles per invocation. */ +const MAX_RECONNECT_ITERATIONS = 60 + +/** + * Backoff for `listEventsAfter` polling while the session is legitimately + * busy (server-side / MCP tools stay in `requires_action` with no + * client-visible events until they finish). Starts at 500ms, doubles up + * to 5s, capped so a stuck session terminates instead of spinning + * forever — see MAX_REQUIRES_ACTION_WAIT_MS. + */ +const REQUIRES_ACTION_BACKOFF_START_MS = 500 +const REQUIRES_ACTION_BACKOFF_MAX_MS = 5000 +/** Hard cap on total time spent waiting on a busy session — ~5 minutes. */ +const MAX_REQUIRES_ACTION_WAIT_MS = 5 * 60 * 1000 + +const impl: ManagedAgentServerImpl = async ( + params: ManagedAgentRunSessionParams +): Promise => { + const startedAt = new Date() + const context = params._context + const workspaceId = context?.workspaceId + // Workflow abort signal — set by `executeTool` on the directExecution + // path. When the workflow is cancelled we forward this to the stream + // fetch, the SSE reader, and the catch-up pagination so the HTTP + // connection is released instead of leaked. + const signal = + context && typeof context === 'object' && 'abortSignal' in context + ? (context as { abortSignal?: AbortSignal }).abortSignal + : undefined + if (!workspaceId) { + return { + success: false, + output: {}, + error: 'Missing workspaceId in tool context — is this workflow tied to a workspace?', + } + } + if (signal?.aborted) { + return { success: false, output: {}, error: 'aborted' } + } + + const keyResult = await getDecryptedApiKey({ id: params.connection, workspaceId }) + if (!keyResult.ok) { + return { + success: false, + output: {}, + error: + keyResult.reason === 'decrypt_failed' + ? 'Managed Agent connection could not be decrypted — the workspace encryption key may have rotated. Rotate the API key in Settings → Managed Agents to re-encrypt.' + : 'Managed Agent connection not found. Reconnect the Claude workspace and retry.', + } + } + const apiKey = keyResult.apiKey + + if (isPayloadDebugEnabled()) { + logger.info('Managed agent tool raw params (pre-normalization)', { + workspaceId, + vaultsType: Array.isArray(params.vaults) ? 'array' : typeof params.vaults, + vaultsValue: params.vaults, + memoryStoreIdValue: params.memoryStoreId, + filesType: Array.isArray(params.files) ? 'array' : typeof params.files, + environmentType: params.environmentType, + }) + } + + const envType = normalizeEnvType(params.environmentType) + const userMessage = (params.userMessage ?? '').trim() + if (!userMessage) { + return { success: false, output: {}, error: 'User message is required.' } + } + + const vaultIds = normalizeStringList(params.vaults) + if (vaultIds.length > 0 && !isTruthyAck(params.vaultsAck)) { + // Security ack — enforced here rather than at the subblock level + // because Sim's `condition` engine cannot natively test array- + // non-empty. Fails closed: attaching any vault requires an explicit + // confirmation that the workflow author is authorized to use it, + // since the session runs with the vault's credentials. + return { + success: false, + output: {}, + error: + 'Vault authorization is required — check the "I own or am authorized to use these vaults" acknowledgement on the block, or remove the selected vault(s).', + } + } + const memoryStoreId = params.memoryStoreId?.trim() || undefined + const memoryAccess = normalizeMemoryAccess(params.memoryAccess) + const files = normalizeFiles(params.files) + const sessionParameters = normalizeSessionParameters(params.sessionParameters) + + // Human-legible session title so runs are traceable from the Claude + // Platform side back to the Sim workflow node that opened them. + // Failure to look up either name is tolerated — we just drop that + // segment from the title so the session still opens. + const title = await buildSessionTitle({ + workspaceId, + workflowId: context?.workflowId, + blockName: context?.blockName, + }) + + const createSessionInput = { + apiKey, + agentId: params.agent, + environmentId: params.environment, + envType, + ...(title ? { title } : {}), + ...(vaultIds.length > 0 ? { vaultIds } : {}), + ...(memoryStoreId ? { memoryStoreId } : {}), + ...(memoryStoreId && memoryAccess ? { memoryAccess } : {}), + ...(files.length > 0 ? { files } : {}), + ...(sessionParameters && Object.keys(sessionParameters).length > 0 + ? { sessionParameters } + : {}), + ...(signal ? { signal } : {}), + } + + // Opt-in payload dump for debugging session-create request shape. + // Enable with `MANAGED_AGENT_DEBUG_PAYLOAD=1` in `.env` — the log line + // does NOT include the api key (buildSessionCreatePayload strips it). + if (isPayloadDebugEnabled()) { + logger.info('Managed agent session-create payload', { + workspaceId, + agentId: params.agent, + environmentId: params.environment, + envType, + payload: buildSessionCreatePayload(createSessionInput), + }) + } + + let sessionId: string + try { + const session = await createSession(createSessionInput) + sessionId = session.id + } catch (error) { + return { + success: false, + output: {}, + error: getErrorMessage(error, 'Failed to create Managed Agent session'), + } + } + + logger.info('Created managed agent session for workflow block', { + workspaceId, + workflowId: context?.workflowId, + sessionId, + agentId: params.agent, + environmentId: params.environment, + envType, + }) + + try { + await sendUserMessage({ apiKey, sessionId, text: userMessage, signal }) + } catch (error) { + return { + success: false, + output: { sessionId }, + error: signal?.aborted + ? 'aborted' + : getErrorMessage(error, 'Failed to send user message'), + } + } + + const assistantText = { value: '' } + const seenIds = new Set() + const eventState: EventState = { + lastCustomToolResponseAt: 0, + lastRequiresActionAt: 0, + requiresActionEnteredAt: 0, + currentBackoffMs: REQUIRES_ACTION_BACKOFF_START_MS, + } + let lastEventId: string | null = null + let terminal: { status: 'complete' | 'error'; reason?: string } | null = null + + try { + for ( + let iteration = 0; + iteration < MAX_RECONNECT_ITERATIONS && !terminal; + iteration++ + ) { + if (signal?.aborted) break + const streamResp = await openSessionStream({ apiKey, sessionId, signal }) + await readSSEEvents(streamResp, { + signal, + onParseError: (raw, err) => { + logger.warn('Un-parseable SSE line', { + sessionId, + preview: raw.slice(0, 200), + error: getErrorMessage(err), + }) + }, + onEvent: async (event) => { + const eventId = (event as { id?: string }).id + if (eventId && seenIds.has(eventId)) return undefined + if (eventId) { + seenIds.add(eventId) + lastEventId = eventId + } + const outcome = await handleEvent({ + event, + assistantText, + apiKey, + sessionId, + eventState, + }) + if (outcome) { + terminal = outcome + return true + } + return undefined + }, + }) + + if (terminal) break + if (signal?.aborted) break + + const missed = await listEventsAfter({ apiKey, sessionId, afterId: lastEventId, signal }) + if (missed.length === 0) { + // Session went idle with no new events to catch up on. Two cases: + // 1. `requires_action` is currently outstanding — either we + // already sent our tool-result reply and the agent is + // processing it, or a server-side / MCP tool is executing + // on the platform side. In BOTH cases the session is + // legitimately busy; back off and re-poll rather than + // failing (server-side tools can stay in requires_action + // for tens of seconds with no client-visible events). + // 2. No pending action → clean completion (usually already + // hit via `end_turn` earlier; this is the fallback path). + if (eventState.lastRequiresActionAt > 0) { + const waitedMs = Date.now() - eventState.requiresActionEnteredAt + if (waitedMs >= MAX_REQUIRES_ACTION_WAIT_MS) { + terminal = { + status: 'error', + reason: `Session paused (requires_action) for over ${Math.floor(MAX_REQUIRES_ACTION_WAIT_MS / 1000)}s without progress — the pending tool call could not complete. Check MCP server / vault configuration on Claude Platform.`, + } + break + } + await sleep(nextBackoffMs(eventState)) + continue + } + terminal = { status: 'complete' } + break + } + // Session made progress — reset the requires_action wait clock + // and backoff so the next pause starts fresh. + eventState.requiresActionEnteredAt = 0 + eventState.currentBackoffMs = REQUIRES_ACTION_BACKOFF_START_MS + for (const event of missed) { + const eventId = (event as { id?: string }).id + if (eventId && seenIds.has(eventId)) continue + if (eventId) { + seenIds.add(eventId) + lastEventId = eventId + } + const outcome = await handleEvent({ + event, + assistantText, + apiKey, + sessionId, + eventState, + }) + if (outcome) { + terminal = outcome + break + } + } + } + } catch (error) { + // A workflow abort surfaces as an AbortError / DOMException here — do + // not log that as a stream failure, and return a clean 'aborted' + // response so the executor can attribute cancellation correctly. + if (signal?.aborted) { + return { + success: false, + output: { sessionId, content: assistantText.value }, + error: 'aborted', + } + } + logger.error('Managed agent stream failed', { sessionId, error: getErrorMessage(error) }) + return { + success: false, + output: { sessionId, content: assistantText.value }, + error: getErrorMessage(error, 'Managed Agent session failed'), + } + } + + const endedAt = new Date() + const timing = { + startTime: startedAt.toISOString(), + endTime: endedAt.toISOString(), + duration: endedAt.getTime() - startedAt.getTime(), + } + + if (signal?.aborted) { + return { + success: false, + output: { sessionId, content: assistantText.value } satisfies ManagedAgentRunSessionOutput, + error: 'aborted', + timing, + } + } + + if (!terminal || terminal.status === 'error') { + return { + success: false, + output: { sessionId, content: assistantText.value } satisfies ManagedAgentRunSessionOutput, + error: terminal?.reason ?? 'Reconnect iteration cap reached without a terminal state.', + timing, + } + } + + return { + success: true, + output: { sessionId, content: assistantText.value } satisfies ManagedAgentRunSessionOutput, + timing, + } +} + +/** Side-effect: bind the impl into the process at import time. */ +registerManagedAgentServerImpl(impl) + +/** + * Tracks progress across `requires_action` idle events. Server-side or + * MCP tools can legitimately keep the session in `requires_action` for + * tens of seconds with no client-visible events; we back off + re-poll + * `listEventsAfter` rather than treating catch-up silence as failure. + * `lastCustomToolResponseAt` retains historical use for tests that check + * "did we reply to a `custom_tool_use`", but the retry policy now applies + * uniformly regardless. + */ +interface EventState { + lastCustomToolResponseAt: number + lastRequiresActionAt: number + /** Timestamp of the first `requires_action` in the current busy stretch. */ + requiresActionEnteredAt: number + /** Next backoff to use if we re-poll on catch-up silence. */ + currentBackoffMs: number +} + +function nextBackoffMs(state: EventState): number { + const next = state.currentBackoffMs + state.currentBackoffMs = Math.min( + Math.max(next * 2, REQUIRES_ACTION_BACKOFF_START_MS), + REQUIRES_ACTION_BACKOFF_MAX_MS + ) + return next +} + +async function handleEvent(args: { + event: AnthropicSessionEvent + assistantText: { value: string } + apiKey: string + sessionId: string + eventState: EventState +}): Promise<{ status: 'complete' | 'error'; reason?: string } | null> { + const { event, assistantText, apiKey, sessionId, eventState } = args + const type = (event as { type?: string }).type + + if (type === 'agent.message') { + const content = (event as { content?: Array<{ type: string; text?: string }> }).content + if (Array.isArray(content)) { + for (const block of content) { + if (block?.type === 'text' && typeof block.text === 'string') { + assistantText.value += block.text + } + } + } + return null + } + + if (type === 'agent.custom_tool_use') { + const toolEvent = event as { id: string; name?: string } + logger.warn( + `Managed Agent invoked a custom tool "${toolEvent.name ?? ''}" that Sim does not provide — replying with error` + ) + try { + await sendSessionEvents({ + apiKey, + sessionId, + events: [ + { + type: 'user.custom_tool_result', + custom_tool_use_id: toolEvent.id, + content: [ + { + type: 'text', + text: 'This Managed Agent is being invoked from a Sim workflow block. Sim does not provide custom tools here — configure the agent to use only tools available in its Claude Platform workspace.', + }, + ], + is_error: true, + }, + ], + }) + eventState.lastCustomToolResponseAt = Date.now() + } catch (err) { + logger.error('Failed to send custom_tool_result error reply', { + sessionId, + error: getErrorMessage(err), + }) + } + return null + } + + if (type === 'session.status_terminated') { + const message = + (event as { error?: { message?: string } }).error?.message ?? 'session_terminated' + return { status: 'error', reason: message } + } + + if (type === 'session.status_idle') { + const stop = (event as { stop_reason?: { type?: string } }).stop_reason?.type + if (stop === 'end_turn') return { status: 'complete' } + if (stop === 'retries_exhausted') return { status: 'error', reason: 'retries_exhausted' } + if (stop === 'requires_action') { + // Session paused for a pending action. Never terminal: either + // (a) we already replied to a `custom_tool_use` and the agent is + // processing it, or (b) a server-side / MCP tool is executing on + // the platform side. Both cases resolve on their own; the outer + // reconnect loop backs off + re-polls `listEventsAfter` until + // either new events arrive or the total-wait cap is hit. + const now = Date.now() + if (eventState.requiresActionEnteredAt === 0) { + eventState.requiresActionEnteredAt = now + } + eventState.lastRequiresActionAt = now + return null + } + return { status: 'error', reason: stop ?? 'idle_without_stop_reason' } + } + + if (type === 'session.error') { + const message = + (event as { error?: { message?: string } }).error?.message ?? + (event as { message?: string }).message ?? + 'session_error' + return { status: 'error', reason: message } + } + + return null +} + +function isPayloadDebugEnabled(): boolean { + const raw = env.MANAGED_AGENT_DEBUG_PAYLOAD + if (raw === undefined || raw === null) return false + const normalized = String(raw).toLowerCase() + return normalized === '1' || normalized === 'true' || normalized === 'yes' +} + +/** + * Assemble the Anthropic session title from the Sim workspace, workflow, + * and node names — so a session listed on Claude Platform links back to + * the origin. + * + * Shape: `sim.ai - - - `. Segments whose + * lookups fail (workspace/workflow deleted, block unnamed) are dropped + * so the title still opens something useful. If we can't build any + * meaningful title, return `undefined` — the session creates untitled. + */ +async function buildSessionTitle(input: { + workspaceId: string + workflowId?: string + blockName?: string +}): Promise { + const [workspaceName, workflowName] = await Promise.all([ + fetchNameSafely(workspaceTable, workspaceTable.id, input.workspaceId), + input.workflowId + ? fetchNameSafely(workflowTable, workflowTable.id, input.workflowId) + : Promise.resolve(undefined), + ]) + const segments = ['sim.ai'] + if (workspaceName) segments.push(workspaceName) + if (workflowName) segments.push(workflowName) + if (input.blockName?.trim()) segments.push(input.blockName.trim()) + if (segments.length === 1) return undefined // only the "sim.ai" prefix — not useful + return segments.join(' - ') +} + +async function fetchNameSafely( + table: { name: unknown } & Record, + idColumn: unknown, + id: string +): Promise { + try { + const rows = (await db + .select({ name: (table as { name: unknown }).name }) + .from(table as never) + .where(eq(idColumn as never, id)) + .limit(1)) as Array<{ name: string | null }> + const name = rows[0]?.name + return typeof name === 'string' && name.trim().length > 0 ? name.trim() : undefined + } catch (err) { + logger.warn('Failed to look up name for session title', { id, error: getErrorMessage(err) }) + return undefined + } +} diff --git a/apps/sim/tools/managed_agent/run_session.ts b/apps/sim/tools/managed_agent/run_session.ts new file mode 100644 index 00000000000..46971c28def --- /dev/null +++ b/apps/sim/tools/managed_agent/run_session.ts @@ -0,0 +1,154 @@ +import type { + ManagedAgentRunSessionOutput, + ManagedAgentRunSessionParams, +} from '@/tools/managed_agent/types' +import type { ToolConfig, ToolResponse } from '@/tools/types' + +/** + * Client-safe half of the Managed Agent tool. + * + * The Sim tools registry is walked from client-side code (schema + * inspection, block editor UI). This module MUST NOT statically import + * any server-only code (`@sim/db`, encryption, drizzle, our + * `session-client` HTTP module). Even a lazy `import()` statically ties + * this module to the server graph and Turbopack transitively pulls + * `postgres` → `fs`/`net`/`tls` into the client bundle, which fails. + * + * Instead, the actual execution lives in `./run_session.server.ts` + * (which imports `@sim/db` freely). At server boot that module + * self-registers a `ManagedAgentServerImpl` via + * `registerManagedAgentServerImpl()` below. `directExecution` looks up + * the registered impl on `globalThis` at call time — Turbopack sees no + * cross-boundary edge. + * + * On the client the impl is never registered, so `directExecution` + * returns a clear error. In practice the tool is never invoked from the + * browser, so that branch is defensive only. + */ + +export type ManagedAgentServerImpl = ( + params: ManagedAgentRunSessionParams +) => Promise + +const GLOBAL_KEY = '__simManagedAgentServerImpl' as const +type ImplHolder = { [GLOBAL_KEY]?: ManagedAgentServerImpl } + +/** + * Registered from `apps/sim/tools/managed_agent/server.ts` (server-only) + * at server boot via a side-effect import in a server file. See + * `apps/sim/tools/managed_agent/register-server.ts`. + */ +export function registerManagedAgentServerImpl(impl: ManagedAgentServerImpl): void { + ;(globalThis as unknown as ImplHolder)[GLOBAL_KEY] = impl +} + +function getServerImpl(): ManagedAgentServerImpl | undefined { + return (globalThis as unknown as ImplHolder)[GLOBAL_KEY] +} + +export const managedAgentRunSessionTool: ToolConfig< + ManagedAgentRunSessionParams, + ToolResponse +> = { + id: 'managed_agent_run_session', + name: 'Managed Agent Run Session', + description: + 'Open a Claude Platform Managed Agent session and return the assistant response as text.', + version: '1.0.0', + + params: { + connection: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'ID of the linked Claude Platform workspace (Managed Agent connection).', + }, + agent: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Managed-agent id inside the selected workspace.', + }, + environment: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Environment id inside the selected workspace.', + }, + environmentType: { + type: 'string', + required: false, + visibility: 'user-only', + description: "Environment config type — 'cloud' or 'self_hosted'.", + }, + vaults: { + type: 'array', + required: false, + visibility: 'user-only', + description: 'Zero or more vault ids for MCP tool auth.', + }, + vaultsAck: { + type: 'boolean', + required: false, + visibility: 'user-only', + description: + "Workflow-author acknowledgement that they are authorized to use the attached vaults. Must be true when `vaults` is non-empty; the tool rejects execution otherwise.", + }, + memoryStoreId: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Optional Agent Memory Store id.', + }, + memoryAccess: { + type: 'string', + required: false, + visibility: 'user-only', + description: "Access mode: 'read_write' (default) or 'read_only'.", + }, + files: { + type: 'array', + required: false, + visibility: 'user-only', + description: + 'File attachments (cloud envs only). Array of `{fileId, mountPath?}` — Anthropic mounts each into the session container.', + }, + sessionParameters: { + type: 'object', + required: false, + visibility: 'user-only', + description: + 'Session metadata (top-level `metadata` on the wire). On self-hosted envs the self-hosted agent sandbox exposes each key as an env var; on cloud envs metadata is stored as opaque tags.', + }, + userMessage: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The user message to send to the Managed Agent.', + }, + }, + + directExecution: async (params: ManagedAgentRunSessionParams): Promise => { + const impl = getServerImpl() + if (!impl) { + return { + success: false, + output: {} satisfies Partial, + error: + 'Managed Agent server impl is not registered. This tool must be invoked from a Sim workflow execution on the server.', + } + } + return impl(params) + }, + + request: { + url: () => 'https://api.anthropic.com/v1/sessions', + method: 'POST', + headers: () => ({}), + }, + + outputs: { + content: { type: 'string', description: 'Final assistant text from the Managed Agent session.' }, + sessionId: { type: 'string', description: 'Anthropic session id (for logs / linking).' }, + }, +} diff --git a/apps/sim/tools/managed_agent/types.ts b/apps/sim/tools/managed_agent/types.ts new file mode 100644 index 00000000000..afce09581af --- /dev/null +++ b/apps/sim/tools/managed_agent/types.ts @@ -0,0 +1,64 @@ +import type { WorkflowToolExecutionContext } from '@/tools/types' + +/** + * Params accepted by the `managed_agent_run_session` tool. Values come + * from the Managed Agent workflow block's subblocks; the executor + * injects `_context` (workspaceId / userId / workflowId) at runtime. + */ +export interface ManagedAgentRunSessionParams { + /** ID of the `managed_agent_connection` row that stores the API key. */ + connection: string + /** Managed-agent id from the linked Claude workspace. */ + agent: string + /** Environment id from the linked Claude workspace. */ + environment: string + /** + * Env `config.type` — set by the block's environment combobox + * `onChange`; used here to route memoryStoreId / sessionParameters + * correctly at session-create time. + */ + environmentType?: 'cloud' | 'self_hosted' | string + /** Zero or more vault ids for MCP auth. Empty array allowed. */ + vaults?: string[] + /** + * Workflow-author acknowledgement that they are authorized to use the + * attached vaults ("I own or am authorized to use these vaults; I + * understand this means this agent can assume the identity granted by + * them"). Required to be `true` when `vaults` is non-empty. Enforced by + * the tool at execution time, not at the block subblock level, because + * the subblock condition engine cannot natively test array-non-empty. + */ + vaultsAck?: boolean | string + /** Optional Agent Memory Store id. */ + memoryStoreId?: string + /** + * Access mode for the attached memory store. `read_write` (default) + * pushes changes back on session exit; `read_only` never writes. + * Ignored when `memoryStoreId` is empty. + */ + memoryAccess?: 'read_write' | 'read_only' | string + /** + * File attachments (cloud envs only). Each row = `{fileId, + * mountPath?}`. Ignored for self-hosted envs. + */ + files?: Array<{ fileId: string; mountPath?: string }> + /** + * Key/value session metadata forwarded to the session's top-level + * `metadata` field. On self-hosted envs the self-hosted agent sandbox + * exposes each key as an env var; on cloud envs metadata is stored + * as opaque tags. Each value has already been variable-resolved by + * the executor. + */ + sessionParameters?: Record + /** The user's turn as plain text. Resolved by the executor. */ + userMessage: string + /** Injected by the executor. */ + _context?: WorkflowToolExecutionContext +} + +export interface ManagedAgentRunSessionOutput { + /** Final assistant text accumulated from `agent.message` events. */ + content: string + /** Anthropic session id (returned so downstream blocks can log/link it). */ + sessionId: string +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 9c301e67b98..c8db8396c88 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -2309,6 +2309,7 @@ import { } from '@/tools/linear' import { linkedInGetProfileTool, linkedInSharePostTool } from '@/tools/linkedin' import { linkupSearchTool } from '@/tools/linkup' +import { managedAgentRunSessionTool } from '@/tools/managed_agent' import { linqAddParticipantTool, linqCheckImessageTool, @@ -5151,6 +5152,7 @@ export const tools: Record = { logs_get: logsGetTool, logs_get_execution: logsGetExecutionTool, logs_get_run_details: logsGetRunDetailsTool, + managed_agent_run_session: managedAgentRunSessionTool, loops_check_contact_suppression: loopsCheckContactSuppressionTool, loops_create_contact: loopsCreateContactTool, loops_create_contact_property: loopsCreateContactPropertyTool, diff --git a/apps/sim/tools/types.ts b/apps/sim/tools/types.ts index 261ac103a50..5b64b4424f1 100644 --- a/apps/sim/tools/types.ts +++ b/apps/sim/tools/types.ts @@ -51,6 +51,14 @@ export type WorkflowToolExecutionContext = { workflowId?: string executionId?: string userId?: string + /** + * Optional block identity injected by the generic handler at execute + * time. Tools that create externally-visible records (e.g. a Claude + * Platform Managed Agent session) use these to build human-legible + * titles that link the record back to the source workflow node. + */ + blockId?: string + blockName?: string } export type OutputType = diff --git a/packages/db/migrations/0264_managed_agent_connection.sql b/packages/db/migrations/0264_managed_agent_connection.sql new file mode 100644 index 00000000000..d44e038d02f --- /dev/null +++ b/packages/db/migrations/0264_managed_agent_connection.sql @@ -0,0 +1,16 @@ +CREATE TABLE "managed_agent_connection" ( + "id" text PRIMARY KEY NOT NULL, + "workspace_id" text NOT NULL, + "user_id" text, + "name" text NOT NULL, + "encrypted_api_key" text NOT NULL, + "last_verified_at" timestamp, + "last_verification_error" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +ALTER TABLE "managed_agent_connection" ADD CONSTRAINT "managed_agent_connection_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "managed_agent_connection" ADD CONSTRAINT "managed_agent_connection_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "managed_agent_connection_workspace_id_idx" ON "managed_agent_connection" USING btree ("workspace_id");--> statement-breakpoint +CREATE UNIQUE INDEX "managed_agent_connection_workspace_name_unique" ON "managed_agent_connection" USING btree ("workspace_id","name"); \ No newline at end of file diff --git a/packages/db/migrations/meta/0264_snapshot.json b/packages/db/migrations/meta/0264_snapshot.json new file mode 100644 index 00000000000..78be441cded --- /dev/null +++ b/packages/db/migrations/meta/0264_snapshot.json @@ -0,0 +1,17498 @@ +{ + "id": "cca39e95-9fb8-4e3d-9e0d-591aa668edb5", + "prevId": "296b31b9-f1e6-4d67-838c-06801e9818a3", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.academy_certificate": { + "name": "academy_certificate", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "course_id": { + "name": "course_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "academy_cert_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "issued_at": { + "name": "issued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "certificate_number": { + "name": "certificate_number", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "academy_certificate_user_id_idx": { + "name": "academy_certificate_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "academy_certificate_course_id_idx": { + "name": "academy_certificate_course_id_idx", + "columns": [ + { + "expression": "course_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "academy_certificate_user_course_unique": { + "name": "academy_certificate_user_course_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "course_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "academy_certificate_number_idx": { + "name": "academy_certificate_number_idx", + "columns": [ + { + "expression": "certificate_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "academy_certificate_status_idx": { + "name": "academy_certificate_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "academy_certificate_user_id_user_id_fk": { + "name": "academy_certificate_user_id_user_id_fk", + "tableFrom": "academy_certificate", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "academy_certificate_certificate_number_unique": { + "name": "academy_certificate_certificate_number_unique", + "nullsNotDistinct": false, + "columns": ["certificate_number"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_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 + }, + "id_token": { + "name": "id_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 + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "account_user_id_idx": { + "name": "account_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_account_on_account_id_provider_id": { + "name": "idx_account_on_account_id_provider_id", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_key": { + "name": "api_key", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key_hash": { + "name": "key_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'personal'" + }, + "last_used": { + "name": "last_used", + "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()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "api_key_workspace_type_idx": { + "name": "api_key_workspace_type_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "api_key_user_type_idx": { + "name": "api_key_user_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "api_key_key_hash_idx": { + "name": "api_key_key_hash_idx", + "columns": [ + { + "expression": "key_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "api_key_user_id_user_id_fk": { + "name": "api_key_user_id_user_id_fk", + "tableFrom": "api_key", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "api_key_workspace_id_workspace_id_fk": { + "name": "api_key_workspace_id_workspace_id_fk", + "tableFrom": "api_key", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "api_key_created_by_user_id_fk": { + "name": "api_key_created_by_user_id_fk", + "tableFrom": "api_key", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_key_key_unique": { + "name": "api_key_key_unique", + "nullsNotDistinct": false, + "columns": ["key"] + } + }, + "policies": {}, + "checkConstraints": { + "workspace_type_check": { + "name": "workspace_type_check", + "value": "(type = 'workspace' AND workspace_id IS NOT NULL) OR (type = 'personal' AND workspace_id IS NULL)" + } + }, + "isRLSEnabled": false + }, + "public.async_jobs": { + "name": "async_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "run_at": { + "name": "run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "max_attempts": { + "name": "max_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 3 + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "output": { + "name": "output", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "async_jobs_status_started_at_idx": { + "name": "async_jobs_status_started_at_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "async_jobs_status_completed_at_idx": { + "name": "async_jobs_status_completed_at_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "completed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "async_jobs_schedule_pending_run_at_idx": { + "name": "async_jobs_schedule_pending_run_at_idx", + "columns": [ + { + "expression": "run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"async_jobs\".\"type\" = 'schedule-execution' AND \"async_jobs\".\"status\" = 'pending'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "async_jobs_schedule_processing_started_at_idx": { + "name": "async_jobs_schedule_processing_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"async_jobs\".\"type\" = 'schedule-execution' AND \"async_jobs\".\"status\" = 'processing'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_log": { + "name": "audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_name": { + "name": "actor_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_email": { + "name": "actor_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resource_name": { + "name": "resource_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "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()" + } + }, + "indexes": { + "audit_log_workspace_created_idx": { + "name": "audit_log_workspace_created_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_workspace_created_at_id_idx": { + "name": "audit_log_workspace_created_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"created_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_actor_created_idx": { + "name": "audit_log_actor_created_idx", + "columns": [ + { + "expression": "actor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_resource_idx": { + "name": "audit_log_resource_idx", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_action_idx": { + "name": "audit_log_action_idx", + "columns": [ + { + "expression": "action", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_log_workspace_id_workspace_id_fk": { + "name": "audit_log_workspace_id_workspace_id_fk", + "tableFrom": "audit_log", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_log_actor_id_user_id_fk": { + "name": "audit_log_actor_id_user_id_fk", + "tableFrom": "audit_log", + "tableTo": "user", + "columnsFrom": ["actor_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.background_work_status": { + "name": "background_work_status", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "background_work_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "background_work_status_value", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "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 + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "background_work_status_workspace_status_idx": { + "name": "background_work_status_workspace_status_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "background_work_status_workflow_status_idx": { + "name": "background_work_status_workflow_status_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "background_work_status_meta_child_ws_idx": { + "name": "background_work_status_meta_child_ws_idx", + "columns": [ + { + "expression": "(\"metadata\" ->> 'childWorkspaceId')", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "background_work_status_meta_other_ws_idx": { + "name": "background_work_status_meta_other_ws_idx", + "columns": [ + { + "expression": "(\"metadata\" ->> 'otherWorkspaceId')", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "background_work_status_workspace_id_workspace_id_fk": { + "name": "background_work_status_workspace_id_workspace_id_fk", + "tableFrom": "background_work_status", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "background_work_status_workflow_id_workflow_id_fk": { + "name": "background_work_status_workflow_id_workflow_id_fk", + "tableFrom": "background_work_status", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.chat": { + "name": "chat", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "customizations": { + "name": "customizations", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'public'" + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "allowed_emails": { + "name": "allowed_emails", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "output_configs": { + "name": "output_configs", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "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": { + "identifier_idx": { + "name": "identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"chat\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "chat_archived_at_partial_idx": { + "name": "chat_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"chat\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_chat_on_workflow_id_archived_at": { + "name": "idx_chat_on_workflow_id_archived_at", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "chat_workflow_id_workflow_id_fk": { + "name": "chat_workflow_id_workflow_id_fk", + "tableFrom": "chat", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chat_user_id_user_id_fk": { + "name": "chat_user_id_user_id_fk", + "tableFrom": "chat", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_async_tool_calls": { + "name": "copilot_async_tool_calls", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "checkpoint_id": { + "name": "checkpoint_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "tool_call_id": { + "name": "tool_call_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "args": { + "name": "args", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "status": { + "name": "status", + "type": "copilot_async_tool_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "result": { + "name": "result", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "claimed_at": { + "name": "claimed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "claimed_by": { + "name": "claimed_by", + "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": { + "copilot_async_tool_calls_run_id_idx": { + "name": "copilot_async_tool_calls_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_checkpoint_id_idx": { + "name": "copilot_async_tool_calls_checkpoint_id_idx", + "columns": [ + { + "expression": "checkpoint_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_tool_call_id_idx": { + "name": "copilot_async_tool_calls_tool_call_id_idx", + "columns": [ + { + "expression": "tool_call_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_status_idx": { + "name": "copilot_async_tool_calls_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_run_status_idx": { + "name": "copilot_async_tool_calls_run_status_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_tool_call_id_unique": { + "name": "copilot_async_tool_calls_tool_call_id_unique", + "columns": [ + { + "expression": "tool_call_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_async_tool_calls_run_id_copilot_runs_id_fk": { + "name": "copilot_async_tool_calls_run_id_copilot_runs_id_fk", + "tableFrom": "copilot_async_tool_calls", + "tableTo": "copilot_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_async_tool_calls_checkpoint_id_copilot_run_checkpoints_id_fk": { + "name": "copilot_async_tool_calls_checkpoint_id_copilot_run_checkpoints_id_fk", + "tableFrom": "copilot_async_tool_calls", + "tableTo": "copilot_run_checkpoints", + "columnsFrom": ["checkpoint_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_chats": { + "name": "copilot_chats", + "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 + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "chat_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'copilot'" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'claude-3-7-sonnet-latest'" + }, + "conversation_id": { + "name": "conversation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "preview_yaml": { + "name": "preview_yaml", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan_artifact": { + "name": "plan_artifact", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "resources": { + "name": "resources", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "pinned": { + "name": "pinned", + "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": { + "copilot_chats_user_id_idx": { + "name": "copilot_chats_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_workflow_id_idx": { + "name": "copilot_chats_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_workflow_idx": { + "name": "copilot_chats_user_workflow_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_workspace_idx": { + "name": "copilot_chats_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_created_at_idx": { + "name": "copilot_chats_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_updated_at_idx": { + "name": "copilot_chats_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_workspace_created_at_id_idx": { + "name": "copilot_chats_workspace_created_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"created_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_chats_user_id_user_id_fk": { + "name": "copilot_chats_user_id_user_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_chats_workflow_id_workflow_id_fk": { + "name": "copilot_chats_workflow_id_workflow_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_chats_workspace_id_workspace_id_fk": { + "name": "copilot_chats_workspace_id_workspace_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_feedback": { + "name": "copilot_feedback", + "schema": "", + "columns": { + "feedback_id": { + "name": "feedback_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_query": { + "name": "user_query", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_response": { + "name": "agent_response", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_positive": { + "name": "is_positive", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "feedback": { + "name": "feedback", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_yaml": { + "name": "workflow_yaml", + "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": { + "copilot_feedback_user_id_idx": { + "name": "copilot_feedback_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_chat_id_idx": { + "name": "copilot_feedback_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_user_chat_idx": { + "name": "copilot_feedback_user_chat_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_is_positive_idx": { + "name": "copilot_feedback_is_positive_idx", + "columns": [ + { + "expression": "is_positive", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_created_at_idx": { + "name": "copilot_feedback_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_feedback_user_id_user_id_fk": { + "name": "copilot_feedback_user_id_user_id_fk", + "tableFrom": "copilot_feedback", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_feedback_chat_id_copilot_chats_id_fk": { + "name": "copilot_feedback_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_feedback", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_messages": { + "name": "copilot_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "stream_id": { + "name": "stream_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parent_message_id": { + "name": "parent_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tokens_in": { + "name": "tokens_in", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "tokens_out": { + "name": "tokens_out", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "seq": { + "name": "seq", + "type": "integer", + "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": { + "copilot_messages_chat_message_unique": { + "name": "copilot_messages_chat_message_unique", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_messages_chat_created_at_idx": { + "name": "copilot_messages_chat_created_at_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_messages\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_messages_chat_seq_idx": { + "name": "copilot_messages_chat_seq_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "seq", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_messages\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_messages_chat_stream_idx": { + "name": "copilot_messages_chat_stream_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "stream_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_messages\".\"stream_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_messages_user_created_at_idx": { + "name": "copilot_messages_user_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_messages\".\"role\" = 'user' AND \"copilot_messages\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_messages_chat_id_copilot_chats_id_fk": { + "name": "copilot_messages_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_messages", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_run_checkpoints": { + "name": "copilot_run_checkpoints", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "pending_tool_call_id": { + "name": "pending_tool_call_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "conversation_snapshot": { + "name": "conversation_snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "agent_state": { + "name": "agent_state", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "provider_request": { + "name": "provider_request", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "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": { + "copilot_run_checkpoints_run_id_idx": { + "name": "copilot_run_checkpoints_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_run_checkpoints_pending_tool_call_id_idx": { + "name": "copilot_run_checkpoints_pending_tool_call_id_idx", + "columns": [ + { + "expression": "pending_tool_call_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_run_checkpoints_run_pending_tool_unique": { + "name": "copilot_run_checkpoints_run_pending_tool_unique", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pending_tool_call_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_run_checkpoints_run_id_copilot_runs_id_fk": { + "name": "copilot_run_checkpoints_run_id_copilot_runs_id_fk", + "tableFrom": "copilot_run_checkpoints", + "tableTo": "copilot_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_runs": { + "name": "copilot_runs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_run_id": { + "name": "parent_run_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stream_id": { + "name": "stream_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent": { + "name": "agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "copilot_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "request_context": { + "name": "request_context", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "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()" + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "copilot_runs_execution_id_idx": { + "name": "copilot_runs_execution_id_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_parent_run_id_idx": { + "name": "copilot_runs_parent_run_id_idx", + "columns": [ + { + "expression": "parent_run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_chat_id_idx": { + "name": "copilot_runs_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_user_id_idx": { + "name": "copilot_runs_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_workflow_id_idx": { + "name": "copilot_runs_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_workspace_id_idx": { + "name": "copilot_runs_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_status_idx": { + "name": "copilot_runs_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_chat_execution_idx": { + "name": "copilot_runs_chat_execution_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_execution_started_at_idx": { + "name": "copilot_runs_execution_started_at_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_workspace_completed_at_id_idx": { + "name": "copilot_runs_workspace_completed_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"completed_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_stream_id_unique": { + "name": "copilot_runs_stream_id_unique", + "columns": [ + { + "expression": "stream_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_runs_chat_id_copilot_chats_id_fk": { + "name": "copilot_runs_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_runs", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_runs_user_id_user_id_fk": { + "name": "copilot_runs_user_id_user_id_fk", + "tableFrom": "copilot_runs", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_runs_workflow_id_workflow_id_fk": { + "name": "copilot_runs_workflow_id_workflow_id_fk", + "tableFrom": "copilot_runs", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_runs_workspace_id_workspace_id_fk": { + "name": "copilot_runs_workspace_id_workspace_id_fk", + "tableFrom": "copilot_runs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_workflow_read_hashes": { + "name": "copilot_workflow_read_hashes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hash": { + "name": "hash", + "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": { + "copilot_workflow_read_hashes_chat_id_idx": { + "name": "copilot_workflow_read_hashes_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_workflow_read_hashes_workflow_id_idx": { + "name": "copilot_workflow_read_hashes_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_workflow_read_hashes_chat_workflow_unique": { + "name": "copilot_workflow_read_hashes_chat_workflow_unique", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_workflow_read_hashes_chat_id_copilot_chats_id_fk": { + "name": "copilot_workflow_read_hashes_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_workflow_read_hashes", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_workflow_read_hashes_workflow_id_workflow_id_fk": { + "name": "copilot_workflow_read_hashes_workflow_id_workflow_id_fk", + "tableFrom": "copilot_workflow_read_hashes", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credential": { + "name": "credential", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "credential_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env_key": { + "name": "env_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env_owner_user_id": { + "name": "env_owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "encrypted_service_account_key": { + "name": "encrypted_service_account_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "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": { + "credential_workspace_id_idx": { + "name": "credential_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_type_idx": { + "name": "credential_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_provider_id_idx": { + "name": "credential_provider_id_idx", + "columns": [ + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_account_id_idx": { + "name": "credential_account_id_idx", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_env_owner_user_id_idx": { + "name": "credential_env_owner_user_id_idx", + "columns": [ + { + "expression": "env_owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_account_unique": { + "name": "credential_workspace_account_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "account_id IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_env_unique": { + "name": "credential_workspace_env_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "env_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "type = 'env_workspace'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_personal_env_unique": { + "name": "credential_workspace_personal_env_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "env_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "env_owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "type = 'env_personal'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_workspace_id_workspace_id_fk": { + "name": "credential_workspace_id_workspace_id_fk", + "tableFrom": "credential", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_account_id_account_id_fk": { + "name": "credential_account_id_account_id_fk", + "tableFrom": "credential", + "tableTo": "account", + "columnsFrom": ["account_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_env_owner_user_id_user_id_fk": { + "name": "credential_env_owner_user_id_user_id_fk", + "tableFrom": "credential", + "tableTo": "user", + "columnsFrom": ["env_owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_created_by_user_id_fk": { + "name": "credential_created_by_user_id_fk", + "tableFrom": "credential", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "credential_oauth_source_check": { + "name": "credential_oauth_source_check", + "value": "(type <> 'oauth') OR (account_id IS NOT NULL AND provider_id IS NOT NULL)" + }, + "credential_workspace_env_source_check": { + "name": "credential_workspace_env_source_check", + "value": "(type <> 'env_workspace') OR (env_key IS NOT NULL AND env_owner_user_id IS NULL)" + }, + "credential_personal_env_source_check": { + "name": "credential_personal_env_source_check", + "value": "(type <> 'env_personal') OR (env_key IS NOT NULL AND env_owner_user_id IS NOT NULL)" + } + }, + "isRLSEnabled": false + }, + "public.credential_member": { + "name": "credential_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "credential_member_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "status": { + "name": "status", + "type": "credential_member_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "joined_at": { + "name": "joined_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "invited_by": { + "name": "invited_by", + "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_member_user_id_idx": { + "name": "credential_member_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_member_role_idx": { + "name": "credential_member_role_idx", + "columns": [ + { + "expression": "role", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_member_status_idx": { + "name": "credential_member_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_member_unique": { + "name": "credential_member_unique", + "columns": [ + { + "expression": "credential_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_member_credential_id_credential_id_fk": { + "name": "credential_member_credential_id_credential_id_fk", + "tableFrom": "credential_member", + "tableTo": "credential", + "columnsFrom": ["credential_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_member_user_id_user_id_fk": { + "name": "credential_member_user_id_user_id_fk", + "tableFrom": "credential_member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_member_invited_by_user_id_fk": { + "name": "credential_member_invited_by_user_id_fk", + "tableFrom": "credential_member", + "tableTo": "user", + "columnsFrom": ["invited_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_block": { + "name": "custom_block", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "outputs": { + "name": "outputs", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_by": { + "name": "created_by", + "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": { + "custom_block_organization_id_idx": { + "name": "custom_block_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "custom_block_workflow_id_idx": { + "name": "custom_block_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "custom_block_organization_type_unique": { + "name": "custom_block_organization_type_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "custom_block_organization_id_organization_id_fk": { + "name": "custom_block_organization_id_organization_id_fk", + "tableFrom": "custom_block", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "custom_block_workflow_id_workflow_id_fk": { + "name": "custom_block_workflow_id_workflow_id_fk", + "tableFrom": "custom_block", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "custom_block_created_by_user_id_fk": { + "name": "custom_block_created_by_user_id_fk", + "tableFrom": "custom_block", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_tools": { + "name": "custom_tools", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "schema": { + "name": "schema", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "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": { + "custom_tools_workspace_id_idx": { + "name": "custom_tools_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "custom_tools_workspace_title_unique": { + "name": "custom_tools_workspace_title_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "title", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "custom_tools_workspace_id_workspace_id_fk": { + "name": "custom_tools_workspace_id_workspace_id_fk", + "tableFrom": "custom_tools", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "custom_tools_user_id_user_id_fk": { + "name": "custom_tools_user_id_user_id_fk", + "tableFrom": "custom_tools", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.data_drain_runs": { + "name": "data_drain_runs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "drain_id": { + "name": "drain_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "data_drain_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "trigger": { + "name": "trigger", + "type": "data_drain_run_trigger", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "finished_at": { + "name": "finished_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "rows_exported": { + "name": "rows_exported", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "bytes_written": { + "name": "bytes_written", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "cursor_before": { + "name": "cursor_before", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cursor_after": { + "name": "cursor_after", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "locators": { + "name": "locators", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + } + }, + "indexes": { + "data_drain_runs_drain_started_idx": { + "name": "data_drain_runs_drain_started_idx", + "columns": [ + { + "expression": "drain_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "data_drain_runs_drain_id_data_drains_id_fk": { + "name": "data_drain_runs_drain_id_data_drains_id_fk", + "tableFrom": "data_drain_runs", + "tableTo": "data_drains", + "columnsFrom": ["drain_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.data_drains": { + "name": "data_drains", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "data_drain_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "destination_type": { + "name": "destination_type", + "type": "data_drain_destination", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "destination_config": { + "name": "destination_config", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "destination_credentials": { + "name": "destination_credentials", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "schedule_cadence": { + "name": "schedule_cadence", + "type": "data_drain_cadence", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "cursor": { + "name": "cursor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_success_at": { + "name": "last_success_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "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": { + "data_drains_org_idx": { + "name": "data_drains_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "data_drains_due_idx": { + "name": "data_drains_due_idx", + "columns": [ + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "data_drains_org_name_unique": { + "name": "data_drains_org_name_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "data_drains_organization_id_organization_id_fk": { + "name": "data_drains_organization_id_organization_id_fk", + "tableFrom": "data_drains", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "data_drains_created_by_user_id_fk": { + "name": "data_drains_created_by_user_id_fk", + "tableFrom": "data_drains", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.docs_embeddings": { + "name": "docs_embeddings", + "schema": "", + "columns": { + "chunk_id": { + "name": "chunk_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "chunk_text": { + "name": "chunk_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_document": { + "name": "source_document", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_link": { + "name": "source_link", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_text": { + "name": "header_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_level": { + "name": "header_level", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "embedding": { + "name": "embedding", + "type": "vector(1536)", + "primaryKey": false, + "notNull": true + }, + "embedding_model": { + "name": "embedding_model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text-embedding-3-small'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "chunk_text_tsv": { + "name": "chunk_text_tsv", + "type": "tsvector", + "primaryKey": false, + "notNull": false, + "generated": { + "as": "to_tsvector('english', \"docs_embeddings\".\"chunk_text\")", + "type": "stored" + } + }, + "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": { + "docs_emb_source_document_idx": { + "name": "docs_emb_source_document_idx", + "columns": [ + { + "expression": "source_document", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_header_level_idx": { + "name": "docs_emb_header_level_idx", + "columns": [ + { + "expression": "header_level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_source_header_idx": { + "name": "docs_emb_source_header_idx", + "columns": [ + { + "expression": "source_document", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "header_level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_model_idx": { + "name": "docs_emb_model_idx", + "columns": [ + { + "expression": "embedding_model", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_created_at_idx": { + "name": "docs_emb_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_embedding_vector_hnsw_idx": { + "name": "docs_embedding_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "docs_emb_metadata_gin_idx": { + "name": "docs_emb_metadata_gin_idx", + "columns": [ + { + "expression": "metadata", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "docs_emb_chunk_text_fts_idx": { + "name": "docs_emb_chunk_text_fts_idx", + "columns": [ + { + "expression": "chunk_text_tsv", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "docs_embedding_not_null_check": { + "name": "docs_embedding_not_null_check", + "value": "\"embedding\" IS NOT NULL" + }, + "docs_header_level_check": { + "name": "docs_header_level_check", + "value": "\"header_level\" >= 1 AND \"header_level\" <= 6" + } + }, + "isRLSEnabled": false + }, + "public.document": { + "name": "document", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_url": { + "name": "file_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chunk_count": { + "name": "chunk_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "character_count": { + "name": "character_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "processing_status": { + "name": "processing_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "processing_started_at": { + "name": "processing_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_completed_at": { + "name": "processing_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_error": { + "name": "processing_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "user_excluded": { + "name": "user_excluded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "tag1": { + "name": "tag1", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag2": { + "name": "tag2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag3": { + "name": "tag3", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag4": { + "name": "tag4", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag5": { + "name": "tag5", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag6": { + "name": "tag6", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag7": { + "name": "tag7", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "number1": { + "name": "number1", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number2": { + "name": "number2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number3": { + "name": "number3", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number4": { + "name": "number4", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number5": { + "name": "number5", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "date1": { + "name": "date1", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "date2": { + "name": "date2", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "boolean1": { + "name": "boolean1", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean2": { + "name": "boolean2", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean3": { + "name": "boolean3", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_url": { + "name": "source_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "doc_kb_id_idx": { + "name": "doc_kb_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_filename_idx": { + "name": "doc_filename_idx", + "columns": [ + { + "expression": "filename", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_processing_status_idx": { + "name": "doc_processing_status_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "processing_status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_connector_external_id_idx": { + "name": "doc_connector_external_id_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"document\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_connector_id_idx": { + "name": "doc_connector_id_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_storage_key_idx": { + "name": "doc_storage_key_idx", + "columns": [ + { + "expression": "storage_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"storage_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_archived_at_partial_idx": { + "name": "doc_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_deleted_at_partial_idx": { + "name": "doc_deleted_at_partial_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag1_idx": { + "name": "doc_tag1_idx", + "columns": [ + { + "expression": "tag1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag2_idx": { + "name": "doc_tag2_idx", + "columns": [ + { + "expression": "tag2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag3_idx": { + "name": "doc_tag3_idx", + "columns": [ + { + "expression": "tag3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag4_idx": { + "name": "doc_tag4_idx", + "columns": [ + { + "expression": "tag4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag5_idx": { + "name": "doc_tag5_idx", + "columns": [ + { + "expression": "tag5", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag6_idx": { + "name": "doc_tag6_idx", + "columns": [ + { + "expression": "tag6", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag7_idx": { + "name": "doc_tag7_idx", + "columns": [ + { + "expression": "tag7", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number1_idx": { + "name": "doc_number1_idx", + "columns": [ + { + "expression": "number1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number2_idx": { + "name": "doc_number2_idx", + "columns": [ + { + "expression": "number2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number3_idx": { + "name": "doc_number3_idx", + "columns": [ + { + "expression": "number3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number4_idx": { + "name": "doc_number4_idx", + "columns": [ + { + "expression": "number4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number5_idx": { + "name": "doc_number5_idx", + "columns": [ + { + "expression": "number5", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_date1_idx": { + "name": "doc_date1_idx", + "columns": [ + { + "expression": "date1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_date2_idx": { + "name": "doc_date2_idx", + "columns": [ + { + "expression": "date2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_boolean1_idx": { + "name": "doc_boolean1_idx", + "columns": [ + { + "expression": "boolean1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_boolean2_idx": { + "name": "doc_boolean2_idx", + "columns": [ + { + "expression": "boolean2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_boolean3_idx": { + "name": "doc_boolean3_idx", + "columns": [ + { + "expression": "boolean3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "document_knowledge_base_id_knowledge_base_id_fk": { + "name": "document_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "document", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "document_connector_id_knowledge_connector_id_fk": { + "name": "document_connector_id_knowledge_connector_id_fk", + "tableFrom": "document", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "document_uploaded_by_user_id_fk": { + "name": "document_uploaded_by_user_id_fk", + "tableFrom": "document", + "tableTo": "user", + "columnsFrom": ["uploaded_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.embedding": { + "name": "embedding", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "document_id": { + "name": "document_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chunk_index": { + "name": "chunk_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "chunk_hash": { + "name": "chunk_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content_length": { + "name": "content_length", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "embedding": { + "name": "embedding", + "type": "vector(1536)", + "primaryKey": false, + "notNull": false + }, + "embedding_model": { + "name": "embedding_model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text-embedding-3-small'" + }, + "start_offset": { + "name": "start_offset", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "end_offset": { + "name": "end_offset", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "tag1": { + "name": "tag1", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag2": { + "name": "tag2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag3": { + "name": "tag3", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag4": { + "name": "tag4", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag5": { + "name": "tag5", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag6": { + "name": "tag6", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag7": { + "name": "tag7", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "number1": { + "name": "number1", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number2": { + "name": "number2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number3": { + "name": "number3", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number4": { + "name": "number4", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number5": { + "name": "number5", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "date1": { + "name": "date1", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "date2": { + "name": "date2", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "boolean1": { + "name": "boolean1", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean2": { + "name": "boolean2", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean3": { + "name": "boolean3", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "content_tsv": { + "name": "content_tsv", + "type": "tsvector", + "primaryKey": false, + "notNull": false, + "generated": { + "as": "to_tsvector('english', \"embedding\".\"content\")", + "type": "stored" + } + }, + "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": { + "emb_kb_id_idx": { + "name": "emb_kb_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_doc_id_idx": { + "name": "emb_doc_id_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_doc_chunk_idx": { + "name": "emb_doc_chunk_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chunk_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_model_idx": { + "name": "emb_kb_model_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "embedding_model", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_enabled_idx": { + "name": "emb_kb_enabled_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_doc_enabled_idx": { + "name": "emb_doc_enabled_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "embedding_vector_hnsw_idx": { + "name": "embedding_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "emb_tag1_idx": { + "name": "emb_tag1_idx", + "columns": [ + { + "expression": "tag1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_tag2_idx": { + "name": "emb_tag2_idx", + "columns": [ + { + "expression": "tag2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_tag3_idx": { + "name": "emb_tag3_idx", + "columns": [ + { + "expression": "tag3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_tag4_idx": { + "name": "emb_tag4_idx", + "columns": [ + { + "expression": "tag4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_tag5_idx": { + "name": "emb_tag5_idx", + "columns": [ + { + "expression": "tag5", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_tag6_idx": { + "name": "emb_tag6_idx", + "columns": [ + { + "expression": "tag6", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_tag7_idx": { + "name": "emb_tag7_idx", + "columns": [ + { + "expression": "tag7", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number1_idx": { + "name": "emb_number1_idx", + "columns": [ + { + "expression": "number1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number2_idx": { + "name": "emb_number2_idx", + "columns": [ + { + "expression": "number2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number3_idx": { + "name": "emb_number3_idx", + "columns": [ + { + "expression": "number3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number4_idx": { + "name": "emb_number4_idx", + "columns": [ + { + "expression": "number4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number5_idx": { + "name": "emb_number5_idx", + "columns": [ + { + "expression": "number5", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_date1_idx": { + "name": "emb_date1_idx", + "columns": [ + { + "expression": "date1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_date2_idx": { + "name": "emb_date2_idx", + "columns": [ + { + "expression": "date2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_boolean1_idx": { + "name": "emb_boolean1_idx", + "columns": [ + { + "expression": "boolean1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_boolean2_idx": { + "name": "emb_boolean2_idx", + "columns": [ + { + "expression": "boolean2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_boolean3_idx": { + "name": "emb_boolean3_idx", + "columns": [ + { + "expression": "boolean3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_content_fts_idx": { + "name": "emb_content_fts_idx", + "columns": [ + { + "expression": "content_tsv", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": { + "embedding_knowledge_base_id_knowledge_base_id_fk": { + "name": "embedding_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "embedding", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "embedding_document_id_document_id_fk": { + "name": "embedding_document_id_document_id_fk", + "tableFrom": "embedding", + "tableTo": "document", + "columnsFrom": ["document_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "embedding_not_null_check": { + "name": "embedding_not_null_check", + "value": "\"embedding\" IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.environment": { + "name": "environment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "environment_user_id_user_id_fk": { + "name": "environment_user_id_user_id_fk", + "tableFrom": "environment", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "environment_user_id_unique": { + "name": "environment_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.execution_large_value_dependencies": { + "name": "execution_large_value_dependencies", + "schema": "", + "columns": { + "parent_key": { + "name": "parent_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "child_key": { + "name": "child_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "execution_large_value_dependencies_workspace_parent_key_idx": { + "name": "execution_large_value_dependencies_workspace_parent_key_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_value_dependencies_workspace_child_key_idx": { + "name": "execution_large_value_dependencies_workspace_child_key_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "child_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "execution_large_value_dependencies_workspace_id_workspace_id_fk": { + "name": "execution_large_value_dependencies_workspace_id_workspace_id_fk", + "tableFrom": "execution_large_value_dependencies", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "execution_large_value_dependencies_parent_key_child_key_pk": { + "name": "execution_large_value_dependencies_parent_key_child_key_pk", + "columns": ["parent_key", "child_key"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.execution_large_value_references": { + "name": "execution_large_value_references", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "execution_large_value_reference_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "execution_large_value_references_workspace_execution_source_idx": { + "name": "execution_large_value_references_workspace_execution_source_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "execution_large_value_references_workspace_id_workspace_id_fk": { + "name": "execution_large_value_references_workspace_id_workspace_id_fk", + "tableFrom": "execution_large_value_references", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "execution_large_value_references_workflow_id_workflow_id_fk": { + "name": "execution_large_value_references_workflow_id_workflow_id_fk", + "tableFrom": "execution_large_value_references", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "execution_large_value_references_key_execution_id_source_pk": { + "name": "execution_large_value_references_key_execution_id_source_pk", + "columns": ["key", "execution_id", "source"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.execution_large_values": { + "name": "execution_large_values", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_execution_id": { + "name": "owner_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "execution_large_values_owner_execution_id_idx": { + "name": "execution_large_values_owner_execution_id_idx", + "columns": [ + { + "expression": "owner_execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_values_cleanup_idx": { + "name": "execution_large_values_cleanup_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"execution_large_values\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_values_tombstone_cleanup_idx": { + "name": "execution_large_values_tombstone_cleanup_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"execution_large_values\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "execution_large_values_workspace_id_workspace_id_fk": { + "name": "execution_large_values_workspace_id_workspace_id_fk", + "tableFrom": "execution_large_values", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "execution_large_values_workflow_id_workflow_id_fk": { + "name": "execution_large_values_workflow_id_workflow_id_fk", + "tableFrom": "execution_large_values", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.idempotency_key": { + "name": "idempotency_key", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "result": { + "name": "result", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idempotency_key_created_at_idx": { + "name": "idempotency_key_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.invitation": { + "name": "invitation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "invitation_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'organization'" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "membership_intent": { + "name": "membership_intent", + "type": "invitation_membership_intent", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'internal'" + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "invitation_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "token": { + "name": "token", + "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": { + "invitation_email_idx": { + "name": "invitation_email_idx", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_organization_id_idx": { + "name": "invitation_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_status_idx": { + "name": "invitation_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_pending_email_org_unique": { + "name": "invitation_pending_email_org_unique", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"invitation\".\"status\" = 'pending' AND \"invitation\".\"organization_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "invitation_inviter_id_user_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "tableTo": "user", + "columnsFrom": ["inviter_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "invitation_token_unique": { + "name": "invitation_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invitation_workspace_grant": { + "name": "invitation_workspace_grant", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "invitation_id": { + "name": "invitation_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission": { + "name": "permission", + "type": "permission_type", + "typeSchema": "public", + "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": { + "invitation_workspace_grant_unique": { + "name": "invitation_workspace_grant_unique", + "columns": [ + { + "expression": "invitation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_workspace_grant_workspace_id_idx": { + "name": "invitation_workspace_grant_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "invitation_workspace_grant_invitation_id_invitation_id_fk": { + "name": "invitation_workspace_grant_invitation_id_invitation_id_fk", + "tableFrom": "invitation_workspace_grant", + "tableTo": "invitation", + "columnsFrom": ["invitation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_workspace_grant_workspace_id_workspace_id_fk": { + "name": "invitation_workspace_grant_workspace_id_workspace_id_fk", + "tableFrom": "invitation_workspace_grant", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.job_execution_logs": { + "name": "job_execution_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule_id": { + "name": "schedule_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "trigger": { + "name": "trigger", + "type": "text", + "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 + }, + "total_duration_ms": { + "name": "total_duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "execution_data": { + "name": "execution_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "cost": { + "name": "cost", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "job_execution_logs_schedule_id_idx": { + "name": "job_execution_logs_schedule_id_idx", + "columns": [ + { + "expression": "schedule_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_workspace_started_at_idx": { + "name": "job_execution_logs_workspace_started_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_workspace_ended_at_id_idx": { + "name": "job_execution_logs_workspace_ended_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"ended_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_execution_id_unique": { + "name": "job_execution_logs_execution_id_unique", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_trigger_idx": { + "name": "job_execution_logs_trigger_idx", + "columns": [ + { + "expression": "trigger", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "job_execution_logs_schedule_id_workflow_schedule_id_fk": { + "name": "job_execution_logs_schedule_id_workflow_schedule_id_fk", + "tableFrom": "job_execution_logs", + "tableTo": "workflow_schedule", + "columnsFrom": ["schedule_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "job_execution_logs_workspace_id_workspace_id_fk": { + "name": "job_execution_logs_workspace_id_workspace_id_fk", + "tableFrom": "job_execution_logs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_base": { + "name": "knowledge_base", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_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 + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "embedding_model": { + "name": "embedding_model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text-embedding-3-small'" + }, + "embedding_dimension": { + "name": "embedding_dimension", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1536 + }, + "chunking_config": { + "name": "chunking_config", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{\"maxSize\": 1024, \"minSize\": 1, \"overlap\": 200}'" + }, + "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": { + "kb_user_id_idx": { + "name": "kb_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_workspace_id_idx": { + "name": "kb_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_user_workspace_idx": { + "name": "kb_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_deleted_at_idx": { + "name": "kb_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_workspace_deleted_partial_idx": { + "name": "kb_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_base\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_workspace_name_active_unique": { + "name": "kb_workspace_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"knowledge_base\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_base_user_id_user_id_fk": { + "name": "knowledge_base_user_id_user_id_fk", + "tableFrom": "knowledge_base", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_base_workspace_id_workspace_id_fk": { + "name": "knowledge_base_workspace_id_workspace_id_fk", + "tableFrom": "knowledge_base", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_base_tag_definitions": { + "name": "knowledge_base_tag_definitions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tag_slot": { + "name": "tag_slot", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "field_type": { + "name": "field_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text'" + }, + "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": { + "kb_tag_definitions_kb_slot_idx": { + "name": "kb_tag_definitions_kb_slot_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tag_slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_tag_definitions_kb_display_name_idx": { + "name": "kb_tag_definitions_kb_display_name_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "display_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_tag_definitions_kb_id_idx": { + "name": "kb_tag_definitions_kb_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_base_tag_definitions_knowledge_base_id_knowledge_base_id_fk": { + "name": "knowledge_base_tag_definitions_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "knowledge_base_tag_definitions", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_connector": { + "name": "knowledge_connector", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connector_type": { + "name": "connector_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_config": { + "name": "source_config", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "sync_mode": { + "name": "sync_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'full'" + }, + "sync_interval_minutes": { + "name": "sync_interval_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1440 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "last_sync_at": { + "name": "last_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_sync_error": { + "name": "last_sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_sync_doc_count": { + "name": "last_sync_doc_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "next_sync_at": { + "name": "next_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "consecutive_failures": { + "name": "consecutive_failures", + "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()" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "kc_knowledge_base_id_idx": { + "name": "kc_knowledge_base_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_status_next_sync_idx": { + "name": "kc_status_next_sync_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_sync_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_archived_at_partial_idx": { + "name": "kc_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_deleted_at_partial_idx": { + "name": "kc_deleted_at_partial_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_connector_knowledge_base_id_knowledge_base_id_fk": { + "name": "knowledge_connector_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "knowledge_connector", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_connector_sync_log": { + "name": "knowledge_connector_sync_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "docs_added": { + "name": "docs_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_updated": { + "name": "docs_updated", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_deleted": { + "name": "docs_deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_unchanged": { + "name": "docs_unchanged", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_failed": { + "name": "docs_failed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "kcsl_connector_id_idx": { + "name": "kcsl_connector_id_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_connector_sync_log_connector_id_knowledge_connector_id_fk": { + "name": "knowledge_connector_sync_log_connector_id_knowledge_connector_id_fk", + "tableFrom": "knowledge_connector_sync_log", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.managed_agent_connection": { + "name": "managed_agent_connection", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_verified_at": { + "name": "last_verified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_verification_error": { + "name": "last_verification_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": { + "managed_agent_connection_workspace_id_idx": { + "name": "managed_agent_connection_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "managed_agent_connection_workspace_name_unique": { + "name": "managed_agent_connection_workspace_name_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "managed_agent_connection_workspace_id_workspace_id_fk": { + "name": "managed_agent_connection_workspace_id_workspace_id_fk", + "tableFrom": "managed_agent_connection", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "managed_agent_connection_user_id_user_id_fk": { + "name": "managed_agent_connection_user_id_user_id_fk", + "tableFrom": "managed_agent_connection", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mcp_server_oauth": { + "name": "mcp_server_oauth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "mcp_server_id": { + "name": "mcp_server_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_information": { + "name": "client_information", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tokens": { + "name": "tokens", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "code_verifier": { + "name": "code_verifier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state_created_at": { + "name": "state_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_refreshed_at": { + "name": "last_refreshed_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": { + "mcp_server_oauth_server_unique": { + "name": "mcp_server_oauth_server_unique", + "columns": [ + { + "expression": "mcp_server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_server_oauth_state_idx": { + "name": "mcp_server_oauth_state_idx", + "columns": [ + { + "expression": "state", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mcp_server_oauth_mcp_server_id_mcp_servers_id_fk": { + "name": "mcp_server_oauth_mcp_server_id_mcp_servers_id_fk", + "tableFrom": "mcp_server_oauth", + "tableTo": "mcp_servers", + "columnsFrom": ["mcp_server_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mcp_server_oauth_user_id_user_id_fk": { + "name": "mcp_server_oauth_user_id_user_id_fk", + "tableFrom": "mcp_server_oauth", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "mcp_server_oauth_workspace_id_workspace_id_fk": { + "name": "mcp_server_oauth_workspace_id_workspace_id_fk", + "tableFrom": "mcp_server_oauth", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mcp_servers": { + "name": "mcp_servers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "transport": { + "name": "transport", + "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": "'headers'" + }, + "oauth_client_id": { + "name": "oauth_client_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_client_secret": { + "name": "oauth_client_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "headers": { + "name": "headers", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "timeout": { + "name": "timeout", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 30000 + }, + "retries": { + "name": "retries", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_connected": { + "name": "last_connected", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "connection_status": { + "name": "connection_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'disconnected'" + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status_config": { + "name": "status_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "tool_count": { + "name": "tool_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_tools_refresh": { + "name": "last_tools_refresh", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_requests": { + "name": "total_requests", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_used": { + "name": "last_used", + "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": { + "mcp_servers_workspace_enabled_idx": { + "name": "mcp_servers_workspace_enabled_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_servers_workspace_deleted_partial_idx": { + "name": "mcp_servers_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"mcp_servers\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mcp_servers_workspace_id_workspace_id_fk": { + "name": "mcp_servers_workspace_id_workspace_id_fk", + "tableFrom": "mcp_servers", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mcp_servers_created_by_user_id_fk": { + "name": "mcp_servers_created_by_user_id_fk", + "tableFrom": "mcp_servers", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.member": { + "name": "member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "member_user_id_unique": { + "name": "member_user_id_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "member_organization_id_idx": { + "name": "member_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.memory": { + "name": "memory", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "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()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "memory_key_idx": { + "name": "memory_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "memory_workspace_idx": { + "name": "memory_workspace_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "memory_workspace_key_idx": { + "name": "memory_workspace_key_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "memory_workspace_deleted_partial_idx": { + "name": "memory_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"memory\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "memory_workspace_id_workspace_id_fk": { + "name": "memory_workspace_id_workspace_id_fk", + "tableFrom": "memory", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_inbox_allowed_sender": { + "name": "mothership_inbox_allowed_sender", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "added_by": { + "name": "added_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "inbox_sender_ws_email_idx": { + "name": "inbox_sender_ws_email_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mothership_inbox_allowed_sender_workspace_id_workspace_id_fk": { + "name": "mothership_inbox_allowed_sender_workspace_id_workspace_id_fk", + "tableFrom": "mothership_inbox_allowed_sender", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mothership_inbox_allowed_sender_added_by_user_id_fk": { + "name": "mothership_inbox_allowed_sender_added_by_user_id_fk", + "tableFrom": "mothership_inbox_allowed_sender", + "tableTo": "user", + "columnsFrom": ["added_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_inbox_task": { + "name": "mothership_inbox_task", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "from_email": { + "name": "from_email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "from_name": { + "name": "from_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subject": { + "name": "subject", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "body_preview": { + "name": "body_preview", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "body_text": { + "name": "body_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "body_html": { + "name": "body_html", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_message_id": { + "name": "email_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "in_reply_to": { + "name": "in_reply_to", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "response_message_id": { + "name": "response_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agentmail_message_id": { + "name": "agentmail_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'received'" + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "trigger_job_id": { + "name": "trigger_job_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "result_summary": { + "name": "result_summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "rejection_reason": { + "name": "rejection_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "has_attachments": { + "name": "has_attachments", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cc_recipients": { + "name": "cc_recipients", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "processing_started_at": { + "name": "processing_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "inbox_task_ws_created_at_idx": { + "name": "inbox_task_ws_created_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_task_ws_status_idx": { + "name": "inbox_task_ws_status_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_task_response_msg_id_idx": { + "name": "inbox_task_response_msg_id_idx", + "columns": [ + { + "expression": "response_message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_task_email_msg_id_idx": { + "name": "inbox_task_email_msg_id_idx", + "columns": [ + { + "expression": "email_message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mothership_inbox_task_workspace_id_workspace_id_fk": { + "name": "mothership_inbox_task_workspace_id_workspace_id_fk", + "tableFrom": "mothership_inbox_task", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mothership_inbox_task_chat_id_copilot_chats_id_fk": { + "name": "mothership_inbox_task_chat_id_copilot_chats_id_fk", + "tableFrom": "mothership_inbox_task", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_inbox_webhook": { + "name": "mothership_inbox_webhook", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "webhook_id": { + "name": "webhook_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "mothership_inbox_webhook_workspace_id_workspace_id_fk": { + "name": "mothership_inbox_webhook_workspace_id_workspace_id_fk", + "tableFrom": "mothership_inbox_webhook", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mothership_inbox_webhook_workspace_id_unique": { + "name": "mothership_inbox_webhook_workspace_id_unique", + "nullsNotDistinct": false, + "columns": ["workspace_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_settings": { + "name": "mothership_settings", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "mcp_tool_refs": { + "name": "mcp_tool_refs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "custom_tool_refs": { + "name": "custom_tool_refs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "skill_refs": { + "name": "skill_refs", + "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": { + "mothership_settings_workspace_id_idx": { + "name": "mothership_settings_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mothership_settings_workspace_id_workspace_id_fk": { + "name": "mothership_settings_workspace_id_workspace_id_fk", + "tableFrom": "mothership_settings", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization": { + "name": "organization", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "whitelabel_settings": { + "name": "whitelabel_settings", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "data_retention_settings": { + "name": "data_retention_settings", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "org_usage_limit": { + "name": "org_usage_limit", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "storage_used_bytes": { + "name": "storage_used_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "limit_notifications": { + "name": "limit_notifications", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "departed_member_usage": { + "name": "departed_member_usage", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "credit_balance": { + "name": "credit_balance", + "type": "numeric", + "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": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_member_usage_limit": { + "name": "organization_member_usage_limit", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "usage_limit": { + "name": "usage_limit", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "set_by": { + "name": "set_by", + "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": { + "org_member_usage_limit_org_user_unique": { + "name": "org_member_usage_limit_org_user_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "org_member_usage_limit_organization_id_idx": { + "name": "org_member_usage_limit_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "organization_member_usage_limit_organization_id_organization_id_fk": { + "name": "organization_member_usage_limit_organization_id_organization_id_fk", + "tableFrom": "organization_member_usage_limit", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_member_usage_limit_user_id_user_id_fk": { + "name": "organization_member_usage_limit_user_id_user_id_fk", + "tableFrom": "organization_member_usage_limit", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_member_usage_limit_set_by_user_id_fk": { + "name": "organization_member_usage_limit_set_by_user_id_fk", + "tableFrom": "organization_member_usage_limit", + "tableTo": "user", + "columnsFrom": ["set_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.outbox_event": { + "name": "outbox_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "max_attempts": { + "name": "max_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 10 + }, + "available_at": { + "name": "available_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "locked_at": { + "name": "locked_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()" + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "outbox_event_status_available_idx": { + "name": "outbox_event_status_available_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "available_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "outbox_event_locked_at_idx": { + "name": "outbox_event_locked_at_idx", + "columns": [ + { + "expression": "locked_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "outbox_event_type_created_idx": { + "name": "outbox_event_type_created_idx", + "columns": [ + { + "expression": "event_type", + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.paused_executions": { + "name": "paused_executions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_snapshot": { + "name": "execution_snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "pause_points": { + "name": "pause_points", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "total_pause_count": { + "name": "total_pause_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "resumed_count": { + "name": "resumed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "automatic_resume_retry_count": { + "name": "automatic_resume_retry_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'paused'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "paused_at": { + "name": "paused_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "next_resume_at": { + "name": "next_resume_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "paused_executions_workflow_id_idx": { + "name": "paused_executions_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "paused_executions_status_idx": { + "name": "paused_executions_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "paused_executions_execution_id_unique": { + "name": "paused_executions_execution_id_unique", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "paused_executions_next_resume_at_idx": { + "name": "paused_executions_next_resume_at_idx", + "columns": [ + { + "expression": "next_resume_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "status = 'paused' AND next_resume_at IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "paused_executions_workflow_id_workflow_id_fk": { + "name": "paused_executions_workflow_id_workflow_id_fk", + "tableFrom": "paused_executions", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pending_credential_draft": { + "name": "pending_credential_draft", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credential_id": { + "name": "credential_id", + "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()" + } + }, + "indexes": { + "pending_draft_user_provider_ws": { + "name": "pending_draft_user_provider_ws", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pending_credential_draft_user_id_user_id_fk": { + "name": "pending_credential_draft_user_id_user_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pending_credential_draft_workspace_id_workspace_id_fk": { + "name": "pending_credential_draft_workspace_id_workspace_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pending_credential_draft_credential_id_credential_id_fk": { + "name": "pending_credential_draft_credential_id_credential_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "credential", + "columnsFrom": ["credential_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permission_group": { + "name": "permission_group", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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, + "default": "'{}'" + }, + "created_by": { + "name": "created_by", + "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()" + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "permission_group_created_by_idx": { + "name": "permission_group_created_by_idx", + "columns": [ + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_organization_name_unique": { + "name": "permission_group_organization_name_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_organization_default_unique": { + "name": "permission_group_organization_default_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "is_default = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permission_group_organization_id_organization_id_fk": { + "name": "permission_group_organization_id_organization_id_fk", + "tableFrom": "permission_group", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_created_by_user_id_fk": { + "name": "permission_group_created_by_user_id_fk", + "tableFrom": "permission_group", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permission_group_member": { + "name": "permission_group_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "permission_group_id": { + "name": "permission_group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "assigned_by": { + "name": "assigned_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "permission_group_member_group_id_idx": { + "name": "permission_group_member_group_id_idx", + "columns": [ + { + "expression": "permission_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_member_group_user_unique": { + "name": "permission_group_member_group_user_unique", + "columns": [ + { + "expression": "permission_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_member_organization_user_idx": { + "name": "permission_group_member_organization_user_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permission_group_member_permission_group_id_permission_group_id_fk": { + "name": "permission_group_member_permission_group_id_permission_group_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "permission_group", + "columnsFrom": ["permission_group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_member_organization_id_organization_id_fk": { + "name": "permission_group_member_organization_id_organization_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_member_user_id_user_id_fk": { + "name": "permission_group_member_user_id_user_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_member_assigned_by_user_id_fk": { + "name": "permission_group_member_assigned_by_user_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "user", + "columnsFrom": ["assigned_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permission_group_workspace": { + "name": "permission_group_workspace", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "permission_group_id": { + "name": "permission_group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "permission_group_workspace_workspace_id_idx": { + "name": "permission_group_workspace_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_workspace_group_workspace_unique": { + "name": "permission_group_workspace_group_workspace_unique", + "columns": [ + { + "expression": "permission_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permission_group_workspace_permission_group_id_permission_group_id_fk": { + "name": "permission_group_workspace_permission_group_id_permission_group_id_fk", + "tableFrom": "permission_group_workspace", + "tableTo": "permission_group", + "columnsFrom": ["permission_group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_workspace_workspace_id_workspace_id_fk": { + "name": "permission_group_workspace_workspace_id_workspace_id_fk", + "tableFrom": "permission_group_workspace", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_workspace_organization_id_organization_id_fk": { + "name": "permission_group_workspace_organization_id_organization_id_fk", + "tableFrom": "permission_group_workspace", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permissions": { + "name": "permissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission_type": { + "name": "permission_type", + "type": "permission_type", + "typeSchema": "public", + "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": { + "permissions_user_id_idx": { + "name": "permissions_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_entity_idx": { + "name": "permissions_entity_idx", + "columns": [ + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_user_entity_type_idx": { + "name": "permissions_user_entity_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_user_entity_permission_idx": { + "name": "permissions_user_entity_permission_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "permission_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_user_entity_idx": { + "name": "permissions_user_entity_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_unique_constraint": { + "name": "permissions_unique_constraint", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permissions_user_id_user_id_fk": { + "name": "permissions_user_id_user_id_fk", + "tableFrom": "permissions", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.public_share": { + "name": "public_share", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'public'" + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "allowed_emails": { + "name": "allowed_emails", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "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": { + "public_share_token_unique": { + "name": "public_share_token_unique", + "columns": [ + { + "expression": "token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "public_share_resource_unique": { + "name": "public_share_resource_unique", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "public_share_resource_id_idx": { + "name": "public_share_resource_id_idx", + "columns": [ + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "public_share_workspace_id_idx": { + "name": "public_share_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "public_share_workspace_id_workspace_id_fk": { + "name": "public_share_workspace_id_workspace_id_fk", + "tableFrom": "public_share", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "public_share_created_by_user_id_fk": { + "name": "public_share_created_by_user_id_fk", + "tableFrom": "public_share", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rate_limit_bucket": { + "name": "rate_limit_bucket", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "tokens": { + "name": "tokens", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.resume_queue": { + "name": "resume_queue", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "paused_execution_id": { + "name": "paused_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_execution_id": { + "name": "parent_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "new_execution_id": { + "name": "new_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "context_id": { + "name": "context_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resume_input": { + "name": "resume_input", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "queued_at": { + "name": "queued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "claimed_at": { + "name": "claimed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "failure_reason": { + "name": "failure_reason", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "resume_queue_parent_status_idx": { + "name": "resume_queue_parent_status_idx", + "columns": [ + { + "expression": "parent_execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "queued_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "resume_queue_new_execution_idx": { + "name": "resume_queue_new_execution_idx", + "columns": [ + { + "expression": "new_execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "resume_queue_paused_execution_id_paused_executions_id_fk": { + "name": "resume_queue_paused_execution_id_paused_executions_id_fk", + "tableFrom": "resume_queue", + "tableTo": "paused_executions", + "columnsFrom": ["paused_execution_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_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 + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "session_user_id_idx": { + "name": "session_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_token_idx": { + "name": "session_token_idx", + "columns": [ + { + "expression": "token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_active_organization_id_organization_id_fk": { + "name": "session_active_organization_id_organization_id_fk", + "tableFrom": "session", + "tableTo": "organization", + "columnsFrom": ["active_organization_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.settings": { + "name": "settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "theme": { + "name": "theme", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'system'" + }, + "auto_connect": { + "name": "auto_connect", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "telemetry_enabled": { + "name": "telemetry_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "email_preferences": { + "name": "email_preferences", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "billing_usage_notifications_enabled": { + "name": "billing_usage_notifications_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "show_training_controls": { + "name": "show_training_controls", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "super_user_mode_enabled": { + "name": "super_user_mode_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "mothership_environment": { + "name": "mothership_environment", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'default'" + }, + "error_notifications_enabled": { + "name": "error_notifications_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "snap_to_grid_size": { + "name": "snap_to_grid_size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "show_action_bar": { + "name": "show_action_bar", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "copilot_enabled_models": { + "name": "copilot_enabled_models", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "copilot_auto_allowed_tools": { + "name": "copilot_auto_allowed_tools", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "last_active_workspace_id": { + "name": "last_active_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "settings_user_id_user_id_fk": { + "name": "settings_user_id_user_id_fk", + "tableFrom": "settings", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "settings_user_id_unique": { + "name": "settings_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sim_trigger_state": { + "name": "sim_trigger_state", + "schema": "", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "block_id": { + "name": "block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scope_key": { + "name": "scope_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "last_fired_at": { + "name": "last_fired_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sim_trigger_state_workflow_id_workflow_id_fk": { + "name": "sim_trigger_state_workflow_id_workflow_id_fk", + "tableFrom": "sim_trigger_state", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "sim_trigger_state_workflow_id_block_id_scope_key_pk": { + "name": "sim_trigger_state_workflow_id_block_id_scope_key_pk", + "columns": ["workflow_id", "block_id", "scope_key"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.skill": { + "name": "skill", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "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": true + }, + "content": { + "name": "content", + "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": { + "skill_workspace_name_unique": { + "name": "skill_workspace_name_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "skill_workspace_id_workspace_id_fk": { + "name": "skill_workspace_id_workspace_id_fk", + "tableFrom": "skill", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "skill_user_id_user_id_fk": { + "name": "skill_user_id_user_id_fk", + "tableFrom": "skill", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sso_provider": { + "name": "sso_provider", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "issuer": { + "name": "issuer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "oidc_config": { + "name": "oidc_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "saml_config": { + "name": "saml_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "sso_provider_provider_id_idx": { + "name": "sso_provider_provider_id_idx", + "columns": [ + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_domain_idx": { + "name": "sso_provider_domain_idx", + "columns": [ + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_user_id_idx": { + "name": "sso_provider_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_organization_id_idx": { + "name": "sso_provider_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sso_provider_user_id_user_id_fk": { + "name": "sso_provider_user_id_user_id_fk", + "tableFrom": "sso_provider", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "sso_provider_organization_id_organization_id_fk": { + "name": "sso_provider_organization_id_organization_id_fk", + "tableFrom": "sso_provider", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.subscription": { + "name": "subscription", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "plan": { + "name": "plan", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripe_subscription_id": { + "name": "stripe_subscription_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "period_start": { + "name": "period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "period_end": { + "name": "period_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cancel_at_period_end": { + "name": "cancel_at_period_end", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "cancel_at": { + "name": "cancel_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "canceled_at": { + "name": "canceled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "seats": { + "name": "seats", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "trial_start": { + "name": "trial_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "trial_end": { + "name": "trial_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "billing_interval": { + "name": "billing_interval", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripe_schedule_id": { + "name": "stripe_schedule_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "json", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "subscription_reference_status_idx": { + "name": "subscription_reference_status_idx", + "columns": [ + { + "expression": "reference_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "check_enterprise_metadata": { + "name": "check_enterprise_metadata", + "value": "plan != 'enterprise' OR metadata IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.table_jobs": { + "name": "table_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "rows_processed": { + "name": "rows_processed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "table_jobs_one_active_per_table": { + "name": "table_jobs_one_active_per_table", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"table_jobs\".\"status\" = 'running' AND \"table_jobs\".\"type\" <> 'export'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_jobs_watchdog_idx": { + "name": "table_jobs_watchdog_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_jobs_table_started_idx": { + "name": "table_jobs_table_started_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "table_jobs_table_id_user_table_definitions_id_fk": { + "name": "table_jobs_table_id_user_table_definitions_id_fk", + "tableFrom": "table_jobs", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_jobs_workspace_id_workspace_id_fk": { + "name": "table_jobs_workspace_id_workspace_id_fk", + "tableFrom": "table_jobs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.table_row_executions": { + "name": "table_row_executions", + "schema": "", + "columns": { + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "row_id": { + "name": "row_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "job_id": { + "name": "job_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "running_block_ids": { + "name": "running_block_ids", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::text[]" + }, + "block_errors": { + "name": "block_errors", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "cancelled_at": { + "name": "cancelled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "enrichment_details": { + "name": "enrichment_details", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "table_row_executions_table_status_idx": { + "name": "table_row_executions_table_status_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"table_row_executions\".\"status\" IN ('queued', 'running', 'pending')", + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_row_executions_execution_id_idx": { + "name": "table_row_executions_execution_id_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"table_row_executions\".\"execution_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_row_executions_table_group_idx": { + "name": "table_row_executions_table_group_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "table_row_executions_table_id_user_table_definitions_id_fk": { + "name": "table_row_executions_table_id_user_table_definitions_id_fk", + "tableFrom": "table_row_executions", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_row_executions_row_id_user_table_rows_id_fk": { + "name": "table_row_executions_row_id_user_table_rows_id_fk", + "tableFrom": "table_row_executions", + "tableTo": "user_table_rows", + "columnsFrom": ["row_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "table_row_executions_row_id_group_id_pk": { + "name": "table_row_executions_row_id_group_id_pk", + "columns": ["row_id", "group_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.table_run_dispatches": { + "name": "table_run_dispatches", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mode": { + "name": "mode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scope": { + "name": "scope", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "cursor": { + "name": "cursor", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "limit": { + "name": "limit", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "processed_count": { + "name": "processed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "is_manual_run": { + "name": "is_manual_run", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "triggered_by_user_id": { + "name": "triggered_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cancelled_at": { + "name": "cancelled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "table_run_dispatches_active_idx": { + "name": "table_run_dispatches_active_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_run_dispatches_watchdog_idx": { + "name": "table_run_dispatches_watchdog_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "requested_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "table_run_dispatches_table_id_user_table_definitions_id_fk": { + "name": "table_run_dispatches_table_id_user_table_definitions_id_fk", + "tableFrom": "table_run_dispatches", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_run_dispatches_workspace_id_workspace_id_fk": { + "name": "table_run_dispatches_workspace_id_workspace_id_fk", + "tableFrom": "table_run_dispatches", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_run_dispatches_triggered_by_user_id_user_id_fk": { + "name": "table_run_dispatches_triggered_by_user_id_user_id_fk", + "tableFrom": "table_run_dispatches", + "tableTo": "user", + "columnsFrom": ["triggered_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.usage_log": { + "name": "usage_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "usage_log_category", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "usage_log_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "cost": { + "name": "cost", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "event_key": { + "name": "event_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "billing_entity_type": { + "name": "billing_entity_type", + "type": "billing_entity_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "billing_entity_id": { + "name": "billing_entity_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "billing_period_start": { + "name": "billing_period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "billing_period_end": { + "name": "billing_period_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "usage_log_user_created_at_idx": { + "name": "usage_log_user_created_at_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": {} + }, + "usage_log_source_idx": { + "name": "usage_log_source_idx", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_workspace_id_idx": { + "name": "usage_log_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_workflow_id_idx": { + "name": "usage_log_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_event_key_unique": { + "name": "usage_log_event_key_unique", + "columns": [ + { + "expression": "event_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"usage_log\".\"event_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_billing_entity_period_idx": { + "name": "usage_log_billing_entity_period_idx", + "columns": [ + { + "expression": "billing_entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_period_start", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_period_end", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"usage_log\".\"billing_entity_type\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_workspace_created_at_idx": { + "name": "usage_log_workspace_created_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_execution_id_idx": { + "name": "usage_log_execution_id_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "usage_log_user_id_user_id_fk": { + "name": "usage_log_user_id_user_id_fk", + "tableFrom": "usage_log", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "usage_log_workspace_id_workspace_id_fk": { + "name": "usage_log_workspace_id_workspace_id_fk", + "tableFrom": "usage_log", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "usage_log_workflow_id_workflow_id_fk": { + "name": "usage_log_workflow_id_workflow_id_fk", + "tableFrom": "usage_log", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "usage_log_billing_scope_all_or_none": { + "name": "usage_log_billing_scope_all_or_none", + "value": "(\n (\"usage_log\".\"billing_entity_type\" IS NULL AND \"usage_log\".\"billing_entity_id\" IS NULL AND \"usage_log\".\"billing_period_start\" IS NULL AND \"usage_log\".\"billing_period_end\" IS NULL)\n OR\n (\"usage_log\".\"billing_entity_type\" IS NOT NULL AND \"usage_log\".\"billing_entity_id\" IS NOT NULL AND \"usage_log\".\"billing_period_start\" IS NOT NULL AND \"usage_log\".\"billing_period_end\" IS NOT NULL AND \"usage_log\".\"billing_period_start\" < \"usage_log\".\"billing_period_end\")\n )" + } + }, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "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 + }, + "normalized_email": { + "name": "normalized_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'user'" + }, + "banned": { + "name": "banned", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + }, + "user_normalized_email_unique": { + "name": "user_normalized_email_unique", + "nullsNotDistinct": false, + "columns": ["normalized_email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_stats": { + "name": "user_stats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "total_manual_executions": { + "name": "total_manual_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_api_calls": { + "name": "total_api_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_webhook_triggers": { + "name": "total_webhook_triggers", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_scheduled_executions": { + "name": "total_scheduled_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_chat_executions": { + "name": "total_chat_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_mcp_executions": { + "name": "total_mcp_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_tokens_used": { + "name": "total_tokens_used", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_cost": { + "name": "total_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "current_usage_limit": { + "name": "current_usage_limit", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'5'" + }, + "usage_limit_updated_at": { + "name": "usage_limit_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "current_period_cost": { + "name": "current_period_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "last_period_cost": { + "name": "last_period_cost", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "billed_overage_this_period": { + "name": "billed_overage_this_period", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "pro_period_cost_snapshot": { + "name": "pro_period_cost_snapshot", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "pro_period_cost_snapshot_at": { + "name": "pro_period_cost_snapshot_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "credit_balance": { + "name": "credit_balance", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "total_copilot_cost": { + "name": "total_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "current_period_copilot_cost": { + "name": "current_period_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "last_period_copilot_cost": { + "name": "last_period_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "total_copilot_tokens": { + "name": "total_copilot_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_copilot_calls": { + "name": "total_copilot_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_mcp_copilot_calls": { + "name": "total_mcp_copilot_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_mcp_copilot_cost": { + "name": "total_mcp_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "current_period_mcp_copilot_cost": { + "name": "current_period_mcp_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "storage_used_bytes": { + "name": "storage_used_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_active": { + "name": "last_active", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "billing_blocked": { + "name": "billing_blocked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "billing_blocked_reason": { + "name": "billing_blocked_reason", + "type": "billing_blocked_reason", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "limit_notifications": { + "name": "limit_notifications", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + } + }, + "indexes": {}, + "foreignKeys": { + "user_stats_user_id_user_id_fk": { + "name": "user_stats_user_id_user_id_fk", + "tableFrom": "user_stats", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_stats_user_id_unique": { + "name": "user_stats_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_table_definitions": { + "name": "user_table_definitions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schema": { + "name": "schema", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "max_rows": { + "name": "max_rows", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 10000 + }, + "row_count": { + "name": "row_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "rows_version": { + "name": "rows_version", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "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_table_def_workspace_id_idx": { + "name": "user_table_def_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_workspace_name_unique": { + "name": "user_table_def_workspace_name_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"user_table_definitions\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_archived_at_idx": { + "name": "user_table_def_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_workspace_archived_partial_idx": { + "name": "user_table_def_workspace_archived_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"user_table_definitions\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_table_definitions_workspace_id_workspace_id_fk": { + "name": "user_table_definitions_workspace_id_workspace_id_fk", + "tableFrom": "user_table_definitions", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_table_definitions_created_by_user_id_fk": { + "name": "user_table_definitions_created_by_user_id_fk", + "tableFrom": "user_table_definitions", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_table_rows": { + "name": "user_table_rows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "order_key": { + "name": "order_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()" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "user_table_rows_tenant_data_gin_idx": { + "name": "user_table_rows_tenant_data_gin_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "\"data\" jsonb_path_ops", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "user_table_rows_workspace_table_idx": { + "name": "user_table_rows_workspace_table_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_table_position_idx": { + "name": "user_table_rows_table_position_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "position", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_table_order_key_idx": { + "name": "user_table_rows_table_order_key_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_table_id_id_idx": { + "name": "user_table_rows_table_id_id_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_table_rows_table_id_user_table_definitions_id_fk": { + "name": "user_table_rows_table_id_user_table_definitions_id_fk", + "tableFrom": "user_table_rows", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_table_rows_workspace_id_workspace_id_fk": { + "name": "user_table_rows_workspace_id_workspace_id_fk", + "tableFrom": "user_table_rows", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_table_rows_created_by_user_id_fk": { + "name": "user_table_rows_created_by_user_id_fk", + "tableFrom": "user_table_rows", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "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": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "verification_expires_at_idx": { + "name": "verification_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.waitlist": { + "name": "waitlist", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "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": { + "waitlist_email_unique": { + "name": "waitlist_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.webhook": { + "name": "webhook", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registration_status": { + "name": "registration_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registration_generation": { + "name": "registration_generation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "config_fingerprint": { + "name": "config_fingerprint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prepared_at": { + "name": "prepared_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "block_id": { + "name": "block_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "routing_key": { + "name": "routing_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_config": { + "name": "provider_config", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "failed_count": { + "name": "failed_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_failed_at": { + "name": "last_failed_at", + "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": { + "path_deployment_unique": { + "name": "path_deployment_unique", + "columns": [ + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"webhook\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_workflow_deployment_idx": { + "name": "webhook_workflow_deployment_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_routing_key_active_idx": { + "name": "webhook_routing_key_active_idx", + "columns": [ + { + "expression": "routing_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"webhook\".\"archived_at\" IS NULL AND \"webhook\".\"routing_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_archived_at_partial_idx": { + "name": "webhook_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"webhook\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_webhook_on_provider_is_active_workflow_id_deploym_bdeed5468": { + "name": "idx_webhook_on_provider_is_active_workflow_id_deploym_bdeed5468", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_tiktok_credential_id_idx": { + "name": "webhook_tiktok_credential_id_idx", + "columns": [ + { + "expression": "((\"provider_config\")::jsonb ->> 'credentialId')", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"webhook\".\"provider\" = 'tiktok' AND \"webhook\".\"is_active\" = true AND \"webhook\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_webhook_on_workflow_id_block_id_updated_at_desc": { + "name": "idx_webhook_on_workflow_id_block_id_updated_at_desc", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_active_registration_unique": { + "name": "webhook_active_registration_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"webhook\".\"registration_status\" = 'active' AND \"webhook\".\"block_id\" IS NOT NULL AND \"webhook\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_candidate_registration_unique": { + "name": "webhook_candidate_registration_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"webhook\".\"registration_status\" = 'candidate' AND \"webhook\".\"block_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_registration_status_generation_idx": { + "name": "webhook_registration_status_generation_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "registration_status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "registration_generation", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "webhook_workflow_id_workflow_id_fk": { + "name": "webhook_workflow_id_workflow_id_fk", + "tableFrom": "webhook", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "webhook_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "webhook_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "webhook", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "webhook_registration_status_check": { + "name": "webhook_registration_status_check", + "value": "\"webhook\".\"registration_status\" IS NULL OR \"webhook\".\"registration_status\" IN ('active', 'candidate', 'retired', 'orphaned')" + }, + "webhook_registration_generation_check": { + "name": "webhook_registration_generation_check", + "value": "\"webhook\".\"registration_generation\" IS NULL OR \"webhook\".\"registration_generation\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.webhook_path_claim": { + "name": "webhook_path_claim", + "schema": "", + "columns": { + "path": { + "name": "path", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "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": { + "webhook_path_claim_workflow_idx": { + "name": "webhook_path_claim_workflow_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "webhook_path_claim_workflow_id_workflow_id_fk": { + "name": "webhook_path_claim_workflow_id_workflow_id_fk", + "tableFrom": "webhook_path_claim", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "webhook_path_claim_generation_check": { + "name": "webhook_path_claim_generation_check", + "value": "\"webhook_path_claim\".\"generation\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.workflow": { + "name": "workflow", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_synced": { + "name": "last_synced", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "is_deployed": { + "name": "is_deployed", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deployed_at": { + "name": "deployed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_public_api": { + "name": "is_public_api", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "locked": { + "name": "locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "fork_sync_excluded": { + "name": "fork_sync_excluded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "run_count": { + "name": "run_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "workflow_user_id_idx": { + "name": "workflow_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_workspace_id_idx": { + "name": "workflow_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_user_workspace_idx": { + "name": "workflow_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_workspace_folder_name_active_unique": { + "name": "workflow_workspace_folder_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"folder_id\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_folder_sort_idx": { + "name": "workflow_folder_sort_idx", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_archived_at_idx": { + "name": "workflow_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_workspace_archived_partial_idx": { + "name": "workflow_workspace_archived_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_user_id_user_id_fk": { + "name": "workflow_user_id_user_id_fk", + "tableFrom": "workflow", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_workspace_id_workspace_id_fk": { + "name": "workflow_workspace_id_workspace_id_fk", + "tableFrom": "workflow", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_folder_id_workflow_folder_id_fk": { + "name": "workflow_folder_id_workflow_folder_id_fk", + "tableFrom": "workflow", + "tableTo": "workflow_folder", + "columnsFrom": ["folder_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_blocks": { + "name": "workflow_blocks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position_x": { + "name": "position_x", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "position_y": { + "name": "position_y", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "horizontal_handles": { + "name": "horizontal_handles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "is_wide": { + "name": "is_wide", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "advanced_mode": { + "name": "advanced_mode", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "trigger_mode": { + "name": "trigger_mode", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "locked": { + "name": "locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "height": { + "name": "height", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "sub_blocks": { + "name": "sub_blocks", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "outputs": { + "name": "outputs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "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": { + "workflow_blocks_workflow_id_idx": { + "name": "workflow_blocks_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_blocks_type_idx": { + "name": "workflow_blocks_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_blocks_workflow_id_workflow_id_fk": { + "name": "workflow_blocks_workflow_id_workflow_id_fk", + "tableFrom": "workflow_blocks", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_checkpoints": { + "name": "workflow_checkpoints", + "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 + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_state": { + "name": "workflow_state", + "type": "json", + "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": { + "workflow_checkpoints_user_id_idx": { + "name": "workflow_checkpoints_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_workflow_id_idx": { + "name": "workflow_checkpoints_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_chat_id_idx": { + "name": "workflow_checkpoints_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_message_id_idx": { + "name": "workflow_checkpoints_message_id_idx", + "columns": [ + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_user_workflow_idx": { + "name": "workflow_checkpoints_user_workflow_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_workflow_chat_idx": { + "name": "workflow_checkpoints_workflow_chat_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_created_at_idx": { + "name": "workflow_checkpoints_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_chat_created_at_idx": { + "name": "workflow_checkpoints_chat_created_at_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_checkpoints_user_id_user_id_fk": { + "name": "workflow_checkpoints_user_id_user_id_fk", + "tableFrom": "workflow_checkpoints", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_checkpoints_workflow_id_workflow_id_fk": { + "name": "workflow_checkpoints_workflow_id_workflow_id_fk", + "tableFrom": "workflow_checkpoints", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_checkpoints_chat_id_copilot_chats_id_fk": { + "name": "workflow_checkpoints_chat_id_copilot_chats_id_fk", + "tableFrom": "workflow_checkpoints", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_deployment_operation": { + "name": "workflow_deployment_operation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "previous_active_version_id": { + "name": "previous_active_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "protocol_version": { + "name": "protocol_version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'preparing'" + }, + "component_readiness": { + "name": "component_readiness", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "idempotency_key": { + "name": "idempotency_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "request_hash": { + "name": "request_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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": { + "workflow_deployment_operation_workflow_generation_unique": { + "name": "workflow_deployment_operation_workflow_generation_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "generation", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_workflow_idempotency_unique": { + "name": "workflow_deployment_operation_workflow_idempotency_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "idempotency_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_deployment_operation\".\"idempotency_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_workflow_in_flight_unique": { + "name": "workflow_deployment_operation_workflow_in_flight_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_deployment_operation\".\"status\" IN ('preparing', 'activating')", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_workflow_status_idx": { + "name": "workflow_deployment_operation_workflow_status_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_deployment_version_idx": { + "name": "workflow_deployment_operation_deployment_version_idx", + "columns": [ + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_workflow_version_generation_idx": { + "name": "workflow_deployment_operation_workflow_version_generation_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "generation", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_deployment_operation_workflow_id_workflow_id_fk": { + "name": "workflow_deployment_operation_workflow_id_workflow_id_fk", + "tableFrom": "workflow_deployment_operation", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_deployment_operation_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_deployment_operation_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_deployment_operation", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_deployment_operation_previous_active_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_deployment_operation_previous_active_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_deployment_operation", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["previous_active_version_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "workflow_deployment_operation_action_check": { + "name": "workflow_deployment_operation_action_check", + "value": "\"workflow_deployment_operation\".\"action\" IN ('deploy', 'activate')" + }, + "workflow_deployment_operation_status_check": { + "name": "workflow_deployment_operation_status_check", + "value": "\"workflow_deployment_operation\".\"status\" IN ('preparing', 'activating', 'active', 'failed', 'superseded')" + }, + "workflow_deployment_operation_generation_check": { + "name": "workflow_deployment_operation_generation_check", + "value": "\"workflow_deployment_operation\".\"generation\" > 0" + }, + "workflow_deployment_operation_protocol_version_check": { + "name": "workflow_deployment_operation_protocol_version_check", + "value": "\"workflow_deployment_operation\".\"protocol_version\" > 0" + } + }, + "isRLSEnabled": false + }, + "public.workflow_deployment_version": { + "name": "workflow_deployment_version", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "workflow_deployment_version_workflow_version_unique": { + "name": "workflow_deployment_version_workflow_version_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "version", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_version_workflow_active_idx": { + "name": "workflow_deployment_version_workflow_active_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_version_created_at_idx": { + "name": "workflow_deployment_version_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_deployment_version_workflow_id_workflow_id_fk": { + "name": "workflow_deployment_version_workflow_id_workflow_id_fk", + "tableFrom": "workflow_deployment_version", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_edges": { + "name": "workflow_edges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_block_id": { + "name": "source_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_block_id": { + "name": "target_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_handle": { + "name": "source_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "target_handle": { + "name": "target_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_edges_workflow_id_idx": { + "name": "workflow_edges_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_edges_workflow_source_idx": { + "name": "workflow_edges_workflow_source_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_edges_workflow_target_idx": { + "name": "workflow_edges_workflow_target_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_edges_workflow_id_workflow_id_fk": { + "name": "workflow_edges_workflow_id_workflow_id_fk", + "tableFrom": "workflow_edges", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_edges_source_block_id_workflow_blocks_id_fk": { + "name": "workflow_edges_source_block_id_workflow_blocks_id_fk", + "tableFrom": "workflow_edges", + "tableTo": "workflow_blocks", + "columnsFrom": ["source_block_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_edges_target_block_id_workflow_blocks_id_fk": { + "name": "workflow_edges_target_block_id_workflow_blocks_id_fk", + "tableFrom": "workflow_edges", + "tableTo": "workflow_blocks", + "columnsFrom": ["target_block_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_execution_logs": { + "name": "workflow_execution_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state_snapshot_id": { + "name": "state_snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "trigger": { + "name": "trigger", + "type": "text", + "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 + }, + "total_duration_ms": { + "name": "total_duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "execution_data": { + "name": "execution_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "cost": { + "name": "cost", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "cost_total": { + "name": "cost_total", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "models_used": { + "name": "models_used", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "files": { + "name": "files", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_execution_logs_workflow_id_idx": { + "name": "workflow_execution_logs_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_state_snapshot_id_idx": { + "name": "workflow_execution_logs_state_snapshot_id_idx", + "columns": [ + { + "expression": "state_snapshot_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_deployment_version_id_idx": { + "name": "workflow_execution_logs_deployment_version_id_idx", + "columns": [ + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_trigger_idx": { + "name": "workflow_execution_logs_trigger_idx", + "columns": [ + { + "expression": "trigger", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_level_idx": { + "name": "workflow_execution_logs_level_idx", + "columns": [ + { + "expression": "level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_started_at_idx": { + "name": "workflow_execution_logs_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_execution_id_unique": { + "name": "workflow_execution_logs_execution_id_unique", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workflow_started_at_idx": { + "name": "workflow_execution_logs_workflow_started_at_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workspace_started_at_idx": { + "name": "workflow_execution_logs_workspace_started_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workspace_started_at_id_desc_idx": { + "name": "workflow_execution_logs_workspace_started_at_id_desc_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "\"started_at\" DESC NULLS LAST", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "\"id\" DESC", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workspace_cost_total_idx": { + "name": "workflow_execution_logs_workspace_cost_total_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "cost_total", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_models_used_idx": { + "name": "workflow_execution_logs_models_used_idx", + "columns": [ + { + "expression": "models_used", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "workflow_execution_logs_workspace_ended_at_id_idx": { + "name": "workflow_execution_logs_workspace_ended_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"ended_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_running_started_at_idx": { + "name": "workflow_execution_logs_running_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "status = 'running'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_completed_ended_at_idx": { + "name": "workflow_execution_logs_completed_ended_at_idx", + "columns": [ + { + "expression": "ended_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_execution_logs\".\"status\" = 'completed' AND \"workflow_execution_logs\".\"level\" = 'info' AND \"workflow_execution_logs\".\"ended_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_execution_logs_workflow_id_workflow_id_fk": { + "name": "workflow_execution_logs_workflow_id_workflow_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_execution_logs_workspace_id_workspace_id_fk": { + "name": "workflow_execution_logs_workspace_id_workspace_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_execution_logs_state_snapshot_id_workflow_execution_snapshots_id_fk": { + "name": "workflow_execution_logs_state_snapshot_id_workflow_execution_snapshots_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workflow_execution_snapshots", + "columnsFrom": ["state_snapshot_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "workflow_execution_logs_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_execution_logs_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_execution_snapshots": { + "name": "workflow_execution_snapshots", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state_hash": { + "name": "state_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state_data": { + "name": "state_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_snapshots_workflow_id_idx": { + "name": "workflow_snapshots_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_snapshots_hash_idx": { + "name": "workflow_snapshots_hash_idx", + "columns": [ + { + "expression": "state_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_snapshots_workflow_hash_idx": { + "name": "workflow_snapshots_workflow_hash_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "state_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_snapshots_created_at_idx": { + "name": "workflow_snapshots_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_execution_snapshots_workflow_id_workflow_id_fk": { + "name": "workflow_execution_snapshots_workflow_id_workflow_id_fk", + "tableFrom": "workflow_execution_snapshots", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_folder": { + "name": "workflow_folder", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'#6B7280'" + }, + "is_expanded": { + "name": "is_expanded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "locked": { + "name": "locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sort_order": { + "name": "sort_order", + "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()" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "workflow_folder_user_idx": { + "name": "workflow_folder_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_folder_workspace_parent_idx": { + "name": "workflow_folder_workspace_parent_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_folder_parent_sort_idx": { + "name": "workflow_folder_parent_sort_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_folder_archived_at_idx": { + "name": "workflow_folder_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_folder_workspace_archived_partial_idx": { + "name": "workflow_folder_workspace_archived_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_folder\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_folder_user_id_user_id_fk": { + "name": "workflow_folder_user_id_user_id_fk", + "tableFrom": "workflow_folder", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_folder_workspace_id_workspace_id_fk": { + "name": "workflow_folder_workspace_id_workspace_id_fk", + "tableFrom": "workflow_folder", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_mcp_server": { + "name": "workflow_mcp_server", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": 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": { + "workflow_mcp_server_workspace_id_idx": { + "name": "workflow_mcp_server_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_server_created_by_idx": { + "name": "workflow_mcp_server_created_by_idx", + "columns": [ + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_server_deleted_at_idx": { + "name": "workflow_mcp_server_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_server_workspace_deleted_partial_idx": { + "name": "workflow_mcp_server_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_mcp_server\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_mcp_server_workspace_id_workspace_id_fk": { + "name": "workflow_mcp_server_workspace_id_workspace_id_fk", + "tableFrom": "workflow_mcp_server", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_mcp_server_created_by_user_id_fk": { + "name": "workflow_mcp_server_created_by_user_id_fk", + "tableFrom": "workflow_mcp_server", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_mcp_tool": { + "name": "workflow_mcp_tool", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "server_id": { + "name": "server_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_description": { + "name": "tool_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parameter_schema": { + "name": "parameter_schema", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "parameter_description_overrides": { + "name": "parameter_description_overrides", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'::json" + }, + "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": { + "workflow_mcp_tool_server_id_idx": { + "name": "workflow_mcp_tool_server_id_idx", + "columns": [ + { + "expression": "server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_tool_workflow_id_idx": { + "name": "workflow_mcp_tool_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_tool_server_workflow_unique": { + "name": "workflow_mcp_tool_server_workflow_unique", + "columns": [ + { + "expression": "server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_mcp_tool\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_tool_archived_at_partial_idx": { + "name": "workflow_mcp_tool_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_mcp_tool\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_mcp_tool_server_id_workflow_mcp_server_id_fk": { + "name": "workflow_mcp_tool_server_id_workflow_mcp_server_id_fk", + "tableFrom": "workflow_mcp_tool", + "tableTo": "workflow_mcp_server", + "columnsFrom": ["server_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_mcp_tool_workflow_id_workflow_id_fk": { + "name": "workflow_mcp_tool_workflow_id_workflow_id_fk", + "tableFrom": "workflow_mcp_tool", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_schedule": { + "name": "workflow_schedule", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deployment_operation_id": { + "name": "deployment_operation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "block_id": { + "name": "block_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "next_run_at": { + "name": "next_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_ran_at": { + "name": "last_ran_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_queued_at": { + "name": "last_queued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "trigger_type": { + "name": "trigger_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'UTC'" + }, + "failed_count": { + "name": "failed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "infra_retry_count": { + "name": "infra_retry_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "last_failed_at": { + "name": "last_failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'workflow'" + }, + "job_title": { + "name": "job_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lifecycle": { + "name": "lifecycle", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'persistent'" + }, + "success_condition": { + "name": "success_condition", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "max_runs": { + "name": "max_runs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "run_count": { + "name": "run_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "source_chat_id": { + "name": "source_chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_task_name": { + "name": "source_task_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_user_id": { + "name": "source_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_workspace_id": { + "name": "source_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "job_history": { + "name": "job_history", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "contexts": { + "name": "contexts", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "excluded_dates": { + "name": "excluded_dates", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "ends_at": { + "name": "ends_at", + "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": { + "workflow_schedule_workflow_block_deployment_unique": { + "name": "workflow_schedule_workflow_block_deployment_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_schedule\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_workflow_deployment_idx": { + "name": "workflow_schedule_workflow_deployment_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_archived_at_partial_idx": { + "name": "workflow_schedule_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_schedule\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_workflow_schedule_on_source_workspace_id_source_t_c07f3bba6": { + "name": "idx_workflow_schedule_on_source_workspace_id_source_t_c07f3bba6", + "columns": [ + { + "expression": "source_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_due_workflow_idx": { + "name": "workflow_schedule_due_workflow_idx", + "columns": [ + { + "expression": "next_run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_queued_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_schedule\".\"archived_at\" IS NULL AND \"workflow_schedule\".\"status\" NOT IN ('disabled', 'completed') AND (\"workflow_schedule\".\"source_type\" = 'workflow' OR \"workflow_schedule\".\"source_type\" IS NULL)", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_due_job_idx": { + "name": "workflow_schedule_due_job_idx", + "columns": [ + { + "expression": "next_run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_queued_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_schedule\".\"archived_at\" IS NULL AND \"workflow_schedule\".\"status\" NOT IN ('disabled', 'completed') AND \"workflow_schedule\".\"source_type\" = 'job'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_schedule_workflow_id_workflow_id_fk": { + "name": "workflow_schedule_workflow_id_workflow_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_schedule_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_schedule_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_schedule_deployment_operation_id_workflow_deployment_operation_id_fk": { + "name": "workflow_schedule_deployment_operation_id_workflow_deployment_operation_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow_deployment_operation", + "columnsFrom": ["deployment_operation_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_schedule_source_user_id_user_id_fk": { + "name": "workflow_schedule_source_user_id_user_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "user", + "columnsFrom": ["source_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_schedule_source_workspace_id_workspace_id_fk": { + "name": "workflow_schedule_source_workspace_id_workspace_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workspace", + "columnsFrom": ["source_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_subflows": { + "name": "workflow_subflows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "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": { + "workflow_subflows_workflow_id_idx": { + "name": "workflow_subflows_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_subflows_workflow_type_idx": { + "name": "workflow_subflows_workflow_type_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_subflows_workflow_id_workflow_id_fk": { + "name": "workflow_subflows_workflow_id_workflow_id_fk", + "tableFrom": "workflow_subflows", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace": { + "name": "workspace", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'#33C482'" + }, + "logo_url": { + "name": "logo_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_mode": { + "name": "workspace_mode", + "type": "workspace_mode", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'grandfathered_shared'" + }, + "billed_account_user_id": { + "name": "billed_account_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "storage_used_bytes": { + "name": "storage_used_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "allow_personal_api_keys": { + "name": "allow_personal_api_keys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "inbox_enabled": { + "name": "inbox_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "inbox_address": { + "name": "inbox_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inbox_provider_id": { + "name": "inbox_provider_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "organization_assigned_at": { + "name": "organization_assigned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "forked_from_workspace_id": { + "name": "forked_from_workspace_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": { + "workspace_owner_id_idx": { + "name": "workspace_owner_id_idx", + "columns": [ + { + "expression": "owner_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_organization_id_idx": { + "name": "workspace_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_mode_idx": { + "name": "workspace_mode_idx", + "columns": [ + { + "expression": "workspace_mode", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_forked_from_workspace_id_idx": { + "name": "workspace_forked_from_workspace_id_idx", + "columns": [ + { + "expression": "forked_from_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_owner_id_user_id_fk": { + "name": "workspace_owner_id_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_organization_id_organization_id_fk": { + "name": "workspace_organization_id_organization_id_fk", + "tableFrom": "workspace", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workspace_billed_account_user_id_user_id_fk": { + "name": "workspace_billed_account_user_id_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": ["billed_account_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "workspace_forked_from_workspace_id_workspace_id_fk": { + "name": "workspace_forked_from_workspace_id_workspace_id_fk", + "tableFrom": "workspace", + "tableTo": "workspace", + "columnsFrom": ["forked_from_workspace_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "workspace_storage_used_bytes_non_negative": { + "name": "workspace_storage_used_bytes_non_negative", + "value": "\"workspace\".\"storage_used_bytes\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.workspace_byok_keys": { + "name": "workspace_byok_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "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": { + "workspace_byok_workspace_provider_idx": { + "name": "workspace_byok_workspace_provider_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_byok_keys_workspace_id_workspace_id_fk": { + "name": "workspace_byok_keys_workspace_id_workspace_id_fk", + "tableFrom": "workspace_byok_keys", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_byok_keys_created_by_user_id_fk": { + "name": "workspace_byok_keys_created_by_user_id_fk", + "tableFrom": "workspace_byok_keys", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_environment": { + "name": "workspace_environment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "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": { + "workspace_environment_workspace_unique": { + "name": "workspace_environment_workspace_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_environment_workspace_id_workspace_id_fk": { + "name": "workspace_environment_workspace_id_workspace_id_fk", + "tableFrom": "workspace_environment", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file": { + "name": "workspace_file", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_file_workspace_id_idx": { + "name": "workspace_file_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_key_idx": { + "name": "workspace_file_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_deleted_at_idx": { + "name": "workspace_file_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_workspace_deleted_partial_idx": { + "name": "workspace_file_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workspace_file\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_file_workspace_id_workspace_id_fk": { + "name": "workspace_file_workspace_id_workspace_id_fk", + "tableFrom": "workspace_file", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_file_uploaded_by_user_id_fk": { + "name": "workspace_file_uploaded_by_user_id_fk", + "tableFrom": "workspace_file", + "tableTo": "user", + "columnsFrom": ["uploaded_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workspace_file_key_unique": { + "name": "workspace_file_key_unique", + "nullsNotDistinct": false, + "columns": ["key"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_folders": { + "name": "workspace_file_folders", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "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": { + "workspace_file_folders_workspace_parent_idx": { + "name": "workspace_file_folders_workspace_parent_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_folders_parent_sort_idx": { + "name": "workspace_file_folders_parent_sort_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_folders_deleted_at_idx": { + "name": "workspace_file_folders_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_folders_workspace_deleted_partial_idx": { + "name": "workspace_file_folders_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workspace_file_folders\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_folders_workspace_parent_name_active_unique": { + "name": "workspace_file_folders_workspace_parent_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"parent_id\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace_file_folders\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_file_folders_user_id_user_id_fk": { + "name": "workspace_file_folders_user_id_user_id_fk", + "tableFrom": "workspace_file_folders", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_file_folders_workspace_id_workspace_id_fk": { + "name": "workspace_file_folders_workspace_id_workspace_id_fk", + "tableFrom": "workspace_file_folders", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_file_folders_parent_id_workspace_file_folders_id_fk": { + "name": "workspace_file_folders_parent_id_workspace_file_folders_id_fk", + "tableFrom": "workspace_file_folders", + "tableTo": "workspace_file_folders", + "columnsFrom": ["parent_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_files": { + "name": "workspace_files", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "context": { + "name": "context", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_name": { + "name": "original_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_files_key_active_unique": { + "name": "workspace_files_key_active_unique", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace_files\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_workspace_folder_name_active_unique": { + "name": "workspace_files_workspace_folder_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"folder_id\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "original_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace_files\".\"deleted_at\" IS NULL AND \"workspace_files\".\"context\" = 'workspace' AND \"workspace_files\".\"workspace_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_chat_display_name_unique": { + "name": "workspace_files_chat_display_name_unique", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "display_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace_files\".\"context\" = 'mothership' AND \"workspace_files\".\"chat_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_key_idx": { + "name": "workspace_files_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_user_id_idx": { + "name": "workspace_files_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_workspace_id_idx": { + "name": "workspace_files_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_folder_id_idx": { + "name": "workspace_files_folder_id_idx", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_context_idx": { + "name": "workspace_files_context_idx", + "columns": [ + { + "expression": "context", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_chat_id_idx": { + "name": "workspace_files_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_deleted_at_idx": { + "name": "workspace_files_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_workspace_deleted_partial_idx": { + "name": "workspace_files_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workspace_files\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_files_user_id_user_id_fk": { + "name": "workspace_files_user_id_user_id_fk", + "tableFrom": "workspace_files", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_files_workspace_id_workspace_id_fk": { + "name": "workspace_files_workspace_id_workspace_id_fk", + "tableFrom": "workspace_files", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_files_folder_id_workspace_file_folders_id_fk": { + "name": "workspace_files_folder_id_workspace_file_folders_id_fk", + "tableFrom": "workspace_files", + "tableTo": "workspace_file_folders", + "columnsFrom": ["folder_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workspace_files_chat_id_copilot_chats_id_fk": { + "name": "workspace_files_chat_id_copilot_chats_id_fk", + "tableFrom": "workspace_files", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_fork_block_map": { + "name": "workspace_fork_block_map", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "child_workspace_id": { + "name": "child_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_workflow_id": { + "name": "parent_workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_block_id": { + "name": "parent_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "child_workflow_id": { + "name": "child_workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "child_block_id": { + "name": "child_block_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": { + "workspace_fork_block_map_child_ws_parent_unique": { + "name": "workspace_fork_block_map_child_ws_parent_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_block_map_child_ws_child_unique": { + "name": "workspace_fork_block_map_child_ws_child_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "child_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_block_map_child_ws_parent_wf_idx": { + "name": "workspace_fork_block_map_child_ws_parent_wf_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_block_map_child_ws_child_wf_idx": { + "name": "workspace_fork_block_map_child_ws_child_wf_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "child_workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_fork_block_map_child_workspace_id_workspace_id_fk": { + "name": "workspace_fork_block_map_child_workspace_id_workspace_id_fk", + "tableFrom": "workspace_fork_block_map", + "tableTo": "workspace", + "columnsFrom": ["child_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_fork_dependent_value": { + "name": "workspace_fork_dependent_value", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "child_workspace_id": { + "name": "child_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_workflow_id": { + "name": "target_workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_block_id": { + "name": "target_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sub_block_key": { + "name": "sub_block_key", + "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": { + "workspace_fork_dependent_value_child_ws_wf_idx": { + "name": "workspace_fork_dependent_value_child_ws_wf_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_dependent_value_field_unique": { + "name": "workspace_fork_dependent_value_field_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sub_block_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_fork_dependent_value_child_workspace_id_workspace_id_fk": { + "name": "workspace_fork_dependent_value_child_workspace_id_workspace_id_fk", + "tableFrom": "workspace_fork_dependent_value", + "tableTo": "workspace", + "columnsFrom": ["child_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_fork_promote_run": { + "name": "workspace_fork_promote_run", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "child_workspace_id": { + "name": "child_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_workspace_id": { + "name": "source_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_workspace_id": { + "name": "target_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "direction": { + "name": "direction", + "type": "workspace_fork_promote_direction", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_fork_promote_run_child_ws_target_unique": { + "name": "workspace_fork_promote_run_child_ws_target_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_promote_run_target_ws_idx": { + "name": "workspace_fork_promote_run_target_ws_idx", + "columns": [ + { + "expression": "target_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_fork_promote_run_child_workspace_id_workspace_id_fk": { + "name": "workspace_fork_promote_run_child_workspace_id_workspace_id_fk", + "tableFrom": "workspace_fork_promote_run", + "tableTo": "workspace", + "columnsFrom": ["child_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_fork_promote_run_created_by_user_id_fk": { + "name": "workspace_fork_promote_run_created_by_user_id_fk", + "tableFrom": "workspace_fork_promote_run", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_fork_resource_map": { + "name": "workspace_fork_resource_map", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "child_workspace_id": { + "name": "child_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "workspace_fork_resource_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "parent_resource_id": { + "name": "parent_resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "child_resource_id": { + "name": "child_resource_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "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": { + "workspace_fork_resource_map_child_ws_idx": { + "name": "workspace_fork_resource_map_child_ws_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_resource_map_child_ws_type_idx": { + "name": "workspace_fork_resource_map_child_ws_type_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_resource_map_child_type_parent_unique": { + "name": "workspace_fork_resource_map_child_type_parent_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_fork_resource_map_child_workspace_id_workspace_id_fk": { + "name": "workspace_fork_resource_map_child_workspace_id_workspace_id_fk", + "tableFrom": "workspace_fork_resource_map", + "tableTo": "workspace", + "columnsFrom": ["child_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_fork_resource_map_created_by_user_id_fk": { + "name": "workspace_fork_resource_map_created_by_user_id_fk", + "tableFrom": "workspace_fork_resource_map", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.academy_cert_status": { + "name": "academy_cert_status", + "schema": "public", + "values": ["active", "revoked", "expired"] + }, + "public.background_work_kind": { + "name": "background_work_kind", + "schema": "public", + "values": ["deployment_side_effects", "fork_content_copy", "fork_sync", "fork_rollback"] + }, + "public.background_work_status_value": { + "name": "background_work_status_value", + "schema": "public", + "values": ["pending", "processing", "completed", "completed_with_warnings", "failed"] + }, + "public.billing_blocked_reason": { + "name": "billing_blocked_reason", + "schema": "public", + "values": ["payment_failed", "dispute"] + }, + "public.billing_entity_type": { + "name": "billing_entity_type", + "schema": "public", + "values": ["user", "organization"] + }, + "public.chat_type": { + "name": "chat_type", + "schema": "public", + "values": ["mothership", "copilot"] + }, + "public.copilot_async_tool_status": { + "name": "copilot_async_tool_status", + "schema": "public", + "values": ["pending", "running", "completed", "failed", "cancelled", "delivered"] + }, + "public.copilot_run_status": { + "name": "copilot_run_status", + "schema": "public", + "values": ["active", "paused_waiting_for_tool", "resuming", "complete", "error", "cancelled"] + }, + "public.credential_member_role": { + "name": "credential_member_role", + "schema": "public", + "values": ["admin", "member"] + }, + "public.credential_member_status": { + "name": "credential_member_status", + "schema": "public", + "values": ["active", "pending", "revoked"] + }, + "public.credential_type": { + "name": "credential_type", + "schema": "public", + "values": ["oauth", "env_workspace", "env_personal", "service_account"] + }, + "public.data_drain_cadence": { + "name": "data_drain_cadence", + "schema": "public", + "values": ["hourly", "daily"] + }, + "public.data_drain_destination": { + "name": "data_drain_destination", + "schema": "public", + "values": ["s3", "gcs", "azure_blob", "datadog", "bigquery", "snowflake", "webhook"] + }, + "public.data_drain_run_status": { + "name": "data_drain_run_status", + "schema": "public", + "values": ["running", "success", "failed"] + }, + "public.data_drain_run_trigger": { + "name": "data_drain_run_trigger", + "schema": "public", + "values": ["cron", "manual"] + }, + "public.data_drain_source": { + "name": "data_drain_source", + "schema": "public", + "values": ["workflow_logs", "job_logs", "audit_logs", "copilot_chats", "copilot_runs"] + }, + "public.execution_large_value_reference_source": { + "name": "execution_large_value_reference_source", + "schema": "public", + "values": ["execution_log", "paused_snapshot"] + }, + "public.invitation_kind": { + "name": "invitation_kind", + "schema": "public", + "values": ["organization", "workspace"] + }, + "public.invitation_membership_intent": { + "name": "invitation_membership_intent", + "schema": "public", + "values": ["internal", "external"] + }, + "public.invitation_status": { + "name": "invitation_status", + "schema": "public", + "values": ["pending", "accepted", "rejected", "cancelled", "expired"] + }, + "public.permission_type": { + "name": "permission_type", + "schema": "public", + "values": ["admin", "write", "read"] + }, + "public.usage_log_category": { + "name": "usage_log_category", + "schema": "public", + "values": ["model", "fixed", "tool"] + }, + "public.usage_log_source": { + "name": "usage_log_source", + "schema": "public", + "values": [ + "workflow", + "wand", + "copilot", + "workspace-chat", + "mcp_copilot", + "mothership_block", + "knowledge-base", + "voice-input", + "enrichment" + ] + }, + "public.workspace_fork_promote_direction": { + "name": "workspace_fork_promote_direction", + "schema": "public", + "values": ["push", "pull"] + }, + "public.workspace_fork_resource_type": { + "name": "workspace_fork_resource_type", + "schema": "public", + "values": [ + "workflow", + "oauth_credential", + "service_account_credential", + "env_var", + "table", + "knowledge_base", + "knowledge_document", + "file", + "mcp_server", + "workflow_mcp_server", + "custom_tool", + "skill" + ] + }, + "public.workspace_mode": { + "name": "workspace_mode", + "schema": "public", + "values": ["personal", "organization", "grandfathered_shared"] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json index 8a9a55e7524..35d8dd533e8 100644 --- a/packages/db/migrations/meta/_journal.json +++ b/packages/db/migrations/meta/_journal.json @@ -1842,6 +1842,13 @@ "when": 1784252317428, "tag": "0263_workflow_fork_sync_excluded", "breakpoints": true + }, + { + "idx": 264, + "version": "7", + "when": 1784439900082, + "tag": "0264_managed_agent_connection", + "breakpoints": true } ] } diff --git a/packages/db/schema.ts b/packages/db/schema.ts index 24157f8fa31..49674c37b52 100644 --- a/packages/db/schema.ts +++ b/packages/db/schema.ts @@ -2832,6 +2832,38 @@ export const outboxEvent = pgTable( }) ) +export const managedAgentConnection = pgTable( + 'managed_agent_connection', + { + id: text('id').primaryKey(), + workspaceId: text('workspace_id') + .notNull() + .references(() => workspace.id, { onDelete: 'cascade' }), + userId: text('user_id').references(() => user.id, { onDelete: 'set null' }), + name: text('name').notNull(), + /** + * Anthropic workspace API key (a `sk-ant-*` value) encrypted with the + * shared `encryptSecret` helper. Never returned to the client — list + * endpoints return a masked preview only, and the tool decrypts + * server-side per invocation. + */ + encryptedApiKey: text('encrypted_api_key').notNull(), + /** Timestamp of the last successful `GET /v1/agents` probe. */ + lastVerifiedAt: timestamp('last_verified_at'), + /** Truncated error text from the most recent failed verify, if any. */ + lastVerificationError: text('last_verification_error'), + createdAt: timestamp('created_at').notNull().defaultNow(), + updatedAt: timestamp('updated_at').notNull().defaultNow(), + }, + (table) => ({ + workspaceIdIdx: index('managed_agent_connection_workspace_id_idx').on(table.workspaceId), + workspaceNameUnique: uniqueIndex('managed_agent_connection_workspace_name_unique').on( + table.workspaceId, + table.name + ), + }) +) + export const mcpServers = pgTable( 'mcp_servers', { diff --git a/scripts/check-api-validation-contracts.ts b/scripts/check-api-validation-contracts.ts index 6e44238b79f..7bbfe14e8c6 100644 --- a/scripts/check-api-validation-contracts.ts +++ b/scripts/check-api-validation-contracts.ts @@ -9,8 +9,8 @@ const QUERY_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/queries') const SELECTOR_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/selectors') const BASELINE = { - totalRoutes: 964, - zodRoutes: 964, + totalRoutes: 973, + zodRoutes: 973, nonZodRoutes: 0, } as const