{
  "openapi": "3.1.0",
  "info": {
    "title": "CellCog API",
    "version": "1.0.0",
    "summary": "Hand CellCog a brief with an API key, get finished work back.",
    "description": "CellCog is an AI sub-agent you hand a brief to. An agent does the whole job and returns finished work: research briefs with sources, PDFs and slide decks, spreadsheets with live formulas, dashboards and web apps, data analysis and code, and, when the brief asks for it, images, video and audio.\n\nThis description covers the API-key surface, the same calls the Python SDK (`pip install cellcog`) makes. Everything else on cellcog.ai is the product's own interface and is not part of this contract.\n\n## Authentication\nEvery request carries the header `X-API-Key: <key>`. A human creates the key at https://cellcog.ai/profile?tab=api-keys (guide: https://cellcog.ai/support/api-keys-guide) and hands it to you; never ask them for a password. Agents that speak MCP can use the connector at https://cellcog.ai/mcp instead (OAuth sign-in, no key).\n\n## The job loop\n1. `POST /api/cellcog/chat/new` with `message` = the brief. A file from your side goes through the files hand-off first (request-upload, PUT, confirm) and is then referenced in the brief as <SHOW_FILE>blob_name</SHOW_FILE>; a file already at a public https URL is just linked. The response carries `chat_id`.\n2. Poll `GET /api/cellcog/chat/{chat_id}` about once a minute until `operating` is false. A brief takes 3 to 8 minutes; several videos take 10 to 40 minutes. Never give up on a long job; keep polling.\n3. `GET /api/cellcog/chat/{chat_id}/history`: the agent's final message and the files it produced, each with a URL. Then `PATCH /api/cellcog/chat/{chat_id}/seen`.\n4. To iterate or answer a question the agent asked: `POST /api/cellcog/chat/{chat_id}/messages` and poll again.\n\n## Credits\nWork spends credits from the account behind the key. `402` = no credits: `GET /api/cellcog/billing/credit-recovery` returns the payment links to show the human; the refused request works when retried after the top-up. Plans and prices: https://cellcog.ai/pricing.\n\n## Errors\n`401` bad or revoked key · `402` no credits · `403` the key's account cannot use this resource · `404` not yours or gone · `422` the body does not match the schema (read `detail`). Every error carries a `detail` field.\n\nSupport: contact@cellcog.ai · Guide for agents: https://cellcog.ai/for-agents · Terms: https://cellcog.ai/support/terms-of-service · Privacy: https://cellcog.ai/support/privacy-policy",
    "termsOfService": "https://cellcog.ai/support/terms-of-service",
    "contact": {
      "name": "CellCog",
      "url": "https://cellcog.ai/for-agents",
      "email": "contact@cellcog.ai"
    }
  },
  "servers": [
    {
      "url": "https://cellcog.ai",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Chat",
      "description": "Create a chat, follow up, poll, read the result, list chats, credits."
    },
    {
      "name": "Files",
      "description": "Hand CellCog a file from your side before a brief."
    },
    {
      "name": "Billing",
      "description": "What to do on 402."
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/api/cellcog/chat/new": {
      "post": {
        "tags": [
          "Chat"
        ],
        "summary": "Create a chat: hand CellCog a brief",
        "description": "Start a job. An agent takes your brief and returns finished work (research with sources, PDFs and decks, spreadsheets with live formulas, dashboards and web apps, code, and images, video or audio when the brief asks for them). Send `message` (the brief), optionally `chat_mode` and `chat_tier`. A file from your side rides INSIDE the message: after the files hand-off, write its `blob_name` in the brief as <SHOW_FILE>blob_name</SHOW_FILE>. Returns the chat with its `chat_id`; the work runs in the background. Poll GET /api/cellcog/chat/{chat_id} (or POST /api/cellcog/chats/status for many) until `operating` is false, then read GET /api/cellcog/chat/{chat_id}/history for the agent's messages and files. A 402 means the account has no credits: GET /api/cellcog/billing/credit-recovery returns the payment links; the same request works after a top-up.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MessageRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatMeta"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Bad or revoked API key."
          },
          "402": {
            "description": "No credits on the account; call GET /api/cellcog/billing/credit-recovery for payment links, retry after the top-up."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/cellcog/chat/{chat_id}/messages": {
      "post": {
        "tags": [
          "Chat"
        ],
        "summary": "Send a follow-up into an existing chat",
        "description": "Continue a chat in context: iterate on the result, answer a question the agent asked, or add files. Same body as chat creation. Poll the chat afterwards exactly as after creation.",
        "parameters": [
          {
            "name": "chat_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Chat Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MessageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatMeta"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Bad or revoked API key."
          },
          "402": {
            "description": "No credits on the account; call GET /api/cellcog/billing/credit-recovery for payment links, retry after the top-up."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/cellcog/chat/{chat_id}": {
      "get": {
        "tags": [
          "Chat"
        ],
        "summary": "Chat status (cheap poll)",
        "parameters": [
          {
            "name": "chat_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Chat Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatMeta"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Bad or revoked API key."
          }
        },
        "description": "The chat's metadata: `operating` (a run is live), status, name, mode and tier. Poll this about once a minute while the job runs; long jobs (several videos) take 10 to 40 minutes.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/cellcog/chats/status": {
      "post": {
        "tags": [
          "Chat"
        ],
        "summary": "Status of many chats in one call",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkChatStatusRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkChatStatusResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Bad or revoked API key."
          },
          "402": {
            "description": "No credits on the account; call GET /api/cellcog/billing/credit-recovery for payment links, retry after the top-up."
          }
        },
        "description": "Bulk form of the status poll for several `chat_id`s at once.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/cellcog/chat/{chat_id}/history": {
      "get": {
        "tags": [
          "Chat"
        ],
        "summary": "Read the chat: the agent's messages and files",
        "parameters": [
          {
            "name": "chat_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Chat Id"
            }
          },
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Employee Id"
            }
          },
          {
            "name": "shift_number",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Shift Number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Chat"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Bad or revoked API key."
          }
        },
        "description": "The full conversation. The agent's final message and every file it produced (each with a URL) are here once `operating` is false. If the agent asked you something, the last message is the question: answer it with a follow-up message.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/cellcog/chat/{chat_id}/seen": {
      "patch": {
        "tags": [
          "Chat"
        ],
        "summary": "Mark the result as collected",
        "description": "Records that you have read the chat, so CellCog does not remind the human by email about a result you already collected.",
        "parameters": [
          {
            "name": "chat_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Chat Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Bad or revoked API key."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/cellcog/chats": {
      "get": {
        "tags": [
          "Chat"
        ],
        "summary": "List recent chats",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "description": "Page number, starting from 1",
              "default": 1,
              "title": "Page"
            },
            "description": "Page number, starting from 1"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "description": "Number of items per page (1-100)",
              "default": 20,
              "title": "Page Size"
            },
            "description": "Number of items per page (1-100)"
          },
          {
            "name": "project_id",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by project. Omit for all chats, empty string ('') for personal chats only, or provide project ID for project-specific chats.",
              "title": "Project Id"
            },
            "description": "Filter by project. Omit for all chats, empty string ('') for personal chats only, or provide project ID for project-specific chats."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedChatsResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Bad or revoked API key."
          }
        },
        "description": "The account's chats, newest first, paginated. Use it to find earlier work.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/cellcog/chat/{chat_id}/credits": {
      "get": {
        "tags": [
          "Chat"
        ],
        "summary": "Credits spent by one chat",
        "description": "What the chat has cost so far, in credits.",
        "parameters": [
          {
            "name": "chat_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Chat Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatCreditsResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Bad or revoked API key."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/cellcog/billing/credit-recovery": {
      "get": {
        "tags": [
          "Billing"
        ],
        "summary": "Payment options when credits run out",
        "description": "Top-up payment links, the billing page and the plans page for the connected account. Call it after a 402 and show the human the link; the payment lands on this account and the refused request works when retried.",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "401": {
            "description": "Bad or revoked API key."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/files/request-upload": {
      "post": {
        "tags": [
          "Files"
        ],
        "summary": "Files hand-off, step 1: get a signed upload URL",
        "description": "For a file on your side that is not at a public https URL (a product photo, a brand PDF). Returns a signed URL to PUT the bytes to (`upload_type` signed_put; above 100 MB a resumable session), a `file_id` and a `blob_name`. PUT the bytes, confirm (step 2), then reference the file in the brief as <SHOW_FILE>blob_name</SHOW_FILE>.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/py__file_svc__api__file__FileUploadRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/py__file_svc__api__file__FileUploadResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Bad or revoked API key."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/files/confirm-upload/{file_id}": {
      "post": {
        "tags": [
          "Files"
        ],
        "summary": "Files hand-off, step 2: confirm the upload",
        "description": "Tell CellCog the bytes landed. Returns `blob_name` (the reference to write into the brief) and a signed URL to view the file.",
        "parameters": [
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "File Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConfirmUploadResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Bad or revoked API key."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "A CellCog API key, created by a human at https://cellcog.ai/profile?tab=api-keys."
      }
    },
    "schemas": {
      "BulkChatStatusRequest": {
        "properties": {
          "chat_ids": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "maxItems": 20,
            "minItems": 1,
            "title": "Chat Ids",
            "description": "List of chat IDs to retrieve status for. Maximum 20 IDs per request.",
            "example": [
              "507f1f77bcf86cd799439011",
              "507f1f77bcf86cd799439012"
            ]
          }
        },
        "type": "object",
        "required": [
          "chat_ids"
        ],
        "title": "BulkChatStatusRequest",
        "description": "Request model for bulk chat status retrieval.\n\nAllows checking status of multiple chats in a single API call."
      },
      "BulkChatStatusResponse": {
        "properties": {
          "chats": {
            "additionalProperties": {
              "$ref": "#/components/schemas/ChatMeta"
            },
            "type": "object",
            "title": "Chats",
            "description": "Dictionary mapping chat IDs to their metadata. Only includes chats that exist and belong to the user.",
            "example": {
              "507f1f77bcf86cd799439011": {
                "id": "507f1f77bcf86cd799439011",
                "name": "Tesla Analysis",
                "operating": false
              }
            }
          }
        },
        "type": "object",
        "required": [
          "chats"
        ],
        "title": "BulkChatStatusResponse",
        "description": "Response model for bulk chat status retrieval.\n\nReturns metadata for multiple chats indexed by their IDs."
      },
      "Chat": {
        "properties": {
          "chat_id": {
            "type": "string",
            "title": "Chat Id",
            "description": "Unique identifier for the chat session",
            "example": "507f1f77bcf86cd799439011"
          },
          "messages": {
            "items": {
              "$ref": "#/components/schemas/Message"
            },
            "type": "array",
            "title": "Messages",
            "description": "Chronological list of committed messages in the conversation",
            "example": []
          },
          "letterbox_messages": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Letterbox Messages",
            "description": "Raw markdown strings of messages queued in letterbox (not yet processed by agents). These are displayed separately in the UI as 'queued messages'. Empty when no messages are queued. BACK-COMPAT: human lane only — new consumers should read letterbox_items.",
            "example": [
              "Also check Apple stock",
              "And compare them side by side"
            ]
          },
          "letterbox_items": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array",
            "title": "Letterbox Items",
            "description": "Unified queue items across BOTH letterbox lanes (letterbox unified visibility PRD): {content, category: human|announcement|email_event|system, lane, lane_index, deletable, queued_at}. System-lane items are view-only; delete is valid ONLY for lane=='human' via lane_index."
          },
          "createdAt": {
            "type": "string",
            "title": "Createdat",
            "description": "ISO 8601 timestamp when the chat was created",
            "example": "2025-10-21T15:30:00Z"
          },
          "blob_name_to_url": {
            "additionalProperties": true,
            "type": "object",
            "title": "Blob Name To Url",
            "description": "Mapping of file blob names to signed URLs for accessing media files (images, documents, etc.) referenced in BOTH messages AND letterbox_messages",
            "example": {
              "507f1f77bcf86cd799439011/output.png": "https://storage.googleapis.com/..."
            }
          },
          "sharing_status": {
            "$ref": "#/components/schemas/ChatSharingStatus",
            "description": "Sharing status of the chat: 'NOT_SHARED', 'SHARED', or other status values",
            "example": "NOT_SHARED"
          },
          "shared_post_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Shared Post Id",
            "description": "ID of the public post if this chat has been shared. Null if not shared.",
            "example": "507f1f77bcf86cd799439015"
          },
          "is_app_public": {
            "type": "boolean",
            "title": "Is App Public",
            "description": "Whether the app is publicly accessible (any active Post exists for this chat_id)",
            "default": false
          },
          "user": {
            "additionalProperties": true,
            "type": "object",
            "title": "User",
            "description": "Public profile information of the chat owner",
            "example": {
              "firebase_uid": "abc123",
              "name": "John Doe",
              "user_type": "HUMAN"
            }
          },
          "credits": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Credits",
            "description": "This chat's credit usage block: {total_credits, has_pending_usage}. Folded into the history response so a single fetch carries both messages and credits (used by the AI-employee continuous shift stream to render each shift's credit bar without a separate /credits call). Null when not computed.",
            "example": {
              "has_pending_usage": false,
              "total_credits": -1200
            }
          }
        },
        "type": "object",
        "required": [
          "chat_id",
          "messages",
          "createdAt",
          "blob_name_to_url",
          "sharing_status",
          "user"
        ],
        "title": "Chat",
        "description": "Complete chat conversation with full message history.\n\nThis model includes all messages exchanged between the user and CellCog agents,\nalong with associated media files and sharing information."
      },
      "ChatCreditsResponse": {
        "properties": {
          "chat_id": {
            "type": "string",
            "title": "Chat Id"
          },
          "total_credits": {
            "type": "integer",
            "title": "Total Credits"
          },
          "has_pending_usage": {
            "type": "boolean",
            "title": "Has Pending Usage"
          },
          "effective_balance": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Effective Balance"
          }
        },
        "type": "object",
        "required": [
          "chat_id",
          "total_credits",
          "has_pending_usage"
        ],
        "title": "ChatCreditsResponse",
        "description": "Response model for chat credits endpoint"
      },
      "ChatMeta": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Unique identifier for the chat session",
            "example": "507f1f77bcf86cd799439011"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Display name for the chat. Auto-generated if not set by user.",
            "example": "Tesla Earnings Analysis"
          },
          "operating": {
            "type": "boolean",
            "title": "Operating",
            "description": "Whether the chat is currently being processed by agents. When false, the chat is idle and waiting for user input.",
            "example": false
          },
          "pending_hire_proposal": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pending Hire Proposal",
            "description": "Pending hire proposal for the owner's approval panel, if any"
          },
          "human_computer_turn": {
            "type": "boolean",
            "title": "Human Computer Turn",
            "description": "Whether the chat is waiting for Human Computer command approval/execution. When true, message sending is blocked.",
            "default": false,
            "example": false
          },
          "paused_mailbox": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Paused Mailbox",
            "description": "True when the just-sent message was queued because the AI employee is paused."
          },
          "mailbox_waiting": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mailbox Waiting",
            "description": "Items waiting in the paused employee's mailbox after this send (both lanes)."
          },
          "project_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Project Id",
            "description": "ID of the project this chat belongs to. Null for personal chats.",
            "example": "507f1f77bcf86cd799439012"
          },
          "project_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Project Name",
            "description": "Name of the project this chat belongs to. Null for personal chats.",
            "example": "Finance Research"
          },
          "general_agent_role_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "General Agent Role Id",
            "description": "ID of the custom agent role used in this chat. Null if using default agent behavior.",
            "example": "507f1f77bcf86cd799439013"
          },
          "general_agent_role_title": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "General Agent Role Title",
            "description": "Title of the custom agent role. Null if using default agent.",
            "example": "Financial Analyst"
          },
          "chat_mode": {
            "$ref": "#/components/schemas/ChatMode",
            "description": "Chat mode: 'agent_in_the_loop' allows autonomous agent operation, 'human_in_the_loop' requires human approval for agent actions.",
            "default": "human_in_the_loop",
            "example": "human_in_the_loop"
          },
          "chat_tier": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Chat Tier",
            "description": "Chat tier within the mode ('flash' | 'core' | 'max'). None on legacy rows pre-migration (resolves to the mode's default).",
            "example": "max"
          },
          "latest_status_update": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Latest Status Update",
            "description": "Most recent agent progress one-liner (AsyncUpdateForHumans) — progress visibility for SDK/API pollers (CEL-1300). None until the first update of a run.",
            "example": "Analyzing Q3 revenue data"
          },
          "ai_employee_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ai Employee Id",
            "description": "For AI Employee chats: the employee's anchor (shift-1) id. Null otherwise."
          },
          "shift_number": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Shift Number",
            "description": "For AI Employee chats: the session/shift number (from 1). Null otherwise."
          },
          "context_pct": {
            "type": "number",
            "title": "Context Pct",
            "description": "Privacy-safe fraction (0.0–1.0) of the usable context window occupied by the latest agent turn — the MAX across agents. Excludes the core system prompt. Only this percentage is exposed — never raw token counts.",
            "default": 0.0,
            "example": 0.41
          },
          "context_pct_by_agent": {
            "additionalProperties": true,
            "type": "object",
            "title": "Context Pct By Agent",
            "description": "Privacy-safe context fraction (0.0–1.0) per agent, keyed by base agent name (e.g. GeneralAgent, WorkerAgent). Agent-team modes have both; single-agent modes have one. For the split-bar UI.",
            "example": {
              "GeneralAgent": 0.41,
              "WorkerAgent": 0.18
            }
          },
          "approved_tool_slugs": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Approved Tool Slugs",
            "description": "List of tool slugs the agent is allowed to use in this chat. Empty list means no tools are approved.",
            "example": [
              "LINEAR_CREATE_LINEAR_ISSUE",
              "LINEAR_LIST_LINEAR_ISSUES"
            ]
          },
          "hc_enabled": {
            "type": "boolean",
            "title": "Hc Enabled",
            "description": "Whether Human Computer is enabled for this chat, allowing agents to run commands on the user's personal machine.",
            "default": false
          },
          "personal_tools_enabled": {
            "type": "boolean",
            "title": "Personal Tools Enabled",
            "description": "Whether Personal Tools is enabled for this chat (gates HumanPersonalTool_Call; search/definitions are always available).",
            "default": false
          },
          "personal_tools_selection": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Personal Tools Selection",
            "description": "Per-chat tool selection: None = all connected tools act here; a list of toolkit slugs (and key:NAME refs for standalone keys) narrows the chat."
          },
          "hc_working_directory": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hc Working Directory",
            "description": "Working directory on the user's machine for Human Computer commands.",
            "example": "/Users/john/projects/my-app"
          },
          "browser_enabled": {
            "type": "boolean",
            "title": "Browser Enabled",
            "description": "Whether Browse my Chrome is enabled for this chat.",
            "default": false
          },
          "browser_profile_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Browser Profile Id",
            "description": "Chrome profile dir (e.g., 'Default', 'Profile 3') the chat is bound to. Phase D multi-profile routing.",
            "example": "Profile 3"
          },
          "terminal_threat_threshold": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Terminal Threat Threshold",
            "description": "Per-chat terminal auto-approve override; None = inherit global default."
          },
          "browser_threat_threshold": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Browser Threat Threshold",
            "description": "Per-chat browser auto-approve override; None = inherit global default."
          },
          "personal_tools_threat_threshold": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Personal Tools Threat Threshold",
            "description": "Per-chat personal-tools auto-approve override; None = inherit global default."
          },
          "stop_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stop Reason",
            "description": "Why the last agent run stopped: 'done' (task finished) or 'needs_input' (agent is blocked on the user). Cleared while operating. Employee shifts also use shift_complete/shift_oom.",
            "example": "needs_input"
          },
          "cache_warm_until": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cache Warm Until",
            "description": "When this chat's provider prompt cache stops being warm (UTC ISO; MIN across agents minus a safety margin), stamped at every stop. None = untracked (no LLM request yet). While operating the cache is warm regardless. Drives the header / shift-divider warm/cold indicator."
          },
          "is_degraded": {
            "type": "boolean",
            "title": "Is Degraded",
            "description": "Whether this chat was silently switched to a fallback AI model after repeated primary-model refusals (CEL-663). Informational — the chat is healthy and continues normally.",
            "default": false,
            "example": false
          },
          "degraded_model": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Degraded Model",
            "description": "The fallback model the chat degraded to (e.g. 'claude-opus-5'); None if never degraded."
          },
          "is_security_threat": {
            "type": "boolean",
            "title": "Is Security Threat",
            "description": "Whether the chat has been flagged as a potential security threat. If true, the chat is locked and cannot continue.",
            "example": false
          },
          "security_threat_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Security Threat Reason",
            "description": "Why the chat was security-locked (from security.threat_reason). Only populated when is_security_threat is true; None otherwise (never leaks stale reasons)."
          },
          "is_out_of_memory": {
            "type": "boolean",
            "title": "Is Out Of Memory",
            "description": "Whether the chat has exceeded memory limits. If true, the chat cannot continue and a new chat must be created.",
            "example": false
          },
          "is_updating_long_term_memory": {
            "type": "boolean",
            "title": "Is Updating Long Term Memory",
            "description": "Whether the chat is currently updating its long-term memory (background task). Rare state, typically false.",
            "example": false
          },
          "lucide_icon": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lucide Icon",
            "description": "Lucide icon name for the chat (e.g. 'code', 'bar-chart-3'). Takes priority over thumbnail_url when present.",
            "example": "code"
          },
          "thumbnail_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Thumbnail Url",
            "description": "Signed URL for the chat's thumbnail image. Null if no thumbnail has been generated. Used as fallback when lucide_icon is not set.",
            "example": "https://storage.googleapis.com/cellcog_thumbnails/chats/507f1f77bcf86cd799439011/thumbnail.jpeg?..."
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At",
            "description": "ISO 8601 timestamp when the chat was created",
            "example": "2025-10-21T15:30:00Z"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated At",
            "description": "ISO 8601 timestamp when the chat was last updated",
            "example": "2025-10-21T15:35:00Z"
          },
          "user_last_messaged_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "User Last Messaged At",
            "description": "ISO 8601 timestamp when the user last sent a message in this chat. The chat list is sorted by this field, so the sidebar's date-group headers (Today/Yesterday/…) must be derived from it too.",
            "example": "2025-10-21T15:35:00Z"
          },
          "updated_long_term_memory_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated Long Term Memory At",
            "description": "ISO 8601 timestamp when the chat's long-term memory was last updated. Null if never updated.",
            "example": "2025-10-21T15:40:00Z"
          },
          "attention_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Attention At",
            "description": "ISO 8601 timestamp when the chat last needed user attention (agent completed or HC turn). Used with user_last_seen_at for notification badges.",
            "example": "2025-10-21T15:35:00Z"
          },
          "user_last_seen_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "User Last Seen At",
            "description": "ISO 8601 timestamp when the user last viewed this chat. Used with attention_at for notification badges.",
            "example": "2025-10-21T15:36:00Z"
          },
          "sdk_agent_provider": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sdk Agent Provider",
            "description": "Name of the SDK agent that created this chat (e.g., 'openclaw', 'claude-code', 'cursor'). Null for web chats.",
            "example": "openclaw"
          },
          "sdk_agent_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sdk Agent Version",
            "description": "Version of the SDK agent that created this chat. Null if not provided or not detectable.",
            "example": "2026.4.1"
          },
          "sdk_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sdk Version",
            "description": "CellCog Python SDK version used to create this chat. Null for web chats.",
            "example": "2.1.0"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "operating",
          "is_security_threat",
          "is_out_of_memory",
          "is_updating_long_term_memory"
        ],
        "title": "ChatMeta",
        "description": "Metadata for a chat session.\n\nThis model contains essential information about a chat without including the full message history.\nUse this for listing chats, checking status, and monitoring processing state."
      },
      "ChatMode": {
        "type": "string",
        "enum": [
          "human_in_the_loop",
          "agent_in_the_loop",
          "agent_team_max",
          "agent_creative",
          "agent_core",
          "ai_employee"
        ],
        "title": "ChatMode",
        "description": "Enum for chat modes."
      },
      "ChatSharingStatus": {
        "type": "string",
        "enum": [
          "NOT_SHARED",
          "SHARED",
          "SHARED_ANONYMOUSLY"
        ],
        "title": "ChatSharingStatus"
      },
      "ConfirmUploadResponse": {
        "properties": {
          "success": {
            "type": "boolean",
            "title": "Success"
          },
          "file_id": {
            "type": "string",
            "title": "File Id"
          },
          "blob_name": {
            "type": "string",
            "title": "Blob Name"
          },
          "signed_url": {
            "type": "string",
            "title": "Signed Url"
          }
        },
        "type": "object",
        "required": [
          "success",
          "file_id",
          "blob_name",
          "signed_url"
        ],
        "title": "ConfirmUploadResponse"
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "Message": {
        "properties": {
          "messageFrom": {
            "type": "string",
            "title": "Messagefrom",
            "description": "Sender of the message. Either the user's name/email or 'CellCog' for agent responses.",
            "example": "CellCog"
          },
          "content": {
            "type": "string",
            "title": "Content",
            "description": "Message content in markdown format. May include text, code blocks, images, and other media.",
            "example": "I've analyzed the Tesla earnings report. Here are the key findings:\n\n## Revenue\n- Q4 Revenue: $25.2B (+10% YoY)\n..."
          },
          "createdAt": {
            "type": "string",
            "title": "Createdat",
            "description": "ISO 8601 timestamp when the message was created",
            "example": "2025-10-21T15:30:00Z"
          }
        },
        "type": "object",
        "required": [
          "messageFrom",
          "content",
          "createdAt"
        ],
        "title": "Message",
        "description": "A single message in a chat conversation.\n\nMessages alternate between the user and CellCog (the AI agent system)."
      },
      "MessageRequest": {
        "properties": {
          "message": {
            "type": "string",
            "maxLength": 50000,
            "minLength": 1,
            "title": "Message",
            "description": "The message content to send to CellCog. Can include text, questions, instructions, or requests for the AI agents. Supports plain text and markdown.",
            "example": "Analyze the latest Tesla earnings report and create a comprehensive summary with key financial metrics."
          },
          "project_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Project Id",
            "description": "Optional project ID to associate with the chat. When provided, the chat will have access to all documents uploaded to the project. Required if using general_agent_role_id.",
            "example": "507f1f77bcf86cd799439012"
          },
          "general_agent_role_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "General Agent Role Id",
            "description": "Optional custom agent role ID within the specified project. Allows using specialized agent configurations. Can only be used if project_id is provided.",
            "example": "507f1f77bcf86cd799439013"
          },
          "chat_mode": {
            "$ref": "#/components/schemas/ChatMode",
            "description": "Chat operation mode. 'agent_in_the_loop' (default) allows the agent to work autonomously. 'human_in_the_loop' requires human approval before the agent takes actions.",
            "default": "human_in_the_loop",
            "example": "human_in_the_loop"
          },
          "chat_tier": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Chat Tier",
            "description": "Chat tier within the mode: 'flash' | 'core' | 'max'. Omit for the mode's default tier. Agent Creative has no flash tier.",
            "example": "max"
          },
          "approved_tool_slugs": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Approved Tool Slugs",
            "description": "List of tool slugs the agent is allowed to use during this chat session. Empty list (default) means no external tools are approved. Tool slugs are managed separately via the tools API.",
            "example": [
              "LINEAR_CREATE_LINEAR_ISSUE",
              "LINEAR_UPDATE_ISSUE"
            ]
          },
          "client_request_id": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ],
            "title": "Client Request Id",
            "description": "Optional idempotency key for chat creation. If a chat was already created recently with the same key by the same user, that chat is returned instead of creating a duplicate. Web clients send a UUID per submission intent; omit to disable deduplication (SDK default)."
          },
          "hc_enabled": {
            "type": "boolean",
            "title": "Hc Enabled",
            "description": "Enable Human Computer for this chat. When enabled, agents can execute commands on the user's personal machine via the CellCog Desktop app.",
            "default": false
          },
          "personal_tools_enabled": {
            "type": "boolean",
            "title": "Personal Tools Enabled",
            "description": "Enable Personal Tools for this chat (gates HumanPersonalTool_Call; search/definitions are always available).",
            "default": false
          },
          "personal_tools_selection": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Personal Tools Selection",
            "description": "Per-chat tool selection at creation: None (default) = all connected tools; a list of toolkit slugs (and key:NAME refs) narrows the chat."
          },
          "terminal_threat_threshold": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Terminal Threat Threshold",
            "description": "Initial per-chat terminal auto-approve override: none|safe|moderate|dangerous"
          },
          "browser_threat_threshold": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Browser Threat Threshold",
            "description": "Initial per-chat browser auto-approve override: none|safe|moderate|dangerous"
          },
          "personal_tools_threat_threshold": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Personal Tools Threat Threshold",
            "description": "Initial per-chat personal-tools auto-approve override: none|safe|moderate|dangerous"
          },
          "hc_working_directory": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hc Working Directory",
            "description": "Working directory on the user's machine where Human Computer commands will run. Only used when hc_enabled is True.",
            "example": "/Users/john/projects/my-app"
          },
          "browser_enabled": {
            "type": "boolean",
            "title": "Browser Enabled",
            "description": "Enable Browse my Chrome for this chat. When enabled, agents can browse the web using the user's Chrome browser via CDP.",
            "default": false
          },
          "browser_profile_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Browser Profile Id",
            "description": "Chrome profile ID to use for browsing. Only used when browser_enabled is True.",
            "example": "Default"
          }
        },
        "type": "object",
        "required": [
          "message"
        ],
        "title": "MessageRequest",
        "description": "Request model for creating a new chat or sending a message to an existing chat.\n\nThis model is used for both POST /chat/new and POST /chat/{chat_id}/messages endpoints."
      },
      "PaginatedChatsResponse": {
        "properties": {
          "chats": {
            "items": {
              "$ref": "#/components/schemas/ChatMeta"
            },
            "type": "array",
            "title": "Chats",
            "description": "List of chat metadata objects for the current page",
            "example": []
          },
          "total": {
            "type": "integer",
            "title": "Total",
            "description": "Total number of chats matching the filter criteria",
            "example": 42
          },
          "page": {
            "type": "integer",
            "title": "Page",
            "description": "Current page number (1-indexed)",
            "example": 1
          },
          "page_size": {
            "type": "integer",
            "title": "Page Size",
            "description": "Number of items per page",
            "example": 20
          },
          "has_more": {
            "type": "boolean",
            "title": "Has More",
            "description": "Whether there are more pages available",
            "example": true
          }
        },
        "type": "object",
        "required": [
          "chats",
          "total",
          "page",
          "page_size",
          "has_more"
        ],
        "title": "PaginatedChatsResponse",
        "description": "Paginated list of chat sessions.\n\nUsed for listing user's chats with pagination support."
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "py__file_svc__api__file__FileUploadRequest": {
        "properties": {
          "filename": {
            "type": "string",
            "title": "Filename"
          },
          "file_size": {
            "type": "integer",
            "title": "File Size"
          },
          "mime_type": {
            "type": "string",
            "title": "Mime Type"
          }
        },
        "type": "object",
        "required": [
          "filename",
          "file_size",
          "mime_type"
        ],
        "title": "FileUploadRequest"
      },
      "py__file_svc__api__file__FileUploadResponse": {
        "properties": {
          "file_id": {
            "type": "string",
            "title": "File Id"
          },
          "upload_url": {
            "type": "string",
            "title": "Upload Url"
          },
          "blob_name": {
            "type": "string",
            "title": "Blob Name"
          },
          "upload_type": {
            "type": "string",
            "title": "Upload Type",
            "default": "signed_put"
          }
        },
        "type": "object",
        "required": [
          "file_id",
          "upload_url",
          "blob_name"
        ],
        "title": "FileUploadResponse"
      }
    }
  }
}
