Maia-analytics chat API

The chat API from Maia-analytics — 8 operation(s) for chat.

OpenAPI Specification

maia-analytics-chat-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: MAIA Ah chat API
  description: API for MAIA application (migrated from Firebase)
  version: 0.1.0
tags:
- name: chat
paths:
  /api/v1/chat/feedback:
    post:
      tags:
      - chat
      summary: Submit Chat Feedback
      description: "Receives and processes feedback for a specific chat message via the ChatService.\n\nArgs:\n    request: The feedback request data.\n    chat_service: The ChatService instance (dependency).\n\nReturns:\n    A confirmation response.\n\nRaises:\n    HTTPException: 400 if saving feedback fails (e.g., invalid data).\n    HTTPException: 500 for unexpected errors."
      operationId: submit_chat_feedback_api_v1_chat_feedback_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatFeedbackRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatFeedbackResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
      - FirebaseAuthMiddleware: []
  /api/v1/chat/models:
    get:
      tags:
      - chat
      summary: List Picker Models
      description: 'Curated model-picker options for the chat composer dropdown.


        Served from the backend registry so the client list cannot drift from the

        keys ``ChatRequest.selected_model`` validates against. 404s when the

        workspace''s model-picker toggle is off — off means the surface is absent.'
      operationId: list_picker_models_api_v1_chat_models_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatModelsResponse'
      security:
      - FirebaseAuthMiddleware: []
  /api/v1/chat/stream:
    post:
      tags:
      - chat
      summary: Chat Main Agent
      description: "Receives and processes a streaming chat request via the AgentService.\n\nThis endpoint streams the agent's response in real-time using Server-Sent Events.\n\nArgs:\n    request: The chat request data containing message and project_id (pre-validated).\n    agent_service: The AgentService instance (dependency).\n\nReturns:\n    StreamingResponse with Server-Sent Events containing streaming chat data.\n\nRaises:\n    HTTPException: 400 for validation errors.\n    HTTPException: 404 if project not found or user doesn't own it.\n    HTTPException: 500 for unexpected errors."
      operationId: chat_main_agent_api_v1_chat_stream_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
      - FirebaseAuthMiddleware: []
  /api/v1/chat/stream/resume:
    post:
      tags:
      - chat
      summary: Resume Chat Main Agent
      description: 'Re-attach to a project''s in-flight chat run after a mid-stream refresh.


        Read-only second reader: tails the existing workflow''s durable stream

        (``read_stream`` replays from offset 0 → the full ordered sequence: the

        user-message echo, every delta so far, then the terminal) WITHOUT starting

        a run or claiming a slot. If no run is live the generator yields nothing; the

        FE then sees no terminal and falls back to reloading persisted history (the

        empty replay is the signal that the run finished and released its slot before

        this reattach).'
      operationId: resume_chat_main_agent_api_v1_chat_stream_resume_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatResumeRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
      - FirebaseAuthMiddleware: []
  /api/v1/chat/chat/interrupt:
    post:
      tags:
      - chat
      summary: Interrupt Chat
      description: "Stop an in-flight chat run via the cooperative interrupt flag.\n\nStopping resolves the chat's ``active_workflow_id`` (liveness from the DBOS\nstatus row) and raises the single cooperative stop signal. The workflow\nobserves it at its next node boundary and finalizes normally — persisting\nthe sanitized partial turn, stamping last-edit, capturing the trace, and\nemitting the ``interrupted`` terminal — while in-flight tools observe the\nsame flag at their checkpoints and bail BEFORE committing DB side-effects.\nNo hard DBOS cancel is issued here: a hard cancel skips finalization and is\nonly seen at the next step boundary (tools would commit after Stop); it\nsurvives solely as the run monitor's escalation backstop for wedged runs.\n\nArgs:\n    request: The interrupt request containing project_id and reason (pre-validated).\n\nReturns:\n    ChatInterruptResponse with ``was_active`` True iff a live run was signalled.\n\nRaises:\n    HTTPException: 400 for an invalid project id; 500 for unexpected errors."
      operationId: interrupt_chat_api_v1_chat_chat_interrupt_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatInterruptRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatInterruptResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
      - FirebaseAuthMiddleware: []
  /api/v1/chat/schemas:
    get:
      tags:
      - chat
      summary: Expose Schemas
      description: 'Schema exposure endpoint for OpenAPI/TypeScript generation.

        This endpoint is never called by the frontend but ensures all chat-related

        schemas are included in the OpenAPI specification for type generation.'
      operationId: expose_schemas_api_v1_chat_schemas_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SchemaExposure'
  /api/v1/chat/archives/{project_id}:
    get:
      tags:
      - chat
      summary: Get Chat Archives
      description: Get archive metadata for a project's chat, without message bodies.
      operationId: get_chat_archives_api_v1_chat_archives__project_id__get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatArchiveMetadataResponseSchema'
      security:
      - FirebaseAuthMiddleware: []
  /api/v1/chat/archives/{project_id}/{archive_id}:
    get:
      tags:
      - chat
      summary: Get Chat Archive Content
      description: 'Get one archive''s message bodies on demand, scoped to the project''s chat.


        The archive UUID doubles as a strong ETag (content never changes once

        written), so a matching ``If-None-Match`` short-circuits to 304 before the

        expensive blob read. The validator is client-constructible from the URL,

        so the short-circuit is gated on a cheap existence+scope check — a forged

        validator for an out-of-scope or missing archive still 404s. Blob

        validation is intentionally skipped on the 304 path: blobs are immutable

        after write, so a validator for a corrupt archive cannot come from a real

        200, and a fresh (unconditional) read still 422s.'
      operationId: get_chat_archive_content_api_v1_chat_archives__project_id___archive_id__get
      security:
      - FirebaseAuthMiddleware: []
      parameters:
      - name: archive_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Archive Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ArchiveContentResponseSchema'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    ThinkingPart:
      properties:
        content:
          type: string
          title: Content
        id:
          anyOf:
          - type: string
          - type: 'null'
          title: Id
        signature:
          anyOf:
          - type: string
          - type: 'null'
          title: Signature
        provider_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Provider Name
        provider_details:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Provider Details
        part_kind:
          type: string
          const: thinking
          title: Part Kind
          default: thinking
      type: object
      required:
      - content
      title: ThinkingPart
      description: A thinking response from a model.
    AudioUrl:
      properties:
        url:
          type: string
          title: Url
        force_download:
          anyOf:
          - type: boolean
          - type: string
            const: allow-local
          title: Force Download
          default: false
        vendor_metadata:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Vendor Metadata
        kind:
          type: string
          const: audio-url
          title: Kind
          default: audio-url
        media_type:
          type: string
          title: Media Type
          description: Return the media type of the file, based on the URL or the provided `media_type`.
          readOnly: true
        identifier:
          type: string
          title: Identifier
          description: 'The identifier of the file, such as a unique ID.


            This identifier can be provided to the model in a message to allow it to refer to this file in a tool call argument,

            and the tool can look up the file in question by iterating over the message history and finding the matching `FileUrl`.


            This identifier is only automatically passed to the model when the `FileUrl` is returned by a tool.

            If you''re passing the `FileUrl` as a user message, it''s up to you to include a separate text part with the identifier,

            e.g. "This is file <identifier>:" preceding the `FileUrl`.


            It''s also included in inline-text delimiters for providers that require inlining text documents, so the model can

            distinguish multiple files.'
          readOnly: true
      type: object
      required:
      - url
      - media_type
      - identifier
      title: AudioUrl
      description: A URL to an audio file.
    AgeRange:
      properties:
        min:
          anyOf:
          - type: integer
          - type: 'null'
          title: Min
        max:
          anyOf:
          - type: integer
          - type: 'null'
          title: Max
        is_approximate:
          type: boolean
          title: Is Approximate
          default: true
        reasoning:
          anyOf:
          - type: string
          - type: 'null'
          title: Reasoning
          description: The reasoning for the age range.
        sources:
          items:
            type: string
          type: array
          title: Sources
          description: The sources for the age range.
      type: object
      title: AgeRange
      description: Age range from PDL. Can represent exact age (min == max) or range.
    LayerStateChangedEvent:
      properties:
        type:
          type: string
          const: layer_state_changed
          title: Type
          default: layer_state_changed
        projectId:
          type: string
          format: uuid
          title: Projectid
        layers:
          items:
            $ref: '#/components/schemas/LayerModel'
          type: array
          title: Layers
          default: []
        deletedLayerIds:
          items:
            type: string
          type: array
          title: Deletedlayerids
          default: []
      type: object
      required:
      - projectId
      title: LayerStateChangedEvent
      description: 'Fired after a layer metadata mutation commits (create / delete / rename /

        restyle / recolor), over the same per-user channel — the layer sibling of

        ``ViewStateChangedEvent``.


        Payload-rich + version-stamped: the FE applies the carried layer(s) straight

        to its React Query cache without a refetch round-trip, and uses each layer''s

        ``metadata_version`` to discard stale or out-of-order events. Carries only the

        *affected* layer(s) plus ``deletedLayerIds`` so the FE merges rather than

        overwrites siblings.


        Unlike views, the nested layers serialize in their **snake_case** wire shape —

        ``LayerModel`` has no field aliases, and the FE reads the same snake_case keys

        off ``GET /projects/{id}/layers`` through ``layerMappers.fromApiModel``. So no

        ``field_serializer`` is needed here; the default dump is already the wire shape.'
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError
    ChatStopReason:
      type: string
      enum:
      - user_requested
      - timeout
      - lock_lost
      title: ChatStopReason
      description: 'Why a chat run was stopped — the cooperative flag''s reason taxonomy.


        Carried in the Redis stop flag and, on the monitor''s escalation path, in the

        durable stop event. ``USER_REQUESTED`` (and any unknown reason) synthesizes

        the generic ``interrupted`` terminal; the two monitor-initiated reasons get

        their specific error copy.'
    StreamChatUserMessage:
      properties:
        type:
          type: string
          const: user_message
          title: Type
          default: user_message
        display:
          type: string
          const: internal
          title: Display
          default: internal
        content:
          type: string
          title: Content
          description: The user's prompt text for this turn.
        timestamp:
          type: string
          format: date-time
          title: Timestamp
          description: Turn start, stamped once when the workflow first writes this event; durable-stream replay preserves the original value, so a reconnecting client anchors its elapsed-time display to the true start instead of the reconnect instant.
      type: object
      required:
      - content
      title: StreamChatUserMessage
      description: 'The acting user''s prompt, emitted as the FIRST durable stream event.


        The live sender already rendered its own message optimistically, so it

        ignores this echo. A client that *reconnects* to an in-flight run (page

        refresh mid-stream) has no optimistic bubble — it replays the durable stream

        from offset 0 and renders the question from this event, then the deltas that

        follow. This makes the stream the single source of truth for an in-progress

        turn (persisted history only carries completed turns).'
    SkillPlanPhase:
      properties:
        label:
          type: string
          maxLength: 200
          title: Label
          description: Short user-facing phase name, e.g. 'Filter parcels by zoning'.
        status:
          $ref: '#/components/schemas/SkillPlanPhaseStatus'
          description: pending | in_progress | completed | skipped
      type: object
      required:
      - label
      - status
      title: SkillPlanPhase
    NativeToolReturnPart:
      properties:
        tool_name:
          type: string
          title: Tool Name
        content:
          $ref: '#/components/schemas/ToolReturnContent'
        tool_call_id:
          type: string
          title: Tool Call Id
        tool_kind:
          anyOf:
          - type: string
            enum:
            - tool-search
            - capability-load
          - type: 'null'
          title: Tool Kind
        metadata:
          title: Metadata
        timestamp:
          type: string
          format: date-time
          title: Timestamp
        outcome:
          type: string
          enum:
          - success
          - failed
          - denied
          title: Outcome
          default: success
        provider_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Provider Name
        provider_details:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Provider Details
        part_kind:
          type: string
          const: builtin-tool-return
          title: Part Kind
          default: builtin-tool-return
      type: object
      required:
      - tool_name
      - content
      title: NativeToolReturnPart
      description: 'A tool return message from a native tool.


        For native tools with a stable cross-provider shape (currently `tool_search`), a

        `NativeToolReturnPart` may be promoted to a typed subclass like

        [`NativeToolSearchReturnPart`][pydantic_ai.messages.NativeToolSearchReturnPart]

        with a narrowed `content` `TypedDict`. See `NativeToolCallPart` for the pattern.'
    TenureRange:
      properties:
        min:
          anyOf:
          - type: integer
          - type: 'null'
          title: Min
        max:
          anyOf:
          - type: integer
          - type: 'null'
          title: Max
        reasoning:
          anyOf:
          - type: string
          - type: 'null'
          title: Reasoning
          description: The reasoning for the tenure range.
        sources:
          items:
            type: string
          type: array
          title: Sources
          description: The sources for the tenure range.
      type: object
      title: TenureRange
      description: 'Job tenure range representing when someone started at their current position/company.


        Used for employment duration (e.g., via PDL data).

        Can represent exact year (min == max) or range of possible years.

        Confidence is inferred: exact year = confirmed, range = approximate.'
    PDLLocation:
      properties:
        name:
          anyOf:
          - type: string
          - type: 'null'
          title: Name
        locality:
          anyOf:
          - type: string
          - type: 'null'
          title: Locality
        region:
          anyOf:
          - type: string
          - type: 'null'
          title: Region
        country:
          anyOf:
          - type: string
          - type: 'null'
          title: Country
        continent:
          anyOf:
          - type: string
          - type: 'null'
          title: Continent
        metro:
          anyOf:
          - type: string
          - type: 'null'
          title: Metro
        geo:
          anyOf:
          - type: string
          - type: 'null'
          title: Geo
        street_address:
          anyOf:
          - type: string
          - type: 'null'
          title: Street Address
        address_line_2:
          anyOf:
          - type: string
          - type: 'null'
          title: Address Line 2
        postal_code:
          anyOf:
          - type: string
          - type: 'null'
          title: Postal Code
      type: object
      title: PDLLocation
      description: Location information from PDL.
    StreamToolCallStart:
      properties:
        type:
          type: string
          const: tool_call_start
          title: Type
          default: tool_call_start
        display:
          type: string
          const: tool_call_start
          title: Display
          default: tool_call_start
        tool_name:
          type: string
          title: Tool Name
          description: Name of the tool being called.
        tool_call_id:
          type: string
          title: Tool Call Id
          description: Unique identifier for this tool call.
        args:
          additionalProperties: true
          type: object
          title: Args
          description: Arguments passed to the tool.
      type: object
      required:
      - tool_name
      - tool_call_id
      - args
      title: StreamToolCallStart
      description: Schema for when a tool call begins.
    ColumnDataType:
      type: string
      enum:
      - string
      - number
      - integer
      - boolean
      - date
      - geometry
      - array
      - object
      title: ColumnDataType
      description: Optional frontend type hint for a layer column.
    UnprocessableQueryReason:
      type: string
      enum:
      - out_of_scope
      - too_vague
      - geographic_restrictions
      - execution_blocked
      title: UnprocessableQueryReason
    OwnerResidentialMailingAddressModel:
      properties:
        street:
          anyOf:
          - type: string
          - type: 'null'
          title: Street
          description: Street line of the residential mailing address.
        city:
          anyOf:
          - type: string
          - type: 'null'
          title: City
          description: City.
        state:
          anyOf:
          - type: string
          - type: 'null'
          title: State
          description: Two-letter state code.
        zip_code:
          anyOf:
          - type: string
          - type: 'null'
          title: Zip Code
          description: ZIP / postal code.
        resolved_owner_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Resolved Owner Name
          description: The person this address belongs to. For an entity owner this is the decision-maker the entity was pierced to, not the entity itself.
        owner_type:
          type: string
          enum:
          - individual
          - entity
          - unknown
          title: Owner Type
          description: Whether the parcel owner is an individual or an entity.
          default: unknown
        is_available:
          type: boolean
          title: Is Available
          description: True only when a reliable RESIDENTIAL mailing address was determined. False when only a business / registered-agent address was found — the caller must not persist a business address as a result.
        confidence:
          anyOf:
          - type: string
          - type: 'null'
          title: Confidence
          description: Qualitative confidence (e.g. high / medium / low).
        mobile_phone:
          anyOf:
          - type: string
          - type: 'null'
          title: Mobile Phone
          description: Resolved owner's mobile phone, if known.
        landline_phone:
          anyOf:
          - type: string
          - type: 'null'
          title: Landline Phone
          description: Resolved owner's landline phone, if known.
        email:
          anyOf:
          - type: string
          - type: 'null'
          title: Email
          description: Resolved owner's email, if known.
        company:
          anyOf:
          - type: string
          - type: 'null'
          title: Company
          description: Company inferred for the resolved owner (from work email domain), if any.
      type: object
      required:
      - is_available
      title: OwnerResidentialMailingAddressModel
      description: A resolved residential mailing address for a parcel's decision-making owner.
    ModelResponse:
      properties:
        parts:
          items:
            oneOf:
            - $ref: '#/components/schemas/TextPart'
            - $ref: '#/components/schemas/ToolSearchCallPart'
            - $ref: '#/components/schemas/LoadCapabilityCallPart'
            - $ref: '#/components/schemas/ToolCallPart'
            - $ref: '#/components/schemas/NativeToolSearchCallPart'
            - $ref: '#/components/schemas/NativeToolCallPart'
            - $ref: '#/components/schemas/NativeToolSearchReturnPart'
            - $ref: '#/components/schemas/NativeToolReturnPart'
            - $ref: '#/components/schemas/ThinkingPart'
            - $ref: '#/components/schemas/CompactionPart'
            - $ref: '#/components/schemas/FilePart'
          type: array
          title: Parts
        usage:
          $ref: '#/components/schemas/RequestUsage'
        model_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Model Name
        timestamp:
          type: string
          format: date-time
          title: Timestamp
        kind:
          type: string
          const: response
          title: Kind
          default: response
        provider_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Provider Name
        provider_url:
          anyOf:
          - type: string
          - type: 'null'
          title: Provider Url
        provider_details:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Provider Details
        provider_response_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Provider Response Id
        finish_reason:
          anyOf:
          - type: string
            enum:
            - stop
            - length
            - content_filter
            - tool_call
            - error
          - type: 'null'
          title: Finish Reason
        run_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Run Id
        conversation_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Conversation Id
        metadata:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Metadata
        state:
          type: string
          enum:
          - complete
          - incomplete
          - interrupted
          title: State
          default: complete
      type: object
      required:
      - parts
      title: ModelResponse
      description: A response from a model, e.g. a message from the model to the Pydantic AI app.
    EnrichmentStatusChangedEvent:
      properties:
        type:
          type: string
          const: enrichment_status_changed
          title: Type
          default: enrichment_status_changed
        workflow_id:
          type: string
          title: Workflow Id
        project_id:
          type: string
          format: uuid
          title: Project Id
        enrichment_id:
          type: string
          format: uuid
          title: Enrichment Id
        feature_id:
          type: string
          title: Feature Id
        status:
          type: string
          enum:
          - SUCCESS
          - FAILURE
          title: Status
        value:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Value
      type: object
      required:
      - workflow_id
      - project_id
      - enrichment_id
      - feature_id
      - status
      title: EnrichmentStatusChangedEvent
      description: "Fired when one enrichment workflow reaches a terminal state.\n\nUnlike ``CreditStateChangedEvent`` this is payload-rich. It carries:\n\n- ``workflow_id`` — the client registry's key; routes the event to the\n  cell/column it belongs to.\n- ``project_id`` / ``enrichment_id`` / ``feature_id`` — the coordinates,\n  so an event for a workflow the client didn't dispatch in this session\n  (e.g. after a reload, before reconcile) can still build a registry\n  entry from the event alone.\n- ``value`` — on SUCCESS, the persisted ``EnrichRowResponse``-shaped dict\n  (``{value, reasoning, citations, state}``) built from the SAME\n  ``db_value`` written to the sandbox, so the live cell is byte-identical\n  to what a refresh re-reads. ``None`` on FAILURE (no value was written).\n\nThe terminal-status policy lives on the server (the workflow's own\nterminal state), not on the client — so the client can no longer drift a\ntransient signal into a false terminal (the bug class this replaces)."
    ToolSearchReturnPart:
      properties:
        tool_name:
          type: string
          const: search_tools
          title: Tool Name
          default: search_tools
        tool_call_id:
          type: string
          title: Tool Call Id
        tool_kind:
          type: string
          const: tool-search
          title: Tool Kind
          default: tool-search
        content:
          $ref: '#/components/schemas/ToolSearchReturnContent'
        metadata:
          title: Metadata
        timestamp:
          type: string
          format: date-time
          title: Timestamp
        outcome:
          type: string
          enum:
          - success
          - failed
          - denied
          title: Outcome
          default: success
        part_kind:
          type: string
          const: tool-return
          title: Part Kind
          default: tool-return
      type: object
      required:
      - content
      title: ToolSearchReturnPart
      description: 'Typed view of a [`ToolReturnPart`][pydantic_ai.messages.ToolReturnPart] for the local `search_tools` function return.


        Used on the local-fallback path (and as the synthetic-injection target on

        non-native providers receiving cross-provider history). The native server-side

        path uses

        [`NativeToolSearchReturnPart`][pydantic_ai.messages.NativeToolSearchReturnPart]

        instead.


        To detect a tool-search part regardless of execution path (native server-side

        vs. local fallback), check `part.tool_kind == ''tool-search''` — this works

        across both call/return and both server/local variants.


        Shadows `content` with a narrower

        [`ToolSearchReturnContent`][pydantic_ai.messages.ToolSearchReturnContent]

        `TypedDict`.'
    StreamWebSearchStatus:
      properties:
        type:
          type: string
          const: web_search_status
          title: Type
          default: web_search_status
        display:
          type: string
          const: internal
          title: Display
          default: internal
        status:
          type: string
          title: Status
          description: Status of the web search operation.
        tool_call_id:
          type: string
          title: Tool Call Id
          description: Unique identifier for this tool call.
        content:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Content
          description: Additional status data if available.
      type: object
      required:
      - status
      - tool_call_id
      title: StreamWebSearchStatus
      description: Schema for web search status updates from built-in tools.
    ChatModelOption:
      properties:
        key:
          type: string
          title: Key
        label:
          type: string
          title: Label


# --- truncated at 32 KB (177 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/maia-analytics/refs/heads/main/openapi/maia-analytics-chat-api-openapi.yml