openapi: 3.1.0
info:
  title: Open Agent Harness API
  version: 0.1.0
  summary: Headless distributed agent runtime API
  description: >
    Open Agent Harness is a headless agent runtime for multi-workspace,
    distributed usage. Identity, membership, and authentication are expected
    to be managed by an external service or upstream gateway. This document
    defines the HTTP API for workspace management, session messaging, run
    lifecycle, action invocation, and SSE event streaming.
servers:
  - url: http://localhost:3000/api/v1
    description: Local development
tags:
  - name: Workspaces
  - name: Files
  - name: Catalog
  - name: Models
  - name: Sessions
  - name: Messages
  - name: Runs
  - name: Actions
  - name: Events
paths:
  /workspace-templates:
    get:
      tags: [Workspaces]
      summary: List workspace templates
      operationId: listWorkspaceTemplates
      responses:
        '200':
          description: Workspace template list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceTemplateList'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /model-providers:
    get:
      tags: [Models]
      summary: List supported model providers
      operationId: listModelProviders
      responses:
        '200':
          description: Supported model provider list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ModelProviderList'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces:
    get:
      tags: [Workspaces]
      summary: List workspaces
      operationId: listWorkspaces
      parameters:
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/Cursor'
      responses:
        '200':
          description: Workspace page
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspacePage'
        default:
          $ref: '#/components/responses/ErrorResponse'
    post:
      tags: [Workspaces]
      summary: Create workspace
      operationId: createWorkspace
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWorkspaceRequest'
      responses:
        '201':
          description: Workspace created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Workspace'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/import:
    post:
      tags: [Workspaces]
      summary: Import an existing workspace directory
      operationId: importWorkspace
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkspaceImportRequest'
      responses:
        '201':
          description: Workspace imported
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Workspace'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/{workspaceId}:
    get:
      tags: [Workspaces]
      summary: Get workspace
      operationId: getWorkspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
      responses:
        '200':
          description: Workspace metadata
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Workspace'
        default:
          $ref: '#/components/responses/ErrorResponse'
    delete:
      tags: [Workspaces]
      summary: Delete workspace
      operationId: deleteWorkspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
      responses:
        '204':
          description: Workspace deleted
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/{workspaceId}/history-mirror:
    get:
      tags: [Workspaces]
      summary: Get workspace history mirror status
      operationId: getWorkspaceHistoryMirrorStatus
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
      responses:
        '200':
          description: Workspace history mirror status
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceHistoryMirrorStatus'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/{workspaceId}/history-mirror/rebuild:
    post:
      tags: [Workspaces]
      summary: Rebuild workspace history mirror
      operationId: rebuildWorkspaceHistoryMirror
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
      responses:
        '200':
          description: Rebuilt workspace history mirror status
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceHistoryMirrorStatus'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/{workspaceId}/catalog:
    get:
      tags: [Catalog]
      summary: Get workspace catalog
      operationId: getWorkspaceCatalog
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
      responses:
        '200':
          description: Workspace-discovered capabilities
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceCatalog'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/{workspaceId}/entries:
    get:
      tags: [Files]
      summary: List direct children of a workspace directory
      operationId: listWorkspaceEntries
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
        - $ref: '#/components/parameters/DirectoryPathQuery'
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/Cursor'
        - $ref: '#/components/parameters/EntrySortBy'
        - $ref: '#/components/parameters/SortOrder'
      responses:
        '200':
          description: Directory entry page
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceEntryPage'
        default:
          $ref: '#/components/responses/ErrorResponse'
    delete:
      tags: [Files]
      summary: Delete a workspace file or directory
      operationId: deleteWorkspaceEntry
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
        - $ref: '#/components/parameters/EntryPathQuery'
        - $ref: '#/components/parameters/Recursive'
      responses:
        '200':
          description: Entry deleted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceDeleteResult'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/{workspaceId}/entries/move:
    patch:
      tags: [Files]
      summary: Rename or move a workspace file or directory
      operationId: moveWorkspaceEntry
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MoveWorkspaceEntryRequest'
      responses:
        '200':
          description: Entry moved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceEntry'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/{workspaceId}/files/content:
    get:
      tags: [Files]
      summary: Read workspace file content
      operationId: getWorkspaceFileContent
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
        - $ref: '#/components/parameters/EntryPathQuery'
        - $ref: '#/components/parameters/FileEncoding'
        - $ref: '#/components/parameters/MaxBytes'
      responses:
        '200':
          description: File content
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceFileContent'
        default:
          $ref: '#/components/responses/ErrorResponse'
    put:
      tags: [Files]
      summary: Create or overwrite workspace file content
      operationId: putWorkspaceFileContent
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PutWorkspaceFileRequest'
      responses:
        '200':
          description: File written
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceEntry'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/{workspaceId}/files/upload:
    put:
      tags: [Files]
      summary: Upload raw file bytes into a workspace path
      operationId: uploadWorkspaceFile
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
        - $ref: '#/components/parameters/EntryPathQuery'
      requestBody:
        required: true
        content:
          application/octet-stream:
            schema:
              type: string
              format: binary
      responses:
        '200':
          description: File uploaded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceEntry'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/{workspaceId}/files/download:
    get:
      tags: [Files]
      summary: Download raw file bytes from a workspace path
      operationId: downloadWorkspaceFile
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
        - $ref: '#/components/parameters/EntryPathQuery'
      responses:
        '200':
          description: File download
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/{workspaceId}/directories:
    post:
      tags: [Files]
      summary: Create a workspace directory
      operationId: createWorkspaceDirectory
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWorkspaceDirectoryRequest'
      responses:
        '201':
          description: Directory created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceEntry'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/{workspaceId}/sessions:
    get:
      tags: [Sessions]
      summary: List workspace sessions
      operationId: listWorkspaceSessions
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/Cursor'
      responses:
        '200':
          description: Session page for a workspace
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SessionPage'
        default:
          $ref: '#/components/responses/ErrorResponse'
    post:
      tags: [Sessions]
      summary: Create session
      operationId: createSession
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSessionRequest'
      responses:
        '201':
          description: Session created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Session'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /workspaces/{workspaceId}/actions/{actionName}/runs:
    post:
      tags: [Actions]
      summary: Trigger action run
      operationId: triggerActionRun
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
        - $ref: '#/components/parameters/ActionName'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateActionRunRequest'
      responses:
        '202':
          description: Action run accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ActionRunAccepted'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /internal/v1/models/generate:
    post:
      tags: [Models]
      summary: Generate text with an internal platform model
      description: >
        Internal local-only model gateway for actions, scripts, and the `oah model`
        CLI. This endpoint is only available from loopback addresses and is not
        intended for external clients or public network exposure.
      operationId: internalGenerateModel
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ModelGenerateRequest'
      responses:
        '200':
          description: Model generation result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ModelGenerateResponse'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /internal/v1/models/stream:
    post:
      tags: [Models]
      summary: Stream text with an internal platform model
      description: >
        Internal local-only model gateway for actions, scripts, and the `oah model`
        CLI. This endpoint is only available from loopback addresses and is not
        intended for external clients or public network exposure.
      operationId: internalStreamModel
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ModelStreamRequest'
      responses:
        '200':
          description: Server-Sent Events stream
          content:
            text/event-stream:
              schema:
                type: string
                description: SSE stream of model response events
              examples:
                started:
                  summary: Response started event
                  value: |
                    event: response.started
                    data: {"model":"openai-default"}
                delta:
                  summary: Text delta event
                  value: |
                    event: text.delta
                    data: {"delta":"hello"}
                completed:
                  summary: Response completed event
                  value: |
                    event: response.completed
                    data: {"model":"openai-default","finishReason":"stop"}
        default:
          $ref: '#/components/responses/ErrorResponse'
  /sessions/{sessionId}:
    get:
      tags: [Sessions]
      summary: Get session
      operationId: getSession
      parameters:
        - $ref: '#/components/parameters/SessionId'
      responses:
        '200':
          description: Session metadata
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Session'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /sessions/{sessionId}/messages:
    get:
      tags: [Messages]
      summary: List session messages
      operationId: listSessionMessages
      parameters:
        - $ref: '#/components/parameters/SessionId'
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/Cursor'
      responses:
        '200':
          description: Message page
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessagePage'
        default:
          $ref: '#/components/responses/ErrorResponse'
    post:
      tags: [Messages]
      summary: Create session message and enqueue run
      operationId: createSessionMessage
      parameters:
        - $ref: '#/components/parameters/SessionId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateMessageRequest'
      responses:
        '202':
          description: Message accepted and run enqueued
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageAccepted'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /sessions/{sessionId}/events:
    get:
      tags: [Events]
      summary: Subscribe to session SSE events
      operationId: streamSessionEvents
      parameters:
        - $ref: '#/components/parameters/SessionId'
        - $ref: '#/components/parameters/RunIdQuery'
        - $ref: '#/components/parameters/Cursor'
      responses:
        '200':
          description: Server-Sent Events stream
          content:
            text/event-stream:
              schema:
                type: string
                description: SSE stream of session and run events
              examples:
                runStarted:
                  summary: Run started event
                  value: |
                    event: run.started
                    data: {"runId":"run_123","sessionId":"ses_123","status":"running"}
                tokenDelta:
                  summary: Token delta event
                  value: |
                    event: message.delta
                    data: {"runId":"run_123","messageId":"msg_456","delta":"hello"}
                toolCompleted:
                  summary: Tool completed event
                  value: |
                    event: tool.completed
                    data: {"runId":"run_123","callId":"tc_001","toolName":"code.review","sourceType":"action"}
        default:
          $ref: '#/components/responses/ErrorResponse'
  /runs/{runId}:
    get:
      tags: [Runs]
      summary: Get run
      operationId: getRun
      parameters:
        - $ref: '#/components/parameters/RunId'
      responses:
        '200':
          description: Run state
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Run'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /runs/{runId}/steps:
    get:
      tags: [Runs]
      summary: List run steps
      operationId: listRunSteps
      parameters:
        - $ref: '#/components/parameters/RunId'
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/Cursor'
      responses:
        '200':
          description: Run step page
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunStepPage'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /runs/{runId}/cancel:
    post:
      tags: [Runs]
      summary: Cancel run
      operationId: cancelRun
      parameters:
        - $ref: '#/components/parameters/RunId'
      responses:
        '202':
          description: Cancellation requested
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CancelRunAccepted'
        default:
          $ref: '#/components/responses/ErrorResponse'
