openapi: 3.1.0
info:
  title: Speech Hub API
  description: Self-hosted Speech-to-Text Hub API
  version: 6.6.0
paths:
  /auth/login:
    post:
      tags:
      - auth
      summary: Login
      operationId: login_auth_login_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /auth/tokens:
    get:
      tags:
      - auth
      summary: List Tokens
      operationId: list_tokens_auth_tokens_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenListResponse'
    post:
      tags:
      - auth
      summary: Create Token
      operationId: create_token_auth_tokens_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TokenCreateRequest'
        required: true
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenCreateResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /auth/tokens/{token_id}:
    delete:
      tags:
      - auth
      summary: Delete Token
      operationId: delete_token_auth_tokens__token_id__delete
      parameters:
      - name: token_id
        in: path
        required: true
        schema:
          type: string
          title: Token Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /auth/scopes:
    get:
      tags:
      - auth
      summary: List Scopes
      description: 'Return the catalog of valid API-token scopes with human-readable
        metadata.


        Consumed by the API-token wizard (e.g. the OpenClaw self-service flow) to

        pre-check the scopes a token needs. JWT-only ∵ the operator hits this

        BEFORE they have provisioned any HUB_TOKEN -- the browser session cookie

        is the only credential available at that point.'
      operationId: list_scopes_auth_scopes_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScopeCatalogResponse'
  /v1/auth/google/login:
    get:
      tags:
      - oauth
      summary: Google Login
      operationId: google_login_v1_auth_google_login_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
  /v1/auth/google/callback:
    get:
      tags:
      - oauth
      summary: Google Callback
      operationId: google_callback_v1_auth_google_callback_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
  /v1/admin/users:
    get:
      tags:
      - admin
      summary: List Users
      operationId: list_users_v1_admin_users_get
      parameters:
      - name: status
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Status
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/users/{user_id}/set-role:
    post:
      tags:
      - admin
      summary: Set User Role
      operationId: set_user_role_v1_admin_users__user_id__set_role_post
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RoleUpdate'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserListItem'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/users/{user_id}/approve:
    post:
      tags:
      - admin
      summary: Approve User
      operationId: approve_user_v1_admin_users__user_id__approve_post
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserListItem'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/settings/pipeline-model:
    get:
      tags:
      - admin
      summary: Get Pipeline Model Setting
      operationId: get_pipeline_model_setting_v1_admin_settings_pipeline_model_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AppSettingResponse'
    put:
      tags:
      - admin
      summary: Update Pipeline Model Setting
      operationId: update_pipeline_model_setting_v1_admin_settings_pipeline_model_put
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PipelineModelUpdate'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AppSettingResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/settings/auto-approve:
    get:
      tags:
      - admin
      summary: Get Auto Approve Setting
      operationId: get_auto_approve_setting_v1_admin_settings_auto_approve_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AppSettingResponse'
    put:
      tags:
      - admin
      summary: Update Auto Approve Setting
      operationId: update_auto_approve_setting_v1_admin_settings_auto_approve_put
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AutoApproveUpdate'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AppSettingResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/settings/routing-log-max-body-bytes:
    get:
      tags:
      - admin
      summary: Get Routing Log Max Body Bytes Setting
      operationId: get_routing_log_max_body_bytes_setting_v1_admin_settings_routing_log_max_body_bytes_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoutingLogMaxBodyBytesSetting'
    put:
      tags:
      - admin
      summary: Update Routing Log Max Body Bytes Setting
      description: 'Set or clear the admin override for the body-size cap.


        ``value=null`` deletes the row so subsequent boots resolve back to

        the env default. ``Field`` constraints enforce 4 KiB..4 MiB bounds

        on the integer path; the override only takes effect on the next

        gateway restart (the `RequestLogger` reads the cap once during

        lifespan startup).'
      operationId: update_routing_log_max_body_bytes_setting_v1_admin_settings_routing_log_max_body_bytes_put
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RoutingLogMaxBodyBytesUpdate'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoutingLogMaxBodyBytesSetting'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/users/{user_id}/reject:
    post:
      tags:
      - admin
      summary: Reject User
      operationId: reject_user_v1_admin_users__user_id__reject_post
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserListItem'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/users/{user_id}:
    delete:
      tags:
      - admin
      summary: Delete User
      operationId: delete_user_v1_admin_users__user_id__delete
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/anthropic/v1/messages:
    post:
      tags:
      - anthropic-compat
      summary: Messages
      operationId: messages_v1_anthropic_v1_messages_post
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
  /v1/anthropic/v1/messages/count_tokens:
    post:
      tags:
      - anthropic-compat
      summary: Count Tokens
      operationId: count_tokens_v1_anthropic_v1_messages_count_tokens_post
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
  /v1/audio/transcriptions/sync:
    post:
      tags:
      - audio
      summary: Transcribe Sync
      description: Synchronous transcription — blocks until the pipeline finishes.
      operationId: transcribe_sync_v1_audio_transcriptions_sync_post
      requestBody:
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Body_transcribe_sync_v1_audio_transcriptions_sync_post'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/audio/transcriptions:
    post:
      tags:
      - audio
      summary: Transcribe
      operationId: transcribe_v1_audio_transcriptions_post
      requestBody:
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Body_transcribe_v1_audio_transcriptions_post'
        required: true
      responses:
        '202':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TranscriptionAccepted'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/audio/batches:
    post:
      tags:
      - audio-batches
      - audio-batches
      summary: Create Batch
      operationId: create_batch_v1_audio_batches_post
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateBatchRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    get:
      tags:
      - audio-batches
      - audio-batches
      summary: List Batches
      operationId: list_batches_v1_audio_batches_get
      parameters:
      - name: status
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Status
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 100
          minimum: 1
          default: 50
          title: Limit
      - name: offset
        in: query
        required: false
        schema:
          type: integer
          minimum: 0
          default: 0
          title: Offset
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudioBatchListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/audio/batches/{batch_id}/chunks:
    post:
      tags:
      - audio-batches
      - audio-batches
      summary: Upload Chunk
      operationId: upload_chunk_v1_audio_batches__batch_id__chunks_post
      parameters:
      - name: batch_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Batch Id
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Body_upload_chunk_v1_audio_batches__batch_id__chunks_post'
      responses:
        '202':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadChunkResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/audio/batches/{batch_id}/finalize:
    post:
      tags:
      - audio-batches
      - audio-batches
      summary: Finalize Batch
      operationId: finalize_batch_v1_audio_batches__batch_id__finalize_post
      parameters:
      - name: batch_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Batch Id
      responses:
        '202':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FinalizeBatchResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/audio/batches/{batch_id}:
    get:
      tags:
      - audio-batches
      - audio-batches
      summary: Get Batch
      operationId: get_batch_v1_audio_batches__batch_id__get
      parameters:
      - name: batch_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Batch Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/chat/completions:
    post:
      tags:
      - chat
      summary: Chat Completions
      description: "Chat completions (OpenAI-compatible, vLLM or Ollama backend).\n\
        \nProxies to vLLM for `qwen3.5:9b` and to Ollama for `qwen2.5:7b` / other\
        \ Ollama-hosted\nmodels. Full OpenAI Chat Completions shape plus Speech Hub\
        \ extensions\n(`system_prompt_id`, `system_prompt`, `use_memory`, `think`).\n\
        \nModes (all optional, default OFF):\n- `think=true`: reasoning mode; vLLM\
        \ sets top-level `chat_template_kwargs.enable_thinking`,\n  Ollama sets top-level\
        \ `think`. 26.6x slower on qwen3.5; 400 on qwen2.5:7b (model rejects it).\n\
        - `tools=[...]`: OpenAI function tools; forwarded unchanged to both backends.\n\
        - `tool_choice`: `auto | required | none | {named}`; Ollama 0.20.3 logs WARN\
        \ and omits.\n- `response_format.type=json_object`: JSON mode on both (Ollama\
        \ `format=json`).\n- `response_format.type=json_schema`: strict schema via\
        \ Outlines; **vLLM-only** (Ollama: 400).\n- `parallel_tool_calls`: vLLM passes-through;\
        \ Ollama silently omits.\n\nResponse exposes `message.reasoning` and `message.tool_calls`\
        \ when present; streaming\ndeltas surface the same under `delta.reasoning`\
        \ and `delta.tool_calls[]`.\n\nExamples (curl with `$TOKEN`):\n\nBare:\n \
        \   curl -X POST $URL/v1/chat/completions -H \"Authorization: Bearer $TOKEN\"\
        \ \\\n      -H \"Content-Type: application/json\" -d '{\"messages\":[{\"role\"\
        :\"user\",\"content\":\"Hi\"}]}'\n\nThink on:\n    ... -d '{\"model\":\"qwen3.5:9b\"\
        ,\"think\":true,\"messages\":[...]}'\n\nTools:\n    ... -d '{\"messages\"\
        :[...],\"tools\":[{\"type\":\"function\",\"function\":{\"name\":\"get_weather\"\
        ,\n      \"parameters\":{\"type\":\"object\",\"properties\":{\"city\":{\"\
        type\":\"string\"}}}}}],\"tool_choice\":\"auto\"}'\n\nJSON mode:\n    ...\
        \ -d '{\"messages\":[...],\"response_format\":{\"type\":\"json_object\"}}'\n\
        \nJSON schema (vLLM only):\n    ... -d '{\"model\":\"qwen3.5:9b\",\"messages\"\
        :[...],\"response_format\":{\"type\":\"json_schema\",\n      \"json_schema\"\
        :{\"name\":\"person\",\"strict\":true,\n      \"schema\":{\"type\":\"object\"\
        ,\"properties\":{\"name\":{\"type\":\"string\"}}}}}}'"
      operationId: chat_completions_v1_chat_completions_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatCompletionRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/images/generations:
    post:
      tags:
      - images
      summary: Generate image (OpenAI-compatible)
      description: 'OpenAI-compatible POST /v1/images/generations.


        Synchronous text-to-image. Returns ImagesResponse with either a `url`

        (default) pointing at GET /v1/images/{id}/file, or `b64_json` when

        `response_format="b64_json"`.'
      operationId: images_generations_v1_images_generations_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ImageGenerationRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImagesResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/images/edits:
    post:
      tags:
      - images
      summary: Edit image (OpenAI-compatible)
      description: "OpenAI-compatible POST /v1/images/edits.\n\nTwo modes — chosen\
        \ by presence of `mask`:\n- With `mask` (true OpenAI-compat behaviour): regional\
        \ inpainting via\n  Flux 2 + SetLatentNoiseMask + ImageCompositeMasked. Only\
        \ mask=white\n  pixels are regenerated, mask=black pixels are bit-for-bit\
        \ preserved.\n- Without `mask`: Flux 2 ReferenceLatent — full-image regen\
        \ using the\n  reference for identity/style hint. NOT regional inpainting.\n\
        \nInpaint mode also accepts `mask_blur` (soft edge px, 0-30) and\n`mask_grow`\
        \ (expand area px, -20..+30) for fine control."
      operationId: images_edits_v1_images_edits_post
      requestBody:
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Body_images_edits_v1_images_edits_post'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImagesResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/images/{request_id}/file:
    get:
      tags:
      - images
      summary: Download generated image PNG
      description: "Serve the PNG file for a previously generated image. Ownership-scoped.\n\
        \n404 is returned when:\n  - the image_requests row does not exist or belongs\
        \ to another user\n  - the row exists but `file_path` is NULL (failure mode)\n\
        \  - the row's status is not `completed`"
      operationId: images_file_v1_images__request_id__file_get
      parameters:
      - name: request_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Request Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/pipelines:
    get:
      tags:
      - pipelines
      summary: List Pipelines
      operationId: list_pipelines_v1_pipelines_get
      parameters:
      - name: status
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: Filter by status
          title: Status
        description: Filter by status
      - name: pipeline_mode
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: Filter by pipeline mode (fast/full)
          title: Pipeline Mode
        description: Filter by pipeline mode (fast/full)
      - name: task
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: Filter by task type
          title: Task
        description: Filter by task type
      - name: date_from
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          description: Filter from date
          title: Date From
        description: Filter from date
      - name: date_to
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          description: Filter to date
          title: Date To
        description: Filter to date
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 100
          minimum: 1
          description: Page size
          default: 50
          title: Limit
        description: Page size
      - name: offset
        in: query
        required: false
        schema:
          type: integer
          minimum: 0
          description: Page offset
          default: 0
          title: Offset
        description: Page offset
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PipelineListResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/pipelines/{run_id}:
    get:
      tags:
      - pipelines
      summary: Get Pipeline
      operationId: get_pipeline_v1_pipelines__run_id__get
      parameters:
      - name: run_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Run Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PipelineDetail'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    delete:
      tags:
      - pipelines
      summary: Delete Pipeline
      operationId: delete_pipeline_v1_pipelines__run_id__delete
      parameters:
      - name: run_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Run Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/pipelines/{run_id}/artifacts/{artifact_id}/download:
    get:
      tags:
      - pipelines
      summary: Download Artifact
      operationId: download_artifact_v1_pipelines__run_id__artifacts__artifact_id__download_get
      parameters:
      - name: run_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Run Id
      - name: artifact_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Artifact Id
      - name: token
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: JWT token for browser playback
          title: Token
        description: JWT token for browser playback
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/prompts:
    get:
      tags:
      - prompts
      summary: List Prompts
      operationId: list_prompts_v1_prompts_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PromptListResponse'
    post:
      tags:
      - prompts
      summary: Create Prompt
      operationId: create_prompt_v1_prompts_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PromptCreate'
        required: true
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PromptResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/prompts/{prompt_id}:
    get:
      tags:
      - prompts
      summary: Get Prompt
      operationId: get_prompt_v1_prompts__prompt_id__get
      parameters:
      - name: prompt_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Prompt Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PromptResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    put:
      tags:
      - prompts
      summary: Update Prompt
      operationId: update_prompt_v1_prompts__prompt_id__put
      parameters:
      - name: prompt_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Prompt Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PromptUpdate'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PromptResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    delete:
      tags:
      - prompts
      summary: Delete Prompt
      operationId: delete_prompt_v1_prompts__prompt_id__delete
      parameters:
      - name: prompt_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Prompt Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/prompts/{prompt_id}/reset:
    post:
      tags:
      - prompts
      summary: Reset Prompt
      operationId: reset_prompt_v1_prompts__prompt_id__reset_post
      parameters:
      - name: prompt_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Prompt Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PromptResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/voices:
    get:
      tags:
      - Voices
      summary: List visible voices (system + personal)
      operationId: list_voices_v1_voices_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                items:
                  $ref: '#/components/schemas/VoiceResponse'
                type: array
                title: Response List Voices V1 Voices Get
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    post:
      tags:
      - Voices
      summary: Create a personal reference voice from an audio sample
      operationId: create_user_voice_v1_voices_post
      requestBody:
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Body_create_user_voice_v1_voices_post'
        required: true
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoiceResponse'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/voices/system:
    post:
      tags:
      - Voices
      summary: Create a system voice (admin only)
      operationId: create_system_voice_v1_voices_system_post
      requestBody:
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Body_create_system_voice_v1_voices_system_post'
        required: true
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoiceResponse'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/voices/{voice_id}:
    patch:
      tags:
      - Voices
      summary: Rename a voice or set personal default
      operationId: update_voice_v1_voices__voice_id__patch
      parameters:
      - name: voice_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Voice Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VoiceUpdate'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoiceResponse'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    delete:
      tags:
      - Voices
      summary: Delete a voice (owner or admin)
      operationId: delete_voice_v1_voices__voice_id__delete
      parameters:
      - name: voice_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Voice Id
      responses:
        '204':
          description: Successful Response
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/voices/{voice_id}/system-default:
    patch:
      tags:
      - Voices
      summary: Toggle the featured flag on a system voice (admin)
      operationId: set_system_default_v1_voices__voice_id__system_default_patch
      parameters:
      - name: voice_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Voice Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VoiceSystemDefaultUpdate'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoiceResponse'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/voices/health:
    get:
      tags:
      - Voices
      summary: Proxy OmniVoice backend health
      operationId: voices_health_v1_voices_health_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                additionalProperties: true
                type: object
                title: Response Voices Health V1 Voices Health Get
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/voices/quota:
    get:
      tags:
      - Voices
      summary: Return the caller's TTS quota usage
      operationId: voices_quota_v1_voices_quota_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoicesQuota'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/voices/synthesize:
    post:
      tags:
      - Voices
      summary: Synthesize speech (TTS or voice clone)
      operationId: synthesize_voice_v1_voices_synthesize_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SynthesizeRequest'
        required: true
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SynthesisResponse'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '410':
          description: Voice reference file missing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: TTS quota exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          description: OmniVoice generation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: OmniVoice unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/voices/syntheses:
    get:
      tags:
      - Voices
      summary: List the caller's recent syntheses
      operationId: list_syntheses_v1_voices_syntheses_get
      parameters:
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          default: 50
          title: Limit
      - name: offset
        in: query
        required: false
        schema:
          type: integer
          default: 0
          title: Offset
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SynthesisResponse'
                title: Response List Syntheses V1 Voices Syntheses Get
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/voices/syntheses/{synthesis_id}/audio:
    get:
      tags:
      - Voices
      summary: Download synthesized WAV
      operationId: download_synthesis_audio_v1_voices_syntheses__synthesis_id__audio_get
      parameters:
      - name: synthesis_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Synthesis Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '410':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Gone
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/voices/{voice_id}/ref-audio:
    get:
      tags:
      - Voices
      summary: Download the reference WAV for a voice
      operationId: download_reference_audio_v1_voices__voice_id__ref_audio_get
      parameters:
      - name: voice_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Voice Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '410':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Gone
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/dictionary:
    get:
      tags:
      - dictionary
      summary: Get Dictionary
      operationId: get_dictionary_v1_dictionary_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DictionaryResponse'
    put:
      tags:
      - dictionary
      summary: Replace Dictionary
      operationId: replace_dictionary_v1_dictionary_put
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DictionaryUpdateRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DictionaryResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    delete:
      tags:
      - dictionary
      summary: Delete Dictionary
      operationId: delete_dictionary_v1_dictionary_delete
      responses:
        '204':
          description: Successful Response
    patch:
      tags:
      - dictionary
      summary: Patch Dictionary
      operationId: patch_dictionary_v1_dictionary_patch
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DictionaryPatchRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DictionaryResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/memory:
    get:
      tags:
      - memory
      summary: List Memories
      operationId: list_memories_v1_memory_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MemoryListResponse'
    post:
      tags:
      - memory
      summary: Create Memory
      operationId: create_memory_v1_memory_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MemoryCreate'
        required: true
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MemoryResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    delete:
      tags:
      - memory
      summary: Delete All Memories
      operationId: delete_all_memories_v1_memory_delete
      responses:
        '204':
          description: Successful Response
  /v1/memory/{memory_id}:
    delete:
      tags:
      - memory
      summary: Delete Memory
      operationId: delete_memory_v1_memory__memory_id__delete
      parameters:
      - name: memory_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Memory Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/tools/optimize:
    post:
      tags:
      - tools
      summary: Optimize Text Endpoint
      operationId: optimize_text_endpoint_v1_tools_optimize_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OptimizeRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OptimizeResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/tools/tokenize:
    post:
      tags:
      - tools
      summary: Tokenize Text
      operationId: tokenize_text_v1_tools_tokenize_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TokenizeRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenizeResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/models:
    get:
      tags:
      - system
      summary: List Models
      operationId: list_models_v1_models_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                additionalProperties: true
                type: object
                title: Response List Models V1 Models Get
  /v1/admin/monitoring/snapshot:
    get:
      tags:
      - admin-monitoring
      summary: Get Snapshot
      operationId: get_snapshot_v1_admin_monitoring_snapshot_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MetricsSnapshot'
  /v1/admin/monitoring/history:
    get:
      tags:
      - admin-monitoring
      summary: Get History
      operationId: get_history_v1_admin_monitoring_history_get
      parameters:
      - name: range
        in: query
        required: false
        schema:
          enum:
          - 1h
          - 6h
          - 1d
          - 5d
          type: string
          description: 'Time window: 1h, 6h, 1d, or 5d'
          default: 1h
          title: Range
        description: 'Time window: 1h, 6h, 1d, or 5d'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MetricsHistory'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/monitoring/gpu-processes:
    get:
      tags:
      - admin-monitoring
      summary: Get Gpu Processes
      operationId: get_gpu_processes_v1_admin_monitoring_gpu_processes_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GpuProcessesResponse'
  /v1/admin/monitoring/system-info:
    get:
      tags:
      - admin-monitoring
      summary: Get System Info
      operationId: get_system_info_v1_admin_monitoring_system_info_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SystemInfo'
  /v1/admin/monitoring/ollama/unload:
    post:
      tags:
      - admin-monitoring
      summary: Unload Ollama Model
      operationId: unload_ollama_model_v1_admin_monitoring_ollama_unload_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OllamaUnloadRequest'
        required: true
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/smart-routing/providers:
    get:
      tags:
      - admin-smart-routing
      summary: List All Providers
      description: 'List every routing provider across all users.


        Read-only — admin-side mutation lives nowhere; users own their

        providers via ``/v1/smart-routing/*``.'
      operationId: list_all_providers_v1_admin_smart_routing_providers_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                items:
                  $ref: '#/components/schemas/ProviderRead'
                type: array
                title: Response List All Providers V1 Admin Smart Routing Providers
                  Get
  /v1/admin/smart-routing/logs:
    get:
      tags:
      - admin-smart-routing
      summary: List Logs
      description: All request logs (newest first), optionally filtered by user.
      operationId: list_logs_v1_admin_smart_routing_logs_get
      parameters:
      - name: user_id
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: User Id
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: before_id
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            maxLength: 64
          - type: 'null'
          title: Before Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequestLogList'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    delete:
      tags:
      - admin-smart-routing
      summary: Delete Logs
      description: "Bulk-delete request logs across users (admin scope).\n\nTwo modes\
        \ (mirror of the user route):\n\n* ``ids`` set → delete only those rows (max\
        \ 200). Optional\n  ``user_id`` filter ANDs on top.\n* Otherwise → delete\
        \ by filter window. Defaults: last 24h, capped\n  at 90 days.\n\n``user_id``\
        \ is opt-in: omit it to delete cross-user, supply it to\nscope to one user.\
        \ Admin-only via the router-wide ``require_admin``\ndependency. Hard delete\
        \ is fine — there are no FK children on\n``routing_request_logs``."
      operationId: delete_logs_v1_admin_smart_routing_logs_delete
      parameters:
      - name: user_id
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: User Id
      - name: since
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Since
      - name: until
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Until
      - name: provider_id
        in: query
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: Provider Id
      - name: ids
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            maxLength: 8192
          - type: 'null'
          title: Ids
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LogDeleteResult'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/smart-routing/logs/export:
    get:
      tags:
      - admin-smart-routing
      summary: Export Logs
      description: 'NDJSON-stream request logs across users (admin scope).


        ``user_id`` filter is opt-in: omit it to export every user''s rows

        in the window (useful for audit / billing dispute reconciliation).

        Window defaults match the user endpoint (last 30d) and are bounded

        at 90d. Admin auth is enforced router-wide via ``require_admin``.'
      operationId: export_logs_v1_admin_smart_routing_logs_export_get
      parameters:
      - name: user_id
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: User Id
      - name: since
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Since
      - name: until
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Until
      - name: provider_id
        in: query
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: Provider Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/smart-routing/stats:
    get:
      tags:
      - admin-smart-routing
      summary: Get Routing Log Stats
      description: 'Storage footprint of ``routing_request_logs`` for the admin UI.


        ``pg_total_relation_size`` reports heap + indexes + TOAST in bytes.

        ``retention_days`` mirrors the GC knob so the dashboard can render

        "X rows / Y MB / Z-day retention" without a second round-trip. No

        user filter — the table is single-tenant from PG''s POV.'
      operationId: get_routing_log_stats_v1_admin_smart_routing_stats_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoutingLogStats'
  /v1/admin/smart-routing/logs/{log_id}:
    get:
      tags:
      - admin-smart-routing
      summary: Get Log
      description: Full detail for one log row, no user-scope check (admin).
      operationId: get_log_v1_admin_smart_routing_logs__log_id__get
      parameters:
      - name: log_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Log Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequestLogDetail'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/smart-routing/provider-presets:
    get:
      tags:
      - smart-routing
      summary: List Provider Presets
      description: 'Return the hardcoded provider preset catalogue for the create-form
        dropdown.


        Backend-owned source of truth so the internal vLLM URL + locked

        model name stay aligned with what is actually deployed without a

        frontend rebuild. Auth mirrors provider CRUD: only callers who can

        create providers need the catalogue.'
      operationId: list_provider_presets_v1_smart_routing_provider_presets_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProviderPresetsResponse'
  /v1/smart-routing/providers:
    get:
      tags:
      - smart-routing
      summary: List Providers
      description: Return providers visible to the caller (personal + system).
      operationId: list_providers_v1_smart_routing_providers_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                items:
                  $ref: '#/components/schemas/ProviderRead'
                type: array
                title: Response List Providers V1 Smart Routing Providers Get
    post:
      tags:
      - smart-routing
      summary: Create Provider
      description: 'Create a personal provider for the caller.


        Backend-side ``client_model_alias`` resolution mirrors the frontend

        auto-fill: if the user did not supply an explicit alias the router

        derives one from ``target_model`` (currently the ``[1m]`` suffix on

        known DeepSeek 1M presets, ``None`` otherwise). An explicit value is

        persisted verbatim so a custom override survives the create path.'
      operationId: create_provider_v1_smart_routing_providers_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProviderCreate'
        required: true
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProviderRead'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/smart-routing/providers/{provider_id}:
    patch:
      tags:
      - smart-routing
      summary: Update Provider
      description: "Partial update of one of the caller's providers.\n\nSending ``api_key``\
        \ rotates the stored ciphertext. System rows\n(``user_id IS NULL``) are NOT\
        \ mutable through this router — they\nare managed by ``/v1/admin/smart-routing/*``.\n\
        \n``client_model_alias`` semantics use ``model_dump(exclude_unset=True)``\n\
        to distinguish \"field omitted\" from \"field explicitly set\":\n\n* Field\
        \ absent + ``target_model`` absent → leave alias unchanged.\n* Field absent\
        \ + ``target_model`` changed → if the current alias was\n  auto-derived (matches\
        \ ``derive_client_model_alias(old_target_model)``),\n  mirror the frontend\
        \ auto-fill and update to the new derived value;\n  otherwise the user has\
        \ a custom override and we leave it intact.\n* Field present + value is a\
        \ string → persist the explicit override.\n* Field present + value is ``None``\
        \ → clear the alias. The repo's\n  whitelisted-update helper drops ``None``\
        \ payloads, so the clear is\n  applied with a direct ORM-level mutation."
      operationId: update_provider_v1_smart_routing_providers__provider_id__patch
      parameters:
      - name: provider_id
        in: path
        required: true
        schema:
          type: integer
          title: Provider Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProviderUpdate'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProviderRead'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    delete:
      tags:
      - smart-routing
      summary: Delete Provider
      description: 'Hard-delete the caller''s personal provider.


        ``routing_request_logs.provider_id`` is ``ON DELETE SET NULL`` so

        historical log rows survive without their provider link.'
      operationId: delete_provider_v1_smart_routing_providers__provider_id__delete
      parameters:
      - name: provider_id
        in: path
        required: true
        schema:
          type: integer
          title: Provider Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/smart-routing/providers/{provider_id}/activate:
    post:
      tags:
      - smart-routing
      summary: Activate Provider
      description: Mark this provider active (mutex-deactivates the user's others).
      operationId: activate_provider_v1_smart_routing_providers__provider_id__activate_post
      parameters:
      - name: provider_id
        in: path
        required: true
        schema:
          type: integer
          title: Provider Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProviderActivateResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/smart-routing/providers/{provider_id}/test:
    post:
      tags:
      - smart-routing
      summary: Test Provider
      description: 'Dry-run probe a provider config WITHOUT writing to ``routing_request_logs``.


        The endpoint sends a minimal ``/v1/messages`` payload to the

        upstream, captures status / latency / a short text excerpt and

        returns it as JSON. Errors (vault decrypt, connect/timeout,

        upstream 4xx/5xx) are surfaced via ``ProviderTestResponse.error_*``

        rather than HTTP 5xx — the user explicitly asked "is this provider

        working?" and a hard exception would defeat the purpose.


        Auth: ``smart-routing:manage`` scope (same as CRUD); rate-limited

        to ``provider_test_per_hour`` per user (admins exempt). The scope

        dependency is declared BEFORE the rate-limit dependency so a token

        without the scope keeps getting 403, not 429.


        Cross-user isolation: a hit on another user''s provider returns 404

        — same shape as "row does not exist", consistent with PATCH /

        DELETE.'
      operationId: test_provider_v1_smart_routing_providers__provider_id__test_post
      parameters:
      - name: provider_id
        in: path
        required: true
        schema:
          type: integer
          title: Provider Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProviderTestRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProviderTestResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/smart-routing/logs:
    get:
      tags:
      - smart-routing
      summary: List Logs
      description: Cursor-paginated read of the caller's request logs (newest first).
      operationId: list_logs_v1_smart_routing_logs_get
      parameters:
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: before_id
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            maxLength: 64
          - type: 'null'
          title: Before Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequestLogList'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    delete:
      tags:
      - smart-routing
      summary: Delete My Logs
      description: "Bulk-delete the caller's request logs.\n\nTwo modes:\n\n* ``ids``\
        \ set → delete only those specific rows (max 200).\n* Otherwise → delete by\
        \ filter window (``since``, ``until``,\n  optional ``provider_id``). Defaults:\
        \ last 24h. Window is hard\n  capped at 90 days to mirror the export endpoint.\n\
        \nCross-user safety: the repo helper ALWAYS ANDs ``user_id =\ncurrent_user.id``\
        \ even when ``ids`` is supplied, so a foreign log\nUUID slipped into ``ids``\
        \ does NOT match anything and is silently\nskipped — the user cannot delete\
        \ other users' rows. Hard delete is\nfine for the single-user system; ``routing_request_logs``\
        \ carries\nno FK children."
      operationId: delete_my_logs_v1_smart_routing_logs_delete
      parameters:
      - name: since
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Since
      - name: until
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Until
      - name: provider_id
        in: query
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: Provider Id
      - name: ids
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            maxLength: 8192
          - type: 'null'
          title: Ids
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LogDeleteResult'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/smart-routing/logs/export:
    get:
      tags:
      - smart-routing
      summary: Export My Logs
      description: 'NDJSON-stream the caller''s request logs in a bounded time window.


        Hard-coded scope: ``user_id`` is ALWAYS the authenticated caller —

        no query param honoured. Default window is the last 30 days; the

        range cannot exceed 90 days (matches the GC retention policy at

        ``routing_logs_retention_days``). Each line is a

        :class:`RequestLogDetail` JSON object; the connection is held open

        while rows stream from PG in batches of 500.


        NOTE: this route is registered BEFORE ``/logs/{log_id}`` so that

        FastAPI''s path matcher reaches it first — otherwise ``"export"``

        would be captured as a ``log_id`` UUID and fail validation.'
      operationId: export_my_logs_v1_smart_routing_logs_export_get
      parameters:
      - name: since
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Since
      - name: until
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Until
      - name: provider_id
        in: query
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: Provider Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/smart-routing/logs/{log_id}:
    get:
      tags:
      - smart-routing
      summary: Get Log
      description: Return one of the caller's logs in full (request+response payloads).
      operationId: get_log_v1_smart_routing_logs__log_id__get
      parameters:
      - name: log_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: Log Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequestLogDetail'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/openclaw/probe-bot:
    post:
      tags:
      - openclaw
      summary: Post Probe Bot
      description: Validate a TG_BOT_TOKEN against Telegram getMe and derive slug.
      operationId: post_probe_bot_v1_openclaw_probe_bot_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProbeBotRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProbeBotResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/openclaw/probe-scopes:
    post:
      tags:
      - openclaw
      summary: Post Probe Scopes
      description: 'Introspect a HUB_TOKEN''s scope matrix.


        Resolved base URL prefers an explicit ``openclaw_probe_base_url``

        Setting (not present in v1) and falls back to the request''s own

        base URL so the gateway always probes itself, never an external

        host.'
      operationId: post_probe_scopes_v1_openclaw_probe_scopes_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProbeScopesRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProbeScopesResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/openclaw/instances:
    post:
      tags:
      - openclaw
      summary: Post Instances
      description: 'Provision a fresh instance for the caller.


        Sync UX, internally async: insert provisioning row -> daemon

        ``POST /provision`` (returns ``202 {job_id}``) -> poll every 2s up

        to 120s -> on success ``state=''active''`` + 201; on daemon failure

        ``state=''failed''`` + 502; on hard-cap timeout leave row as-is and

        raise 504 so the operator can poll later.


        M-A10: ``Idempotency-Key`` header is REQUIRED. Without an

        operator-chosen key we cannot dedupe wizard retries against an

        in-flight provision; an auto-generated UUID would silently turn

        every retry into a fresh attempt, defeating crash safety. The

        daemon does the actual replay check; we just propagate.


        M3-review: the rate-limit slot is reserved up-front then refunded

        on terminal pre-insert failures (validation 400s, hub_token

        mismatch, slug 409, DaemonError BEFORE the instance row is

        inserted) so the per-hour limit measures *successful provision

        attempts that landed an instance row*, not "operator typo count".

        Once the row exists, the row itself is the rate boundary -- we do

        NOT refund post-insert failures.'
      operationId: post_instances_v1_openclaw_instances_post
      parameters:
      - name: Idempotency-Key
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Idempotency-Key
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProvisionRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProvisionResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    get:
      tags:
      - openclaw
      summary: Get Instances
      description: 'List instances visible to caller.


        ``scope=''all''`` requires admin; non-admin callers asking for ``all``

        are SILENTLY downgraded to ``scope=''mine''`` (M-A6). A 403 here

        leaked the existence of the admin-only branch to wizard scripts

        that probe for it — the SR/Voices pattern is "show the operator

        only what they own, never tell them more exists". An INFO-level

        log records the downgrade so operators noticing weird

        "where are my admin rows?" complaints can grep for the line.


        B4: each row carries ``last_action`` + ``last_action_at`` sourced

        from ``openclaw_audit_log`` via a LEFT JOIN LATERAL keyed on

        ``instance_slug``. LATERAL keeps the per-row "latest audit" lookup

        co-located with the parent select (rather than fetching N+1 in a

        second pass) and the index

        ``ix_openclaw_audit_log_slug_at(instance_slug, at)`` makes the

        inner ORDER BY ... LIMIT 1 a single index scan. An instance with

        no audit rows yet (race between insert + first start()) returns

        NULL for both fields, matching the Optional schema.'
      operationId: get_instances_v1_openclaw_instances_get
      parameters:
      - name: scope
        in: query
        required: false
        schema:
          enum:
          - mine
          - all
          type: string
          default: mine
          title: Scope
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/InstanceListItem'
                title: Response Get Instances V1 Openclaw Instances Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/openclaw/instances/{slug}:
    get:
      tags:
      - openclaw
      summary: Get Instance
      description: 'Return the rich InstanceDetail merging DB row + daemon read.


        The DB row is the source of truth for ownership + lifecycle state;

        the daemon contributes operator identity, UX toggles, ``unit_active``,

        and ``last_log_line`` (all of which live in the per-instance

        ``.env`` and on the systemd unit). On daemon outage the endpoint

        still returns a coherent DTO populated with empty strings + the

        template defaults so the admin UI can surface the stranded instance.'
      operationId: get_instance_v1_openclaw_instances__slug__get
      parameters:
      - name: slug
        in: path
        required: true
        schema:
          type: string
          title: Slug
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InstanceDetail'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    patch:
      tags:
      - openclaw
      summary: Patch Instance
      description: "Partial edit -> sequenced daemon calls -> one coalesced restart.\n\
        \nOrder:\n1. ``hub_token`` rotation. B1 -- the gateway revokes the OLD token\n\
        \   row and points ``openclaw_instances.hub_token_id`` at the new id\n   BEFORE\
        \ the daemon call, so a crash mid-rotate leaves the DB\n   consistent with\
        \ the operator's next retry rather than pointing\n   at a token the daemon\
        \ already overwrote on disk.\n2. Field edits via daemon ``POST /edit/{slug}``\
        \ (no_restart=True).\n3. Toggle edits via daemon ``POST /toggle/{slug}/{key}``.\n\
        \   The LAST daemon call in the sequence sends ``no_restart=False``\n   so\
        \ the coalesced restart fires exactly once.\n\nM-A1: a slug-scoped advisory\
        \ lock serializes concurrent PATCHes to\nthe same instance ∵ multiple wizard\
        \ tabs (or a retried request)\ncould otherwise interleave token-rotation +\
        \ edit + toggle and the\ndaemon would observe a corrupted final state (e.g.\
        \ new token on\ndisk but DB still pointing at the old id). The lock is taken\
        \ at\nthe top of the handler inside the transaction; PostgreSQL releases\n\
        it on commit/rollback ∵ ``pg_advisory_xact_lock`` is transaction-\nscoped\
        \ (not session-scoped, which would leak on connection reuse).\n\nM-A2: ``rotate_token``\
        \ is idempotent — passing the SAME token as\nthe one currently stored is a\
        \ no-op. We compare by hash so a\nwizard \"click Save twice\" retry collapses\
        \ to one daemon write +\naudit row instead of double-rotating."
      operationId: patch_instance_v1_openclaw_instances__slug__patch
      parameters:
      - name: slug
        in: path
        required: true
        schema:
          type: string
          title: Slug
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PatchInstanceRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PatchInstanceResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    delete:
      tags:
      - openclaw
      summary: Delete Instance
      description: "Decommission an instance with archive.\n\nFlow:\n1. Visibility\
        \ check (cross-user -> 404).\n2. Flip row to ``state='deleting'`` so the partial\
        \ unique index\n   releases the owner slot.\n3. Daemon ``POST /delete/{slug}``\
        \ (archive=True).\n4. On success: hard-delete the row + return archive_path.\n\
        5. On daemon failure: leave the row in ``deleting`` so the\n   operator can\
        \ retry; raise the daemon exception verbatim."
      operationId: delete_instance_v1_openclaw_instances__slug__delete
      parameters:
      - name: slug
        in: path
        required: true
        schema:
          type: string
          title: Slug
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteInstanceResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/rate-limits/default:
    get:
      tags:
      - admin-rate-limits
      summary: Get Default Policy
      operationId: get_default_policy_v1_admin_rate_limits_default_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PolicyDTO'
    put:
      tags:
      - admin-rate-limits
      summary: Update Default Policy
      operationId: update_default_policy_v1_admin_rate_limits_default_put
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PolicyUpdate'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PolicyDTO'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/rate-limits/users:
    get:
      tags:
      - admin-rate-limits
      summary: List User Overrides
      operationId: list_user_overrides_v1_admin_rate_limits_users_get
      parameters:
      - name: page
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          default: 1
          title: Page
      - name: size
        in: query
        required: false
        schema:
          type: integer
          maximum: 500
          minimum: 1
          default: 50
          title: Size
      - name: search
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Search
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/UserOverrideDTO'
                title: Response List User Overrides V1 Admin Rate Limits Users Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/admin/rate-limits/users/{user_id}:
    get:
      tags:
      - admin-rate-limits
      summary: Get User Policy
      operationId: get_user_policy_v1_admin_rate_limits_users__user_id__get
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PolicyDTO'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    put:
      tags:
      - admin-rate-limits
      summary: Upsert User Override
      operationId: upsert_user_override_v1_admin_rate_limits_users__user_id__put
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PolicyUpdate'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PolicyDTO'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    delete:
      tags:
      - admin-rate-limits
      summary: Delete User Override
      operationId: delete_user_override_v1_admin_rate_limits_users__user_id__delete
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          title: User Id
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/users/me/limits:
    get:
      tags:
      - rate-limits
      summary: Get My Limits
      description: 'SQLAlchemy `AsyncSession` is NOT concurrency-safe — two queries
        on the

        same session at the same time raise `InterfaceError`. The four usage

        sums are therefore awaited sequentially. Per-query latency is sub-ms on

        the `ix_rate_limit_usage_user_kind_time` index so the serialization cost

        is negligible.'
      operationId: get_my_limits_v1_users_me_limits_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserLimitsDTO'
  /health:
    get:
      tags:
      - system
      summary: Health
      operationId: health_health_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
components:
  schemas:
    AppSettingResponse:
      properties:
        key:
          type: string
          title: Key
        value:
          type: string
          title: Value
        updated_at:
          type: string
          format: date-time
          title: Updated At
        updated_by:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Updated By
      type: object
      required:
      - key
      - value
      - updated_at
      title: AppSettingResponse
    ArtifactDetail:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        artifact_type:
          type: string
          enum:
          - original_audio
          - processed_audio
          - raw_transcript
          - processed_transcript
          - llm_input
          - llm_output
          - whisper_segments
          title: Artifact Type
        content_text:
          anyOf:
          - type: string
          - type: 'null'
          title: Content Text
        file_path:
          anyOf:
          - type: string
          - type: 'null'
          title: File Path
        content_type:
          anyOf:
          - type: string
          - type: 'null'
          title: Content Type
        size_bytes:
          anyOf:
          - type: integer
          - type: 'null'
          title: Size Bytes
        download_url:
          anyOf:
          - type: string
          - type: 'null'
          title: Download Url
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - artifact_type
      - created_at
      title: ArtifactDetail
    AudioBatchListItem:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        status:
          type: string
          title: Status
        pipeline_mode:
          type: string
          title: Pipeline Mode
        language:
          anyOf:
          - type: string
          - type: 'null'
          title: Language
        chunk_count:
          type: integer
          title: Chunk Count
        created_at:
          type: string
          format: date-time
          title: Created At
        finalized_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Finalized At
        duration_ms:
          anyOf:
          - type: integer
          - type: 'null'
          title: Duration Ms
        text_preview:
          anyOf:
          - type: string
          - type: 'null'
          title: Text Preview
        error:
          anyOf:
          - type: string
          - type: 'null'
          title: Error
      type: object
      required:
      - id
      - status
      - pipeline_mode
      - language
      - chunk_count
      - created_at
      - finalized_at
      - duration_ms
      - text_preview
      - error
      title: AudioBatchListItem
    AudioBatchListResponse:
      properties:
        items:
          items:
            $ref: '#/components/schemas/AudioBatchListItem'
          type: array
          title: Items
        total:
          type: integer
          title: Total
        limit:
          type: integer
          title: Limit
        offset:
          type: integer
          title: Offset
      type: object
      required:
      - items
      - total
      - limit
      - offset
      title: AudioBatchListResponse
    AutoApproveUpdate:
      properties:
        enabled:
          type: boolean
          title: Enabled
      type: object
      required:
      - enabled
      title: AutoApproveUpdate
    BatchChunkStatus:
      properties:
        chunk_index:
          type: integer
          title: Chunk Index
        chunk_run_id:
          type: string
          format: uuid
          title: Chunk Run Id
        status:
          type: string
          enum:
          - processing
          - completed
          - failed
          title: Status
        raw_text:
          anyOf:
          - type: string
          - type: 'null'
          title: Raw Text
        duration_sec:
          anyOf:
          - type: number
          - type: 'null'
          title: Duration Sec
        tail_used_for_next:
          anyOf:
          - type: string
          - type: 'null'
          title: Tail Used For Next
      type: object
      required:
      - chunk_index
      - chunk_run_id
      - status
      title: BatchChunkStatus
    BatchResponse:
      properties:
        batch_id:
          type: string
          format: uuid
          title: Batch Id
        status:
          type: string
          enum:
          - open
          - finalizing
          - finalized
          - failed
          title: Status
        pipeline_mode:
          type: string
          enum:
          - full
          - fast
          title: Pipeline Mode
        task:
          type: string
          enum:
          - transcribe
          - translate
          title: Task
        language:
          anyOf:
          - type: string
          - type: 'null'
          title: Language
        detected_language:
          anyOf:
          - type: string
          - type: 'null'
          title: Detected Language
        created_at:
          type: string
          format: date-time
          title: Created At
        finalized_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Finalized At
        chunks:
          items:
            $ref: '#/components/schemas/BatchChunkStatus'
          type: array
          title: Chunks
        concatenated_text:
          anyOf:
          - type: string
          - type: 'null'
          title: Concatenated Text
        final_text:
          anyOf:
          - type: string
          - type: 'null'
          title: Final Text
        error:
          anyOf:
          - type: string
          - type: 'null'
          title: Error
        user_metadata:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: User Metadata
      type: object
      required:
      - batch_id
      - status
      - pipeline_mode
      - task
      - created_at
      - chunks
      title: BatchResponse
    Body_create_system_voice_v1_voices_system_post:
      properties:
        name:
          type: string
          maxLength: 255
          title: Name
        ref_text:
          anyOf:
          - type: string
          - type: 'null'
          title: Ref Text
        trim_silence:
          type: boolean
          title: Trim Silence
          description: Trim silence from both ends and truncate to the max duration
            when input exceeds it. When false, long inputs are rejected.
          default: true
        audio:
          type: string
          contentMediaType: application/octet-stream
          title: Audio
          description: Reference audio clip
      type: object
      required:
      - name
      - audio
      title: Body_create_system_voice_v1_voices_system_post
    Body_create_user_voice_v1_voices_post:
      properties:
        name:
          type: string
          maxLength: 255
          title: Name
        ref_text:
          anyOf:
          - type: string
          - type: 'null'
          title: Ref Text
        trim_silence:
          type: boolean
          title: Trim Silence
          description: Trim silence from both ends and truncate to the max duration
            when input exceeds it. When false, long inputs are rejected.
          default: true
        audio:
          type: string
          contentMediaType: application/octet-stream
          title: Audio
          description: Reference audio clip (mp3/wav/m4a/ogg/flac/webm)
      type: object
      required:
      - name
      - audio
      title: Body_create_user_voice_v1_voices_post
    Body_images_edits_v1_images_edits_post:
      properties:
        image:
          type: string
          contentMediaType: application/octet-stream
          title: Image
          description: Reference image (PNG, JPEG, or WEBP; max 20 MB)
        prompt:
          type: string
          maxLength: 4000
          minLength: 1
          title: Prompt
        model:
          anyOf:
          - type: string
          - type: 'null'
          title: Model
        n:
          type: integer
          title: N
          default: 1
        size:
          type: string
          title: Size
          default: 1024x1024
        response_format:
          type: string
          title: Response Format
          default: url
        mask:
          anyOf:
          - type: string
            contentMediaType: application/octet-stream
          - type: 'null'
          title: Mask
          description: Optional. PNG/JPEG/WEBP, same dimensions as `image`. White
            pixels mark regions to regenerate per `prompt`; black pixels are pixel-perfect
            preserved via ImageCompositeMasked. When omitted, falls back to ReferenceLatent
            identity-preserving full-image regeneration.
        mask_blur:
          type: integer
          maximum: 30.0
          minimum: 0.0
          title: Mask Blur
          description: Soft mask edge in pixels (FeatherMask). 0 = hard cut, higher
            = blurred boundary blending into preserved region. Only used when `mask`
            is provided.
          default: 0
        mask_grow:
          type: integer
          maximum: 30.0
          minimum: -20.0
          title: Mask Grow
          description: Expand mask area in pixels (GrowMask). Negative shrinks the
            mask, positive grows it. 0 = use as drawn. Only used when `mask` is provided.
          default: 0
      type: object
      required:
      - image
      - prompt
      title: Body_images_edits_v1_images_edits_post
    Body_transcribe_sync_v1_audio_transcriptions_sync_post:
      properties:
        file:
          type: string
          contentMediaType: application/octet-stream
          title: File
          description: Audio file for transcription (mp3, wav, m4a, ogg, flac, webm;
            max 500 MB)
        model:
          type: string
          title: Model
          description: Whisper ASR model. Optional — defaults to large-v3-turbo.
        language:
          type: string
          title: Language
          description: Audio language (ISO 639-1 code). Use 'auto' for automatic detection.
          default: auto
        pipeline:
          type: string
          title: Pipeline
          description: 'Processing pipeline: ''fast'' (Whisper only) or ''full'' (Whisper
            + LLM text cleanup).'
          default: full
        audio_processing:
          type: string
          enum:
          - none
          - fast
          - full
          title: Audio Processing
          description: Audio preprocessing level.
          default: fast
        response_format:
          type: string
          title: Response Format
          description: 'Response format: json, text, verbose_json, srt, or vtt.'
          default: json
        prompt:
          type: string
          title: Prompt
          description: Hint text for Whisper.
        system_prompt_id:
          anyOf:
          - type: string
          - type: 'null'
          title: System Prompt Id
          description: UUID of a custom system prompt for LLM cleanup.
        max_segment_duration:
          type: number
          title: Max Segment Duration
          description: Max subtitle segment duration in seconds.
          default: 5.0
        min_silence_duration:
          type: number
          title: Min Silence Duration
          description: Min silence duration in seconds for segment splitting.
          default: 0.3
        word_timestamps:
          type: boolean
          title: Word Timestamps
          description: Include word-level timestamps in verbose_json output.
          default: false
      type: object
      required:
      - file
      title: Body_transcribe_sync_v1_audio_transcriptions_sync_post
    Body_transcribe_v1_audio_transcriptions_post:
      properties:
        file:
          type: string
          contentMediaType: application/octet-stream
          title: File
          description: Audio file for transcription (mp3, wav, m4a, ogg, flac, webm;
            max 500 MB)
        model:
          type: string
          title: Model
          description: Whisper ASR model. Optional — defaults to large-v3-turbo. Most
            users should omit this.
        language:
          type: string
          title: Language
          description: 'Audio language (ISO 639-1 code). Use ''auto'' for automatic
            detection. Supported: ru, en, de, fr, es, zh, ja, ko.'
          default: auto
        pipeline:
          type: string
          title: Pipeline
          description: 'Processing pipeline: ''fast'' (Whisper only) or ''full'' (Whisper
            + LLM text cleanup).'
          default: full
        audio_processing:
          type: string
          enum:
          - none
          - fast
          - full
          title: Audio Processing
          description: 'Audio preprocessing level: ''none'' (resample only, fastest),
            ''fast'' (dynaudnorm, default), ''full'' (loudnorm, broadcast quality).'
          default: fast
        response_format:
          type: string
          title: Response Format
          description: 'Response format: json, text, verbose_json, srt, or vtt.'
          default: json
        prompt:
          type: string
          title: Prompt
          description: 'Hint text for Whisper: domain-specific terms, abbreviations,
            context.'
        system_prompt_id:
          anyOf:
          - type: string
          - type: 'null'
          title: System Prompt Id
          description: UUID of a custom system prompt for LLM cleanup (pipeline=full
            only).
        max_segment_duration:
          type: number
          title: Max Segment Duration
          description: Max subtitle segment duration in seconds (affects srt/vtt/verbose_json
            only).
          default: 5.0
        min_silence_duration:
          type: number
          title: Min Silence Duration
          description: Min silence duration in seconds for segment splitting (affects
            srt/vtt/verbose_json only).
          default: 0.3
        word_timestamps:
          type: boolean
          title: Word Timestamps
          description: Include word-level timestamps in verbose_json output.
          default: false
      type: object
      required:
      - file
      title: Body_transcribe_v1_audio_transcriptions_post
    Body_upload_chunk_v1_audio_batches__batch_id__chunks_post:
      properties:
        file:
          type: string
          contentMediaType: application/octet-stream
          title: File
        chunk_index:
          type: integer
          minimum: 0.0
          title: Chunk Index
      type: object
      required:
      - file
      - chunk_index
      title: Body_upload_chunk_v1_audio_batches__batch_id__chunks_post
    ChatCompletionRequest:
      properties:
        model:
          anyOf:
          - type: string
          - type: 'null'
          title: Model
          description: 'LLM model identifier. If omitted, server picks the default.
            Available: qwen3.5:9b (vLLM AWQ, chat default), qwen2.5:7b (Ollama, pipeline
            default). Full list: GET /v1/models'
          examples:
          - qwen3.5:9b
          - qwen2.5:7b
        messages:
          items:
            $ref: '#/components/schemas/ChatMessage'
          type: array
          title: Messages
        system_prompt_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: System Prompt Id
        system_prompt:
          anyOf:
          - type: string
          - type: 'null'
          title: System Prompt
        use_memory:
          type: boolean
          title: Use Memory
          default: false
        think:
          type: boolean
          title: Think
          default: false
        temperature:
          type: number
          title: Temperature
          default: 0.7
        top_p:
          type: number
          title: Top P
          default: 1.0
        max_tokens:
          anyOf:
          - type: integer
          - type: 'null'
          title: Max Tokens
        stream:
          type: boolean
          title: Stream
          default: false
        stop:
          anyOf:
          - type: string
          - items:
              type: string
            type: array
          - type: 'null'
          title: Stop
        tools:
          anyOf:
          - items:
              $ref: '#/components/schemas/ChatTool'
            type: array
          - type: 'null'
          title: Tools
          description: OpenAI-style function tool definitions. Forwarded unchanged
            to both backends. Empty list is coerced to null.
        tool_choice:
          anyOf:
          - type: string
            enum:
            - auto
            - required
            - none
          - $ref: '#/components/schemas/NamedToolChoice'
          - type: 'null'
          title: Tool Choice
          description: 'Tool call policy: ''auto'' | ''required'' | ''none'' or a
            named-function object. Ollama may ignore ''required'' on older tags.'
        response_format:
          anyOf:
          - $ref: '#/components/schemas/ResponseFormat'
          - type: 'null'
          description: Structured output control. text=unconstrained, json_object=JSON
            mode, json_schema=strict schema (vLLM only; Ollama backend returns 400).
        parallel_tool_calls:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Parallel Tool Calls
          description: 'Allow the model to emit multiple tool calls in one turn. vLLM:
            passed-through. Ollama: silently omitted.'
      type: object
      required:
      - messages
      title: ChatCompletionRequest
    ChatMessage:
      properties:
        role:
          type: string
          enum:
          - system
          - user
          - assistant
          - tool
          title: Role
          description: Message author role. "system" sets behavior, "user" is the
            human turn, "assistant" is the model turn, "tool" is a tool/function response
            in a function-calling roundtrip (requires tool_call_id).
        content:
          anyOf:
          - type: string
          - type: 'null'
          title: Content
          description: Message text. Accepts EITHER a plain string OR an OpenAI-compatible
            array of text parts [{"type":"text","text":"..."}]. Array parts are concatenated
            server-side (joined with newline) before forwarding to the model. Non-text
            part types (image_url, audio, etc.) return HTTP 422. After validation
            the stored value is always a plain string.
        reasoning:
          anyOf:
          - type: string
          - type: 'null'
          title: Reasoning
        tool_calls:
          anyOf:
          - items:
              $ref: '#/components/schemas/ToolCall'
            type: array
          - type: 'null'
          title: Tool Calls
        tool_call_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Tool Call Id
          description: ID of the assistant tool_call this message is responding to.
            REQUIRED when role=="tool" (request returns 422 otherwise); ignored for
            other roles.
        name:
          anyOf:
          - type: string
          - type: 'null'
          title: Name
          description: Optional identifier of the participant or tool/function. OpenAI
            spec-compliant; passed through to upstream models.
      type: object
      required:
      - role
      title: ChatMessage
    ChatTool:
      properties:
        type:
          type: string
          const: function
          title: Type
          default: function
        function:
          $ref: '#/components/schemas/ChatToolFunction'
      type: object
      required:
      - function
      title: ChatTool
    ChatToolFunction:
      properties:
        name:
          type: string
          title: Name
        description:
          anyOf:
          - type: string
          - type: 'null'
          title: Description
        parameters:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Parameters
      type: object
      required:
      - name
      title: ChatToolFunction
    CreateBatchRequest:
      properties:
        pipeline_mode:
          type: string
          enum:
          - full
          - fast
          title: Pipeline Mode
        language:
          anyOf:
          - type: string
            enum:
            - ru
            - en
          - type: 'null'
          title: Language
        language_candidates:
          anyOf:
          - items:
              type: string
              enum:
              - ru
              - en
            type: array
          - type: 'null'
          title: Language Candidates
        task:
          type: string
          enum:
          - transcribe
          - translate
          title: Task
          default: transcribe
        user_metadata:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: User Metadata
      type: object
      required:
      - pipeline_mode
      title: CreateBatchRequest
    DeleteInstanceResponse:
      properties:
        slug:
          type: string
          pattern: ^[a-z][a-z0-9-]{2,30}$
          title: Slug
        archive_path:
          type: string
          title: Archive Path
      type: object
      required:
      - slug
      - archive_path
      title: DeleteInstanceResponse
    DictionaryEntry:
      properties:
        term:
          type: string
          title: Term
        context:
          type: string
          title: Context
          default: ''
      type: object
      required:
      - term
      title: DictionaryEntry
    DictionaryPatchRequest:
      properties:
        add:
          items:
            $ref: '#/components/schemas/DictionaryEntry'
          type: array
          title: Add
          default: []
        remove:
          items:
            type: string
          type: array
          title: Remove
          default: []
      type: object
      title: DictionaryPatchRequest
    DictionaryResponse:
      properties:
        entries:
          items:
            $ref: '#/components/schemas/DictionaryEntry'
          type: array
          title: Entries
        updated_at:
          type: string
          format: date-time
          title: Updated At
      type: object
      required:
      - entries
      - updated_at
      title: DictionaryResponse
    DictionaryUpdateRequest:
      properties:
        entries:
          items:
            $ref: '#/components/schemas/DictionaryEntry'
          type: array
          title: Entries
      type: object
      required:
      - entries
      title: DictionaryUpdateRequest
    DiskUsage:
      properties:
        mount:
          type: string
          title: Mount
        used_bytes:
          type: integer
          title: Used Bytes
        total_bytes:
          type: integer
          title: Total Bytes
      type: object
      required:
      - mount
      - used_bytes
      - total_bytes
      title: DiskUsage
    ErrorDetail:
      properties:
        type:
          type: string
          title: Type
        message:
          type: string
          title: Message
        param:
          anyOf:
          - type: string
          - type: 'null'
          title: Param
      type: object
      required:
      - type
      - message
      title: ErrorDetail
    ErrorResponse:
      properties:
        error:
          $ref: '#/components/schemas/ErrorDetail'
      type: object
      required:
      - error
      title: ErrorResponse
    FinalizeBatchResponse:
      properties:
        batch_id:
          type: string
          format: uuid
          title: Batch Id
        status:
          type: string
          const: finalizing
          title: Status
          default: finalizing
      type: object
      required:
      - batch_id
      title: FinalizeBatchResponse
    GpuProcess:
      properties:
        pid:
          type: integer
          title: Pid
        name:
          type: string
          title: Name
        gpu_memory_mib:
          type: integer
          title: Gpu Memory Mib
      type: object
      required:
      - pid
      - name
      - gpu_memory_mib
      title: GpuProcess
    GpuProcessesResponse:
      properties:
        processes:
          items:
            $ref: '#/components/schemas/GpuProcess'
          type: array
          title: Processes
        ollama_models:
          items:
            $ref: '#/components/schemas/OllamaModelInfo'
          type: array
          title: Ollama Models
        collected_at:
          type: number
          title: Collected At
      type: object
      required:
      - processes
      - ollama_models
      - collected_at
      title: GpuProcessesResponse
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ImageData:
      properties:
        url:
          anyOf:
          - type: string
          - type: 'null'
          title: Url
        b64_json:
          anyOf:
          - type: string
          - type: 'null'
          title: B64 Json
        revised_prompt:
          anyOf:
          - type: string
          - type: 'null'
          title: Revised Prompt
      type: object
      title: ImageData
      description: Single image item in ImagesResponse.data[].
    ImageGenerationRequest:
      properties:
        prompt:
          type: string
          maxLength: 4000
          minLength: 1
          title: Prompt
        model:
          anyOf:
          - type: string
            enum:
            - flux2-dev
            - flux2-klein-9b
          - type: 'null'
          title: Model
        n:
          type: integer
          maximum: 4.0
          minimum: 1.0
          title: N
          default: 1
        size:
          type: string
          enum:
          - 1024x1024
          - 1024x1536
          - 1536x1024
          title: Size
          default: 1024x1024
        response_format:
          type: string
          enum:
          - url
          - b64_json
          title: Response Format
          default: url
        user:
          anyOf:
          - type: string
          - type: 'null'
          title: User
        quality:
          anyOf:
          - type: string
          - type: 'null'
          title: Quality
        style:
          anyOf:
          - type: string
          - type: 'null'
          title: Style
      type: object
      required:
      - prompt
      title: ImageGenerationRequest
      description: OpenAI-compatible POST /v1/images/generations body.
    ImagesResponse:
      properties:
        created:
          type: integer
          title: Created
        data:
          items:
            $ref: '#/components/schemas/ImageData'
          type: array
          title: Data
      type: object
      required:
      - data
      title: ImagesResponse
      description: OpenAI-compatible response envelope for both /generations and /edits.
    InstanceDetail:
      properties:
        id:
          type: string
          format: uuid4
          title: Id
        owner_user_id:
          type: string
          format: uuid4
          title: Owner User Id
        slug:
          type: string
          pattern: ^[a-z][a-z0-9-]{2,30}$
          title: Slug
        assistant_name:
          type: string
          title: Assistant Name
        bot_username:
          type: string
          title: Bot Username
        state:
          type: string
          enum:
          - provisioning
          - active
          - failed
          - deleting
          title: State
        created_at:
          type: string
          format: date-time
          title: Created At
        last_state_check_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last State Check At
        owner_email:
          anyOf:
          - type: string
          - type: 'null'
          title: Owner Email
        last_action_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last Action At
        last_action:
          anyOf:
          - type: string
          - type: 'null'
          title: Last Action
        operator_name:
          type: string
          title: Operator Name
          default: ''
        operator_tg_jid:
          type: string
          title: Operator Tg Jid
          default: ''
        operator_email:
          type: string
          title: Operator Email
          default: ''
        tz:
          type: string
          title: Tz
          default: ''
        brewpage_ns:
          type: string
          title: Brewpage Ns
          default: ''
        sdk_model_hint:
          type: string
          title: Sdk Model Hint
          default: ''
        show_thinking:
          type: boolean
          title: Show Thinking
          default: false
        show_typing:
          type: boolean
          title: Show Typing
          default: true
        show_tool_progress:
          type: boolean
          title: Show Tool Progress
          default: true
        tool_progress_mode:
          type: string
          enum:
          - merge
          - stream
          - 'off'
          title: Tool Progress Mode
          default: merge
        unit_active:
          type: boolean
          title: Unit Active
          default: false
        last_log_line:
          anyOf:
          - type: string
          - type: 'null'
          title: Last Log Line
      type: object
      required:
      - id
      - owner_user_id
      - slug
      - assistant_name
      - bot_username
      - state
      - created_at
      title: InstanceDetail
    InstanceListItem:
      properties:
        id:
          type: string
          format: uuid4
          title: Id
        owner_user_id:
          type: string
          format: uuid4
          title: Owner User Id
        slug:
          type: string
          pattern: ^[a-z][a-z0-9-]{2,30}$
          title: Slug
        assistant_name:
          type: string
          title: Assistant Name
        bot_username:
          type: string
          title: Bot Username
        state:
          type: string
          enum:
          - provisioning
          - active
          - failed
          - deleting
          title: State
        created_at:
          type: string
          format: date-time
          title: Created At
        last_state_check_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last State Check At
        owner_email:
          anyOf:
          - type: string
          - type: 'null'
          title: Owner Email
        last_action_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last Action At
        last_action:
          anyOf:
          - type: string
          - type: 'null'
          title: Last Action
      type: object
      required:
      - id
      - owner_user_id
      - slug
      - assistant_name
      - bot_username
      - state
      - created_at
      title: InstanceListItem
    JsonSchemaFormat:
      properties:
        name:
          type: string
          title: Name
        schema:
          additionalProperties: true
          type: object
          title: Schema
        strict:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Strict
        description:
          anyOf:
          - type: string
          - type: 'null'
          title: Description
      type: object
      required:
      - name
      - schema
      title: JsonSchemaFormat
    LogDeleteResult:
      properties:
        deleted:
          type: integer
          title: Deleted
      type: object
      required:
      - deleted
      title: LogDeleteResult
      description: 'Response for ``DELETE /v1/smart-routing/logs`` and the admin mirror.


        ``deleted`` is the rowcount returned by PG — 0 is a valid response

        (no rows matched the filter). The endpoint is idempotent.'
    LoginRequest:
      properties:
        email:
          type: string
          title: Email
        password:
          type: string
          title: Password
      type: object
      required:
      - email
      - password
      title: LoginRequest
    LoginResponse:
      properties:
        access_token:
          type: string
          title: Access Token
        token_type:
          type: string
          title: Token Type
          default: bearer
        expires_in:
          type: integer
          title: Expires In
        user:
          $ref: '#/components/schemas/UserInfo'
      type: object
      required:
      - access_token
      - expires_in
      - user
      title: LoginResponse
    MemoryCreate:
      properties:
        content:
          type: string
          title: Content
      type: object
      required:
      - content
      title: MemoryCreate
    MemoryListResponse:
      properties:
        items:
          items:
            $ref: '#/components/schemas/MemoryResponse'
          type: array
          title: Items
        total:
          type: integer
          title: Total
        total_tokens:
          type: integer
          title: Total Tokens
      type: object
      required:
      - items
      - total
      - total_tokens
      title: MemoryListResponse
    MemoryResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        content:
          type: string
          title: Content
        optimized_content:
          type: string
          title: Optimized Content
        original_tokens:
          type: integer
          title: Original Tokens
        optimized_tokens:
          type: integer
          title: Optimized Tokens
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - content
      - optimized_content
      - original_tokens
      - optimized_tokens
      - created_at
      title: MemoryResponse
    MetricDetail:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        step:
          type: string
          enum:
          - ffmpeg
          - demucs
          - whisper
          - qwen
          title: Step
        duration_ms:
          type: integer
          title: Duration Ms
        metadata:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Metadata
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - step
      - duration_ms
      - created_at
      title: MetricDetail
    MetricsHistory:
      properties:
        timestamps:
          items:
            type: number
          type: array
          title: Timestamps
        cpu_percent:
          items:
            type: number
          type: array
          title: Cpu Percent
        ram_used_bytes:
          items:
            type: integer
          type: array
          title: Ram Used Bytes
        gpu_vram_used_bytes:
          items:
            anyOf:
            - type: integer
            - type: 'null'
          type: array
          title: Gpu Vram Used Bytes
        gpu_utilization_percent:
          items:
            anyOf:
            - type: number
            - type: 'null'
          type: array
          title: Gpu Utilization Percent
        point_count:
          type: integer
          title: Point Count
      type: object
      required:
      - timestamps
      - cpu_percent
      - ram_used_bytes
      - gpu_vram_used_bytes
      - point_count
      title: MetricsHistory
    MetricsSnapshot:
      properties:
        timestamp:
          type: number
          title: Timestamp
        cpu_percent:
          type: number
          title: Cpu Percent
        ram_used_bytes:
          type: integer
          title: Ram Used Bytes
        ram_total_bytes:
          type: integer
          title: Ram Total Bytes
        disks:
          items:
            $ref: '#/components/schemas/DiskUsage'
          type: array
          title: Disks
        gpu_vram_used_bytes:
          anyOf:
          - type: integer
          - type: 'null'
          title: Gpu Vram Used Bytes
        gpu_vram_total_bytes:
          anyOf:
          - type: integer
          - type: 'null'
          title: Gpu Vram Total Bytes
        gpu_utilization_percent:
          anyOf:
          - type: number
          - type: 'null'
          title: Gpu Utilization Percent
        collection_errors:
          items:
            type: string
          type: array
          title: Collection Errors
      type: object
      required:
      - timestamp
      - cpu_percent
      - ram_used_bytes
      - ram_total_bytes
      - disks
      title: MetricsSnapshot
    NamedToolChoice:
      properties:
        type:
          type: string
          const: function
          title: Type
          default: function
        function:
          additionalProperties: true
          type: object
          title: Function
      type: object
      required:
      - function
      title: NamedToolChoice
    OllamaModelInfo:
      properties:
        name:
          type: string
          title: Name
        size_bytes:
          type: integer
          title: Size Bytes
        vram_bytes:
          type: integer
          title: Vram Bytes
        expires_at:
          anyOf:
          - type: string
          - type: 'null'
          title: Expires At
      type: object
      required:
      - name
      - size_bytes
      - vram_bytes
      title: OllamaModelInfo
    OllamaUnloadRequest:
      properties:
        model:
          type: string
          title: Model
      type: object
      required:
      - model
      title: OllamaUnloadRequest
    OptimizeRequest:
      properties:
        text:
          type: string
          maxLength: 100000
          title: Text
        model:
          anyOf:
          - type: string
          - type: 'null'
          title: Model
      type: object
      required:
      - text
      title: OptimizeRequest
    OptimizeResponse:
      properties:
        original_text:
          type: string
          title: Original Text
        optimized_text:
          type: string
          title: Optimized Text
        original_tokens:
          type: integer
          title: Original Tokens
        optimized_tokens:
          type: integer
          title: Optimized Tokens
        reduction_percent:
          type: number
          title: Reduction Percent
      type: object
      required:
      - original_text
      - optimized_text
      - original_tokens
      - optimized_tokens
      - reduction_percent
      title: OptimizeResponse
    PatchInstanceRequest:
      properties:
        operator_name:
          anyOf:
          - type: string
            maxLength: 128
            minLength: 1
          - type: 'null'
          title: Operator Name
        operator_tg_jid:
          anyOf:
          - type: string
            maxLength: 32
            minLength: 1
            pattern: ^-?\d+$
          - type: 'null'
          title: Operator Tg Jid
        operator_email:
          anyOf:
          - type: string
            maxLength: 254
            minLength: 3
            pattern: ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$
          - type: 'null'
          title: Operator Email
        tz:
          anyOf:
          - type: string
            maxLength: 64
            minLength: 1
          - type: 'null'
          title: Tz
        brewpage_ns:
          anyOf:
          - type: string
            maxLength: 64
            minLength: 1
          - type: 'null'
          title: Brewpage Ns
        sdk_model_hint:
          anyOf:
          - type: string
            maxLength: 128
            minLength: 1
          - type: 'null'
          title: Sdk Model Hint
        hub_token:
          anyOf:
          - type: string
            maxLength: 512
            minLength: 1
          - type: 'null'
          title: Hub Token
        show_thinking:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Show Thinking
        show_typing:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Show Typing
        show_tool_progress:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Show Tool Progress
        tool_progress_mode:
          anyOf:
          - type: string
            enum:
            - merge
            - stream
            - 'off'
          - type: 'null'
          title: Tool Progress Mode
      type: object
      title: PatchInstanceRequest
    PatchInstanceResponse:
      properties:
        applied:
          items:
            type: string
          type: array
          title: Applied
        restarted:
          type: boolean
          title: Restarted
      type: object
      required:
      - applied
      - restarted
      title: PatchInstanceResponse
      description: 'Result of a PATCH /instances/{slug}.


        All-or-nothing semantics: the gateway sequences the daemon calls

        inside a single handler scope and the first daemon failure aborts

        the remainder of the sequence, surfacing the underlying daemon

        exception verbatim. Partial success is therefore NOT a response

        shape; callers either get ``applied=[...all fields...]`` (HTTP 200)

        or an error (HTTP 4xx/5xx) -- never a 200 with a partial ``applied``

        list. The audit row records the same all-or-nothing outcome via

        ``result=''success''`` / ``result=''failure''``.


        Exception: ``hub_token`` rotation is audited in its own row (action

        ``rotate_token``) so a successful rotation followed by a failed edit

        still records the rotation as ``success`` (B1: DB is already pointing

        at the new token at that point and the operator should not need to

        re-rotate).'
    PipelineDetail:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        status:
          type: string
          enum:
          - processing
          - completed
          - failed
          title: Status
        pipeline_mode:
          type: string
          enum:
          - fast
          - full
          - none
          - whisper_only_batch_chunk
          title: Pipeline Mode
        task:
          type: string
          enum:
          - transcribe
          - translate
          - enhance
          title: Task
        language:
          type: string
          title: Language
        original_filename:
          anyOf:
          - type: string
          - type: 'null'
          title: Original Filename
        created_at:
          type: string
          format: date-time
          title: Created At
        completed_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Completed At
        duration_ms:
          anyOf:
          - type: integer
          - type: 'null'
          title: Duration Ms
        error:
          anyOf:
          - type: string
          - type: 'null'
          title: Error
        artifacts:
          items:
            $ref: '#/components/schemas/ArtifactDetail'
          type: array
          title: Artifacts
        metrics:
          items:
            $ref: '#/components/schemas/MetricDetail'
          type: array
          title: Metrics
      type: object
      required:
      - id
      - status
      - pipeline_mode
      - task
      - language
      - created_at
      - artifacts
      - metrics
      title: PipelineDetail
    PipelineListItem:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        status:
          type: string
          enum:
          - processing
          - completed
          - failed
          title: Status
        pipeline_mode:
          type: string
          enum:
          - fast
          - full
          - none
          - whisper_only_batch_chunk
          title: Pipeline Mode
        task:
          type: string
          enum:
          - transcribe
          - translate
          - enhance
          title: Task
        language:
          type: string
          title: Language
        original_filename:
          anyOf:
          - type: string
          - type: 'null'
          title: Original Filename
        created_at:
          type: string
          format: date-time
          title: Created At
        completed_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Completed At
        duration_ms:
          anyOf:
          - type: integer
          - type: 'null'
          title: Duration Ms
        error:
          anyOf:
          - type: string
          - type: 'null'
          title: Error
        text_preview:
          anyOf:
          - type: string
          - type: 'null'
          title: Text Preview
      type: object
      required:
      - id
      - status
      - pipeline_mode
      - task
      - language
      - created_at
      title: PipelineListItem
    PipelineListResponse:
      properties:
        items:
          items:
            $ref: '#/components/schemas/PipelineListItem'
          type: array
          title: Items
        total:
          type: integer
          title: Total
        limit:
          type: integer
          title: Limit
        offset:
          type: integer
          title: Offset
      type: object
      required:
      - items
      - total
      - limit
      - offset
      title: PipelineListResponse
    PipelineModelUpdate:
      properties:
        model:
          type: string
          title: Model
      type: object
      required:
      - model
      title: PipelineModelUpdate
    PolicyDTO:
      properties:
        id:
          type: integer
          title: Id
        user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: User Id
        chat_per_hour:
          type: integer
          title: Chat Per Hour
        transcription_requests_per_hour:
          type: integer
          title: Transcription Requests Per Hour
        transcription_seconds_per_hour:
          type: integer
          title: Transcription Seconds Per Hour
        image_per_hour:
          type: integer
          title: Image Per Hour
        tts_daily_chars:
          type: integer
          title: Tts Daily Chars
        tts_request_chars:
          type: integer
          title: Tts Request Chars
        provider_test_per_hour:
          type: integer
          title: Provider Test Per Hour
        anthropic_messages_per_minute:
          type: integer
          title: Anthropic Messages Per Minute
        updated_at:
          type: string
          format: date-time
          title: Updated At
      type: object
      required:
      - id
      - user_id
      - chat_per_hour
      - transcription_requests_per_hour
      - transcription_seconds_per_hour
      - image_per_hour
      - tts_daily_chars
      - tts_request_chars
      - provider_test_per_hour
      - anthropic_messages_per_minute
      - updated_at
      title: PolicyDTO
    PolicyUpdate:
      properties:
        chat_per_hour:
          anyOf:
          - type: integer
            minimum: 0.0
          - type: 'null'
          title: Chat Per Hour
        transcription_requests_per_hour:
          anyOf:
          - type: integer
            minimum: 0.0
          - type: 'null'
          title: Transcription Requests Per Hour
        transcription_seconds_per_hour:
          anyOf:
          - type: integer
            minimum: 0.0
          - type: 'null'
          title: Transcription Seconds Per Hour
        image_per_hour:
          anyOf:
          - type: integer
            minimum: 0.0
          - type: 'null'
          title: Image Per Hour
        tts_daily_chars:
          anyOf:
          - type: integer
            minimum: 0.0
          - type: 'null'
          title: Tts Daily Chars
        tts_request_chars:
          anyOf:
          - type: integer
            minimum: 0.0
          - type: 'null'
          title: Tts Request Chars
        provider_test_per_hour:
          anyOf:
          - type: integer
            minimum: 0.0
          - type: 'null'
          title: Provider Test Per Hour
        anthropic_messages_per_minute:
          anyOf:
          - type: integer
            minimum: 0.0
          - type: 'null'
          title: Anthropic Messages Per Minute
      type: object
      title: PolicyUpdate
      description: 'Partial update of a policy row. At least one field must be present
        —

        the router enforces this so we can return a 400 with a domain error

        instead of a generic 422.'
    ProbeBotRequest:
      properties:
        tg_bot_token:
          type: string
          maxLength: 128
          minLength: 1
          pattern: ^\d{6,12}:[A-Za-z0-9_-]{30,}$
          title: Tg Bot Token
      type: object
      required:
      - tg_bot_token
      title: ProbeBotRequest
    ProbeBotResponse:
      properties:
        bot_username:
          type: string
          title: Bot Username
        bot_id:
          type: integer
          title: Bot Id
        can_join_groups:
          type: boolean
          title: Can Join Groups
        derived_slug:
          type: string
          pattern: ^[a-z][a-z0-9-]{2,30}$
          title: Derived Slug
        derived_assistant_name:
          type: string
          title: Derived Assistant Name
      type: object
      required:
      - bot_username
      - bot_id
      - can_join_groups
      - derived_slug
      - derived_assistant_name
      title: ProbeBotResponse
    ProbeScopesRequest:
      properties:
        hub_token:
          type: string
          maxLength: 512
          minLength: 1
          title: Hub Token
      type: object
      required:
      - hub_token
      title: ProbeScopesRequest
    ProbeScopesResponse:
      properties:
        has_smart_routing_invoke:
          type: boolean
          title: Has Smart Routing Invoke
        has_smart_routing_manage:
          type: boolean
          title: Has Smart Routing Manage
        has_transcribe:
          type: boolean
          title: Has Transcribe
        has_all_required:
          type: boolean
          title: Has All Required
      type: object
      required:
      - has_smart_routing_invoke
      - has_smart_routing_manage
      - has_transcribe
      - has_all_required
      title: ProbeScopesResponse
    PromptCreate:
      properties:
        name:
          type: string
          title: Name
        text:
          type: string
          title: Text
        is_default:
          type: boolean
          title: Is Default
          default: false
      type: object
      required:
      - name
      - text
      title: PromptCreate
    PromptListResponse:
      properties:
        prompts:
          items:
            $ref: '#/components/schemas/PromptResponse'
          type: array
          title: Prompts
        total:
          type: integer
          title: Total
      type: object
      required:
      - prompts
      - total
      title: PromptListResponse
    PromptResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        name:
          type: string
          title: Name
        text:
          type: string
          title: Text
        is_default:
          type: boolean
          title: Is Default
        is_system:
          type: boolean
          title: Is System
        token_count:
          type: integer
          title: Token Count
        created_at:
          type: string
          format: date-time
          title: Created At
        updated_at:
          type: string
          format: date-time
          title: Updated At
      type: object
      required:
      - id
      - name
      - text
      - is_default
      - is_system
      - token_count
      - created_at
      - updated_at
      title: PromptResponse
    PromptUpdate:
      properties:
        name:
          anyOf:
          - type: string
          - type: 'null'
          title: Name
        text:
          anyOf:
          - type: string
          - type: 'null'
          title: Text
        is_default:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Is Default
      type: object
      title: PromptUpdate
    ProviderActivateResponse:
      properties:
        id:
          type: integer
          title: Id
        is_active:
          type: boolean
          title: Is Active
      type: object
      required:
      - id
      - is_active
      title: ProviderActivateResponse
      description: Response for ``POST /v1/smart-routing/providers/{id}/activate``.
    ProviderCreate:
      properties:
        name:
          type: string
          maxLength: 64
          minLength: 1
          title: Name
        base_url:
          type: string
          maxLength: 2083
          minLength: 1
          format: uri
          title: Base Url
        api_key:
          type: string
          maxLength: 512
          minLength: 1
          title: Api Key
        target_model:
          type: string
          maxLength: 128
          minLength: 1
          title: Target Model
        provider_type:
          type: string
          const: anthropic
          title: Provider Type
          default: anthropic
        client_model_alias:
          anyOf:
          - type: string
            maxLength: 160
            minLength: 1
          - type: 'null'
          title: Client Model Alias
        thinking_mode:
          type: string
          enum:
          - auto
          - passthrough
          - strip
          title: Thinking Mode
          default: auto
      type: object
      required:
      - name
      - base_url
      - api_key
      - target_model
      title: ProviderCreate
      description: 'Body for ``POST /v1/smart-routing/providers``.


        ``api_key`` is plaintext on input and is encrypted server-side via

        Fernet before the row hits the DB. ``provider_type`` is currently

        fixed to ``"anthropic"`` — the field is reserved for future

        transports (OpenAI, Bedrock) without a schema migration.


        ``client_model_alias`` is the optional model name the user types in

        their client (e.g. ``deepseek-v4-flash[1m]``). When set, the

        passthrough router rewrites incoming ``model`` requests carrying this

        alias to the provider''s real ``target_model`` before forwarding

        upstream. Unset (``None``) disables the rewrite. Capped at 160 chars

        to match the DB column.


        ``thinking_mode`` defaults to ``"auto"`` — the gateway picks

        ``passthrough`` or ``strip`` based on ``base_url``. Operators can

        pin the value to override the heuristic.'
    ProviderPreset:
      properties:
        id:
          type: string
          title: Id
        label:
          type: string
          title: Label
        base_url:
          type: string
          title: Base Url
        target_model:
          anyOf:
          - type: string
          - type: 'null'
          title: Target Model
        model_locked:
          type: boolean
          title: Model Locked
        reveal_url:
          type: boolean
          title: Reveal Url
        client_model_alias:
          anyOf:
          - type: string
          - type: 'null'
          title: Client Model Alias
      type: object
      required:
      - id
      - label
      - base_url
      - target_model
      - model_locked
      - reveal_url
      title: ProviderPreset
      description: "One row in the dropdown the UI renders on the provider-create\
        \ form.\n\nThe catalogue is owned by the backend (see\n:mod:`app.services.routing.presets`)\
        \ so the internal vLLM URL +\nlocked model name stay in lockstep with what\
        \ is actually deployed —\nthe frontend should never hardcode infrastructure-shaped\
        \ strings.\n\nField semantics:\n\n* ``base_url`` — canonical URL for the preset.\
        \ Empty string for the\n  ``custom`` row, which means \"let the user type\
        \ one in\".\n* ``target_model`` — locked model name when ``model_locked=True``,\n\
        \  otherwise ``None`` (the user picks a model in the form).\n* ``reveal_url``\
        \ — UI toggle for whether to show the URL field.\n  ``False`` for the ``internal-vllm``\
        \ row to keep the bridge URL out\n  of casual sight; the value is still hardcoded\
        \ here, this is purely\n  a presentation hint.\n* ``client_model_alias`` —\
        \ suggested SDK-facing model id the\n  frontend should auto-fill into the\
        \ provider's ``client_model_alias``\n  field on preset selection. ``None``\
        \ means \"leave it blank\" (the\n  catch-all v6.2 behaviour). Currently populated\
        \ only for known\n  1M-context DeepSeek presets so the Anthropic Agent SDK\
        \ reasons\n  about a 1M token window even though the upstream model id stays\n\
        \  clean (gateway rewrites ``body.model = provider.target_model``\n  before\
        \ forwarding)."
    ProviderPresetsResponse:
      properties:
        data:
          items:
            $ref: '#/components/schemas/ProviderPreset'
          type: array
          title: Data
      type: object
      required:
      - data
      title: ProviderPresetsResponse
      description: Wrapper for ``GET /v1/smart-routing/provider-presets``.
    ProviderRead:
      properties:
        id:
          type: integer
          title: Id
        user_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: User Id
        name:
          type: string
          title: Name
        base_url:
          type: string
          title: Base Url
        target_model:
          type: string
          title: Target Model
        provider_type:
          type: string
          title: Provider Type
        is_active:
          type: boolean
          title: Is Active
        has_api_key:
          type: boolean
          title: Has Api Key
        client_model_alias:
          anyOf:
          - type: string
          - type: 'null'
          title: Client Model Alias
        thinking_mode:
          type: string
          enum:
          - auto
          - passthrough
          - strip
          title: Thinking Mode
          default: auto
        created_at:
          type: string
          format: date-time
          title: Created At
        updated_at:
          type: string
          format: date-time
          title: Updated At
      type: object
      required:
      - id
      - user_id
      - name
      - base_url
      - target_model
      - provider_type
      - is_active
      - has_api_key
      - created_at
      - updated_at
      title: ProviderRead
      description: 'Public provider DTO. NEVER includes the ciphertext or plaintext
        key.


        ``has_api_key`` is computed (``api_key_ciphertext IS NOT NULL``) and

        lets the UI render a "key configured" badge without revealing the

        secret. ``is_active`` is the single mutex flag enforced by the

        partial unique index ``ix_routing_providers_user_active``.'
    ProviderTestRequest:
      properties:
        message:
          anyOf:
          - type: string
            maxLength: 2000
          - type: 'null'
          title: Message
      type: object
      title: ProviderTestRequest
      description: 'Body for ``POST /v1/smart-routing/providers/{id}/test``.


        ``message`` is the user-facing probe text appended to a minimal

        Anthropic-Messages payload. Empty / missing means "use the default

        smoke prompt baked into the router" — a fixed-string single-line

        OK-probe that exercises auth + sanitization without nudging the

        upstream model into long generations.'
    ProviderTestResponse:
      properties:
        ok:
          type: boolean
          title: Ok
        status_code:
          type: integer
          title: Status Code
        latency_ms:
          type: integer
          title: Latency Ms
        response_excerpt:
          anyOf:
          - type: string
          - type: 'null'
          title: Response Excerpt
        error_type:
          anyOf:
          - type: string
          - type: 'null'
          title: Error Type
        error_message:
          anyOf:
          - type: string
          - type: 'null'
          title: Error Message
      type: object
      required:
      - ok
      - status_code
      - latency_ms
      - response_excerpt
      - error_type
      - error_message
      title: ProviderTestResponse
      description: 'Response for ``POST /v1/smart-routing/providers/{id}/test``.


        Dry-run probe result. Never includes ``Authorization`` headers,

        decrypted ``api_key`` plaintext, or any vault material — the

        excerpt is the upstream JSON body''s own response text, capped

        at ~256 chars. ``error_type`` values mirror the canonical

        routing log set: ``upstream_4xx``, ``upstream_5xx``,

        ``upstream_unreachable``, ``upstream_error``, ``vault_error``,

        ``invalid_request``.'
    ProviderUpdate:
      properties:
        name:
          anyOf:
          - type: string
            maxLength: 64
            minLength: 1
          - type: 'null'
          title: Name
        base_url:
          anyOf:
          - type: string
            maxLength: 2083
            minLength: 1
            format: uri
          - type: 'null'
          title: Base Url
        api_key:
          anyOf:
          - type: string
            maxLength: 512
            minLength: 1
          - type: 'null'
          title: Api Key
        target_model:
          anyOf:
          - type: string
            maxLength: 128
            minLength: 1
          - type: 'null'
          title: Target Model
        provider_type:
          anyOf:
          - type: string
            const: anthropic
          - type: 'null'
          title: Provider Type
        client_model_alias:
          anyOf:
          - type: string
            maxLength: 160
            minLength: 1
          - type: 'null'
          title: Client Model Alias
        thinking_mode:
          anyOf:
          - type: string
            enum:
            - auto
            - passthrough
            - strip
          - type: 'null'
          title: Thinking Mode
      type: object
      title: ProviderUpdate
      description: 'Partial update — every field optional, ``None`` = leave unchanged.


        Sending ``api_key`` rotates the stored ciphertext. There is no

        "clear key" workflow in v1 — the field must be non-empty when set.


        ``client_model_alias`` follows the same "absent = leave unchanged"

        convention as the other Update fields — the router uses

        ``model_dump(exclude_unset=True)`` to distinguish "field omitted"

        from "field explicitly set". To CLEAR a previously-set alias, callers

        should send an explicit ``null`` (which `exclude_unset=True` still

        surfaces, while the field stays absent on routes that don''t touch

        it). Empty strings are rejected via ``min_length=1`` — the canonical

        clear signal is ``null``.'
    ProvisionRequest:
      properties:
        tg_bot_token:
          type: string
          maxLength: 128
          minLength: 1
          pattern: ^\d{6,12}:[A-Za-z0-9_-]{30,}$
          title: Tg Bot Token
        tg_bot_username:
          type: string
          maxLength: 64
          minLength: 1
          title: Tg Bot Username
        assistant_name:
          type: string
          maxLength: 32
          minLength: 1
          title: Assistant Name
        operator_name:
          type: string
          maxLength: 128
          minLength: 1
          title: Operator Name
        operator_tg_jid:
          type: string
          maxLength: 32
          minLength: 1
          pattern: ^-?\d+$
          title: Operator Tg Jid
        operator_email:
          type: string
          maxLength: 254
          minLength: 3
          pattern: ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$
          title: Operator Email
        tz:
          type: string
          maxLength: 64
          minLength: 1
          title: Tz
        brewpage_ns:
          type: string
          maxLength: 64
          minLength: 1
          title: Brewpage Ns
        sdk_model_hint:
          type: string
          maxLength: 128
          minLength: 1
          title: Sdk Model Hint
        hub_token:
          type: string
          maxLength: 512
          minLength: 1
          title: Hub Token
      type: object
      required:
      - tg_bot_token
      - tg_bot_username
      - assistant_name
      - operator_name
      - operator_tg_jid
      - operator_email
      - tz
      - brewpage_ns
      - sdk_model_hint
      - hub_token
      title: ProvisionRequest
    ProvisionResponse:
      properties:
        id:
          type: string
          format: uuid4
          title: Id
        slug:
          type: string
          pattern: ^[a-z][a-z0-9-]{2,30}$
          title: Slug
        state:
          type: string
          enum:
          - provisioning
          - active
          - failed
          - deleting
          title: State
        created_at:
          type: string
          format: date-time
          title: Created At
        last_state_check_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last State Check At
      type: object
      required:
      - id
      - slug
      - state
      - created_at
      title: ProvisionResponse
    RequestLogDetail:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        user_id:
          type: string
          format: uuid
          title: User Id
        provider_id:
          anyOf:
          - type: integer
          - type: 'null'
          title: Provider Id
        provider_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Provider Name
        request_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Request Id
        request_at:
          type: string
          format: date-time
          title: Request At
        request_method:
          type: string
          title: Request Method
        request_path:
          type: string
          title: Request Path
        is_stream:
          type: boolean
          title: Is Stream
        response_status:
          anyOf:
          - type: integer
          - type: 'null'
          title: Response Status
        upstream_latency_ms:
          anyOf:
          - type: integer
          - type: 'null'
          title: Upstream Latency Ms
        error_type:
          anyOf:
          - type: string
          - type: 'null'
          title: Error Type
        completed_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Completed At
        request_headers:
          additionalProperties: true
          type: object
          title: Request Headers
        request_body:
          additionalProperties: true
          type: object
          title: Request Body
        response_headers:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Response Headers
        response_body:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Response Body
        stream_chunks:
          anyOf:
          - items:
              additionalProperties: true
              type: object
            type: array
          - type: 'null'
          title: Stream Chunks
        error_message:
          anyOf:
          - type: string
          - type: 'null'
          title: Error Message
      type: object
      required:
      - id
      - user_id
      - provider_id
      - request_id
      - request_at
      - request_method
      - request_path
      - is_stream
      - response_status
      - upstream_latency_ms
      - error_type
      - completed_at
      - request_headers
      - request_body
      - response_headers
      - response_body
      - stream_chunks
      - error_message
      title: RequestLogDetail
      description: 'Detail DTO with full request/response payloads.


        Headers and bodies are returned exactly as stored — the writer

        (``RequestLogger``) is responsible for redaction at insert time.'
    RequestLogList:
      properties:
        data:
          items:
            $ref: '#/components/schemas/RequestLogSummary'
          type: array
          title: Data
        next_cursor:
          anyOf:
          - type: string
          - type: 'null'
          title: Next Cursor
      type: object
      required:
      - data
      - next_cursor
      title: RequestLogList
      description: 'Paginated list response. ``next_cursor`` is the last seen UUID

        (URL-safe string) or ``None`` when no further pages exist.'
    RequestLogSummary:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        user_id:
          type: string
          format: uuid
          title: User Id
        provider_id:
          anyOf:
          - type: integer
          - type: 'null'
          title: Provider Id
        provider_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Provider Name
        request_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Request Id
        request_at:
          type: string
          format: date-time
          title: Request At
        request_method:
          type: string
          title: Request Method
        request_path:
          type: string
          title: Request Path
        is_stream:
          type: boolean
          title: Is Stream
        response_status:
          anyOf:
          - type: integer
          - type: 'null'
          title: Response Status
        upstream_latency_ms:
          anyOf:
          - type: integer
          - type: 'null'
          title: Upstream Latency Ms
        error_type:
          anyOf:
          - type: string
          - type: 'null'
          title: Error Type
        completed_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Completed At
      type: object
      required:
      - id
      - user_id
      - provider_id
      - request_id
      - request_at
      - request_method
      - request_path
      - is_stream
      - response_status
      - upstream_latency_ms
      - error_type
      - completed_at
      title: RequestLogSummary
      description: 'List-row DTO — small payload, safe to return in bulk.


        Bodies, headers, and stream chunks are stripped; full detail is

        reachable via ``GET /v1/smart-routing/logs/{id}``.'
    ResponseFormat:
      properties:
        type:
          type: string
          enum:
          - text
          - json_object
          - json_schema
          title: Type
          default: text
        json_schema:
          anyOf:
          - $ref: '#/components/schemas/JsonSchemaFormat'
          - type: 'null'
      type: object
      title: ResponseFormat
    RoleUpdate:
      properties:
        role:
          type: string
          enum:
          - admin
          - user
          title: Role
      type: object
      required:
      - role
      title: RoleUpdate
    RoutingLogMaxBodyBytesSetting:
      properties:
        value:
          type: integer
          title: Value
        source:
          type: string
          enum:
          - default
          - override
          title: Source
        default:
          type: integer
          title: Default
      type: object
      required:
      - value
      - source
      - default
      title: RoutingLogMaxBodyBytesSetting
      description: 'Response for the admin body-cap setting endpoints.


        ``value`` is the effective cap currently applied to log writes

        (override when set, env default otherwise). ``source`` distinguishes

        the two so the UI can render an "Active override / Using default"

        badge. ``default`` is the env-supplied baseline — handy for the

        "reset" affordance without forcing the UI to know the env value.'
    RoutingLogMaxBodyBytesUpdate:
      properties:
        value:
          anyOf:
          - type: integer
            maximum: 4194304.0
            minimum: 4096.0
          - type: 'null'
          title: Value
      type: object
      title: RoutingLogMaxBodyBytesUpdate
      description: 'Body for ``PUT /v1/admin/settings/routing-log-max-body-bytes``.


        ``value=None`` deletes the override and reverts to the env default.

        Numeric values are validated against the same 4 KiB..4 MiB bounds

        as ``settings.routing_log_max_body_bytes``.'
    RoutingLogStats:
      properties:
        log_count:
          type: integer
          title: Log Count
        bytes_used:
          type: integer
          title: Bytes Used
        retention_days:
          type: integer
          title: Retention Days
      type: object
      required:
      - log_count
      - bytes_used
      - retention_days
      title: RoutingLogStats
      description: 'Response for ``GET /v1/admin/smart-routing/stats``.


        ``bytes_used`` comes from ``pg_total_relation_size`` so it includes

        the table heap + indexes + TOAST — it is the on-disk footprint, not

        the JSONB-payload byte sum. ``retention_days`` mirrors the GC knob

        so the UI doesn''t need a second round-trip.'
    ScopeCatalogEntry:
      properties:
        name:
          type: string
          maxLength: 64
          minLength: 1
          title: Name
        label:
          type: string
          maxLength: 128
          minLength: 1
          title: Label
        description:
          type: string
          title: Description
        requires_admin:
          type: boolean
          title: Requires Admin
      type: object
      required:
      - name
      - label
      - description
      - requires_admin
      title: ScopeCatalogEntry
    ScopeCatalogResponse:
      properties:
        scopes:
          items:
            $ref: '#/components/schemas/ScopeCatalogEntry'
          type: array
          title: Scopes
      type: object
      required:
      - scopes
      title: ScopeCatalogResponse
    SynthesisResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        voice_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Voice Id
        text:
          type: string
          title: Text
        text_length:
          type: integer
          title: Text Length
        duration_sec:
          anyOf:
          - type: number
          - type: 'null'
          title: Duration Sec
        status:
          type: string
          enum:
          - completed
          - failed
          title: Status
        audio_url:
          type: string
          title: Audio Url
          description: 'Relative path to fetch audio: /v1/voices/syntheses/{id}/audio'
        created_at:
          type: string
          format: date-time
          title: Created At
        expires_at:
          type: string
          format: date-time
          title: Expires At
      type: object
      required:
      - id
      - voice_id
      - text
      - text_length
      - duration_sec
      - status
      - audio_url
      - created_at
      - expires_at
      title: SynthesisResponse
    SynthesizeRequest:
      properties:
        text:
          type: string
          minLength: 1
          title: Text
          description: Text to synthesize
        voice_id:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Voice Id
          description: Voice to use; null → personal default → Automatic
        language:
          anyOf:
          - type: string
            enum:
            - ru
            - en
            - auto
          - type: 'null'
          title: Language
          description: Hint for /tts and /design; ignored for clone
        instruct:
          anyOf:
          - type: string
            maxLength: 500
          - type: 'null'
          title: Instruct
          description: 'OmniVoice /design style tokens — comma-separated from a fixed
            vocabulary. When set, routes to /design instead of /tts or /clone; voice_id
            is ignored. Free-form prose is NOT supported (OmniVoice will 500). Allowed
            English tokens: american accent, australian accent, british accent, canadian
            accent, child, chinese accent, elderly, female, high pitch, indian accent,
            japanese accent, korean accent, low pitch, male, middle-aged, moderate
            pitch, portuguese accent, russian accent, teenager, very high pitch, very
            low pitch, whisper, young adult. Allowed Chinese tokens include: 东北话,
            中年, 中音调, 云南话, 低音调, 儿童 (and more). Example: ''male, low pitch, russian
            accent''.'
      type: object
      required:
      - text
      title: SynthesizeRequest
    SystemInfo:
      properties:
        os:
          $ref: '#/components/schemas/SystemInfoOS'
        cpu:
          $ref: '#/components/schemas/SystemInfoCpu'
        memory:
          $ref: '#/components/schemas/SystemInfoMemory'
        gpu:
          $ref: '#/components/schemas/SystemInfoGpu'
        runtime:
          $ref: '#/components/schemas/SystemInfoRuntime'
        collected_at:
          type: number
          title: Collected At
      type: object
      required:
      - os
      - cpu
      - memory
      - gpu
      - runtime
      - collected_at
      title: SystemInfo
    SystemInfoCpu:
      properties:
        model:
          type: string
          title: Model
        cores_logical:
          type: integer
          title: Cores Logical
        cores_physical:
          type: integer
          title: Cores Physical
        cache_l2_bytes:
          anyOf:
          - type: integer
          - type: 'null'
          title: Cache L2 Bytes
        cache_l3_bytes:
          anyOf:
          - type: integer
          - type: 'null'
          title: Cache L3 Bytes
      type: object
      required:
      - model
      - cores_logical
      - cores_physical
      title: SystemInfoCpu
    SystemInfoGpu:
      properties:
        name:
          anyOf:
          - type: string
          - type: 'null'
          title: Name
        driver_version:
          anyOf:
          - type: string
          - type: 'null'
          title: Driver Version
        cuda_version:
          anyOf:
          - type: string
          - type: 'null'
          title: Cuda Version
        vram_total_bytes:
          anyOf:
          - type: integer
          - type: 'null'
          title: Vram Total Bytes
      type: object
      title: SystemInfoGpu
    SystemInfoMemory:
      properties:
        ram_total_bytes:
          type: integer
          title: Ram Total Bytes
      type: object
      required:
      - ram_total_bytes
      title: SystemInfoMemory
    SystemInfoOS:
      properties:
        name:
          type: string
          title: Name
        version:
          type: string
          title: Version
        pretty:
          type: string
          title: Pretty
        kernel:
          type: string
          title: Kernel
      type: object
      required:
      - name
      - version
      - pretty
      - kernel
      title: SystemInfoOS
    SystemInfoRuntime:
      properties:
        python_version:
          type: string
          title: Python Version
        gateway_version:
          type: string
          title: Gateway Version
      type: object
      required:
      - python_version
      - gateway_version
      title: SystemInfoRuntime
    TokenCreateRequest:
      properties:
        name:
          type: string
          title: Name
        scopes:
          items:
            type: string
          type: array
          title: Scopes
          default:
          - transcribe
        expires_in_days:
          type: integer
          maximum: 365.0
          minimum: 1.0
          title: Expires In Days
          default: 30
      type: object
      required:
      - name
      title: TokenCreateRequest
    TokenCreateResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        name:
          type: string
          title: Name
        token:
          type: string
          title: Token
        scopes:
          items:
            type: string
          type: array
          title: Scopes
        expires_at:
          type: string
          format: date-time
          title: Expires At
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - name
      - token
      - scopes
      - expires_at
      - created_at
      title: TokenCreateResponse
    TokenListItem:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        name:
          type: string
          title: Name
        scopes:
          items:
            type: string
          type: array
          title: Scopes
        expires_at:
          type: string
          format: date-time
          title: Expires At
        last_used_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Last Used At
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - name
      - scopes
      - expires_at
      - created_at
      title: TokenListItem
    TokenListResponse:
      properties:
        tokens:
          items:
            $ref: '#/components/schemas/TokenListItem'
          type: array
          title: Tokens
      type: object
      required:
      - tokens
      title: TokenListResponse
    TokenizeRequest:
      properties:
        text:
          type: string
          title: Text
      type: object
      required:
      - text
      title: TokenizeRequest
    TokenizeResponse:
      properties:
        token_count:
          type: integer
          title: Token Count
        model:
          type: string
          title: Model
          default: heuristic
      type: object
      required:
      - token_count
      title: TokenizeResponse
    ToolCall:
      properties:
        id:
          type: string
          title: Id
        type:
          type: string
          const: function
          title: Type
          default: function
        function:
          $ref: '#/components/schemas/ToolCallFunction'
      type: object
      required:
      - id
      - function
      title: ToolCall
    ToolCallFunction:
      properties:
        name:
          type: string
          title: Name
        arguments:
          type: string
          title: Arguments
      type: object
      required:
      - name
      - arguments
      title: ToolCallFunction
    TranscriptionAccepted:
      properties:
        run_id:
          type: string
          format: uuid
          title: Run Id
        status:
          type: string
          const: processing
          title: Status
          default: processing
      type: object
      required:
      - run_id
      title: TranscriptionAccepted
    UploadChunkResponse:
      properties:
        batch_id:
          type: string
          format: uuid
          title: Batch Id
        chunk_index:
          type: integer
          title: Chunk Index
        chunk_run_id:
          type: string
          format: uuid
          title: Chunk Run Id
        status:
          type: string
          const: processing
          title: Status
          default: processing
      type: object
      required:
      - batch_id
      - chunk_index
      - chunk_run_id
      title: UploadChunkResponse
    UsageSnapshot:
      properties:
        chat_requests:
          type: integer
          title: Chat Requests
        transcription_requests:
          type: integer
          title: Transcription Requests
        transcription_seconds:
          type: integer
          title: Transcription Seconds
        image_requests:
          type: integer
          title: Image Requests
        window_seconds:
          type: integer
          title: Window Seconds
      type: object
      required:
      - chat_requests
      - transcription_requests
      - transcription_seconds
      - image_requests
      - window_seconds
      title: UsageSnapshot
    UserInfo:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        email:
          type: string
          title: Email
        name:
          type: string
          title: Name
        role:
          type: string
          enum:
          - admin
          - user
          title: Role
        status:
          type: string
          enum:
          - pending
          - approved
          - rejected
          title: Status
      type: object
      required:
      - id
      - email
      - name
      - role
      - status
      title: UserInfo
    UserLimitsDTO:
      properties:
        policy:
          $ref: '#/components/schemas/PolicyDTO'
        usage:
          $ref: '#/components/schemas/UsageSnapshot'
        is_admin:
          type: boolean
          title: Is Admin
      type: object
      required:
      - policy
      - usage
      - is_admin
      title: UserLimitsDTO
      description: 'Response for `GET /v1/users/me/limits`. `is_admin=true` means
        the

        service layer short-circuits limit checks for this user — the policy

        numbers are informational only in that case.'
    UserListItem:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        email:
          type: string
          title: Email
        name:
          type: string
          title: Name
        role:
          type: string
          enum:
          - admin
          - user
          title: Role
        status:
          type: string
          enum:
          - pending
          - approved
          - rejected
          title: Status
        auth_provider:
          type: string
          enum:
          - local
          - google
          title: Auth Provider
        created_at:
          type: string
          format: date-time
          title: Created At
      type: object
      required:
      - id
      - email
      - name
      - role
      - status
      - auth_provider
      - created_at
      title: UserListItem
    UserListResponse:
      properties:
        users:
          items:
            $ref: '#/components/schemas/UserListItem'
          type: array
          title: Users
      type: object
      required:
      - users
      title: UserListResponse
    UserOverrideDTO:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
        user_email:
          type: string
          title: User Email
        user_name:
          anyOf:
          - type: string
          - type: 'null'
          title: User Name
        chat_per_hour:
          type: integer
          title: Chat Per Hour
        transcription_requests_per_hour:
          type: integer
          title: Transcription Requests Per Hour
        transcription_seconds_per_hour:
          type: integer
          title: Transcription Seconds Per Hour
        image_per_hour:
          type: integer
          title: Image Per Hour
        tts_daily_chars:
          type: integer
          title: Tts Daily Chars
        tts_request_chars:
          type: integer
          title: Tts Request Chars
        provider_test_per_hour:
          type: integer
          title: Provider Test Per Hour
        anthropic_messages_per_minute:
          type: integer
          title: Anthropic Messages Per Minute
        updated_at:
          type: string
          format: date-time
          title: Updated At
      type: object
      required:
      - user_id
      - user_email
      - user_name
      - chat_per_hour
      - transcription_requests_per_hour
      - transcription_seconds_per_hour
      - image_per_hour
      - tts_daily_chars
      - tts_request_chars
      - provider_test_per_hour
      - anthropic_messages_per_minute
      - updated_at
      title: UserOverrideDTO
    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
    VoiceResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        name:
          type: string
          title: Name
          description: Human-readable voice name
        duration_sec:
          anyOf:
          - type: number
          - type: 'null'
          title: Duration Sec
          description: Reference audio duration in seconds; null for Automatic
        sample_rate:
          anyOf:
          - type: integer
          - type: 'null'
          title: Sample Rate
          description: Reference audio sample rate; null for Automatic
        is_default:
          type: boolean
          title: Is Default
          description: Featured (system) or personal default (owner)
        is_system:
          type: boolean
          title: Is System
          description: True if user_id IS NULL
        is_valid:
          type: boolean
          title: Is Valid
          description: False when reference file is missing on disk
        invalidated_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Invalidated At
        created_at:
          type: string
          format: date-time
          title: Created At
        updated_at:
          type: string
          format: date-time
          title: Updated At
      type: object
      required:
      - id
      - name
      - is_default
      - is_system
      - is_valid
      - created_at
      - updated_at
      title: VoiceResponse
    VoiceSystemDefaultUpdate:
      properties:
        is_default:
          type: boolean
          title: Is Default
      type: object
      required:
      - is_default
      title: VoiceSystemDefaultUpdate
    VoiceUpdate:
      properties:
        name:
          anyOf:
          - type: string
            maxLength: 255
          - type: 'null'
          title: Name
        is_default:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Is Default
      type: object
      title: VoiceUpdate
    VoicesQuota:
      properties:
        used:
          type: integer
          title: Used
          description: Characters used in the trailing 24h (completed syntheses)
        limit:
          type: integer
          title: Limit
          description: Daily char budget; 0 means unlimited (admin)
        request_limit:
          type: integer
          title: Request Limit
          description: Per-request char cap; 0 means unlimited (admin)
        resets_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Resets At
          description: When the oldest counted synthesis rolls out of the 24h window
      type: object
      required:
      - used
      - limit
      - request_limit
      title: VoicesQuota
  securitySchemes:
    APIKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key
      description: API token with sh- prefix
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT access token
security:
- APIKeyHeader: []
- BearerAuth: []
