diff --git a/PRIVACY.md b/PRIVACY.md index dfff8b7499..c66f4aa7c5 100644 --- a/PRIVACY.md +++ b/PRIVACY.md @@ -256,7 +256,13 @@ message, on the same terms and bounds (see "Files you attach to a coding agent"): an answer carrying one is always handed to the agent, and our service also keeps each file, with its name, in our database beside the item, where every member of the task's workspace can open it, until the answer is -taken back or the agent posts the item again. While you are signed in, Luke +taken back or the agent posts the item again. Any member of the task's +workspace can also add a message to an item's thread at any point, answered +or not, with files on the same terms: our service keeps the message's words +and files with the item under the account of the member who wrote it, which +every member of the workspace sees by name beside it, and hands it to the +agent as one of your messages, kept in its transcript. A thread stays until +the item is deleted with its task. While you are signed in, Luke on your Mac keeps a read open to our service for every item waiting in your workspaces, each in brief (its task, agent, title, and the account that started the agent), and for every task holding an item; it counts in its sidebar and on diff --git a/apps/web/server/api-rewrites.json b/apps/web/server/api-rewrites.json index e14f592f65..f88b85b331 100644 --- a/apps/web/server/api-rewrites.json +++ b/apps/web/server/api-rewrites.json @@ -191,6 +191,10 @@ "src": "/api/inbox/([^/]+)/attachments/([^/]+)", "dest": "/api/default.js?route=inbox/attachment&id=$1&attachment=$2" }, + { + "src": "/api/inbox/([^/]+)/messages", + "dest": "/api/default.js?route=inbox/messages&id=$1" + }, { "src": "/api/inbox/([^/]+)", "dest": "/api/default.js?route=inbox/item&id=$1" diff --git a/apps/web/server/function-rewrites.ts b/apps/web/server/function-rewrites.ts index 7625b9606d..e02b929e59 100644 --- a/apps/web/server/function-rewrites.ts +++ b/apps/web/server/function-rewrites.ts @@ -159,6 +159,7 @@ const SEGMENT_REWRITES: readonly SegmentRewrite[] = [ route: "inbox/attachment", query: "id=$1&attachment=$2", }, + { src: "/api/inbox/([^/]+)/messages", route: "inbox/messages", query: "id=$1" }, { src: "/api/inbox/([^/]+)", route: "inbox/item", query: "id=$1" }, { src: "/api/workspaces/([^/]+)/photo", route: "workspaces/photo", query: "id=$1" }, { src: "/api/automations/([^/]+)/webhook", route: "automations/webhook", query: "id=$1" }, diff --git a/apps/web/server/routes/inbox/messages.ts b/apps/web/server/routes/inbox/messages.ts new file mode 100644 index 0000000000..c0c04a5559 --- /dev/null +++ b/apps/web/server/routes/inbox/messages.ts @@ -0,0 +1,9 @@ +import { deploymentEveOrigin } from "@luke/service/agents/brain-host/eve-origin"; +import { codingAgentsApp } from "@luke/service/agents/coding-agents-app"; +import { resolveHostedUserId } from "@luke/service/auth/bearer"; +import { routeFromHttpRouter } from "../../route-effect.js"; + +/** A member's message on one inbox item's thread (POST), handed to the agent that posted the item. The logic lives in `packages/service/src/agents/coding-agents-app.ts`; this file only hands it the deployment's real seams. */ +export default routeFromHttpRouter( + codingAgentsApp({ resolveUserId: resolveHostedUserId, eveOrigin: deploymentEveOrigin }), +); diff --git a/apps/web/tests/storage-schema.test.ts b/apps/web/tests/storage-schema.test.ts index 6253d40d77..b4713cc069 100644 --- a/apps/web/tests/storage-schema.test.ts +++ b/apps/web/tests/storage-schema.test.ts @@ -63,6 +63,7 @@ const DECLARED_TABLES = [ "hosted_usage", "inbox_attachment", "inbox_item", + "inbox_message", "integration_connection", "invitation", "issue", diff --git a/packages/database/migrations/20261017134832_inbox_message_thread/migration.sql b/packages/database/migrations/20261017134832_inbox_message_thread/migration.sql new file mode 100644 index 0000000000..a90d109918 --- /dev/null +++ b/packages/database/migrations/20261017134832_inbox_message_thread/migration.sql @@ -0,0 +1,28 @@ +CREATE TABLE IF NOT EXISTS "inbox_message" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(), + "item_id" uuid NOT NULL, + "author" text NOT NULL, + "user_id" text, + "text" text NOT NULL, + "client_key" text, + "created_at" timestamp with time zone NOT NULL +); +--> statement-breakpoint +-- A nullable column with no default is written to the catalog alone, so no row of the table is rewritten; the same holds below. +ALTER TABLE "inbox_attachment" ADD COLUMN IF NOT EXISTS "message_id" uuid;--> statement-breakpoint +-- No backfill: a read takes a settled item's last change for a null settled_at, and the first message on its thread keeps that instant here before moving the change (`inbox-store.ts`). +ALTER TABLE "inbox_item" ADD COLUMN IF NOT EXISTS "settled_at" timestamp with time zone;--> statement-breakpoint +-- The table holds a few rows per item, their bytes stored out of line, and the column is null on every one, so the build reads little under its lock. +CREATE INDEX IF NOT EXISTS "inbox_attachment_message" ON "inbox_attachment" ("message_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "inbox_message_item_created" ON "inbox_message" ("item_id","created_at");--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS "inbox_message_client_key" ON "inbox_message" ("item_id","client_key") WHERE "client_key" is not null;--> statement-breakpoint +ALTER TABLE "inbox_attachment" DROP CONSTRAINT IF EXISTS "inbox_attachment_message_id_inbox_message_id_fkey";--> statement-breakpoint +-- Every row standing names no message, so the constraint is not validated over them: a validation would read the whole table under a lock that holds back every attachment written meanwhile. +ALTER TABLE "inbox_attachment" ADD CONSTRAINT "inbox_attachment_message_id_inbox_message_id_fkey" FOREIGN KEY ("message_id") REFERENCES "inbox_message"("id") ON DELETE CASCADE NOT VALID;--> statement-breakpoint +ALTER TABLE "inbox_message" DROP CONSTRAINT IF EXISTS "inbox_message_item_id_inbox_item_id_fkey";--> statement-breakpoint +ALTER TABLE "inbox_message" ADD CONSTRAINT "inbox_message_item_id_inbox_item_id_fkey" FOREIGN KEY ("item_id") REFERENCES "inbox_item"("id") ON DELETE CASCADE;--> statement-breakpoint +ALTER TABLE "inbox_message" DROP CONSTRAINT IF EXISTS "inbox_message_user_id_user_id_fkey";--> statement-breakpoint +ALTER TABLE "inbox_message" ADD CONSTRAINT "inbox_message_user_id_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE SET NULL;--> statement-breakpoint +ALTER TABLE "inbox_attachment" DROP CONSTRAINT IF EXISTS "inbox_attachment_kind_bound";--> statement-breakpoint +-- Every row standing is a picture or an answer's file and names no message, which the old check already held of it, so the new one is not validated over them, for the reason above. +ALTER TABLE "inbox_attachment" ADD CONSTRAINT "inbox_attachment_kind_bound" CHECK (("kind" = 'image' and octet_length("bytes") <= 1500000 and "name" is null and "position" is null and "message_id" is null) or ("kind" = 'answer' and octet_length("bytes") <= 3000000 and "name" is not null and "position" is not null and "message_id" is null) or ("kind" = 'message' and octet_length("bytes") <= 3000000 and "name" is not null and "position" is not null and "message_id" is not null)) NOT VALID; diff --git a/packages/database/migrations/20261017134832_inbox_message_thread/snapshot.json b/packages/database/migrations/20261017134832_inbox_message_thread/snapshot.json new file mode 100644 index 0000000000..b084adaa70 --- /dev/null +++ b/packages/database/migrations/20261017134832_inbox_message_thread/snapshot.json @@ -0,0 +1,13351 @@ +{ + "version": "8", + "dialect": "postgres", + "id": "4a1a9204-cc3b-48ac-a06f-665a87105cfb", + "prevIds": ["efc374cc-05d0-489c-9c22-a5f2db270b0d"], + "ddl": [ + { + "isRlsEnabled": false, + "name": "account_provider_key", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "agent_pin", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "account", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "invitation", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "jwks", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "member", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_access_token", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_client", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_client_assertion", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_client_resource", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_consent", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_refresh_token", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_resource", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "organization", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "session", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "user", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "verification", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "automation", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "automation_run", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "chat_attachment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "chat_channel", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "chat_member", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "chat_message", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "chat_read", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "workspace_chat", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "coding_agent", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "coding_agent_delegation", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "conversation_attachment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "admin_favorite", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "github_connect_intent", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "github_install_intent", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "github_installation", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "inbox_item", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "inbox_attachment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "inbox_message", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "integration_connection", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "issue", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "mac_command", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "mac_command_listener", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "personal_workspace", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "plan_attachment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "plan_comment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "plan_comment_thread", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "plan_page_version", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "plan_revision", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "account_plan_template_revision", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "account_preference", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "repository_pin", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "sandbox_terminal_lease", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "session_sandbox_cleanup", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "asks", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "conversations", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "messages", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "turns", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "task", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "task_board", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "task_pin", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "task_section", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "task_section_entry", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "hosted_usage", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "voice_session_usage", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "voice_avatar_sessions", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "voice_sessions", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "voice_transcript_segments", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "workspace_integration_connection", + "entityType": "tables", + "schema": "public" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "provider", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "key_version", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sealed_data_key", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sealed_key", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "hint", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status_at", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "fast_access", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "agent_pin" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "coding_agent_id", + "entityType": "columns", + "schema": "public", + "table": "agent_pin" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "position", + "entityType": "columns", + "schema": "public", + "table": "agent_pin" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "pinned_at", + "entityType": "columns", + "schema": "public", + "table": "agent_pin" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "account_id", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "provider_id", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "access_token", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "refresh_token", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id_token", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "access_token_expires_at", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "refresh_token_expires_at", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "scope", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "password", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "email", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'pending'", + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "inviter_id", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "public_key", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "private_key", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "alg", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "crv", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'member'", + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "token", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "session_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reference_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "authorization_code_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "resources", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "requested_user_info_claims", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "refresh_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "revoked", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "confirmation", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "scopes", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_secret", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_discovery_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "disabled", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "skip_consent", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "enable_end_session", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "subject_type", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "scopes", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": "'{}'", + "generated": null, + "identity": null, + "name": "client_credentials_scopes", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "uri", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "icon", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "contacts", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "tos", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "policy", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "software_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "software_version", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "software_statement", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "redirect_uris", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "post_logout_redirect_uris", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "backchannel_logout_uri", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "backchannel_logout_session_required", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "token_endpoint_auth_method", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "application_type", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "jwks", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "jwks_uri", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "grant_types", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "response_types", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "public", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "type", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "require_pkce", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "dpop_bound_access_tokens", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reference_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "metadata", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_assertion" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_assertion" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "resource_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "metadata", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reference_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "resources", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "requested_user_info_claims", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "scopes", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "token", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "session_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reference_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "authorization_code_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "resources", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "requested_user_info_claims", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "revoked", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "rotated_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "rotation_replay_response", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "rotation_replay_expires_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "auth_time", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "confirmation", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "scopes", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "identifier", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "access_token_ttl", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "refresh_token_ttl", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "signing_algorithm", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "signing_key_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "allowed_scopes", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "custom_claims", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "dpop_bound_access_tokens_required", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "disabled", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "policy_version", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "metadata", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "slug", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "logo", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "metadata", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "token", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ip_address", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_agent", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "active_organization_id", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "email", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "email_verified", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "image", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "last_login_method", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": "'user'", + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "identifier", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "value", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'personal'", + "generated": null, + "identity": null, + "name": "scope", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "enabled", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "trigger_kind", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "trigger", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "action", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "guards", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "next_run_at", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "webhook_secret_hash", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'[]'", + "generated": null, + "identity": null, + "name": "repositories", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'new-agent'", + "generated": null, + "identity": null, + "name": "target_kind", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "target_agent_id", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "archive_successful", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "automation_id", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "dedupe_key", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "firing", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "payload", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reason", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "coding_agent_id", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "fired_at", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "settled_at", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "claimed_agent_id", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "archive_settled_at", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "message_id", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "content_type", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "byte_count", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "bytea", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "bytes", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "kind", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "dm_a_member_id", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "dm_b_member_id", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_by_member_id", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "archived_at", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "kind", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "agent_id", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "handle", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ordinal", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "read_seq", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "notice_seq", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "notice_channel_id", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "joined_at", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "left_at", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "channel_id", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "touched_seq", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "parent_id", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "author_member_id", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "blocks", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": "'{}'", + "generated": null, + "identity": null, + "name": "mentions", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_key", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "touched_at", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ask", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ask_key", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ask_revision", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ask_status", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "answer", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "answer_key", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "answered_by_member_id", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "closed_reason", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "member_id", + "entityType": "columns", + "schema": "public", + "table": "chat_read" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "channel_id", + "entityType": "columns", + "schema": "public", + "table": "chat_read" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "read_seq", + "entityType": "columns", + "schema": "public", + "table": "chat_read" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "workspace_chat" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "next_seq", + "entityType": "columns", + "schema": "public", + "table": "workspace_chat" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "automation_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "automation_origin", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_from", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "model", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "effort", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'long'", + "generated": null, + "identity": null, + "name": "context_window", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "plan_snapshot", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "prompt", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "repository", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'[]'", + "generated": null, + "identity": null, + "name": "repositories", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "branch", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "start_branch", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "title", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "last_step", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "compacted_at", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "published", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "archived_at", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "archived_by", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "disabled_servers", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "mentioned_servers", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "author", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "idempotency_key", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "child_conversation_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent_delegation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "call_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent_delegation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "model", + "entityType": "columns", + "schema": "public", + "table": "coding_agent_delegation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "effort", + "entityType": "columns", + "schema": "public", + "table": "coding_agent_delegation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sha256", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "content_type", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "width", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "height", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "byte_count", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "bytea", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "bytes", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "admin_id", + "entityType": "columns", + "schema": "public", + "table": "admin_favorite" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "admin_favorite" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "github_connect_intent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "github_connect_intent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "github_connect_intent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "github_connect_intent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "state_hash", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "installation_id", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "code_verifier", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "installation_id", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "account_id", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "account_login", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "account_type", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "agent_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "key", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "revision", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "version", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "title", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "blocks", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "response", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "needs_reply", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "answer", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "answer_key", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "answered_by", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "closed_reason", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "posted_at", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "settled_at", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "item_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "message_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'image'", + "generated": null, + "identity": null, + "name": "kind", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "position", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "content_type", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "byte_count", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "bytea", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "bytes", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "item_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "author", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "text", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_key", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "provider", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connect_subject", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connection_name", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "label", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "state", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "state_issued_at", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connect_verifier", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connected_at", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "number", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "title", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "''", + "generated": null, + "identity": null, + "name": "description", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'backlog'", + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'none'", + "generated": null, + "identity": null, + "name": "priority", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "creator_id", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "archived_at", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "command", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "timeout_seconds", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "queued_at", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "claimed_at", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "result", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "mac_command_listener" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seen_at", + "entityType": "columns", + "schema": "public", + "table": "mac_command_listener" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "personal_workspace" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "personal_workspace" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "personal_workspace" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "content_type", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "byte_count", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "bytea", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "bytes", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "saved_at", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "thread_id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "kind", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "actor", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "agent_id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "words", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "asked_actor", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "asked_agent_id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_key", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "edited_at", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "scope", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "quote", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "anchor_from", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "anchor_to", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "section", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "revision", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "page_id", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "version", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "title", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "html", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "shown_by", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "at", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "actor", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "agent_id", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "live_session_id", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "document", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "changes", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "at", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "restored_from", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "actor", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "document", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "changes", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "at", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "restored_from", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "voice", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "coding_agent_model", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "coding_agent_effort", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "coding_agent_context_window", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "plan_template", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "experiments", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "repository_pin" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "repository", + "entityType": "columns", + "schema": "public", + "table": "repository_pin" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "pinned_at", + "entityType": "columns", + "schema": "public", + "table": "repository_pin" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "held_until", + "entityType": "columns", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "tried_at", + "entityType": "columns", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "credential_at", + "entityType": "columns", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "credential_session", + "entityType": "columns", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "session_id", + "entityType": "columns", + "schema": "public", + "table": "session_sandbox_cleanup" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "queued_at", + "entityType": "columns", + "schema": "public", + "table": "session_sandbox_cleanup" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "tried_at", + "entityType": "columns", + "schema": "public", + "table": "session_sandbox_cleanup" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "origin", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "session_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "delivery_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "turn_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "cancel_requested_at", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "voice_session_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ask_revision", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "told_seq", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "end_told_at", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "kind", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "title", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "parent_conversation_id", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "runtime_session_id", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "last_activity_at", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "deleted_at", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "next_message_seq", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "journal_revision", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "label", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "true", + "generated": null, + "identity": null, + "name": "expects_completion", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "turn_id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "parts", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "metadata", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "finished_at", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "revision", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "placed_at", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sender", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sender_user_id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sender_name", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "taken_after_step", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "origin", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "model", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reasoning_effort", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "prompt_hash", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "tool_set_hash", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "response_ids", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "usage", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "eve_turn_id", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "queued_at", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "settled_at", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "failure", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "failure_detail", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "cancel_requested_at", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "fast_refused", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'[]'", + "generated": null, + "identity": null, + "name": "agent_edits", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "document", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "repository", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "linear_issue", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "pinned_at", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "archived_at", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'[]'", + "generated": null, + "identity": null, + "name": "elements", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "applied_drawing", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "drawing", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "drawing_number", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "image", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "task_pin" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "task_pin" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "position", + "entityType": "columns", + "schema": "public", + "table": "task_pin" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "pinned_at", + "entityType": "columns", + "schema": "public", + "table": "task_pin" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "title", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "icon", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "position", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "task_section_entry" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "task_section_entry" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "section_id", + "entityType": "columns", + "schema": "public", + "table": "task_section_entry" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "position", + "entityType": "columns", + "schema": "public", + "table": "task_section_entry" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "added_at", + "entityType": "columns", + "schema": "public", + "table": "task_section_entry" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "hosted_usage" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "day", + "entityType": "columns", + "schema": "public", + "table": "hosted_usage" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "calls", + "entityType": "columns", + "schema": "public", + "table": "hosted_usage" + }, + { + "type": "double precision", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "dictation_seconds", + "entityType": "columns", + "schema": "public", + "table": "hosted_usage" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "session_id", + "entityType": "columns", + "schema": "public", + "table": "voice_session_usage" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "voice_session_usage" + }, + { + "type": "double precision", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seconds", + "entityType": "columns", + "schema": "public", + "table": "voice_session_usage" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "recorded_at", + "entityType": "columns", + "schema": "public", + "table": "voice_session_usage" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "voice_session_id", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "persona_id", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ended_at", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seconds", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "end_reason", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "device_id", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "live_session_id", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "delegation_mode", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "closed_at", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "close_reason", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "usage", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "model", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "detached_at", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "attach_id", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "voice_session_id", + "entityType": "columns", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "text", + "entityType": "columns", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "start_ms", + "entityType": "columns", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "end_ms", + "entityType": "columns", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "provider", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "state", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "state_issued_at", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connect_verifier", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connected_by_user_id", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connected_at", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "coding_agent_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "agent_pin_agent", + "entityType": "indexes", + "schema": "public", + "table": "agent_pin" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "account_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "account" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "invitation_organizationId_idx", + "entityType": "indexes", + "schema": "public", + "table": "invitation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "email", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "invitation_email_idx", + "entityType": "indexes", + "schema": "public", + "table": "invitation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "member_organizationId_idx", + "entityType": "indexes", + "schema": "public", + "table": "member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "member_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "client_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthAccessToken_clientId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "session_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthAccessToken_sessionId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthAccessToken_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "authorization_code_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthAccessToken_authorizationCodeId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "refresh_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthAccessToken_refreshId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthClient_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_client" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "client_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "resource_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthClientResource_clientId_resourceId_uidx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "client_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthClientResource_clientId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "resource_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthClientResource_resourceId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "client_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthConsent_clientId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_consent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthConsent_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_consent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "client_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthRefreshToken_clientId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "session_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthRefreshToken_sessionId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthRefreshToken_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "authorization_code_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthRefreshToken_authorizationCodeId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "session_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "session" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "identifier", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "verification_identifier_idx", + "entityType": "indexes", + "schema": "public", + "table": "verification" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "automation_user_created", + "entityType": "indexes", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "next_run_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"next_run_at\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "automation_next_run", + "entityType": "indexes", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "trigger_kind", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "automation_trigger_task", + "entityType": "indexes", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "scope", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "automation_org_scope_created", + "entityType": "indexes", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "automation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "dedupe_key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "automation_run_dedupe", + "entityType": "indexes", + "schema": "public", + "table": "automation_run" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "automation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "fired_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "automation_run_automation_fired", + "entityType": "indexes", + "schema": "public", + "table": "automation_run" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "message_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_attachment_message", + "entityType": "indexes", + "schema": "public", + "table": "chat_attachment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "name", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"name\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_channel_organization_name", + "entityType": "indexes", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "dm_a_member_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "dm_b_member_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"kind\" = 'dm'", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_channel_organization_dm", + "entityType": "indexes", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"kind\" = 'plan'", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_channel_task", + "entityType": "indexes", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_channel_organization_created", + "entityType": "indexes", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "handle", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"kind\" <> 'planner'", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_member_organization_handle", + "entityType": "indexes", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "kind", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "ordinal", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_member_organization_kind_ordinal", + "entityType": "indexes", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"user_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_member_organization_user", + "entityType": "indexes", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "agent_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"agent_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_member_agent", + "entityType": "indexes", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"task_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_member_task", + "entityType": "indexes", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "seq", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_organization_seq", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "channel_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "client_key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_channel_client_key", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "channel_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "seq", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_channel_seq", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "parent_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "seq", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"parent_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_parent_seq", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "touched_seq", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_organization_touched", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "author_member_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "ask_key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"ask_key\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_author_ask_key", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "ask_status", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"ask_key\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_organization_ask_status", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "channel_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_read_channel", + "entityType": "indexes", + "schema": "public", + "table": "chat_read" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "idempotency_key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "coding_agent_user_idempotency", + "entityType": "indexes", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "coding_agent_task_created", + "entityType": "indexes", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "coding_agent_org_created", + "entityType": "indexes", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "conversation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "sha256", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "conversation_attachment_conversation_sha256", + "entityType": "indexes", + "schema": "public", + "table": "conversation_attachment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_connect_intent_user_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_connect_intent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_installation_organization_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_installation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "agent_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_item_agent_key", + "entityType": "indexes", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "updated_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_item_task_updated", + "entityType": "indexes", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "updated_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_item_org_updated", + "entityType": "indexes", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "status", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "updated_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_item_user_status_updated", + "entityType": "indexes", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "item_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_attachment_item", + "entityType": "indexes", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "message_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_attachment_message", + "entityType": "indexes", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "item_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_message_item_created", + "entityType": "indexes", + "schema": "public", + "table": "inbox_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "item_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "client_key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"client_key\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_message_client_key", + "entityType": "indexes", + "schema": "public", + "table": "inbox_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "connection_name", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "integration_connection_user_name_idx", + "entityType": "indexes", + "schema": "public", + "table": "integration_connection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "provider", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "connect_subject", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "integration_connection_provider_subject_idx", + "entityType": "indexes", + "schema": "public", + "table": "integration_connection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "state", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "integration_connection_state_idx", + "entityType": "indexes", + "schema": "public", + "table": "integration_connection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "provider", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "integration_connection_user_provider_idx", + "entityType": "indexes", + "schema": "public", + "table": "integration_connection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "number", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "issue_org_number", + "entityType": "indexes", + "schema": "public", + "table": "issue" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "updated_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "issue_org_updated", + "entityType": "indexes", + "schema": "public", + "table": "issue" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "claimed_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "mac_command_waiting", + "entityType": "indexes", + "schema": "public", + "table": "mac_command" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_attachment_task", + "entityType": "indexes", + "schema": "public", + "table": "plan_attachment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"saved_at\" is null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_attachment_unsaved", + "entityType": "indexes", + "schema": "public", + "table": "plan_attachment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "thread_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "seq", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_comment_thread_seq", + "entityType": "indexes", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_comment_task", + "entityType": "indexes", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "client_key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"client_key\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_comment_client_key", + "entityType": "indexes", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_comment_thread_task_created", + "entityType": "indexes", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_page_version_task", + "entityType": "indexes", + "schema": "public", + "table": "plan_page_version" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "tried_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "held_until", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "sandbox_terminal_lease_next", + "entityType": "indexes", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "tried_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "queued_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "session_sandbox_cleanup_next", + "entityType": "indexes", + "schema": "public", + "table": "session_sandbox_cleanup" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "conversation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "client_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "asks_conversation_client", + "entityType": "indexes", + "schema": "public", + "table": "asks" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "asks_by_user", + "entityType": "indexes", + "schema": "public", + "table": "asks" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "conversation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "delivery_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "asks_conversation_delivery", + "entityType": "indexes", + "schema": "public", + "table": "asks" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "voice_session_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"voice_session_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "asks_by_voice_session", + "entityType": "indexes", + "schema": "public", + "table": "asks" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"kind\" = 'main' and \"deleted_at\" is null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "conversations_standing_main", + "entityType": "indexes", + "schema": "public", + "table": "conversations" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "deleted_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"deleted_at\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "conversations_deleted_at", + "entityType": "indexes", + "schema": "public", + "table": "conversations" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "kind", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "conversations_user_kind", + "entityType": "indexes", + "schema": "public", + "table": "conversations" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "conversation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "revision", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"revision\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "messages_conversation_revision", + "entityType": "indexes", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "turns_by_user", + "entityType": "indexes", + "schema": "public", + "table": "turns" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "conversation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "queued_at", + "isExpression": false, + "asc": false, + "nullsFirst": true, + "opclass": null + }, + { + "value": "id", + "isExpression": false, + "asc": false, + "nullsFirst": true, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "turns_conversation_queued", + "entityType": "indexes", + "schema": "public", + "table": "turns" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "started_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"status\" = 'running'", + "with": "", + "method": "btree", + "concurrently": false, + "name": "turns_running_started", + "entityType": "indexes", + "schema": "public", + "table": "turns" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_user_created", + "entityType": "indexes", + "schema": "public", + "table": "task" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_organization_created", + "entityType": "indexes", + "schema": "public", + "table": "task" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_pin_task", + "entityType": "indexes", + "schema": "public", + "table": "task_pin" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_section_user", + "entityType": "indexes", + "schema": "public", + "table": "task_section" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_section_organization", + "entityType": "indexes", + "schema": "public", + "table": "task_section" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_section_entry_task", + "entityType": "indexes", + "schema": "public", + "table": "task_section_entry" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "section_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_section_entry_section", + "entityType": "indexes", + "schema": "public", + "table": "task_section_entry" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "voice_session_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"ended_at\" is null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "voice_avatar_sessions_open", + "entityType": "indexes", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "live_session_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "voice_sessions_by_owner", + "entityType": "indexes", + "schema": "public", + "table": "voice_sessions" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "detached_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"closed_at\" is null and \"detached_at\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "voice_sessions_detached", + "entityType": "indexes", + "schema": "public", + "table": "voice_sessions" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "state", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "workspace_integration_connection_state_idx", + "entityType": "indexes", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "account_provider_key_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "account_provider_key" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "agent_pin_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "agent_pin" + }, + { + "nameExplicit": false, + "columns": ["coding_agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "agent_pin_coding_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "agent_pin" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "account_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "account" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "invitation_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "invitation" + }, + { + "nameExplicit": false, + "columns": ["inviter_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "invitation_inviter_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "invitation" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "member_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "member" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "member_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "member" + }, + { + "nameExplicit": false, + "columns": ["client_id"], + "schemaTo": "public", + "tableTo": "oauth_client", + "columnsTo": ["client_id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_access_token_client_id_oauth_client_client_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": false, + "columns": ["session_id"], + "schemaTo": "public", + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "oauth_access_token_session_id_session_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_access_token_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": false, + "columns": ["refresh_id"], + "schemaTo": "public", + "tableTo": "oauth_refresh_token", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_access_token_refresh_id_oauth_refresh_token_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_client_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_client" + }, + { + "nameExplicit": false, + "columns": ["client_id"], + "schemaTo": "public", + "tableTo": "oauth_client", + "columnsTo": ["client_id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_client_resource_client_id_oauth_client_client_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "nameExplicit": false, + "columns": ["resource_id"], + "schemaTo": "public", + "tableTo": "oauth_resource", + "columnsTo": ["identifier"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_client_resource_resource_id_oauth_resource_identifier_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "nameExplicit": false, + "columns": ["client_id"], + "schemaTo": "public", + "tableTo": "oauth_client", + "columnsTo": ["client_id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_consent_client_id_oauth_client_client_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_consent" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_consent_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_consent" + }, + { + "nameExplicit": false, + "columns": ["client_id"], + "schemaTo": "public", + "tableTo": "oauth_client", + "columnsTo": ["client_id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_refresh_token_client_id_oauth_client_client_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": false, + "columns": ["session_id"], + "schemaTo": "public", + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "oauth_refresh_token_session_id_session_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_refresh_token_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "session_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "session" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "automation_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "automation_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "automation_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": false, + "columns": ["target_agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "automation_target_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": false, + "columns": ["automation_id"], + "schemaTo": "public", + "tableTo": "automation", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "automation_run_automation_id_automation_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation_run" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "automation_run_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation_run" + }, + { + "nameExplicit": false, + "columns": ["coding_agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "automation_run_coding_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation_run" + }, + { + "nameExplicit": false, + "columns": ["claimed_agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "automation_run_claimed_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation_run" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_attachment_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_attachment" + }, + { + "nameExplicit": false, + "columns": ["message_id"], + "schemaTo": "public", + "tableTo": "chat_message", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_attachment_message_id_chat_message_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_attachment" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_channel_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_channel_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": false, + "columns": ["dm_a_member_id"], + "schemaTo": "public", + "tableTo": "chat_member", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_channel_dm_a_member_id_chat_member_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": false, + "columns": ["dm_b_member_id"], + "schemaTo": "public", + "tableTo": "chat_member", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_channel_dm_b_member_id_chat_member_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": false, + "columns": ["created_by_member_id"], + "schemaTo": "public", + "tableTo": "chat_member", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "chat_channel_created_by_member_id_chat_member_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_member_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_member_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": false, + "columns": ["agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "chat_member_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "chat_member_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": false, + "columns": ["notice_channel_id"], + "schemaTo": "public", + "tableTo": "chat_channel", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "chat_member_notice_channel_id_chat_channel_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_message_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": false, + "columns": ["channel_id"], + "schemaTo": "public", + "tableTo": "chat_channel", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_message_channel_id_chat_channel_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": false, + "columns": ["parent_id"], + "schemaTo": "public", + "tableTo": "chat_message", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "chat_message_parent_id_chat_message_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": false, + "columns": ["author_member_id"], + "schemaTo": "public", + "tableTo": "chat_member", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_message_author_member_id_chat_member_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": false, + "columns": ["answered_by_member_id"], + "schemaTo": "public", + "tableTo": "chat_member", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "chat_message_answered_by_member_id_chat_member_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": false, + "columns": ["member_id"], + "schemaTo": "public", + "tableTo": "chat_member", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_read_member_id_chat_member_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_read" + }, + { + "nameExplicit": false, + "columns": ["channel_id"], + "schemaTo": "public", + "tableTo": "chat_channel", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_read_channel_id_chat_channel_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_read" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "workspace_chat_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "workspace_chat" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "coding_agent_plan_id_plan_id_fk", + "entityType": "fks", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "coding_agent_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": false, + "columns": ["automation_id"], + "schemaTo": "public", + "tableTo": "automation", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "coding_agent_automation_id_automation_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "coding_agent_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "coding_agent_conversation_id_conversations_id_fk", + "entityType": "fks", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": true, + "columns": ["child_conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "coding_agent_delegation_child_conversation_id_conversations_id_", + "entityType": "fks", + "schema": "public", + "table": "coding_agent_delegation" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "conversation_attachment_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "conversation_attachment" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "conversation_attachment_conversation_id_conversations_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "conversation_attachment" + }, + { + "nameExplicit": false, + "columns": ["admin_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "admin_favorite_admin_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "admin_favorite" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "admin_favorite_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "admin_favorite" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "github_connect_intent_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_connect_intent" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "github_install_intent_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_install_intent" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "github_install_intent_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_install_intent" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "github_installation_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_installation" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_item_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_item_plan_id_plan_id_fk", + "entityType": "fks", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_item_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": false, + "columns": ["agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_item_agent_id_coding_agent_id_fk", + "entityType": "fks", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": false, + "columns": ["answered_by"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "inbox_item_answered_by_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_attachment_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_attachment_plan_id_plan_id_fk", + "entityType": "fks", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_attachment_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": false, + "columns": ["item_id"], + "schemaTo": "public", + "tableTo": "inbox_item", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_attachment_item_id_inbox_item_id_fk", + "entityType": "fks", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": false, + "columns": ["message_id"], + "schemaTo": "public", + "tableTo": "inbox_message", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_attachment_message_id_inbox_message_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": false, + "columns": ["item_id"], + "schemaTo": "public", + "tableTo": "inbox_item", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_message_item_id_inbox_item_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_message" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "inbox_message_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_message" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "integration_connection_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "integration_connection" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "issue_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "issue" + }, + { + "nameExplicit": false, + "columns": ["creator_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "issue_creator_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "issue" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "mac_command_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "mac_command" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "mac_command_listener_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "mac_command_listener" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "personal_workspace_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "personal_workspace" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "personal_workspace_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "personal_workspace" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_attachment_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_attachment" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_attachment_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_attachment" + }, + { + "nameExplicit": false, + "columns": ["thread_id"], + "schemaTo": "public", + "tableTo": "plan_comment_thread", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_comment_thread_id_plan_comment_thread_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_comment_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_comment_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": false, + "columns": ["agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_comment_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": false, + "columns": ["asked_agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_comment_asked_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_comment_thread_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_page_version_plan_id_plan_id_fk", + "entityType": "fks", + "schema": "public", + "table": "plan_page_version" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_revision_plan_id_plan_id_fk", + "entityType": "fks", + "schema": "public", + "table": "plan_revision" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_revision_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_revision" + }, + { + "nameExplicit": false, + "columns": ["agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_revision_agent_id_coding_agent_id_fk", + "entityType": "fks", + "schema": "public", + "table": "plan_revision" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "account_plan_template_revision_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "account_preference_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "account_preference" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "repository_pin_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "repository_pin" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "sandbox_terminal_lease_conversation_id_conversations_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "asks_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "asks" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "asks_conversation_id_conversations_id_fk", + "entityType": "fks", + "schema": "public", + "table": "asks" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "conversations_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "conversations" + }, + { + "nameExplicit": false, + "columns": ["parent_conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "conversations_parent_conversation_id_conversations_id_fk", + "entityType": "fks", + "schema": "public", + "table": "conversations" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "messages_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "messages_conversation_id_conversations_id_fk", + "entityType": "fks", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": false, + "columns": ["turn_id"], + "schemaTo": "public", + "tableTo": "turns", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "NO ACTION", + "name": "messages_turn_id_turns_id_fk", + "entityType": "fks", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": false, + "columns": ["sender_user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "messages_sender_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "turns_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "turns" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "turns_conversation_id_conversations_id_fk", + "entityType": "fks", + "schema": "public", + "table": "turns" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "task" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_conversation_id_conversations_id_fk", + "entityType": "fks", + "schema": "public", + "table": "task" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_board_plan_id_plan_id_fk", + "entityType": "fks", + "schema": "public", + "table": "task_board" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_pin_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_pin" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_pin_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_pin" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "task_section_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_section" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "task_section_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_section" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "task_section_entry_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_section_entry" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "task_section_entry_task_id_task_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_section_entry" + }, + { + "nameExplicit": false, + "columns": ["section_id"], + "schemaTo": "public", + "tableTo": "task_section", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "task_section_entry_section_id_task_section_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_section_entry" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "hosted_usage_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "hosted_usage" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "voice_session_usage_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "voice_session_usage" + }, + { + "nameExplicit": false, + "columns": ["voice_session_id"], + "schemaTo": "public", + "tableTo": "voice_sessions", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "voice_avatar_sessions_voice_session_id_voice_sessions_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "voice_avatar_sessions_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "voice_sessions_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "voice_sessions" + }, + { + "nameExplicit": false, + "columns": ["voice_session_id"], + "schemaTo": "public", + "tableTo": "voice_sessions", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "voice_transcript_segments_voice_session_id_voice_sessions_id_fk", + "entityType": "fks", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "workspace_integration_connection_HMbDsJWkK6TV_fkey", + "entityType": "fks", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "nameExplicit": false, + "columns": ["connected_by_user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "workspace_integration_connection_3ggWlPzIKenx_fkey", + "entityType": "fks", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "columns": ["user_id", "provider"], + "nameExplicit": false, + "name": "account_provider_key_user_id_provider_pk", + "entityType": "pks", + "schema": "public", + "table": "account_provider_key" + }, + { + "columns": ["user_id", "coding_agent_id"], + "nameExplicit": false, + "name": "agent_pin_pkey", + "entityType": "pks", + "schema": "public", + "table": "agent_pin" + }, + { + "columns": ["member_id", "channel_id"], + "nameExplicit": false, + "name": "chat_read_pkey", + "entityType": "pks", + "schema": "public", + "table": "chat_read" + }, + { + "columns": ["admin_id", "user_id"], + "nameExplicit": false, + "name": "admin_favorite_admin_id_user_id_pk", + "entityType": "pks", + "schema": "public", + "table": "admin_favorite" + }, + { + "columns": ["task_id", "seq"], + "nameExplicit": false, + "name": "plan_revision_plan_id_seq_pk", + "entityType": "pks", + "schema": "public", + "table": "plan_revision" + }, + { + "columns": ["user_id", "seq"], + "nameExplicit": false, + "name": "account_plan_template_revision_user_id_seq_pk", + "entityType": "pks", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "columns": ["user_id", "repository"], + "nameExplicit": false, + "name": "repository_pin_user_id_repository_pk", + "entityType": "pks", + "schema": "public", + "table": "repository_pin" + }, + { + "columns": ["user_id", "task_id"], + "nameExplicit": false, + "name": "plan_pin_pkey", + "entityType": "pks", + "schema": "public", + "table": "task_pin" + }, + { + "columns": ["user_id", "task_id"], + "nameExplicit": false, + "name": "task_section_entry_pkey", + "entityType": "pks", + "schema": "public", + "table": "task_section_entry" + }, + { + "columns": ["user_id", "day"], + "nameExplicit": false, + "name": "hosted_usage_user_id_day_pk", + "entityType": "pks", + "schema": "public", + "table": "hosted_usage" + }, + { + "columns": ["voice_session_id", "seq"], + "nameExplicit": false, + "name": "voice_transcript_segments_voice_session_id_seq_pk", + "entityType": "pks", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "columns": ["organization_id", "provider"], + "nameExplicit": false, + "name": "workspace_integration_connection_pkey", + "entityType": "pks", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "account_pkey", + "schema": "public", + "table": "account", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "invitation_pkey", + "schema": "public", + "table": "invitation", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "jwks_pkey", + "schema": "public", + "table": "jwks", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "member_pkey", + "schema": "public", + "table": "member", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_access_token_pkey", + "schema": "public", + "table": "oauth_access_token", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_client_pkey", + "schema": "public", + "table": "oauth_client", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_client_assertion_pkey", + "schema": "public", + "table": "oauth_client_assertion", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_client_resource_pkey", + "schema": "public", + "table": "oauth_client_resource", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_consent_pkey", + "schema": "public", + "table": "oauth_consent", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_refresh_token_pkey", + "schema": "public", + "table": "oauth_refresh_token", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_resource_pkey", + "schema": "public", + "table": "oauth_resource", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "organization_pkey", + "schema": "public", + "table": "organization", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "session_pkey", + "schema": "public", + "table": "session", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "user_pkey", + "schema": "public", + "table": "user", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "verification_pkey", + "schema": "public", + "table": "verification", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "automation_pkey", + "schema": "public", + "table": "automation", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "automation_run_pkey", + "schema": "public", + "table": "automation_run", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "chat_attachment_pkey", + "schema": "public", + "table": "chat_attachment", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "chat_channel_pkey", + "schema": "public", + "table": "chat_channel", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "chat_member_pkey", + "schema": "public", + "table": "chat_member", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "chat_message_pkey", + "schema": "public", + "table": "chat_message", + "entityType": "pks" + }, + { + "columns": ["organization_id"], + "nameExplicit": false, + "name": "workspace_chat_pkey", + "schema": "public", + "table": "workspace_chat", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "coding_agent_pkey", + "schema": "public", + "table": "coding_agent", + "entityType": "pks" + }, + { + "columns": ["child_conversation_id"], + "nameExplicit": false, + "name": "coding_agent_delegation_pkey", + "schema": "public", + "table": "coding_agent_delegation", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "conversation_attachment_pkey", + "schema": "public", + "table": "conversation_attachment", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "github_connect_intent_pkey", + "schema": "public", + "table": "github_connect_intent", + "entityType": "pks" + }, + { + "columns": ["state_hash"], + "nameExplicit": false, + "name": "github_install_intent_pkey", + "schema": "public", + "table": "github_install_intent", + "entityType": "pks" + }, + { + "columns": ["installation_id"], + "nameExplicit": false, + "name": "github_installation_pkey", + "schema": "public", + "table": "github_installation", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "inbox_item_pkey", + "schema": "public", + "table": "inbox_item", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "inbox_attachment_pkey", + "schema": "public", + "table": "inbox_attachment", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "inbox_message_pkey", + "schema": "public", + "table": "inbox_message", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "integration_connection_pkey", + "schema": "public", + "table": "integration_connection", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "issue_pkey", + "schema": "public", + "table": "issue", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "mac_command_pkey", + "schema": "public", + "table": "mac_command", + "entityType": "pks" + }, + { + "columns": ["user_id"], + "nameExplicit": false, + "name": "mac_command_listener_pkey", + "schema": "public", + "table": "mac_command_listener", + "entityType": "pks" + }, + { + "columns": ["user_id"], + "nameExplicit": false, + "name": "personal_workspace_pkey", + "schema": "public", + "table": "personal_workspace", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "plan_attachment_pkey", + "schema": "public", + "table": "plan_attachment", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "plan_comment_pkey", + "schema": "public", + "table": "plan_comment", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "plan_comment_thread_pkey", + "schema": "public", + "table": "plan_comment_thread", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "plan_page_version_pkey", + "schema": "public", + "table": "plan_page_version", + "entityType": "pks" + }, + { + "columns": ["user_id"], + "nameExplicit": false, + "name": "account_preference_pkey", + "schema": "public", + "table": "account_preference", + "entityType": "pks" + }, + { + "columns": ["conversation_id"], + "nameExplicit": false, + "name": "sandbox_terminal_lease_pkey", + "schema": "public", + "table": "sandbox_terminal_lease", + "entityType": "pks" + }, + { + "columns": ["session_id"], + "nameExplicit": false, + "name": "session_sandbox_cleanup_pkey", + "schema": "public", + "table": "session_sandbox_cleanup", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "asks_pkey", + "schema": "public", + "table": "asks", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "conversations_pkey", + "schema": "public", + "table": "conversations", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "messages_pkey", + "schema": "public", + "table": "messages", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "turns_pkey", + "schema": "public", + "table": "turns", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "plan_pkey", + "schema": "public", + "table": "task", + "entityType": "pks" + }, + { + "columns": ["task_id"], + "nameExplicit": false, + "name": "plan_board_pkey", + "schema": "public", + "table": "task_board", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "task_section_pkey", + "schema": "public", + "table": "task_section", + "entityType": "pks" + }, + { + "columns": ["session_id"], + "nameExplicit": false, + "name": "voice_session_usage_pkey", + "schema": "public", + "table": "voice_session_usage", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "voice_avatar_sessions_pkey", + "schema": "public", + "table": "voice_avatar_sessions", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "voice_sessions_pkey", + "schema": "public", + "table": "voice_sessions", + "entityType": "pks" + }, + { + "nameExplicit": true, + "columns": ["page_id", "version"], + "nullsNotDistinct": false, + "name": "plan_page_version_page_version", + "entityType": "uniques", + "schema": "public", + "table": "plan_page_version" + }, + { + "nameExplicit": true, + "columns": ["conversation_id", "client_id"], + "nullsNotDistinct": false, + "name": "messages_conversation_client", + "entityType": "uniques", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": true, + "columns": ["conversation_id", "seq"], + "nullsNotDistinct": false, + "name": "messages_conversation_seq", + "entityType": "uniques", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": false, + "columns": ["token"], + "nullsNotDistinct": false, + "name": "oauth_access_token_token_unique", + "schema": "public", + "table": "oauth_access_token", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["client_id"], + "nullsNotDistinct": false, + "name": "oauth_client_client_id_unique", + "schema": "public", + "table": "oauth_client", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["token"], + "nullsNotDistinct": false, + "name": "oauth_refresh_token_token_unique", + "schema": "public", + "table": "oauth_refresh_token", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["identifier"], + "nullsNotDistinct": false, + "name": "oauth_resource_identifier_unique", + "schema": "public", + "table": "oauth_resource", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["slug"], + "nullsNotDistinct": false, + "name": "organization_slug_key", + "schema": "public", + "table": "organization", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["token"], + "nullsNotDistinct": false, + "name": "session_token_unique", + "schema": "public", + "table": "session", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["email"], + "nullsNotDistinct": false, + "name": "user_email_unique", + "schema": "public", + "table": "user", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["account_id"], + "nullsNotDistinct": false, + "name": "github_installation_account_id_key", + "schema": "public", + "table": "github_installation", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "nullsNotDistinct": false, + "name": "personal_workspace_organization_id_key", + "schema": "public", + "table": "personal_workspace", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["live_session_id"], + "nullsNotDistinct": false, + "name": "voice_sessions_live_session_id_unique", + "schema": "public", + "table": "voice_sessions", + "entityType": "uniques" + }, + { + "value": "octet_length(\"bytes\") <= 1500000", + "name": "chat_attachment_bytes_bound", + "entityType": "checks", + "schema": "public", + "table": "chat_attachment" + }, + { + "value": "(\"kind\" = 'dm') = (\"name\" is null)\n and (\"kind\" = 'dm') = (\"dm_a_member_id\" is not null and \"dm_b_member_id\" is not null)\n and (\"dm_a_member_id\" is null or \"dm_a_member_id\" < \"dm_b_member_id\")", + "name": "chat_channel_shape_of_kind", + "entityType": "checks", + "schema": "public", + "table": "chat_channel" + }, + { + "value": "(\"kind\" = 'human') = (\"user_id\" is not null)\n and (\"agent_id\" is null or \"kind\" = 'agent')\n and (\"task_id\" is null or \"kind\" = 'planner')", + "name": "chat_member_id_of_kind", + "entityType": "checks", + "schema": "public", + "table": "chat_member" + }, + { + "value": "(\"ask_key\" is null) = (\"ask\" is null)\n and (\"ask_key\" is null) = (\"ask_revision\" is null)\n and (\"ask_key\" is null) = (\"ask_status\" is null)", + "name": "chat_message_ask_whole", + "entityType": "checks", + "schema": "public", + "table": "chat_message" + }, + { + "value": "octet_length(\"bytes\") <= 4000000", + "name": "conversation_attachment_bytes_bound", + "entityType": "checks", + "schema": "public", + "table": "conversation_attachment" + }, + { + "value": "(\"kind\" = 'image' and octet_length(\"bytes\") <= 1500000 and \"name\" is null and \"position\" is null and \"message_id\" is null) or (\"kind\" = 'answer' and octet_length(\"bytes\") <= 3000000 and \"name\" is not null and \"position\" is not null and \"message_id\" is null) or (\"kind\" = 'message' and octet_length(\"bytes\") <= 3000000 and \"name\" is not null and \"position\" is not null and \"message_id\" is not null)", + "name": "inbox_attachment_kind_bound", + "entityType": "checks", + "schema": "public", + "table": "inbox_attachment" + }, + { + "value": "octet_length(\"bytes\") <= 1500000", + "name": "plan_attachment_bytes_bound", + "entityType": "checks", + "schema": "public", + "table": "plan_attachment" + } + ], + "renames": [] +} diff --git a/packages/database/package.json b/packages/database/package.json index a13c371925..bea4652863 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -66,6 +66,7 @@ "./schemas/inbox": "./src/schemas/inbox.js", "./schemas/conversation-attachment": "./src/schemas/conversation-attachment.js", "./schemas/inbox-attachment": "./src/schemas/inbox-attachment.js", + "./schemas/inbox-message": "./src/schemas/inbox-message.js", "./schemas/integration": "./src/schemas/integration.js", "./schemas/issue": "./src/schemas/issue.js", "./schemas/mac-command": "./src/schemas/mac-command.js", diff --git a/packages/database/src/schemas/inbox-attachment.ts b/packages/database/src/schemas/inbox-attachment.ts index 60cad57e2c..8e9e9bdf54 100644 --- a/packages/database/src/schemas/inbox-attachment.ts +++ b/packages/database/src/schemas/inbox-attachment.ts @@ -9,6 +9,7 @@ import { INBOX_ATTACHMENT_KIND, type InboxAttachmentKind } from "../storage-voca import { bytea, timestamptz } from "./_helpers.js"; import { organization, user } from "./auth.js"; import { inboxItem } from "./inbox.js"; +import { inboxMessage } from "./inbox-message.js"; import { task } from "./task.js"; /** A value written into the check as SQL rather than a parameter, which a constraint cannot take. */ @@ -42,6 +43,12 @@ const bound = (bytes: number) => sql.raw(String(bytes)); * answer's file has a name and a place. An answer's files go when the * answer is taken back, or when the agent posts the item again, which opens * it and clears the answer. + * + * A file a message on the item's thread carried is kept here too, as a row + * of the message kind naming its message, held to an answer's file's bound + * with a name and a place among the message's files. It goes with its + * message, which goes with the item, and stays when the agent posts the + * item again, since the thread does. */ export const inboxAttachment = pgTable( "inbox_attachment", @@ -59,11 +66,13 @@ export const inboxAttachment = pgTable( itemId: uuid("item_id") .notNull() .references(() => inboxItem.id, { onDelete: "cascade" }), - /** A picture of an image block's, as every row before answers carried files was, or a file of the answer's. */ + /** The message on the item's thread whose file it is; null for a picture and an answer's file. */ + messageId: uuid("message_id").references(() => inboxMessage.id, { onDelete: "cascade" }), + /** A picture of an image block's, as every row before answers carried files was, a file of the answer's, or a file of a message's. */ kind: text("kind").$type().notNull().default(INBOX_ATTACHMENT_KIND.IMAGE), - /** An answer's file's own name, never a path, such as `trace.txt`; null for a picture, whose words are its block's alt. */ + /** An answer's or a message's file's own name, never a path, such as `trace.txt`; null for a picture, whose words are its block's alt. */ name: text("name"), - /** An answer's file's place among the answer's files, from zero, in the order the developer attached them; null for a picture. */ + /** An answer's or a message's file's place among its files, from zero, in the order they were attached; null for a picture. */ position: integer("position"), /** The media type a picture's bytes were sniffed to be, or the type an answer's file travelled as: what the bytes are served under. */ contentType: text("content_type").$type().notNull(), @@ -75,10 +84,12 @@ export const inboxAttachment = pgTable( (table) => [ // An item's attachments are read and deleted by the item. index("inbox_attachment_item").on(table.itemId), - // Each kind is held to its own bound, and only an answer's file has a name and a place. + // A message's files are read by the message, and go with it. + index("inbox_attachment_message").on(table.messageId), + // Each kind is held to its own bound, only an answer's or a message's file has a name and a place, and only a message's names a message. check( "inbox_attachment_kind_bound", - sql`(${table.kind} = ${literal(INBOX_ATTACHMENT_KIND.IMAGE)} and octet_length(${table.bytes}) <= ${bound(INBOX_BOUNDS.MAX_IMAGE_BYTES)} and ${table.name} is null and ${table.position} is null) or (${table.kind} = ${literal(INBOX_ATTACHMENT_KIND.ANSWER)} and octet_length(${table.bytes}) <= ${bound(CODING_AGENT_BOUNDS.MAX_PDF_BYTES)} and ${table.name} is not null and ${table.position} is not null)`, + sql`(${table.kind} = ${literal(INBOX_ATTACHMENT_KIND.IMAGE)} and octet_length(${table.bytes}) <= ${bound(INBOX_BOUNDS.MAX_IMAGE_BYTES)} and ${table.name} is null and ${table.position} is null and ${table.messageId} is null) or (${table.kind} = ${literal(INBOX_ATTACHMENT_KIND.ANSWER)} and octet_length(${table.bytes}) <= ${bound(CODING_AGENT_BOUNDS.MAX_PDF_BYTES)} and ${table.name} is not null and ${table.position} is not null and ${table.messageId} is null) or (${table.kind} = ${literal(INBOX_ATTACHMENT_KIND.MESSAGE)} and octet_length(${table.bytes}) <= ${bound(CODING_AGENT_BOUNDS.MAX_PDF_BYTES)} and ${table.name} is not null and ${table.position} is not null and ${table.messageId} is not null)`, ), ], ); diff --git a/packages/database/src/schemas/inbox-message.ts b/packages/database/src/schemas/inbox-message.ts new file mode 100644 index 0000000000..1b84fd9943 --- /dev/null +++ b/packages/database/src/schemas/inbox-message.ts @@ -0,0 +1,50 @@ +import type { InboxMessageAuthor } from "@luke/features/inbox-wire"; +import { sql } from "drizzle-orm"; +import { index, pgTable, text, uniqueIndex, uuid } from "drizzle-orm/pg-core"; +import { timestamptz } from "./_helpers.js"; +import { user } from "./auth.js"; +import { inboxItem } from "./inbox.js"; + +/** + * inbox-message.ts -- one message on an inbox item's thread: words a member of the item's workspace, or the item's own agent, added at any point, open or settled. + * + * An item holds one answer (`inbox.ts`) and, beside it, a thread a member + * or the agent adds to whenever there is something to say, so a message is + * a row of its own rather than a column of the item's. Who wrote it is its + * author: a member, kept by their account, or the agent, which is the + * item's own and so needs no column; a message stays when its member's + * account is gone, naming nobody. The words are Markdown kept as they were + * sent, as an answer's note is, so a mention in them stands as its link. + * The files a message carried are rows of the item's attachments of the + * message kind, naming the message (`inbox-attachment.ts`). The key a + * member's client wrote it under is unique on the item, so a message sent + * again after a lost reply is written once. A message goes with its item, + * and with it the account, the task, and the agent the item goes with; a + * post under the item's key changes what it asks and leaves the thread. + */ +export const inboxMessage = pgTable( + "inbox_message", + { + id: uuid("id").primaryKey().defaultRandom(), + itemId: uuid("item_id") + .notNull() + .references(() => inboxItem.id, { onDelete: "cascade" }), + /** Who wrote it: a member of the item's workspace, or the item's agent. */ + author: text("author").$type().notNull(), + /** The member who wrote it; null for the agent's, and once the member's account is gone. */ + userId: text("user_id").references(() => user.id, { onDelete: "set null" }), + /** The words in Markdown, as they were sent; empty where the files carry the message alone. */ + text: text("text").notNull(), + /** The key a member's client wrote it under; null for the agent's. */ + clientKey: text("client_key"), + createdAt: timestamptz("created_at").notNull(), + }, + (table) => [ + // An item's thread is read in the order it was written. + index("inbox_message_item_created").on(table.itemId, table.createdAt), + // A message sent again under its key is the message already written. + uniqueIndex("inbox_message_client_key") + .on(table.itemId, table.clientKey) + .where(sql`${table.clientKey} is not null`), + ], +); diff --git a/packages/database/src/schemas/inbox.ts b/packages/database/src/schemas/inbox.ts index eb066542e8..c82e4a293e 100644 --- a/packages/database/src/schemas/inbox.ts +++ b/packages/database/src/schemas/inbox.ts @@ -29,7 +29,9 @@ import { task } from "./task.js"; * the key the client sent it under, so an answer sent again after a lost * reply is taken once, or until the agent closes it, which writes why. The task is * the agent's, kept on the row so a task's inbox is read by one index, and - * the account's open items are read by another. The row goes with its + * the account's open items are read by another. A message on the item's + * thread (`inbox-message.ts`) moves when it last changed and never when it + * was settled. The row goes with its * account, its task, and its agent alike. The columns * the fixed kinds stood in, `kind`, `details`, `options`, and * `recommended`, are declared no longer and wait on their drop @@ -77,6 +79,14 @@ export const inboxItem = pgTable( /** Why the agent took the item back; null until it does. */ closedReason: text("closed_reason"), postedAt: timestamptz("posted_at").notNull(), + /** + * When the item was last answered or closed; null while it is open, and + * on an item settled before the column was kept, which a read takes as + * its last change until a message on its thread first moves that, the + * write that keeps the old instant here (`inbox-store.ts`). + */ + settledAt: timestamptz("settled_at"), + /** When the item last changed, by the agent, an answer, or a message on its thread. */ updatedAt: timestamptz("updated_at").notNull(), }, (table) => [ diff --git a/packages/database/src/schemas/index.ts b/packages/database/src/schemas/index.ts index 1e2fa9acac..16744e4562 100644 --- a/packages/database/src/schemas/index.ts +++ b/packages/database/src/schemas/index.ts @@ -13,6 +13,7 @@ export * from "./github-install-intent.js"; export * from "./github-installation.js"; export * from "./inbox.js"; export * from "./inbox-attachment.js"; +export * from "./inbox-message.js"; export * from "./integration.js"; export * from "./issue.js"; export * from "./mac-command.js"; diff --git a/packages/database/src/storage-vocabulary.ts b/packages/database/src/storage-vocabulary.ts index 1acea9178a..23d4f4446c 100644 --- a/packages/database/src/storage-vocabulary.ts +++ b/packages/database/src/storage-vocabulary.ts @@ -27,12 +27,14 @@ export type MessageSender = (typeof MESSAGE_SENDER)[keyof typeof MESSAGE_SENDER] /** * What an inbox item's attachment is: a picture the agent posted with an - * image block, which the block names, or a file the developer's answer - * carried, which the item names as its answer's. + * image block, which the block names, a file the developer's answer + * carried, which the item names as its answer's, or a file a message on the + * item's thread carried, which the message names. */ export const INBOX_ATTACHMENT_KIND = { IMAGE: "image", ANSWER: "answer", + MESSAGE: "message", } as const; export type InboxAttachmentKind = diff --git a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnswerViewSchema.json b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnswerViewSchema.json index 32dd1509a3..5b9e2775f4 100644 --- a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnswerViewSchema.json +++ b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnswerViewSchema.json @@ -487,10 +487,89 @@ "closedReason": { "type": "string" }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "author": { + "type": "string", + "enum": [ + "member", + "agent" + ] + }, + "member": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + }, + "text": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attachmentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "name": { + "type": "string" + }, + "mediaType": { + "type": "string" + } + }, + "required": [ + "attachmentId", + "name", + "mediaType" + ], + "additionalProperties": false + } + }, + "createdAt": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "id", + "author", + "text", + "createdAt" + ], + "additionalProperties": false + } + }, "postedAt": { "type": "number", "minimum": 0 }, + "settledAt": { + "type": "number", + "minimum": 0 + }, "updatedAt": { "type": "number", "minimum": 0 diff --git a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnsweredViewSchema.json b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnsweredViewSchema.json index 2fcf4427e4..8133278e17 100644 --- a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnsweredViewSchema.json +++ b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnsweredViewSchema.json @@ -485,10 +485,89 @@ "closedReason": { "type": "string" }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "author": { + "type": "string", + "enum": [ + "member", + "agent" + ] + }, + "member": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + }, + "text": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attachmentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "name": { + "type": "string" + }, + "mediaType": { + "type": "string" + } + }, + "required": [ + "attachmentId", + "name", + "mediaType" + ], + "additionalProperties": false + } + }, + "createdAt": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "id", + "author", + "text", + "createdAt" + ], + "additionalProperties": false + } + }, "postedAt": { "type": "number", "minimum": 0 }, + "settledAt": { + "type": "number", + "minimum": 0 + }, "updatedAt": { "type": "number", "minimum": 0 diff --git a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxMessagedViewSchema.json b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxMessagedViewSchema.json new file mode 100644 index 0000000000..03025a4038 --- /dev/null +++ b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxMessagedViewSchema.json @@ -0,0 +1,623 @@ +{ + "anyOf": [ + { + "type": "object", + "properties": { + "item": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "agentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "key": { + "type": "string" + }, + "revision": { + "type": "number", + "minimum": 0 + }, + "version": { + "type": "number", + "minimum": 0 + }, + "title": { + "type": "string" + }, + "blocks": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "markdown" + ] + }, + "text": { + "type": "string", + "minLength": 1, + "maxLength": 8000 + } + }, + "required": [ + "type", + "text" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "link" + ] + }, + "url": { + "type": "string", + "maxLength": 2000 + }, + "label": { + "type": "string", + "minLength": 1, + "maxLength": 160 + } + }, + "required": [ + "type", + "url", + "label" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "code" + ] + }, + "repo": { + "type": "string", + "maxLength": 140 + }, + "path": { + "type": "string", + "minLength": 1, + "maxLength": 1024 + }, + "startLine": { + "type": "integer", + "minimum": 1 + }, + "endLine": { + "type": "integer", + "minimum": 1 + }, + "sha": { + "type": "string", + "minLength": 40, + "maxLength": 40 + } + }, + "required": [ + "type", + "repo", + "path", + "startLine", + "endLine", + "sha" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "image" + ] + }, + "attachmentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "alt": { + "type": "string", + "minLength": 1, + "maxLength": 300 + } + }, + "required": [ + "type", + "attachmentId", + "alt" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + } + }, + "response": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "choice" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string", + "minLength": 1, + "maxLength": 160 + }, + "detail": { + "type": "string", + "maxLength": 600 + } + }, + "required": [ + "label" + ], + "additionalProperties": false + }, + "minItems": 2, + "maxItems": 6 + }, + "multiple": { + "type": "boolean" + }, + "recommended": { + "type": "string" + } + }, + "required": [ + "type", + "options" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "approval" + ] + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "text" + ] + }, + "placeholder": { + "type": "string", + "maxLength": 160 + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "task" + ] + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "form" + ] + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "text", + "number", + "select", + "boolean" + ] + }, + "label": { + "type": "string", + "minLength": 1, + "maxLength": 160 + }, + "required": { + "type": "boolean" + }, + "options": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 160 + }, + "minItems": 2, + "maxItems": 6 + } + }, + "required": [ + "type", + "label" + ], + "additionalProperties": false + }, + "minItems": 1, + "maxItems": 8 + } + }, + "required": [ + "type", + "fields" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "none" + ] + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "needsReply": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": [ + "open", + "answered", + "closed" + ] + }, + "startedBy": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + }, + "answer": { + "type": "object", + "properties": { + "reply": { + "type": "string", + "enum": [ + "chose", + "approved", + "declined", + "answered", + "done", + "not-done", + "submitted", + "acknowledged" + ] + }, + "choices": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 6 + }, + "values": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string", + "minLength": 1, + "maxLength": 160 + }, + "value": { + "anyOf": [ + { + "type": "string", + "maxLength": 1000 + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "required": [ + "label", + "value" + ], + "additionalProperties": false + }, + "maxItems": 8 + }, + "note": { + "type": "string", + "maxLength": 4000 + } + }, + "required": [ + "reply" + ], + "additionalProperties": false + }, + "answerFiles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attachmentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "name": { + "type": "string" + }, + "mediaType": { + "type": "string" + } + }, + "required": [ + "attachmentId", + "name", + "mediaType" + ], + "additionalProperties": false + } + }, + "answeredBy": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + }, + "closedReason": { + "type": "string" + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "author": { + "type": "string", + "enum": [ + "member", + "agent" + ] + }, + "member": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + }, + "text": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attachmentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "name": { + "type": "string" + }, + "mediaType": { + "type": "string" + } + }, + "required": [ + "attachmentId", + "name", + "mediaType" + ], + "additionalProperties": false + } + }, + "createdAt": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "id", + "author", + "text", + "createdAt" + ], + "additionalProperties": false + } + }, + "postedAt": { + "type": "number", + "minimum": 0 + }, + "settledAt": { + "type": "number", + "minimum": 0 + }, + "updatedAt": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "id", + "agentId", + "key", + "revision", + "version", + "title", + "blocks", + "response", + "needsReply", + "status", + "postedAt", + "updatedAt" + ], + "additionalProperties": false + } + }, + "required": [ + "item" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "failure": { + "type": "string", + "enum": [ + "unanswered", + "not-found", + "no-repository", + "repository-not-reachable", + "github-unanswered", + "invalid-choice", + "message-too-long", + "agent-not-ready", + "agent-retired", + "plan-archived" + ] + } + }, + "required": [ + "failure" + ], + "additionalProperties": false + } + ] +} diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxAnswerSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxAnswerSchema.json index 5ff6e911b7..c7b20875c6 100644 --- a/packages/features/fixtures/json-schema/inbox-wire-inboxAnswerSchema.json +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxAnswerSchema.json @@ -485,10 +485,89 @@ "closedReason": { "type": "string" }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "author": { + "type": "string", + "enum": [ + "member", + "agent" + ] + }, + "member": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + }, + "text": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attachmentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "name": { + "type": "string" + }, + "mediaType": { + "type": "string" + } + }, + "required": [ + "attachmentId", + "name", + "mediaType" + ], + "additionalProperties": false + } + }, + "createdAt": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "id", + "author", + "text", + "createdAt" + ], + "additionalProperties": false + } + }, "postedAt": { "type": "number", "minimum": 0 }, + "settledAt": { + "type": "number", + "minimum": 0 + }, "updatedAt": { "type": "number", "minimum": 0 diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxAnsweredSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxAnsweredSchema.json index 66c1fee60d..87b7d2cdcc 100644 --- a/packages/features/fixtures/json-schema/inbox-wire-inboxAnsweredSchema.json +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxAnsweredSchema.json @@ -483,10 +483,89 @@ "closedReason": { "type": "string" }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "author": { + "type": "string", + "enum": [ + "member", + "agent" + ] + }, + "member": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + }, + "text": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attachmentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "name": { + "type": "string" + }, + "mediaType": { + "type": "string" + } + }, + "required": [ + "attachmentId", + "name", + "mediaType" + ], + "additionalProperties": false + } + }, + "createdAt": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "id", + "author", + "text", + "createdAt" + ], + "additionalProperties": false + } + }, "postedAt": { "type": "number", "minimum": 0 }, + "settledAt": { + "type": "number", + "minimum": 0 + }, "updatedAt": { "type": "number", "minimum": 0 diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxItemSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxItemSchema.json index e636cb4a5d..ae05815cae 100644 --- a/packages/features/fixtures/json-schema/inbox-wire-inboxItemSchema.json +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxItemSchema.json @@ -480,10 +480,89 @@ "closedReason": { "type": "string" }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "author": { + "type": "string", + "enum": [ + "member", + "agent" + ] + }, + "member": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + }, + "text": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attachmentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "name": { + "type": "string" + }, + "mediaType": { + "type": "string" + } + }, + "required": [ + "attachmentId", + "name", + "mediaType" + ], + "additionalProperties": false + } + }, + "createdAt": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "id", + "author", + "text", + "createdAt" + ], + "additionalProperties": false + } + }, "postedAt": { "type": "number", "minimum": 0 }, + "settledAt": { + "type": "number", + "minimum": 0 + }, "updatedAt": { "type": "number", "minimum": 0 diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxMessageRequestSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxMessageRequestSchema.json new file mode 100644 index 0000000000..345acafd2f --- /dev/null +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxMessageRequestSchema.json @@ -0,0 +1,53 @@ +{ + "type": "object", + "properties": { + "text": { + "type": "string", + "maxLength": 8000 + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "mediaType": { + "type": "string", + "enum": [ + "image/png", + "image/jpeg", + "image/webp", + "application/pdf", + "text/plain" + ] + }, + "data": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name", + "mediaType", + "data" + ], + "additionalProperties": false + }, + "maxItems": 10 + }, + "clientKey": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + }, + "required": [ + "text", + "clientKey" + ], + "additionalProperties": false +} diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxMessageSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxMessageSchema.json new file mode 100644 index 0000000000..b3cd1a1d0a --- /dev/null +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxMessageSchema.json @@ -0,0 +1,72 @@ +{ + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "author": { + "type": "string", + "enum": [ + "member", + "agent" + ] + }, + "member": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + }, + "text": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attachmentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "name": { + "type": "string" + }, + "mediaType": { + "type": "string" + } + }, + "required": [ + "attachmentId", + "name", + "mediaType" + ], + "additionalProperties": false + } + }, + "createdAt": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "id", + "author", + "text", + "createdAt" + ], + "additionalProperties": false +} diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxMessagedSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxMessagedSchema.json new file mode 100644 index 0000000000..9395351016 --- /dev/null +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxMessagedSchema.json @@ -0,0 +1,595 @@ +{ + "type": "object", + "properties": { + "item": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "agentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "key": { + "type": "string" + }, + "revision": { + "type": "number", + "minimum": 0 + }, + "version": { + "type": "number", + "minimum": 0 + }, + "title": { + "type": "string" + }, + "blocks": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "markdown" + ] + }, + "text": { + "type": "string", + "minLength": 1, + "maxLength": 8000 + } + }, + "required": [ + "type", + "text" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "link" + ] + }, + "url": { + "type": "string", + "maxLength": 2000 + }, + "label": { + "type": "string", + "minLength": 1, + "maxLength": 160 + } + }, + "required": [ + "type", + "url", + "label" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "code" + ] + }, + "repo": { + "type": "string", + "maxLength": 140 + }, + "path": { + "type": "string", + "minLength": 1, + "maxLength": 1024 + }, + "startLine": { + "type": "integer", + "minimum": 1 + }, + "endLine": { + "type": "integer", + "minimum": 1 + }, + "sha": { + "type": "string", + "minLength": 40, + "maxLength": 40 + } + }, + "required": [ + "type", + "repo", + "path", + "startLine", + "endLine", + "sha" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "image" + ] + }, + "attachmentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "alt": { + "type": "string", + "minLength": 1, + "maxLength": 300 + } + }, + "required": [ + "type", + "attachmentId", + "alt" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + } + }, + "response": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "choice" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string", + "minLength": 1, + "maxLength": 160 + }, + "detail": { + "type": "string", + "maxLength": 600 + } + }, + "required": [ + "label" + ], + "additionalProperties": false + }, + "minItems": 2, + "maxItems": 6 + }, + "multiple": { + "type": "boolean" + }, + "recommended": { + "type": "string" + } + }, + "required": [ + "type", + "options" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "approval" + ] + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "text" + ] + }, + "placeholder": { + "type": "string", + "maxLength": 160 + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "task" + ] + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "form" + ] + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "text", + "number", + "select", + "boolean" + ] + }, + "label": { + "type": "string", + "minLength": 1, + "maxLength": 160 + }, + "required": { + "type": "boolean" + }, + "options": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 160 + }, + "minItems": 2, + "maxItems": 6 + } + }, + "required": [ + "type", + "label" + ], + "additionalProperties": false + }, + "minItems": 1, + "maxItems": 8 + } + }, + "required": [ + "type", + "fields" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "none" + ] + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + ] + }, + "needsReply": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": [ + "open", + "answered", + "closed" + ] + }, + "startedBy": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + }, + "answer": { + "type": "object", + "properties": { + "reply": { + "type": "string", + "enum": [ + "chose", + "approved", + "declined", + "answered", + "done", + "not-done", + "submitted", + "acknowledged" + ] + }, + "choices": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 6 + }, + "values": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string", + "minLength": 1, + "maxLength": 160 + }, + "value": { + "anyOf": [ + { + "type": "string", + "maxLength": 1000 + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ] + } + }, + "required": [ + "label", + "value" + ], + "additionalProperties": false + }, + "maxItems": 8 + }, + "note": { + "type": "string", + "maxLength": 4000 + } + }, + "required": [ + "reply" + ], + "additionalProperties": false + }, + "answerFiles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attachmentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "name": { + "type": "string" + }, + "mediaType": { + "type": "string" + } + }, + "required": [ + "attachmentId", + "name", + "mediaType" + ], + "additionalProperties": false + } + }, + "answeredBy": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + }, + "closedReason": { + "type": "string" + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "author": { + "type": "string", + "enum": [ + "member", + "agent" + ] + }, + "member": { + "type": "object", + "properties": { + "userId": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "userId", + "name" + ], + "additionalProperties": false + }, + "text": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attachmentId": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "name": { + "type": "string" + }, + "mediaType": { + "type": "string" + } + }, + "required": [ + "attachmentId", + "name", + "mediaType" + ], + "additionalProperties": false + } + }, + "createdAt": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "id", + "author", + "text", + "createdAt" + ], + "additionalProperties": false + } + }, + "postedAt": { + "type": "number", + "minimum": 0 + }, + "settledAt": { + "type": "number", + "minimum": 0 + }, + "updatedAt": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "id", + "agentId", + "key", + "revision", + "version", + "title", + "blocks", + "response", + "needsReply", + "status", + "postedAt", + "updatedAt" + ], + "additionalProperties": false + } + }, + "required": [ + "item" + ], + "additionalProperties": false +} diff --git a/packages/features/src/coding-agent-client.test.ts b/packages/features/src/coding-agent-client.test.ts index 83b9bbeddb..23d27fdbad 100644 --- a/packages/features/src/coding-agent-client.test.ts +++ b/packages/features/src/coding-agent-client.test.ts @@ -236,6 +236,62 @@ it.effect( }), ); +it.effect( + "writes a message on an inbox item's thread at the item's own path, its words trimmed, answers the item as it then stands, names a refusal as a message's, and sends nothing that carries neither words nor files", + () => + Effect.gen(function* () { + const itemId = "5d2b8f0e-1a3c-4e6f-9b7d-2c4e6a8b0d1f"; + const item = { + id: itemId, + agentId: AGENT_ID, + key: "invite-copy", + revision: 1, + version: 4, + title: "What should the invitation email say?", + blocks: [], + response: { type: "text" }, + needsReply: true, + status: "answered", + messages: [ + { + id: "6e3c9a1f-2b4d-4f70-8c8e-3d5f7b9c1e2a", + author: "member", + member: { userId: "user-dana", name: "Dana" }, + text: "Drop the emoji.", + createdAt: 2, + }, + ], + postedAt: 1, + updatedAt: 2, + }; + const path = `POST /api/inbox/${itemId}/messages`; + const api = fakeCloudApi({ [path]: { answer: () => ({ item }) } }); + const refusing = fakeCloudApi({ + [path]: { + answer: () => ({ error: HOSTED_API_ERROR.AGENT_NOT_READY }), + status: HTTP_STATUS.CONFLICT, + }, + }); + const message = { text: " Drop the emoji. ", clientKey: "key-1" }; + + const sent = yield* Effect.provide(client().messageInbox(itemId, message), api.layer); + const refused = yield* Effect.provide(client().messageInbox(itemId, message), refusing.layer); + const empty = yield* Effect.provide( + client().messageInbox(itemId, { text: " ", clientKey: "key-2" }), + api.layer, + ); + + assert.deepEqual(sent, { item }); + assert.deepEqual(JSON.parse(api.requests()[0]?.body ?? "null"), { + text: "Drop the emoji.", + clientKey: "key-1", + }); + assert.deepEqual(refused, { failure: CODING_AGENT_CALL_FAILURE.AGENT_NOT_READY }); + assert.deepEqual(empty, { failure: CODING_AGENT_CALL_FAILURE.UNANSWERED }); + assert.equal(api.requests().length, 1, "nothing is sent for a message of neither"); + }), +); + it.effect( "lists a workspace's agents by its id and the repository named, and a workspace the account is not in as not found", () => diff --git a/packages/features/src/coding-agent-client.ts b/packages/features/src/coding-agent-client.ts index c2d75406bb..38710d858e 100644 --- a/packages/features/src/coding-agent-client.ts +++ b/packages/features/src/coding-agent-client.ts @@ -36,6 +36,7 @@ import { type CodingAgentInboxAnsweredView, type CodingAgentInboxAnswerView, type CodingAgentInboxAttachmentView, + type CodingAgentInboxMessagedView, type CodingAgentListAnswer, type CodingAgentMessagesAnswerView, type CodingAgentModelsAnswer, @@ -89,10 +90,13 @@ import { dictationAnswerSchema, dictationRequestSchema } from "./dictation-wire. import { imageBodyOf } from "./image-body.js"; import { type InboxAnswerRequest, + type InboxMessageRequest, inboxAnsweredSchema, inboxAnswerRequestSchema, inboxAnswerSchema, inboxImageTypeSchema, + inboxMessagedSchema, + inboxMessageRequestSchema, } from "./inbox-wire.js"; import { codingAgentDefaultAnswerSchema, @@ -135,6 +139,7 @@ import { HOSTED_SERVICE_PATH, inboxAttachmentPath, inboxItemPath, + inboxMessagesPath, planTemplateRestorePath, planTemplateRevisionPath, taskAgentsPath, @@ -941,4 +946,26 @@ export class HostedCodingAgentClient { (answer) => readAnswer(answer, inboxAnsweredSchema, INBOX_ANSWER_REFUSALS), ); } + + /** + * A message of the account's on one item's thread, open or settled: the + * item as it then stands, its thread with the message on it, where the + * service wrote it and handed it to the agent; the refusals a message to + * the agent answers with otherwise, since it reaches the agent as one. + */ + messageInbox( + itemId: string, + request: InboxMessageRequest, + ): Effect.Effect { + const admitted = Result.getOrUndefined(readEither(inboxMessageRequestSchema)(request)); + if (admitted === undefined) return Effect.succeed(UNANSWERED); + return Effect.flatMap( + this.#call.send({ + method: HTTP_METHOD.POST, + path: inboxMessagesPath(itemId), + body: JSON.stringify(admitted), + }), + (answer) => readAnswer(answer, inboxMessagedSchema, INBOX_ANSWER_REFUSALS), + ); + } } diff --git a/packages/features/src/coding-agent-view.ts b/packages/features/src/coding-agent-view.ts index 1471937000..196f4f8ba8 100644 --- a/packages/features/src/coding-agent-view.ts +++ b/packages/features/src/coding-agent-view.ts @@ -22,7 +22,12 @@ import { } from "./coding-agent-wire.js"; import { dictationAnswerSchema, dictationRequestSchema } from "./dictation-wire.js"; import { GITHUB_IMAGE_BOUNDS, GITHUB_IMAGE_TYPE } from "./github-image.js"; -import { inboxAnsweredSchema, inboxAnswerRequestSchema, inboxAnswerSchema } from "./inbox-wire.js"; +import { + inboxAnsweredSchema, + inboxAnswerRequestSchema, + inboxAnswerSchema, + inboxMessagedSchema, +} from "./inbox-wire.js"; import { catalogModelSchema, modelChoiceSchema } from "./models-wire.js"; import { planTemplateAnswerSchema, @@ -432,6 +437,11 @@ export const codingAgentInboxAnsweredViewSchema = EffectSchema.Union([inboxAnswe export type CodingAgentInboxAnsweredView = typeof codingAgentInboxAnsweredViewSchema.Type; +/** A message on an item's thread, as the window hears it: the item as it then stands, its thread with the message on it, or why there is no answer. */ +export const codingAgentInboxMessagedViewSchema = EffectSchema.Union([inboxMessagedSchema, failed]); + +export type CodingAgentInboxMessagedView = typeof codingAgentInboxMessagedViewSchema.Type; + /** What waits across the account past a cursor, as main asks it: where it stands. */ export const codingAgentAccountInboxParamsSchema = EffectSchema.Struct({ after: EffectSchema.NonEmptyString, diff --git a/packages/features/src/hosted-wire-schemas.test.ts b/packages/features/src/hosted-wire-schemas.test.ts index f8027dc2d6..a1d7e08569 100644 --- a/packages/features/src/hosted-wire-schemas.test.ts +++ b/packages/features/src/hosted-wire-schemas.test.ts @@ -164,11 +164,14 @@ const EFFECT_MODULE_SCHEMAS = { inboxReadBlockSchema: inboxWire.inboxReadBlockSchema, inboxReadResponseSchema: inboxWire.inboxReadResponseSchema, inboxAnswerFileSchema: inboxWire.inboxAnswerFileSchema, + inboxMessageSchema: inboxWire.inboxMessageSchema, inboxItemSchema: inboxWire.inboxItemSchema, inboxCursorSchema: inboxWire.inboxCursorSchema, inboxAnswerSchema: inboxWire.inboxAnswerSchema, inboxAnswerRequestSchema: inboxWire.inboxAnswerRequestSchema, inboxAnsweredSchema: inboxWire.inboxAnsweredSchema, + inboxMessageRequestSchema: inboxWire.inboxMessageRequestSchema, + inboxMessagedSchema: inboxWire.inboxMessagedSchema, } satisfies RecordedEffectJsonSchemas, "coding-agent-view": { codingAgentModelsAnswerSchema: codingAgentView.codingAgentModelsAnswerSchema, @@ -222,6 +225,7 @@ const EFFECT_MODULE_SCHEMAS = { codingAgentInboxAnswerViewSchema: codingAgentView.codingAgentInboxAnswerViewSchema, codingAgentInboxAnswerParamsSchema: codingAgentView.codingAgentInboxAnswerParamsSchema, codingAgentInboxAnsweredViewSchema: codingAgentView.codingAgentInboxAnsweredViewSchema, + codingAgentInboxMessagedViewSchema: codingAgentView.codingAgentInboxMessagedViewSchema, codingAgentAccountInboxParamsSchema: codingAgentView.codingAgentAccountInboxParamsSchema, codingAgentAccountInboxAnswerViewSchema: codingAgentView.codingAgentAccountInboxAnswerViewSchema, diff --git a/packages/features/src/inbox-wire.ts b/packages/features/src/inbox-wire.ts index ba564147c1..fa9bdbdb28 100644 --- a/packages/features/src/inbox-wire.ts +++ b/packages/features/src/inbox-wire.ts @@ -5,6 +5,7 @@ import { CODING_AGENT_BOUNDS, type CodingAgentAttachment, codingAgentMessageRequestSchema, + hasWordsOrFiles, } from "./coding-agent-wire.js"; import { githubRepositoryFullNameSchema } from "./github-repositories-wire.js"; import { countedNumber, memberRefSchema, wireUuidSchema } from "./service-wire.js"; @@ -46,6 +47,17 @@ import { CODE_PATH_MAX_CHARS, codeLineSchema, commitShaSchema } from "./task-wir * which the item names by attachment, file name, and type until the answer * is taken back or the agent posts the item again. * + * Beside its one answer, an item holds a thread: messages a member of its + * workspace or its agent adds at any point, open or settled, each in + * Markdown with the files it carried, read oldest first. A message changes + * neither the item's status, nor its answer, nor its revision, and moves + * the instant the item last changed, so the item comes to the top of the + * inbox. A member's message reaches the agent as one of the developer's + * messages, under its own lead, as an answer does, and wakes an agent that + * stopped as a message typed in its tab does. The thread outlives a post + * under the item's key, which changes what the item asks and not what was + * said about it. + * * The agent posts, closes, and reads its items through the tools named * below, whose inputs are declared here so the model is shown, eve holds, * and the desktop draws one shape. A task's inbox is read past a cursor the @@ -115,6 +127,10 @@ export const INBOX_BOUNDS = { MAX_CURSOR_CHARS: 64, /** The most characters an answer's key may spell; a UUID is the usual. */ MAX_CLIENT_KEY_CHARS: 128, + /** The most characters a message on an item's thread may spell: a Markdown block's bound, whoever writes it. */ + MAX_MESSAGE_CHARS: 8_000, + /** The most messages an item read carries, the latest ones, oldest first among them: a thread read at a glance, never a log. */ + MAX_MESSAGES_READ: 50, } as const; /** The tools an agent keeps its items with, by the names their tool parts carry in its transcript. */ @@ -505,6 +521,36 @@ export const inboxAnswerFileSchema = EffectSchema.Struct({ type InboxAnswerFile = typeof inboxAnswerFileSchema.Type; +/** Who wrote a message on an item's thread: a member of the item's workspace, or the item's own agent. */ +export const INBOX_MESSAGE_AUTHOR = { + MEMBER: "member", + AGENT: "agent", +} as const; + +export type InboxMessageAuthor = (typeof INBOX_MESSAGE_AUTHOR)[keyof typeof INBOX_MESSAGE_AUTHOR]; + +/** + * One message on an item's thread as an item read carries it: who wrote it, + * the member by id and name where a member did, and none for a member whose + * account is gone or for the agent, which is the item's own; the words as + * Markdown, written as they were sent, so a mention in them stands as its + * link; the files it carried, named as an answer's are and fetched by the + * same attachment path; and when it was written. + */ +export const inboxMessageSchema = EffectSchema.Struct({ + id: wireUuidSchema, + author: EffectSchema.Literals(Object.values(INBOX_MESSAGE_AUTHOR)), + /** The member who wrote it, on a member's message whose account still stands. */ + member: EffectSchema.optionalKey(memberRefSchema), + /** The words in Markdown; empty where the files carry the message alone. */ + text: EffectSchema.String, + /** The files it carried, in the order they were attached; absent where it carried none. */ + files: EffectSchema.optionalKey(EffectSchema.Array(inboxAnswerFileSchema)), + createdAt: countedNumber, +}); + +export type InboxMessage = typeof inboxMessageSchema.Type; + /** One item as the desktop reads it. */ export const inboxItemSchema = EffectSchema.Struct({ id: wireUuidSchema, @@ -538,9 +584,17 @@ export const inboxItemSchema = EffectSchema.Struct({ answeredBy: EffectSchema.optionalKey(memberRefSchema), /** Why the agent took the item back, on a closed one. */ closedReason: EffectSchema.optionalKey(EffectSchema.String), + /** The item's thread, oldest first, the latest `MAX_MESSAGES_READ` of it; absent where nobody wrote one. */ + messages: EffectSchema.optionalKey(EffectSchema.Array(inboxMessageSchema)), /** When the agent first posted the item under its key. */ postedAt: countedNumber, - /** When the item last changed, by the agent or the developer. */ + /** + * When the item was last answered or closed, on a settled item; absent on + * an open one, and from a service before it was kept, which a reader takes + * as `updatedAt`. A message on the thread never moves it. + */ + settledAt: EffectSchema.optionalKey(countedNumber), + /** When the item last changed, by the agent or the developer, a message on its thread included. */ updatedAt: countedNumber, }); @@ -583,6 +637,38 @@ export const inboxAnsweredSchema = EffectSchema.Struct({ /** How the developer's answer opens, in the message that hands it to the agent. */ export const INBOX_ANSWER_LEAD = "Inbox answer"; +/** + * A member's message on an item's thread: the words in Markdown, trimmed and + * bounded, the files they attached, bounded as a message's to an agent are, + * words or files or both and never neither, and a key the client made, so + * a message sent again after a lost reply is written once. + */ +export const inboxMessageRequestSchema = EffectSchema.Struct({ + text: EffectSchema.Trim.check(EffectSchema.isMaxLength(INBOX_BOUNDS.MAX_MESSAGE_CHARS)), + attachments: codingAgentMessageRequestSchema.fields.attachments, + clientKey: filledText(INBOX_BOUNDS.MAX_CLIENT_KEY_CHARS), +}).check(EffectSchema.makeFilter(({ text, attachments }) => hasWordsOrFiles(text, attachments))); + +export type InboxMessageRequest = typeof inboxMessageRequestSchema.Type; + +/** What a member's message comes back as: the item as it then stands, its thread with the message on it. */ +export const inboxMessagedSchema = EffectSchema.Struct({ item: inboxItemSchema }); + +/** How a member's message on an item's thread opens, in the message that hands it to the agent. */ +export const INBOX_MESSAGE_LEAD = "Inbox message"; + +/** + * The message a member's message on an item's thread reaches the agent as: + * a first line naming the item by its key and title, as an answer's does, + * then the member's words as they wrote them, so what they mention reads as + * it was written. + */ +export function inboxThreadMessage(item: Pick, text: string): string { + const title = item.title.replace(/\s+/gu, " ").trim(); + const header = `${INBOX_MESSAGE_LEAD} on "${title}" (key ${item.key}):`; + return text.trim() === "" ? header : `${header}\n\n${text.trim()}`; +} + /** Whether a response read off the wire is one this build knows, which its type decides. */ export function knownResponse(response: InboxReadResponse): response is InboxResponse { return Object.values(INBOX_RESPONSE).includes(response.type); diff --git a/packages/features/src/service-paths.ts b/packages/features/src/service-paths.ts index efc2abc295..ea3f17400e 100644 --- a/packages/features/src/service-paths.ts +++ b/packages/features/src/service-paths.ts @@ -523,6 +523,11 @@ export function inboxItemPath(itemId: string): string { return `/api/inbox/${encodeURIComponent(itemId)}`; } +/** One item's thread, a member's message written on it (POST), open or settled; `inbox-wire.ts` declares the request and the answer. */ +export function inboxMessagesPath(itemId: string): string { + return `${inboxItemPath(itemId)}/messages`; +} + /** One workspace's photo, as its bytes under its own media type (GET), served to the workspace's members alone. */ export function workspacePhotoPath(workspaceId: string): string { return `${HOSTED_SERVICE_PATH.WORKSPACES}/${encodeURIComponent(workspaceId)}/photo`; diff --git a/packages/service/src/agents/coder-host/inbox-store.test.ts b/packages/service/src/agents/coder-host/inbox-store.test.ts index c0c5ad0872..9482542e38 100644 --- a/packages/service/src/agents/coder-host/inbox-store.test.ts +++ b/packages/service/src/agents/coder-host/inbox-store.test.ts @@ -24,6 +24,7 @@ import { INBOX_BLOCK, INBOX_CURSOR_START, INBOX_IMAGE_TYPE, + INBOX_MESSAGE_AUTHOR, INBOX_REPLY, INBOX_RESPONSE, INBOX_STATUS, @@ -31,21 +32,25 @@ import { type InboxPost, } from "@luke/features/inbox-wire"; import { eq } from "drizzle-orm"; -import { Effect, Option, Result } from "effect"; +import { Duration, Effect, Option, Result } from "effect"; +import { TestClock } from "effect/testing"; import { accountInboxTasks, accountWaitingItems, answerInboxItem, closeInboxItem, + INBOX_MESSAGE_OUTCOME, type InboxAgent, type InboxFile, postInboxItem, + postInboxMessage, readInboxAttachment, readInboxItem, taskInboxItems, withdrawInboxAnswer, + withdrawInboxMessage, } from "../../inbox/inbox-store.js"; -import { accountInboxPast } from "./inbox-page.js"; +import { accountInboxPast, taskInboxPast } from "./inbox-page.js"; /** * The developer's inbox as the store keeps it, through its public functions @@ -55,8 +60,10 @@ import { accountInboxPast } from "./inbox-page.js"; * withdrawn under its key, a read keeps every open item however many others * changed, every member of the task's workspace reads and answers the items * of an agent any of them started, an agent with no task posts to its - * workspace's members as one on a task does to its task's, and nothing of - * a workspace the account is not in is read or written. + * workspace's members as one on a task does to its task's, a member writes + * on an item's thread whatever its status, which moves the item's last + * change and nothing else of it, and nothing of a workspace the account is + * not in is read or written. * * Synthetic accounts, tasks, and words throughout. */ @@ -528,4 +535,202 @@ it.layer(getTestDB())("the inbox store", (it) => { assert.ok(Option.isNone(yield* answerInboxItem(stranger, id, 1, done, randomUUID()))); }), ); + it.effect( + "a member's message, a teammate's as much as the starter's, stands on the thread of an open item and of an answered one, oldest first and naming its writer, leaves the status, the answer, and the revision as they stood, moves the item's last change and the plan read's cursor, and an outsider writes none", + () => + Effect.gen(function* () { + const { agent, workspaceId } = yield* openAgentIn; + const teammate = yield* openUser; + const outsider = yield* openUser; + yield* joinWorkspace(workspaceId, teammate); + const open = yield* postInboxItem(agent, SETTINGS); + const settled = yield* postInboxItem(agent, { ...SETTINGS, key: "settled" }); + assert.ok(Result.isSuccess(open) && Result.isSuccess(settled)); + const answered = Option.getOrThrow( + yield* answerInboxItem(agent.userId, settled.success.id, 1, DONE, randomUUID()), + ); + const before = yield* taskInboxPast(agent.userId, agent.taskId, INBOX_CURSOR_START); + const write = (userId: string, itemId: string, text: string) => + Effect.gen(function* () { + yield* TestClock.adjust(Duration.seconds(1)); + return yield* postInboxMessage(userId, itemId, { text, clientKey: randomUUID() }); + }); + + assert.ok(Option.isNone(yield* write(outsider, open.success.id, "Not my workspace."))); + yield* write( + agent.userId, + open.success.id, + "Is [@main](https://github.com/acme/relay) it?", + ); + const onOpen = Option.getOrThrow(yield* write(teammate, open.success.id, "Main, yes.")); + const onSettled = Option.getOrThrow( + yield* write(teammate, settled.success.id, "One more thing on this."), + ); + + assert.deepEqual( + [onOpen.outcome, onSettled.outcome], + [INBOX_MESSAGE_OUTCOME.WRITTEN, INBOX_MESSAGE_OUTCOME.WRITTEN], + ); + assert.deepEqual( + onOpen.item.messages?.map((message) => [ + message.author, + message.member?.userId, + message.text, + ]), + [ + [ + INBOX_MESSAGE_AUTHOR.MEMBER, + agent.userId, + "Is [@main](https://github.com/acme/relay) it?", + ], + [INBOX_MESSAGE_AUTHOR.MEMBER, teammate, "Main, yes."], + ], + ); + assert.deepEqual( + [onOpen.item.status, onOpen.item.revision], + [INBOX_STATUS.OPEN, open.success.revision], + ); + assert.deepEqual( + [ + onSettled.item.status, + onSettled.item.revision, + onSettled.item.answer, + onSettled.item.answeredBy, + ], + [answered.status, answered.revision, answered.answer, answered.answeredBy], + ); + assert.ok(onSettled.item.updatedAt > answered.updatedAt, "the message moves the item"); + assert.equal(onSettled.item.updatedAt, onSettled.item.messages?.[0]?.createdAt); + const byStarter = yield* readInboxItem(agent.userId, settled.success.id); + const byTeammate = yield* readInboxItem(teammate, settled.success.id); + assert.deepEqual( + [byStarter, byTeammate].map((read) => Option.getOrThrow(read).item.messages), + [onSettled.item.messages, onSettled.item.messages], + ); + const after = yield* taskInboxPast(agent.userId, agent.taskId, INBOX_CURSOR_START); + assert.notEqual(after.cursor, before.cursor, "a holder of the cursor before hears it"); + assert.deepEqual(yield* taskInboxItems(outsider, agent.taskId), []); + }), + ); + + it.effect( + "a message's files are kept in the order attached and served to every member, and stay with the thread when the agent posts the item again; a message sent again under its key is written once and moves nothing, other words under its key are refused as the key reused, and one withdrawn goes with its files", + () => + Effect.gen(function* () { + const agent = yield* openAgent; + const posted = yield* postInboxItem(agent, SETTINGS); + assert.ok(Result.isSuccess(posted)); + const { id } = posted.success; + const files = [ + attached("trace.txt", CODING_AGENT_ATTACHMENT_TYPE.TEXT, TRACE), + attached("after.png", CODING_AGENT_ATTACHMENT_TYPE.PNG, SHOT), + ]; + const key = randomUUID(); + yield* TestClock.adjust(Duration.seconds(1)); + + const first = Option.getOrThrow( + yield* postInboxMessage(agent.userId, id, { text: "", clientKey: key, files }), + ); + yield* TestClock.adjust(Duration.seconds(1)); + const again = Option.getOrThrow( + yield* postInboxMessage(agent.userId, id, { text: "", clientKey: key, files }), + ); + + const reused = Option.getOrThrow( + yield* postInboxMessage(agent.userId, id, { + text: "Other words.", + clientKey: key, + files, + }), + ); + assert.deepEqual( + [first.outcome, again.outcome, reused.outcome], + [ + INBOX_MESSAGE_OUTCOME.WRITTEN, + INBOX_MESSAGE_OUTCOME.REPEATED, + INBOX_MESSAGE_OUTCOME.KEY_REUSED, + ], + ); + assert.deepEqual(again.item, first.item, "a repeat writes nothing and moves nothing"); + assert.deepEqual(reused.item, first.item, "a key reused writes nothing either"); + const [message] = first.item.messages ?? []; + assert.deepEqual( + message?.files?.map((file) => [file.name, file.mediaType]), + [ + ["trace.txt", CODING_AGENT_ATTACHMENT_TYPE.TEXT], + ["after.png", CODING_AGENT_ATTACHMENT_TYPE.PNG], + ], + ); + const [trace] = message?.files ?? []; + assert.ok(trace); + const served = yield* readInboxAttachment(agent.userId, id, trace.attachmentId); + assert.deepEqual(new Uint8Array(Option.getOrThrow(served).bytes), TRACE); + + const askedAgain = yield* postInboxItem(agent, { + ...SETTINGS, + title: "Require two reviews", + }); + assert.ok(Result.isSuccess(askedAgain)); + assert.deepEqual(askedAgain.success.messages, first.item.messages); + assert.ok(Option.isSome(yield* readInboxAttachment(agent.userId, id, trace.attachmentId))); + + yield* withdrawInboxMessage(agent.userId, id, key); + assert.equal( + Option.getOrThrow(yield* readInboxItem(agent.userId, id)).item.messages, + undefined, + ); + assert.ok(Option.isNone(yield* readInboxAttachment(agent.userId, id, trace.attachmentId))); + }), + ); + it.effect( + "an item answered or closed is stamped settled at that instant, which a message on its thread leaves while moving the last change; one settled before the stamp was kept reads its last change as settled and keeps it through the first message; a post that opens it again clears it", + () => + Effect.gen(function* () { + const agent = yield* openAgent; + const posted = yield* postInboxItem(agent, SETTINGS); + const closing = yield* postInboxItem(agent, { ...SETTINGS, key: "closing" }); + assert.ok(Result.isSuccess(posted) && Result.isSuccess(closing)); + const { id } = posted.success; + assert.equal(posted.success.settledAt, undefined, "an open item is not settled"); + const say = (itemId: string) => + Effect.gen(function* () { + yield* TestClock.adjust(Duration.seconds(1)); + const said = yield* postInboxMessage(agent.userId, itemId, { + text: "Following up.", + clientKey: randomUUID(), + }); + return Option.getOrThrow(said).item; + }); + + yield* TestClock.adjust(Duration.seconds(1)); + const answered = Option.getOrThrow( + yield* answerInboxItem(agent.userId, id, 1, DONE, randomUUID()), + ); + const messaged = yield* say(id); + assert.equal(answered.settledAt, answered.updatedAt); + assert.equal(messaged.settledAt, answered.settledAt, "a message leaves when it settled"); + assert.ok(messaged.updatedAt > answered.updatedAt, "and moves when it last changed"); + + const closed = Option.getOrThrow(yield* closeInboxItem(agent, "closing", "Not needed.")); + assert.equal(closed.settledAt, closed.updatedAt); + // As an item settled before the stamp was kept stands. + yield* Database.use((db) => + db.update(inboxItem).set({ settledAt: null }).where(eq(inboxItem.id, closed.id)), + ); + const legacy = Option.getOrThrow(yield* readInboxItem(agent.userId, closed.id)).item; + assert.equal(legacy.settledAt, closed.updatedAt); + const first = yield* say(closed.id); + const second = yield* say(closed.id); + assert.deepEqual([first.settledAt, second.settledAt], [closed.updatedAt, closed.updatedAt]); + + const reopened = yield* postInboxItem(agent, SETTINGS); + assert.ok(Result.isSuccess(reopened)); + assert.equal(reopened.success.settledAt, undefined); + assert.equal( + (yield* say(id)).settledAt, + undefined, + "a message on an open item settles nothing", + ); + }), + ); }); diff --git a/packages/service/src/agents/coding-agents-app.test.ts b/packages/service/src/agents/coding-agents-app.test.ts index b9f4c100e4..b9cf1d3f35 100644 --- a/packages/service/src/agents/coding-agents-app.test.ts +++ b/packages/service/src/agents/coding-agents-app.test.ts @@ -118,12 +118,15 @@ import { INBOX_BLOCK, INBOX_CURSOR_START, INBOX_IMAGE_TYPE, + INBOX_MESSAGE_LEAD, INBOX_REPLY, INBOX_RESPONSE, + INBOX_STATUS, type InboxImageBlock, type InboxPost, inboxAnsweredSchema, inboxAnswerSchema, + inboxMessagedSchema, } from "@luke/features/inbox-wire"; import { INTEGRATION_PROVIDER, type IntegrationProvider } from "@luke/features/integration-wire"; import { MENTION_KIND, mentionMarkdown } from "@luke/features/mention-link"; @@ -2901,6 +2904,7 @@ const TASK_INBOX = "/api/plans/inbox"; const INBOX_ITEM = "/api/inbox/item"; const ACCOUNT_INBOX = "/api/inbox"; const INBOX_ATTACHMENT = "/api/inbox/attachment"; +const INBOX_MESSAGES = "/api/inbox/messages"; /** The first bytes of a PNG, as a screenshot's file starts. */ const PNG = Uint8Array.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0, 0, 0, 13]); @@ -2937,7 +2941,34 @@ it.layer(getTestDB())("the developer's inbox", (it) => { opened.ask(request(ACCOUNT_INBOX, bearer, after === undefined ? undefined : { after })), (answered) => readAnswer(accountInboxAnswerSchema, HOSTED_HTTP_STATUS.OK, answered), ); - return { ...opened, agent, target, post, read, answer, waiting }; + /** A member's message on an item's thread, as the route answers it. */ + const message = (itemId: string, body: WireBoundaryInput, bearer = opened.owner) => + opened.ask(request(INBOX_MESSAGES, bearer, { method: "POST", id: itemId, body })); + /** The agent's transcript as the owner reads it: the developer's lines, and where it stands. */ + const transcript = () => + Effect.map( + opened.ask(request(AGENT_MESSAGES, opened.owner, { id: agent.id })), + (answered) => { + const page = readAnswer( + codingAgentMessagesAnswerSchema, + HOSTED_HTTP_STATUS.OK, + answered, + ); + return { lines: userTexts(page), status: page.status }; + }, + ); + return { + ...opened, + agent, + target, + sessionId, + post, + read, + answer, + waiting, + message, + transcript, + }; }); const QUESTION = { @@ -3103,6 +3134,173 @@ it.layer(getTestDB())("the developer's inbox", (it) => { }), ); + /** The agent's one turn run to its end, as the relay writes a turn that settled: the agent stopped, and waits on nothing. */ + const turnEnded = (target: { readonly userId: string; readonly conversationId: string }) => + Effect.gen(function* () { + const writer = yield* storeWriter({ tools: CODER_TOOL_SET }); + const turnId = randomUUID(); + const turn = { conversationId: sessionKey(target.conversationId), turnId }; + yield* writer.enqueueTurn(target, { turnId, origin: TURN_ORIGIN.TYPED, eveTurnId: "turn_0" }); + yield* writer.consume(target, { + ...turn, + kind: BRAIN_RUN_EVENT.TURN_STARTED, + sequence: 1, + origin: BRAIN_TURN_ORIGIN.TYPED, + trigger: BRAIN_TURN_TRIGGER.ASK, + at: 0, + }); + yield* writer.consume(target, { + ...turn, + kind: BRAIN_RUN_EVENT.MESSAGE_COMPLETED, + sequence: 2, + message: userMessage( + randomUUID(), + SNAPSHOT, + userMetadataOf(BRAIN_TURN_TRIGGER.ASK, undefined), + ), + }); + yield* writer.consume(target, { + ...turn, + kind: BRAIN_RUN_EVENT.TURN_ENDED, + sequence: 3, + status: BRAIN_REQUEST_STATUS.SUCCEEDED, + responseIds: [], + at: 0, + }); + }); + + it.effect( + "a member's message on an answered item wakes the agent that stopped, reaching it under its own lead with its files, and leaves the item answered at its revision, its thread naming the member; a teammate writes as the starter does, a repeat under its key reaches the agent once, and an outsider, no bearer, and an empty message are refused", + () => + Effect.gen(function* () { + const eve = fakeEve(); + const { owner, other, task, target, ask, post, answer, read, message, transcript } = + yield* openInbox(eve); + const asked = yield* post({ + key: "flag-thread", + title: "Turn on the agent-mail flag in staging", + response: { type: INBOX_RESPONSE.TODO }, + needsReply: false, + }); + assert.ok(Result.isSuccess(asked)); + const { id, key, title } = asked.success; + // A bare Done on an item that asks nothing back reaches nobody, so the turn below is the agent's last. + const answered = readAnswer( + inboxAnsweredSchema, + HOSTED_HTTP_STATUS.OK, + yield* answer(id, { + revision: asked.success.revision, + clientKey: randomUUID(), + reply: INBOX_REPLY.DONE, + }), + ).item; + yield* turnEnded(target); + assert.equal((yield* transcript()).status, CODING_AGENT_STATUS.COMPLETED); + const before = eve.sent.length; + const trace = { + name: "copy-review.txt", + mediaType: CODING_AGENT_ATTACHMENT_TYPE.TEXT, + data: Buffer.from("subject line too long\n").toString("base64"), + }; + const body = { + text: "One more: drop the emoji.", + attachments: [trace], + clientKey: randomUUID(), + }; + + const sent = readAnswer( + inboxMessagedSchema, + HOSTED_HTTP_STATUS.OK, + yield* message(id, body), + ); + assert.deepEqual( + [sent.item.status, sent.item.revision, sent.item.answer], + [INBOX_STATUS.ANSWERED, answered.revision, answered.answer], + ); + assert.deepEqual( + sent.item.messages?.map((each) => [ + each.member?.userId, + each.text, + each.files?.map((file) => file.name), + ]), + [[owner, body.text, [trace.name]]], + ); + const handed = JSON.stringify(eve.sent.slice(before).map((each) => each.message.message)); + assert.ok(handed.includes(`${INBOX_MESSAGE_LEAD} on \\"${title}\\" (key ${key})`)); + assert.ok(handed.includes(body.text), "it carries the words"); + assert.ok(handed.includes("subject line too long"), "it carries the file"); + const woken = yield* transcript(); + assert.equal(woken.status, CODING_AGENT_STATUS.RUNNING, "the message woke the agent"); + assert.ok(woken.lines.some((line) => line?.includes(body.text))); + + yield* message(id, body); + assert.equal(eve.sent.length, before + 1, "a repeat under the key reaches the agent once"); + assert.deepEqual( + yield* message(id, { ...body, text: "Something else." }), + refusal(HOSTED_HTTP_STATUS.BAD_REQUEST, HOSTED_API_ERROR.INVALID_REQUEST), + "other words under a key already taken are refused, so the agent never hears what the thread does not show", + ); + assert.equal(eve.sent.length, before + 1); + + assert.deepEqual( + yield* message(id, { text: "Before I joined.", clientKey: randomUUID() }, other), + refusal(HOSTED_HTTP_STATUS.NOT_FOUND, HOSTED_API_ERROR.NOT_FOUND), + ); + yield* joinWorkspace(task.workspaceId, other); + yield* TestClock.adjust(Duration.seconds(1)); + readAnswer( + inboxMessagedSchema, + HOSTED_HTTP_STATUS.OK, + yield* message(id, { text: "Agreed.", clientKey: randomUUID() }, other), + ); + const kept = (yield* read()).items.find((item) => item.id === id); + assert.deepEqual( + kept?.messages?.map((each) => [each.member?.userId, each.text]), + [ + [owner, body.text], + [other, "Agreed."], + ], + ); + assert.equal(kept?.status, INBOX_STATUS.ANSWERED); + + assert.deepEqual( + yield* ask( + request(INBOX_MESSAGES, undefined, { + method: "POST", + id, + body: { text: "Hello.", clientKey: randomUUID() }, + }), + ), + refusal(HOSTED_HTTP_STATUS.UNAUTHORIZED, HOSTED_API_ERROR.INVALID_TOKEN), + ); + assert.deepEqual( + yield* message(id, { text: " ", clientKey: randomUUID() }), + refusal(HOSTED_HTTP_STATUS.BAD_REQUEST, HOSTED_API_ERROR.INVALID_REQUEST), + ); + }), + ); + + it.effect( + "a message the agent's session did not take is taken back off the thread, so the thread never shows what the agent was not told", + () => + Effect.gen(function* () { + const { post, read, message } = yield* openInbox( + fakeEve({ sends: EVE_SEND_OUTCOME.FAILED }), + ); + const asked = yield* post(QUESTION); + assert.ok(Result.isSuccess(asked)); + + const sent = yield* message(asked.success.id, { + text: "Still there?", + clientKey: randomUUID(), + }); + + assert.equal(sent.status, HOSTED_HTTP_STATUS.SERVICE_UNAVAILABLE); + const kept = (yield* read()).items.find((item) => item.id === asked.success.id); + assert.equal(kept?.messages, undefined); + }), + ); + it.effect( "a run of the account's own automation that failed to start rides the account's inbox read and moves its cursor, as no item, and another account's read carries none", () => diff --git a/packages/service/src/agents/coding-agents-app.ts b/packages/service/src/agents/coding-agents-app.ts index 96ef7ee7a8..c871fec4f3 100644 --- a/packages/service/src/agents/coding-agents-app.ts +++ b/packages/service/src/agents/coding-agents-app.ts @@ -52,7 +52,9 @@ import { inboxAnswerMessage, inboxAnswerRequestSchema, inboxCursorSchema, + inboxMessageRequestSchema, inboxReplyRefusal, + inboxThreadMessage, } from "@luke/features/inbox-wire"; import { modelChoiceSchema } from "@luke/features/models-wire"; import { @@ -103,10 +105,13 @@ import { import { logStoreFailure } from "../http/store-failure.js"; import { answerInboxItem, + INBOX_MESSAGE_OUTCOME, + postInboxMessage, readInboxAttachment, readInboxItem, type StoredInboxItem, withdrawInboxAnswer, + withdrawInboxMessage, } from "../inbox/inbox-store.js"; import type { ModelCatalog, ModelChoiceRefused } from "../providers/model-catalog.js"; import { ANY_METHOD, type WebRoutes } from "../route.js"; @@ -273,6 +278,8 @@ const AGENTS_PATH = { INBOX_OF_AGENT: "/api/agents/inbox", /** POST answers one inbox item; the rewrite moves the path's item id into the `id` query. */ INBOX_ITEM: "/api/inbox/item", + /** POST writes a member's message on one inbox item's thread; the rewrite moves the path's item id into the `id` query. */ + INBOX_MESSAGES: "/api/inbox/messages", /** GET reads what waits on the developer across the account's tasks past `after`. */ INBOX: "/api/inbox", /** GET serves one attachment of an inbox item, an image block's picture; the rewrite moves the item id into the `id` query and the attachment id into `attachment`. */ @@ -1324,6 +1331,72 @@ const inboxAnswerEndpoint = /* @__PURE__ */ Effect.fn("web/inboxAnswerEndpoint") return inboxAnswered(taken, true); }); +/** A message is its words and the files a message may carry: the words' bound at JSON's widest escape, the files, and room for the key. */ +const MAXIMUM_INBOX_MESSAGE_BODY_BYTES = + 6 * INBOX_BOUNDS.MAX_MESSAGE_CHARS + MAXIMUM_ATTACHMENTS_BODY_BYTES + 2_048; + +/** + * POST writes a member's message on the thread of one item of the account's + * workspaces, open or settled, whichever member started its agent, and + * answers with the item as it then stands. The message is written first, + * with its files, moving the item's last change and nothing else of it, + * and then handed to the agent as one of the developer's messages, under + * its own lead and its files with it, through the one steer path + * (`coder-host/steer.ts`), which opens a turn for an agent that stopped as + * a message typed in its tab does. A hand-off that fails, is interrupted, + * or dies takes the message back off the thread, so the thread never shows + * a message the agent was not told, where this send wrote it; a message sent again under its key is the one already + * written and handed off again, which the steer's own key makes reach the + * agent once, and another message under a key already taken, by another + * member or with other words or files, is refused. An agent whose session has ended for good can + * hear nothing again, so its item keeps the message. + */ +const inboxMessageEndpoint = /* @__PURE__ */ Effect.fn("web/inboxMessageEndpoint")(function* ( + seams: CodingAgentsAppSeams, + writer: Effect.Effect, +): Effect.fn.Return { + const incoming = yield* HttpServerRequest.HttpServerRequest; + if (incoming.method !== HTTP_METHOD.POST) { + return yield* Effect.fail(HOSTED_REFUSAL.METHOD_NOT_ALLOWED); + } + const request = yield* Effect.orDie(HttpServerRequest.toWeb(incoming)); + const itemId = yield* idOf(request); + const userId = yield* resolvedUserId(seams, request); + const body = yield* readJsonBodyEffect(MAXIMUM_INBOX_MESSAGE_BODY_BYTES); + const asked = readEither(inboxMessageRequestSchema)(body); + if (Result.isFailure(asked)) return yield* Effect.fail(HOSTED_REFUSAL.INVALID_REQUEST); + const { text, clientKey, attachments = [] } = asked.success; + const posted = yield* hostedStoreOrUnavailable( + postInboxMessage(userId, itemId, { text, clientKey, files: attachments }), + ); + if (Option.isNone(posted)) return yield* Effect.fail(HOSTED_REFUSAL.NOT_FOUND); + const { item, outcome } = posted.value; + if (outcome === INBOX_MESSAGE_OUTCOME.KEY_REUSED) { + return yield* Effect.fail(HOSTED_REFUSAL.INVALID_REQUEST); + } + // Note that a repeat leaves the message standing on failure, because the write that wrote it decides whether it stays. + const unheard = + outcome === INBOX_MESSAGE_OUTCOME.WRITTEN + ? withdrawInboxMessage(userId, itemId, clientKey) + : Effect.void; + const handedOver = Effect.gen(function* () { + const agent = yield* hostedStoreOrUnavailable(readCodingAgent(userId, item.agentId)); + if (Option.isNone(agent)) return yield* Effect.fail(HOSTED_REFUSAL.AGENT_RETIRED); + const eve = yield* eveFor(seams, request); + yield* steerCodingAgent(eve, writer, userId, agent.value, { + text: inboxThreadMessage(item, text), + attachments, + clientKey, + sender: { kind: MESSAGE_SENDER.MEMBER, userId }, + }); + }); + yield* handedOver.pipe( + Effect.catchIf(retiredRefusal, () => Effect.void), + Effect.onError(() => unheard.pipe(Effect.tapError(logStoreFailure), Effect.ignore)), + ); + return hostedJsonResponse(HOSTED_HTTP_STATUS.OK, { item }); +}); + /** * The item with the answer standing on it under the request's key: taken * now where the item is open at the revision named and takes the answer, @@ -1433,6 +1506,11 @@ export function codingAgentsApp(seams: CodingAgentsAppSeams): WebRoutes`(select coalesce(jsonb_agg(jsonb_build_object('attachmentId', ${inboxAttachment.id}, 'name', ${inboxAttachment.name}, 'mediaType', ${inboxAttachment.contentType}) order by ${inboxAttachment.position}), '[]'::jsonb) from ${inboxAttachment} where ${inboxAttachment.itemId} = ${ITEM_ID} and ${inboxAttachment.kind} = ${INBOX_ATTACHMENT_KIND.ANSWER})`; +/** A column named by its table, for a subquery nested inside another whose own columns would otherwise take the bare name. */ +function qualified(table: AnyPgTable, column: AnyPgColumn): SQL { + return sql`${sql.identifier(getTableName(table))}.${sql.identifier(column.name)}`; +} + +const MESSAGE = { + id: qualified(inboxMessage, inboxMessage.id), + author: qualified(inboxMessage, inboxMessage.author), + userId: qualified(inboxMessage, inboxMessage.userId), + text: qualified(inboxMessage, inboxMessage.text), + createdAt: qualified(inboxMessage, inboxMessage.createdAt), +}; + +/** The files one message of the thread carried, in the order they were attached, each named as an answer's file is. */ +const MESSAGE_FILES = sql`(select coalesce(jsonb_agg(jsonb_build_object('attachmentId', ${inboxAttachment.id}, 'name', ${inboxAttachment.name}, 'mediaType', ${inboxAttachment.contentType}) order by ${inboxAttachment.position}), '[]'::jsonb) from ${inboxAttachment} where ${inboxAttachment.messageId} = ${MESSAGE.id})`; + +/** The item's latest messages, as many as a read carries, under the table's own name so the columns above name them. */ +const LATEST_MESSAGES = sql`(select * from ${inboxMessage} where ${inboxMessage.itemId} = ${ITEM_ID} order by ${inboxMessage.createdAt} desc, ${inboxMessage.id} desc limit ${sql.raw(String(INBOX_BOUNDS.MAX_MESSAGES_READ))}) as ${sql.identifier(getTableName(inboxMessage))}`; + +/** + * The item's thread, the latest messages oldest first, each with its + * author, the member's name as their account holds it now, its words, its + * files, and when it was written in epoch milliseconds. + */ +const MESSAGES = sql`(select coalesce(jsonb_agg(jsonb_build_object('id', ${MESSAGE.id}, 'author', ${MESSAGE.author}, 'userId', ${MESSAGE.userId}, 'name', (select "name" from ${user} where ${user.id} = ${MESSAGE.userId}), 'text', ${MESSAGE.text}, 'files', ${MESSAGE_FILES}, 'createdAt', floor(extract(epoch from ${MESSAGE.createdAt}) * 1000)::bigint) order by ${MESSAGE.createdAt}, ${MESSAGE.id}), '[]'::jsonb) from ${LATEST_MESSAGES})`; + +/** Whether the item is settled: answered, or closed by its agent. */ +const SETTLED = sql`${inboxItem.status} <> ${INBOX_STATUS.OPEN}`; + +/** + * When a settled item was settled, in epoch milliseconds: the instant kept, + * or, on an item settled before it was kept, its last change, which no + * message has moved yet, since the first one keeps that instant first. + */ +const SETTLED_AT = sql< + number | null +>`floor(extract(epoch from coalesce(${inboxItem.settledAt}, case when ${SETTLED} then ${inboxItem.updatedAt} end)) * 1000)::float8`; + /** The columns every read and every `returning` projects, so a row decodes one way whatever wrote it. */ const INBOX_COLUMNS = { id: inboxItem.id, @@ -177,10 +225,44 @@ const INBOX_COLUMNS = { string | null >`(select "name" from ${user} where ${user.id} = ${inboxItem.answeredBy})`, closedReason: inboxItem.closedReason, + messages: MESSAGES, postedAt: inboxItem.postedAt, + settledAt: SETTLED_AT, updatedAt: inboxItem.updatedAt, }; +const FileRowSchema = Schema.Struct({ + attachmentId: Schema.String, + name: Schema.String, + mediaType: Schema.String, +}); + +const MessageRowSchema = Schema.Struct({ + id: Schema.String, + author: Schema.Literals(Object.values(INBOX_MESSAGE_AUTHOR)), + userId: Schema.NullOr(Schema.String), + name: Schema.NullOr(Schema.String), + text: Schema.String, + files: Schema.Array(FileRowSchema), + createdAt: Schema.Number, +}); + +type MessageRow = typeof MessageRowSchema.Type; + +/** A message as the wire carries it: the member named where their account stands, and no files where it carried none. */ +function storedMessage(row: MessageRow): InboxMessage { + return { + id: row.id, + author: row.author, + ...(row.userId === null || row.name === null + ? undefined + : { member: { userId: row.userId, name: row.name } }), + text: row.text, + ...(row.files.length === 0 ? undefined : { files: row.files }), + createdAt: row.createdAt, + }; +} + const InboxRowSchema = Schema.Struct({ id: Schema.String, agentId: Schema.String, @@ -195,14 +277,14 @@ const InboxRowSchema = Schema.Struct({ startedBy: Schema.String, startedByName: Schema.NullOr(Schema.String), answer: Schema.NullOr(inboxReplySchema), - answerFiles: Schema.Array( - Schema.Struct({ attachmentId: Schema.String, name: Schema.String, mediaType: Schema.String }), - ), + answerFiles: Schema.Array(FileRowSchema), answerKey: Schema.NullOr(Schema.String), answeredBy: Schema.NullOr(Schema.String), answeredByName: Schema.NullOr(Schema.String), closedReason: Schema.NullOr(Schema.String), + messages: Schema.Array(MessageRowSchema), postedAt: InstantColumnSchema, + settledAt: Schema.NullOr(Schema.Number), updatedAt: InstantColumnSchema, }); @@ -231,7 +313,9 @@ function storedItem(row: InboxRow): StoredInboxItem { ? undefined : { answeredBy: { userId: row.answeredBy, name: row.answeredByName } }), ...(row.closedReason === null ? undefined : { closedReason: row.closedReason }), + ...(row.messages.length === 0 ? undefined : { messages: row.messages.map(storedMessage) }), postedAt: row.postedAt.getTime(), + ...(row.settledAt === null ? undefined : { settledAt: row.settledAt }), updatedAt: row.updatedAt.getTime(), }, answerKey: row.answerKey, @@ -366,7 +450,11 @@ const deleteAnswerFiles = SqlSchema.void({ ), }); -/** The item's attachments no block of its names any longer, deleted, its answer's files among them, since a post clears the answer. */ +/** + * The item's attachments no block of its names any longer, deleted, its + * answer's files among them, since a post clears the answer. Note that the + * thread's files are kept, because a post leaves the thread standing. + */ const deleteOtherAttachments = SqlSchema.void({ Request: Schema.Struct({ itemId: Schema.String, kept: Schema.Array(Schema.String) }), execute: ({ itemId, kept }) => @@ -374,13 +462,88 @@ const deleteOtherAttachments = SqlSchema.void({ db .delete(inboxAttachment) .where( - kept.length === 0 - ? eq(inboxAttachment.itemId, itemId) - : and(eq(inboxAttachment.itemId, itemId), notInArray(inboxAttachment.id, [...kept])), + and( + eq(inboxAttachment.itemId, itemId), + ne(inboxAttachment.kind, INBOX_ATTACHMENT_KIND.MESSAGE), + kept.length === 0 ? undefined : notInArray(inboxAttachment.id, [...kept]), + ), ), ), }); +const MessageWriteSchema = Schema.Struct({ + itemId: Schema.String, + author: Schema.Literals(Object.values(INBOX_MESSAGE_AUTHOR)), + userId: Schema.NullOr(Schema.String), + text: Schema.String, + clientKey: Schema.NullOr(Schema.String), + now: Schema.Date, +}); + +/** The message written on the item's thread; nothing where a message of the item's stands under its key already. */ +const insertMessage = SqlSchema.findOneOption({ + Request: MessageWriteSchema, + Result: Schema.Struct({ id: Schema.String }), + execute: ({ now, ...message }) => + Database.use((db) => + db + .insert(inboxMessage) + .values({ ...message, createdAt: now }) + .onConflictDoNothing() + .returning({ id: inboxMessage.id }), + ), +}); + +const MessageFileWriteSchema = Schema.Struct({ + ...AnswerFileWriteSchema.fields, + messageId: Schema.String, +}); + +/** One file of a message's written as a row of the item's, naming the message, at its place among the message's files. */ +const insertMessageFile = SqlSchema.void({ + Request: MessageFileWriteSchema, + execute: ({ now, ...file }) => + Database.use((db) => + db.insert(inboxAttachment).values({ + ...file, + kind: INBOX_ATTACHMENT_KIND.MESSAGE, + byteCount: file.bytes.byteLength, + createdAt: now, + }), + ), +}); + +/** + * The item's last change moved to now, and nothing else of it: what a + * message on its thread does to the item. Note that a settled item settled + * before the instant was kept keeps its last change as that instant first, + * because the change is what a read took it for until now. + */ +const touchItem = SqlSchema.void({ + Request: Schema.Struct({ itemId: Schema.String, now: Schema.Date }), + execute: ({ itemId, now }) => + Database.use((db) => + db + .update(inboxItem) + .set({ + settledAt: sql`case when ${SETTLED} then coalesce(${inboxItem.settledAt}, ${inboxItem.updatedAt}) end`, + updatedAt: now, + }) + .where(eq(inboxItem.id, itemId)), + ), +}); + +/** The message the member's client wrote under its key on the item, deleted with its files; nothing else of the thread is. */ +const deleteMessage = SqlSchema.void({ + Request: Schema.Struct({ itemId: Schema.String, clientKey: Schema.String }), + execute: ({ itemId, clientKey }) => + Database.use((db) => + db + .delete(inboxMessage) + .where(and(eq(inboxMessage.itemId, itemId), eq(inboxMessage.clientKey, clientKey))), + ), +}); + /** The attachment, a block's picture or an answer's file, where it is the item's and the account reaches the item's task: its type and its bytes. */ const findAttachment = SqlSchema.findOneOption({ Request: Schema.Struct({ @@ -437,6 +600,7 @@ const upsertItem = SqlSchema.findOne({ answerKey: null, answeredBy: null, closedReason: null, + settledAt: null, updatedAt: write.now, }; return Database.use((db) => @@ -478,6 +642,7 @@ const closeItem = SqlSchema.findOneOption({ status: INBOX_STATUS.CLOSED, closedReason: reason, revision: sql`${inboxItem.revision} + 1`, + settledAt: now, updatedAt: now, }) .where( @@ -808,6 +973,14 @@ const findItem = SqlSchema.findOneOption({ ), }); +/** The item by its id alone, read where the caller has reached it already. */ +const findItemOf = SqlSchema.findOneOption({ + Request: Schema.Struct({ itemId: Schema.String }), + Result: InboxRowSchema, + execute: ({ itemId }) => + Database.use((db) => db.select(INBOX_COLUMNS).from(inboxItem).where(eq(inboxItem.id, itemId))), +}); + /** The account, task, and workspace an item stands under, which its attachments are written under too. */ const findItemScope = SqlSchema.findOne({ Request: Schema.Struct({ itemId: Schema.String }), @@ -854,6 +1027,7 @@ const answerItem = SqlSchema.findOneOption({ answer, answerKey, answeredBy: userId, + settledAt: now, updatedAt: now, }) .where( @@ -1053,6 +1227,7 @@ const withdrawAnswer = SqlSchema.findOneOption({ answer: null, answerKey: null, answeredBy: null, + settledAt: null, updatedAt: now, }) .where( @@ -1133,6 +1308,190 @@ export function answerInboxItem( ); } +/** Who writes a message on an item's thread: a member of its workspace by their account, under the key their client made, or the item's own agent. */ +type InboxMessageWriter = + | { + readonly author: typeof INBOX_MESSAGE_AUTHOR.MEMBER; + readonly userId: string; + readonly clientKey: string; + } + | { readonly author: typeof INBOX_MESSAGE_AUTHOR.AGENT }; + +/** What a member's message under its key came to. */ +export const INBOX_MESSAGE_OUTCOME = { + /** This write wrote it. */ + WRITTEN: "written", + /** The key found the same message written already, by the same member, with the same words and files. */ + REPEATED: "repeated", + /** The key found another message written already, by another member or with other words or files; nothing was written. */ + KEY_REUSED: "key-reused", +} as const; + +type InboxMessageOutcome = (typeof INBOX_MESSAGE_OUTCOME)[keyof typeof INBOX_MESSAGE_OUTCOME]; + +/** What a message came to: the item as it then stands, and what this write did. */ +export interface InboxMessageWritten { + readonly item: InboxItem; + readonly outcome: InboxMessageOutcome; +} + +const KeyedMessageSchema = Schema.Struct({ + userId: Schema.NullOr(Schema.String), + text: Schema.String, + files: Schema.Array(Schema.Struct({ name: Schema.String, mediaType: Schema.String })), +}); + +/** The message standing under a member's key on the item: who wrote it, its words, and its files by name and type in order. */ +const findKeyedMessage = SqlSchema.findOneOption({ + Request: Schema.Struct({ itemId: Schema.String, clientKey: Schema.String }), + Result: KeyedMessageSchema, + execute: ({ itemId, clientKey }) => + Database.use((db) => + db + .select({ + userId: inboxMessage.userId, + text: inboxMessage.text, + files: sql`(select coalesce(jsonb_agg(jsonb_build_object('name', ${inboxAttachment.name}, 'mediaType', ${inboxAttachment.contentType}) order by ${inboxAttachment.position}), '[]'::jsonb) from ${inboxAttachment} where ${inboxAttachment.messageId} = ${MESSAGE.id})`, + }) + .from(inboxMessage) + .where(and(eq(inboxMessage.itemId, itemId), eq(inboxMessage.clientKey, clientKey))), + ), +}); + +/** Whether the message standing under the key is the one sent again: the same member, the same words, and the same files by name and type. */ +function sameMessage( + standing: typeof KeyedMessageSchema.Type, + sent: { + readonly userId: string; + readonly text: string; + readonly files: readonly CodingAgentAttachment[]; + }, +): boolean { + return ( + standing.userId === sent.userId && + standing.text === sent.text && + standing.files.length === sent.files.length && + standing.files.every( + (file, at) => + file.name === sent.files[at]?.name && file.mediaType === sent.files[at]?.mediaType, + ) + ); +} + +/** + * The message written on the item's thread, the item standing open or + * settled, with the files it carried in the order given, and the item's + * last change moved to now, all in one write: the item's status, answer, + * and revision are left as they stand. A member's message sent again under + * its key is the one already written, which writes nothing and moves + * nothing; another message under a key already taken, by another member or + * with other words or files, is refused as the key reused, so the thread + * never names one message while the agent hears another. The caller has read the item as the writer may reach it, so the + * item named is one that stands. + */ +function writeInboxMessage( + itemId: string, + writer: InboxMessageWriter, + text: string, + files: readonly CodingAgentAttachment[], +): InboxStoreEffect> { + const member = writer.author === INBOX_MESSAGE_AUTHOR.MEMBER ? writer : undefined; + return Effect.flatMap(SqlClient.SqlClient, (client) => + client.withTransaction( + Effect.gen(function* () { + const now = yield* DateTime.nowAsDate; + const written = yield* insertMessage({ + itemId, + author: writer.author, + userId: member?.userId ?? null, + text, + clientKey: member?.clientKey ?? null, + now, + }); + if (Option.isSome(written)) { + const scope = yield* itemScope({ itemId }); + yield* Effect.forEach(files, (file, position) => + insertMessageFile({ + ...scope, + itemId, + messageId: written.value.id, + name: file.name, + position, + contentType: file.mediaType, + bytes: bytesOf(file), + now, + }), + ); + yield* touchItem({ itemId, now }); + } + const outcome = Option.isSome(written) + ? INBOX_MESSAGE_OUTCOME.WRITTEN + : yield* repeatOutcome(itemId, member, text, files); + const found = yield* findItemOf({ itemId }); + return Option.map(found, (row) => ({ item: storedItem(row).item, outcome })); + }), + ), + ); +} + +/** What a member's message whose key found one standing came to: the same message sent again, or another under a key reused. */ +function repeatOutcome( + itemId: string, + member: { readonly userId: string; readonly clientKey: string } | undefined, + text: string, + files: readonly CodingAgentAttachment[], +): InboxStoreEffect { + if (member === undefined) return Effect.succeed(INBOX_MESSAGE_OUTCOME.KEY_REUSED); + return Effect.map(findKeyedMessage({ itemId, clientKey: member.clientKey }), (standing) => + Option.isSome(standing) && sameMessage(standing.value, { userId: member.userId, text, files }) + ? INBOX_MESSAGE_OUTCOME.REPEATED + : INBOX_MESSAGE_OUTCOME.KEY_REUSED, + ); +} + +/** + * A member's message on an item of a workspace they are a member of, open + * or settled, as `writeInboxMessage` writes one; nothing where the account + * reaches no such item. + */ +export function postInboxMessage( + userId: string, + itemId: string, + message: { + readonly text: string; + readonly clientKey: string; + readonly files?: readonly CodingAgentAttachment[] | undefined; + }, +): InboxStoreEffect> { + return Effect.flatMap(findItem({ userId, itemId }), (found) => + Option.isNone(found) + ? Effect.succeed(Option.none()) + : writeInboxMessage( + itemId, + { author: INBOX_MESSAGE_AUTHOR.MEMBER, userId, clientKey: message.clientKey }, + message.text, + message.files ?? [], + ), + ); +} + +/** + * The member's message written under the key taken back off the item's + * thread, its files with it, where the account still reaches the item: what + * a hand-off to the agent that failed leaves, so the thread never shows a + * message the agent was not told. The item's last change stays where the + * message moved it. + */ +export function withdrawInboxMessage( + userId: string, + itemId: string, + clientKey: string, +): InboxStoreEffect { + return Effect.flatMap(findItem({ userId, itemId }), (found) => + Option.isNone(found) ? Effect.void : deleteMessage({ itemId, clientKey }), + ); +} + /** One item that waits as the account's read holds it: the entry the wire carries, and where it stands, which a cursor digests. */ type AccountWaitingRow = AccountInboxEntry & Pick; diff --git a/vercel.json b/vercel.json index 2778633ea6..149d3ac841 100644 --- a/vercel.json +++ b/vercel.json @@ -200,6 +200,10 @@ "src": "/api/inbox/([^/]+)/attachments/([^/]+)", "dest": "/api/default.js?route=inbox/attachment&id=$1&attachment=$2" }, + { + "src": "/api/inbox/([^/]+)/messages", + "dest": "/api/default.js?route=inbox/messages&id=$1" + }, { "src": "/api/inbox/([^/]+)", "dest": "/api/default.js?route=inbox/item&id=$1"