components:
  parameters:
    WorkspaceId:
      name: workspaceId
      in: path
      required: true
      schema:
        type: string
    SessionId:
      name: sessionId
      in: path
      required: true
      schema:
        type: string
    RunId:
      name: runId
      in: path
      required: true
      schema:
        type: string
    ActionName:
      name: actionName
      in: path
      required: true
      schema:
        type: string
    PageSize:
      name: pageSize
      in: query
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 200
        default: 50
    Cursor:
      name: cursor
      in: query
      required: false
      schema:
        type: string
    DirectoryPathQuery:
      name: path
      in: query
      required: false
      schema:
        type: string
        default: .
    EntryPathQuery:
      name: path
      in: query
      required: true
      schema:
        type: string
        minLength: 1
    EntrySortBy:
      name: sortBy
      in: query
      required: false
      schema:
        type: string
        enum: [name, updatedAt, sizeBytes, type]
        default: name
    SortOrder:
      name: sortOrder
      in: query
      required: false
      schema:
        type: string
        enum: [asc, desc]
        default: asc
    Recursive:
      name: recursive
      in: query
      required: false
      schema:
        type: boolean
        default: false
    FileEncoding:
      name: encoding
      in: query
      required: false
      schema:
        type: string
        enum: [utf8, base64]
        default: utf8
    MaxBytes:
      name: maxBytes
      in: query
      required: false
      schema:
        type: integer
        minimum: 1
    RunIdQuery:
      name: runId
      in: query
      required: false
      schema:
        type: string
  responses:
    ErrorResponse:
      description: Error response
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  schemas:
    Timestamp:
      type: string
      format: date-time
    JsonObject:
      type: object
      additionalProperties: true
    WorkspaceTemplate:
      type: object
      required: [name]
      properties:
        name:
          type: string
    WorkspaceTemplateList:
      type: object
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/WorkspaceTemplate'
    ModelProvider:
      type: object
      required:
        - id
        - packageName
        - description
        - requiresUrl
        - useCases
      properties:
        id:
          type: string
          enum: [openai, openai-compatible]
        packageName:
          type: string
        description:
          type: string
        requiresUrl:
          type: boolean
        useCases:
          type: array
          items:
            type: string
      additionalProperties: false
    ModelProviderList:
      type: object
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/ModelProvider'
      additionalProperties: false
    Workspace:
      type: object
      required:
        - id
        - name
        - rootPath
        - executionPolicy
        - status
        - kind
        - readOnly
        - historyMirrorEnabled
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
        externalRef:
          type: string
        name:
          type: string
        rootPath:
          type: string
        executionPolicy:
          type: string
          enum: [local, container, remote_runner]
        status:
          type: string
          enum: [active, archived, disabled]
        kind:
          type: string
          enum: [project, chat]
        readOnly:
          type: boolean
        historyMirrorEnabled:
          type: boolean
        createdAt:
          $ref: '#/components/schemas/Timestamp'
        updatedAt:
          $ref: '#/components/schemas/Timestamp'
    WorkspacePage:
      type: object
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Workspace'
        nextCursor:
          type: string
    WorkspaceEntry:
      type: object
      required:
        - path
        - name
        - type
        - readOnly
      properties:
        path:
          type: string
        name:
          type: string
        type:
          type: string
          enum: [file, directory]
        sizeBytes:
          type: integer
          minimum: 0
        mimeType:
          type: string
        etag:
          type: string
        updatedAt:
          $ref: '#/components/schemas/Timestamp'
        createdAt:
          $ref: '#/components/schemas/Timestamp'
        readOnly:
          type: boolean
      additionalProperties: false
    WorkspaceEntryPage:
      type: object
      required:
        - workspaceId
        - path
        - items
      properties:
        workspaceId:
          type: string
        path:
          type: string
        items:
          type: array
          items:
            $ref: '#/components/schemas/WorkspaceEntry'
        nextCursor:
          type: string
      additionalProperties: false
    WorkspaceFileContent:
      type: object
      required:
        - workspaceId
        - path
        - encoding
        - content
        - truncated
        - readOnly
      properties:
        workspaceId:
          type: string
        path:
          type: string
        encoding:
          type: string
          enum: [utf8, base64]
        content:
          type: string
        truncated:
          type: boolean
        sizeBytes:
          type: integer
          minimum: 0
        mimeType:
          type: string
        etag:
          type: string
        updatedAt:
          $ref: '#/components/schemas/Timestamp'
        readOnly:
          type: boolean
      additionalProperties: false
    WorkspaceDeleteResult:
      type: object
      required:
        - workspaceId
        - path
        - type
        - deleted
      properties:
        workspaceId:
          type: string
        path:
          type: string
        type:
          type: string
          enum: [file, directory]
        deleted:
          type: boolean
      additionalProperties: false
    WorkspaceHistoryMirrorStatus:
      type: object
      required:
        - workspaceId
        - supported
        - enabled
        - state
      properties:
        workspaceId:
          type: string
        supported:
          type: boolean
        enabled:
          type: boolean
        dbPath:
          type: string
        state:
          type: string
          enum: [unsupported, disabled, missing, idle, error]
        lastEventId:
          type: integer
        lastSyncedAt:
          $ref: '#/components/schemas/Timestamp'
        errorMessage:
          type: string
      additionalProperties: false
    AgentCatalogItem:
      type: object
      required: [name, source]
      properties:
        name:
          type: string
        source:
          type: string
          enum: [platform, workspace]
        description:
          type: string
    ModelCatalogItem:
      type: object
      required: [ref, name, source, provider]
      properties:
        ref:
          type: string
          pattern: '^(platform|workspace)/.+$'
        name:
          type: string
        source:
          type: string
          enum: [platform, workspace]
        provider:
          type: string
        modelName:
          type: string
        url:
          type: string
    ChatMessage:
      oneOf:
        - $ref: '#/components/schemas/SystemChatMessage'
        - $ref: '#/components/schemas/UserChatMessage'
        - $ref: '#/components/schemas/AssistantChatMessage'
        - $ref: '#/components/schemas/ToolChatMessage'
    SystemChatMessage:
      type: object
      required: [role, content]
      properties:
        role:
          type: string
          enum: [system]
        content:
          type: string
      additionalProperties: false
    UserChatMessage:
      type: object
      required: [role, content]
      properties:
        role:
          type: string
          enum: [user]
        content:
          oneOf:
            - type: string
            - type: array
              items:
                oneOf:
                  - $ref: '#/components/schemas/TextMessagePart'
                  - $ref: '#/components/schemas/ImageMessagePart'
                  - $ref: '#/components/schemas/FileMessagePart'
      additionalProperties: false
    AssistantChatMessage:
      type: object
      required: [role, content]
      properties:
        role:
          type: string
          enum: [assistant]
        content:
          oneOf:
            - type: string
            - type: array
              items:
                oneOf:
                  - $ref: '#/components/schemas/TextMessagePart'
                  - $ref: '#/components/schemas/FileMessagePart'
                  - $ref: '#/components/schemas/ReasoningMessagePart'
                  - $ref: '#/components/schemas/ToolCallMessagePart'
                  - $ref: '#/components/schemas/ToolResultMessagePart'
                  - $ref: '#/components/schemas/ToolApprovalRequestMessagePart'
      additionalProperties: false
    ToolChatMessage:
      type: object
      required: [role, content]
      properties:
        role:
          type: string
          enum: [tool]
        content:
          type: array
          items:
            oneOf:
              - $ref: '#/components/schemas/ToolResultMessagePart'
              - $ref: '#/components/schemas/ToolApprovalResponseMessagePart'
      additionalProperties: false
    MessagePart:
      oneOf:
        - $ref: '#/components/schemas/TextMessagePart'
        - $ref: '#/components/schemas/ImageMessagePart'
        - $ref: '#/components/schemas/FileMessagePart'
        - $ref: '#/components/schemas/ReasoningMessagePart'
        - $ref: '#/components/schemas/ToolCallMessagePart'
        - $ref: '#/components/schemas/ToolResultMessagePart'
        - $ref: '#/components/schemas/ToolApprovalRequestMessagePart'
        - $ref: '#/components/schemas/ToolApprovalResponseMessagePart'
    TextMessagePart:
      type: object
      required: [type, text]
      properties:
        type:
          type: string
          enum: [text]
        text:
          type: string
        providerOptions:
          $ref: '#/components/schemas/JsonObject'
      additionalProperties: false
    ImageMessagePart:
      type: object
      required: [type, image]
      properties:
        type:
          type: string
          enum: [image]
        image:
          type: string
        mediaType:
          type: string
        providerOptions:
          $ref: '#/components/schemas/JsonObject'
      additionalProperties: false
    FileMessagePart:
      type: object
      required: [type, data, mediaType]
      properties:
        type:
          type: string
          enum: [file]
        data:
          type: string
        filename:
          type: string
        mediaType:
          type: string
        providerOptions:
          $ref: '#/components/schemas/JsonObject'
      additionalProperties: false
    ReasoningMessagePart:
      type: object
      required: [type, text]
      properties:
        type:
          type: string
          enum: [reasoning]
        text:
          type: string
        providerOptions:
          $ref: '#/components/schemas/JsonObject'
      additionalProperties: false
    ToolCallMessagePart:
      type: object
      required: [type, toolCallId, toolName, input]
      properties:
        type:
          type: string
          enum: [tool-call]
        toolCallId:
          type: string
        toolName:
          type: string
        input: {}
        providerExecuted:
          type: boolean
        providerOptions:
          $ref: '#/components/schemas/JsonObject'
      additionalProperties: false
    ToolResultOutput:
      oneOf:
        - type: object
          required: [type, value]
          properties:
            type:
              type: string
              enum: [text]
            value:
              type: string
            providerOptions:
              $ref: '#/components/schemas/JsonObject'
          additionalProperties: false
        - type: object
          required: [type, value]
          properties:
            type:
              type: string
              enum: [json]
            value: {}
            providerOptions:
              $ref: '#/components/schemas/JsonObject'
          additionalProperties: false
        - type: object
          required: [type]
          properties:
            type:
              type: string
              enum: [execution-denied]
            reason:
              type: string
            providerOptions:
              $ref: '#/components/schemas/JsonObject'
          additionalProperties: false
        - type: object
          required: [type, value]
          properties:
            type:
              type: string
              enum: [error-text]
            value:
              type: string
            providerOptions:
              $ref: '#/components/schemas/JsonObject'
          additionalProperties: false
        - type: object
          required: [type, value]
          properties:
            type:
              type: string
              enum: [error-json]
            value: {}
            providerOptions:
              $ref: '#/components/schemas/JsonObject'
          additionalProperties: false
        - type: object
          required: [type, value]
          properties:
            type:
              type: string
              enum: [content]
            value:
              type: array
              items: {}
          additionalProperties: false
    ToolResultMessagePart:
      type: object
      required: [type, toolCallId, toolName, output]
      properties:
        type:
          type: string
          enum: [tool-result]
        toolCallId:
          type: string
        toolName:
          type: string
        output:
          $ref: '#/components/schemas/ToolResultOutput'
        providerOptions:
          $ref: '#/components/schemas/JsonObject'
      additionalProperties: false
    ToolApprovalRequestMessagePart:
      type: object
      required: [type, approvalId, toolCallId]
      properties:
        type:
          type: string
          enum: [tool-approval-request]
        approvalId:
          type: string
        toolCallId:
          type: string
      additionalProperties: false
    ToolApprovalResponseMessagePart:
      type: object
      required: [type, approvalId, approved]
      properties:
        type:
          type: string
          enum: [tool-approval-response]
        approvalId:
          type: string
        approved:
          type: boolean
        reason:
          type: string
        providerExecuted:
          type: boolean
      additionalProperties: false
    Usage:
      type: object
      properties:
        inputTokens:
          type: integer
          minimum: 0
        outputTokens:
          type: integer
          minimum: 0
        totalTokens:
          type: integer
          minimum: 0
      additionalProperties: false
    ActionCatalogItem:
      type: object
      required: [name]
      properties:
        name:
          type: string
        description:
          type: string
        exposeToLlm:
          type: boolean
        callableByUser:
          type: boolean
        callableByApi:
          type: boolean
        retryPolicy:
          type: string
          enum: [manual, safe]
    SkillCatalogItem:
      type: object
      required: [name]
      properties:
        name:
          type: string
        description:
          type: string
        exposeToLlm:
          type: boolean
    ToolCatalogItem:
      type: object
      required: [name]
      properties:
        name:
          type: string
        transportType:
          type: string
        toolPrefix:
          type: string
    HookCatalogItem:
      type: object
      required: [name]
      properties:
        name:
          type: string
        matcher:
          type: string
        handlerType:
          type: string
          enum: [command, http, prompt, agent]
        events:
          type: array
          items:
            type: string
    WorkspaceCatalog:
      type: object
      required:
        - workspaceId
        - agents
        - models
        - actions
        - skills
        - tools
        - hooks
        - nativeTools
      properties:
        workspaceId:
          type: string
        agents:
          type: array
          items:
            $ref: '#/components/schemas/AgentCatalogItem'
        models:
          type: array
          items:
            $ref: '#/components/schemas/ModelCatalogItem'
        actions:
          type: array
          items:
            $ref: '#/components/schemas/ActionCatalogItem'
        skills:
          type: array
          items:
            $ref: '#/components/schemas/SkillCatalogItem'
        tools:
          type: array
          items:
            $ref: '#/components/schemas/ToolCatalogItem'
        hooks:
          type: array
          items:
            $ref: '#/components/schemas/HookCatalogItem'
        nativeTools:
          type: array
          items:
            type: string
    Session:
      type: object
      required:
        - id
        - workspaceId
        - subjectRef
        - activeAgentName
        - status
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
        workspaceId:
          type: string
        subjectRef:
          type: string
        agentName:
          type: string
        activeAgentName:
          type: string
        title:
          type: string
        status:
          type: string
          enum: [active, archived, closed]
        lastRunAt:
          $ref: '#/components/schemas/Timestamp'
        createdAt:
          $ref: '#/components/schemas/Timestamp'
        updatedAt:
          $ref: '#/components/schemas/Timestamp'
    SessionPage:
      type: object
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Session'
        nextCursor:
          type: string
    Message:
      allOf:
        - oneOf:
            - $ref: '#/components/schemas/SystemChatMessage'
            - $ref: '#/components/schemas/UserChatMessage'
            - $ref: '#/components/schemas/AssistantChatMessage'
            - $ref: '#/components/schemas/ToolChatMessage'
        - type: object
          required:
            - id
            - sessionId
            - createdAt
          properties:
            id:
              type: string
            sessionId:
              type: string
            runId:
              type: string
            metadata:
              $ref: '#/components/schemas/JsonObject'
            createdAt:
              $ref: '#/components/schemas/Timestamp'
    MessagePage:
      type: object
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Message'
        nextCursor:
          type: string
    Run:
      type: object
      required:
        - id
        - workspaceId
        - triggerType
        - effectiveAgentName
        - status
        - createdAt
      properties:
        id:
          type: string
        workspaceId:
          type: string
        sessionId:
          type: string
        parentRunId:
          type: string
        initiatorRef:
          type: string
        triggerType:
          type: string
          enum: [message, manual_action, api_action, hook, system]
        triggerRef:
          type: string
        agentName:
          type: string
        effectiveAgentName:
          type: string
        switchCount:
          type: integer
          minimum: 0
        status:
          type: string
          enum: [queued, running, waiting_tool, completed, failed, cancelled, timed_out]
        cancelRequestedAt:
          $ref: '#/components/schemas/Timestamp'
        startedAt:
          $ref: '#/components/schemas/Timestamp'
        heartbeatAt:
          $ref: '#/components/schemas/Timestamp'
        endedAt:
          $ref: '#/components/schemas/Timestamp'
        createdAt:
          $ref: '#/components/schemas/Timestamp'
        errorCode:
          type: string
        errorMessage:
          type: string
        metadata:
          $ref: '#/components/schemas/JsonObject'
    CreateWorkspaceRequest:
      type: object
      required:
        - name
        - template
      properties:
        externalRef:
          type: string
        name:
          type: string
          minLength: 1
        template:
          type: string
          minLength: 1
        rootPath:
          type: string
          minLength: 1
        agentsMd:
          type: string
          minLength: 1
        toolServers:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/JsonObject'
        skills:
          type: array
          items:
            type: object
            required:
              - name
              - content
            properties:
              name:
                type: string
                minLength: 1
              content:
                type: string
                minLength: 1
            additionalProperties: false
        executionPolicy:
          type: string
          enum: [local, container, remote_runner]
          default: local
      additionalProperties: false
    PutWorkspaceFileRequest:
      type: object
      required:
        - path
        - content
      properties:
        path:
          type: string
          minLength: 1
        content:
          type: string
        encoding:
          type: string
          enum: [utf8, base64]
          default: utf8
        overwrite:
          type: boolean
          default: true
        ifMatch:
          type: string
      additionalProperties: false
    CreateWorkspaceDirectoryRequest:
      type: object
      required:
        - path
      properties:
        path:
          type: string
          minLength: 1
        createParents:
          type: boolean
          default: true
      additionalProperties: false
    MoveWorkspaceEntryRequest:
      type: object
      required:
        - sourcePath
        - targetPath
      properties:
        sourcePath:
          type: string
          minLength: 1
        targetPath:
          type: string
          minLength: 1
        overwrite:
          type: boolean
          default: false
      additionalProperties: false
    WorkspaceImportRequest:
      type: object
      required:
        - rootPath
      properties:
        rootPath:
          type: string
          minLength: 1
        kind:
          type: string
          enum: [project, chat]
        name:
          type: string
        externalRef:
          type: string
      additionalProperties: false
    CreateSessionRequest:
      type: object
      properties:
        title:
          type: string
        agentName:
          type: string
      additionalProperties: false
    RunStep:
      type: object
      required:
        - id
        - runId
        - seq
        - stepType
        - status
      properties:
        id:
          type: string
        runId:
          type: string
        seq:
          type: integer
          minimum: 1
        stepType:
          type: string
          enum: [model_call, tool_call, agent_switch, agent_delegate, hook, system]
        name:
          type: string
        agentName:
          type: string
        status:
          type: string
          enum: [queued, running, completed, failed, cancelled]
        input:
          $ref: '#/components/schemas/JsonObject'
        output:
          $ref: '#/components/schemas/JsonObject'
        startedAt:
          $ref: '#/components/schemas/Timestamp'
        endedAt:
          $ref: '#/components/schemas/Timestamp'
    RunStepPage:
      type: object
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/RunStep'
        nextCursor:
          type: string
    CreateMessageRequest:
      type: object
      required:
        - content
      properties:
        content:
          type: string
          minLength: 1
        metadata:
          $ref: '#/components/schemas/JsonObject'
      additionalProperties: false
    MessageAccepted:
      type: object
      required:
        - messageId
        - runId
        - status
      properties:
        messageId:
          type: string
        runId:
          type: string
        status:
          type: string
          enum: [queued]
    CreateActionRunRequest:
      type: object
      properties:
        sessionId:
          type: string
        agentName:
          type: string
          description: Optional agent context to associate with this action run
        input:
          oneOf:
            - type: object
              additionalProperties: true
            - type: 'null'
      additionalProperties: false
    ModelGenerateRequest:
      type: object
      properties:
        model:
          type: string
          minLength: 1
          description: Platform model name from the server models directory
        prompt:
          type: string
        messages:
          type: array
          items:
            $ref: '#/components/schemas/ChatMessage'
        temperature:
          type: number
        maxTokens:
          type: integer
          minimum: 1
      additionalProperties: false
      anyOf:
        - required: [prompt]
        - required: [messages]
    ModelStreamRequest:
      allOf:
        - $ref: '#/components/schemas/ModelGenerateRequest'
    ModelGenerateResponse:
      type: object
      required:
        - model
        - text
      properties:
        model:
          type: string
        text:
          type: string
        finishReason:
          type: string
        usage:
          $ref: '#/components/schemas/Usage'
      additionalProperties: false
    ActionRunAccepted:
      type: object
      required:
        - runId
        - status
        - actionName
      properties:
        runId:
          type: string
        status:
          type: string
          enum: [queued]
        actionName:
          type: string
        sessionId:
          type: string
    CancelRunAccepted:
      type: object
      required:
        - runId
        - status
      properties:
        runId:
          type: string
        status:
          type: string
          enum: [cancellation_requested]
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
        message:
          type: string
        details:
          $ref: '#/components/schemas/JsonObject'
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          $ref: '#/components/schemas/Error'
