> ## Documentation Index
> Fetch the complete documentation index at: https://docs.narrative.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Get a run's current state

> Returns the run's current state — status, iterations used so far, token usage,
submitted inference job IDs, the model's final answer (if completed), pending tool
calls (if requires_action), or the error (if failed).

## Polling

Runs are asynchronous. After `POST /agents/conversations/{id}/runs` you poll this
endpoint until you see a terminal status (`completed`, `requires_action`, or
`failed`). A reasonable polling cadence:

- Start with 2-second polls — most simple runs complete in a single iteration
  (5–15 seconds wall-clock).
- Back off to 4–8 seconds for longer-running runs (multi-iteration tool loops).
- Hard-cap at maybe 5 minutes — if a run hasn't terminated by then either something
  is wrong (check `submitted_inference_job_ids` in the data plane's `jobs` table) or
  the workflow timed out and will land `failed` shortly.

## Which fields are populated when

| `status` | Populated fields |
|---|---|
| `pending` | `id`, `conversation_id`, `client_op_id`, `effective_config`, `started_at` |
| `running` | above + `submitted_inference_job_ids` (one per iteration completed) |
| `completed` | above + `iterations_used`, `usage`, exactly one of `final_text` / `final_structured_output`, `completed_at` |
| `requires_action` | above + `iterations_used`, `usage`, `pending_tool_calls`, `completed_at` |
| `failed` | above + `error`, possibly partial `iterations_used`/`usage`, `completed_at` |

`effective_config` is **always** populated — it's the fully-merged config used for
this run (conversation defaults + this run's `config_override`). Helpful for
confirming the model saw what you expected.

## Run vs. inference iteration

Each run runs N iterations, where N ≤ `effective_config.max_iterations`. Each
iteration is one inference job submitted to the data plane (one Bedrock or Cortex
API call). `submitted_inference_job_ids` carries the platform's `jobs.id` for each
iteration — use those to drill into the raw model request/response in the data
plane's logs / job table.

`iterations_used` and `submitted_inference_job_ids.length` match for any terminal
state.

## Error structure

On `status: "failed"` the `error` field carries:

- `type` — opaque incident code (e.g. `AgentLoopMaxIterationsExceeded`,
  `AgentLoopInvalidEffectiveConfig`, `UnknownTool`). Stable across versions, used
  for log correlation.
- `message` — human-readable detail.
- `title` and `docs_url` — caller-facing presentation looked up from the platform's
  [error catalog](https://docs.narrative.io/reference/architecture/agent-conversations/errors/unexpected).
  Absent if the API doesn't recognize the `type` (usually because the workflow
  workers have been upgraded ahead of the API); in that case rely on `type` and
  `message`.

Note: this endpoint always returns 200 for a known run — even one with `status:
"failed"`. The HTTP-level error path (RFC 7807) only applies when the call itself
fails (token invalid, run not found, etc.).

## Scope: per-user, not per-company

Runs are scoped to the **`(company_id, user_id)`** pair that created them. Returns
404 for "run does not exist", "run belongs to a different company", and "run was
created by a different user in the same company" alike — the API does not
distinguish them to avoid leaking existence.

## Permission

`agent_conversations` resource with `read` verb.

## Example: completed run

```json
{
  "id": "82eb9cb7-619e-46bb-ac1c-8a32b0112c1c",
  "conversation_id": "bc2505b7-068d-44ed-8055-a6f6ffe54ab1",
  "company_id": 1,
  "user_id": 407,
  "client_op_id": "696b022c-e86d-4b3e-b6d7-ceb7eb1a495e",
  "status": "completed",
  "tool_choice": null,
  "effective_config": { "...": "..." },
  "iterations_used": 1,
  "usage": { "prompt_tokens": 169, "completion_tokens": 8, "total_tokens": 177 },
  "submitted_inference_job_ids": ["e94c6eab-019f-4e96-bb47-049fa60e7988"],
  "pending_tool_calls": [],
  "final_text": "4",
  "final_structured_output": null,
  "error": null,
  "started_at": "2026-05-18T13:21:30.355180Z",
  "completed_at": "2026-05-18T13:21:51.983952Z"
}
```

## Example: completed structured-output run

```json
{
  "id": "8dda70ab-9f81-4613-a3c9-68b3b584e82d",
  "status": "completed",
  "iterations_used": 1,
  "final_text": null,
  "final_structured_output": {
    "event": {
      "type": "login",
      "user_id": "u-123",
      "session_duration_seconds": 1800
    }
  },
  ...
}
```

## Example: requires_action run

```json
{
  "id": "19082f49-0280-4e32-a8b4-7df8dea9dbed",
  "status": "requires_action",
  "iterations_used": 1,
  "pending_tool_calls": [{
    "tool_use_id": "tooluse_DWXPKZ50JDGib5GmShyUgJ",
    "name": "confirm_booking",
    "arguments": { "proposed_slot": "tomorrow afternoon" }
  }],
  "final_text": null,
  "final_structured_output": null,
  ...
}
```

Resume by posting a new run with `payload.kind: "tool_outputs"` carrying the same
`tool_use_id`.

## Example: failed run

```json
{
  "id": "...",
  "status": "failed",
  "iterations_used": null,
  "usage": null,
  "final_text": null,
  "final_structured_output": null,
  "error": {
    "type": "AgentLoopMaxIterationsExceeded",
    "message": "max iterations exceeded after 5 iterations",
    "title": "Max Iterations Exceeded",
    "docs_url": "https://docs.narrative.io/reference/architecture/agent-conversations/errors/max-iterations-exceeded"
  },
  ...
}
```



## OpenAPI

````yaml https://docs-cdn.narrative.io/api-reference/main/openapi.json get /agents/runs/{id}
openapi: 3.1.1
info:
  contact:
    email: support@narrative.io
    name: Narrative Support
    url: https://www.narrative.io
  termsOfService: https://www.narrative.io/legal/terms-of-service
  x-logo:
    url: >-
      https://cdn.narrative.io/images/company-logos/prod/narrative-logo-text-white.svg
    backgroundColor: rgb(9, 34, 166)
    altText: Narrative Logo
  description: >-
    The [Narrative Data Collaboration Platform](https://app.narrative.io) API is
    organized around REST. Our API has predictable resource-oriented URLs,
    accepts form-encoded request bodies, returns JSON-encoded responses, and
    uses standard HTTP response codes, authentication, and verbs.



    The current version is a pre-release beta.  It may result in unexpected
    behavior and there may be breaking changes in future releases up to the 1.0
    release.
  title: Narrative Data Collaboration Platform API
  version: 2.4.x
servers:
  - url: https://api-dev.narrative.io
  - url: https://api.narrative.io
security: []
tags:
  - name: Access Rules
    description: >-
      Access rules let data providers control who can purchase their data and
      the terms of purchase.


      The `access-rules` API allows you to manage access rules for your
      datasets.


      Related guides:
        - [What is an access rule?](https://kb.narrative.io/access-rules)
  - name: Agent Conversations
    description: >-
      Build LLM-driven workflows that can call MCP tools, ask the caller for
      input, and return structured answers.


      A conversation pins a model, a system prompt, and a tool catalog. Each run
      sends the model a user message (or

      a batch of tool outputs from a previously-paused run); the model decides
      whether to answer directly, call a

      server-side tool (resolved by the platform via Model Context Protocol), or
      call a client-side tool (which pauses

      the run with `requires_action` and waits for the caller to reply).


      Related guides:
        - [Agent Conversations Reference](https://docs.narrative.io/reference/architecture/agent-conversations)
        - [Error catalog](https://docs.narrative.io/reference/architecture/agent-conversations/errors/conversation-not-found)
  - name: MCP Connections
    description: >-
      Connect external (non-Narrative) MCP servers so agent runs can call their
      tools with the

      calling user's own OAuth authorization.


      A connection is created interactively: `POST /mcp-connections` runs OAuth
      discovery and

      Dynamic Client Registration against the server and returns a consent URL;
      the user authorizes

      in a browser; the authorization server redirects to `GET
      /mcp-connections/callback`, which

      finishes the token exchange and marks the connection `connected`. Tokens
      are stored encrypted

      and used server-side — they are never returned by the API. Once connected,
      reference the

      connection by id from an agent run's `mcp_servers[].connection_id`.
  - name: App Invites
    description: >-
      App invites allow applications to create one-time, shareable links on
      behalf of their users. These links

      enable users to invite third parties who do not have a Narrative account
      to perform actions within the

      application.


      For example, a Narrative user can send an invite link to a third party who
      then completes a Pinterest

      OAuth flow and creates a connector profile in the inviter's account,
      allowing the inviter to deliver

      audience data to the third party's Pinterest account without the third
      party needing a Narrative account.


      This API is intended to be used by applications (via app client
      credentials) to create and manage invites

      on behalf of their users, which can then be shared with invitees.
  - name: Apps
    description: >-
      Apps are applications bundled with a UI that can perform various actions
      on behalf of a user utilizing the Narrative API.

      Related guides:
        - [Building a Narrative Native App](https://www.narrative.io/knowledge-base/how-to-guides/building-a-narrative-native-app)
  - name: Access Tokens
    description: API Access Token management
  - name: Attributes
    description: >-
      An attribute models a standardized data point available for sale on the
      Narrative marketplace.


      Narrative automatically turns data points from provider datasets into
      attributes so that buyers can purchase well-formed, standardized data from
      any supplier on the marketplace.
  - name: Auth
    description: >-
      API token is a crucial step for developers to securely authenticate
      requests to the Narrative API

      Related guides:
        - [How to Create an API Token](https://www.narrative.io/knowledge-base/how-to-guides/understanding-narratives-apis/create-an-api-token)
  - name: Authentication
    description: User login and registration
  - name: Billings
    description: Used by Narrative internally to bill customers
  - name: Companies
    description: A collection of employees
  - name: Company Marketing Information
    description: Useful information related to companies
  - name: Compute Pools
    description: >-
      Compute pools represent compute resources (e.g. Snowflake warehouses)
      provisioned within a data plane.

      Companies can manage and share compute pools, assign them to jobs, and set
      a default compute pool on data planes.
  - name: Connections
    description: Associations between connectors and datasets
  - name: Data Shops
    description: |-
      Self-hosted website to sell your data
      Related guides:
        - [Setting up your datashop](https://www.narrative.io/knowledge-base/how-to-guides/shop-builder/settting-up-your-data-shop)
  - name: Data Streams
    description: >-
      The `data-stream` API endpoints allows one to create and update
      data-streams. Additionally the endpoints allow

      finding data-streams using free text search. A few of the endpoints are
      behind authorization.


      Update endpoint allows a client to post an edited data-stream document as
      is, without having to change its shape.

      The API ensures that only certain fields are allowed to be modified.
      Attempts to modify fields not up for client

      modifications are ignored.


      Related guides:
        - [What is a data stream?](https://kb.narrative.io/what-is-a-data-stream)
  - name: Contracts
    description: Contracts related APIs
  - name: Datasets
    description: >-
      Any kind of data, in any schema, can be pushed into the Narrative Data
      Collaboration Platform as a dataset exactly as it is stored in your own
      system.


      The `datasets` API allows you to manage your datasets.
  - name: Destinations
    description: >-
      Destinations associate a subscription to a profile. Optionally, ad-hoc
      quick settings can be configured to a destination.

      Those quick settings have to match the format defined on the app manifest.
  - name: Installations
    description: Installations of Applications for a profile
  - name: Jobs
    description: >-
      Jobs represent an operation done on a given data plane. All jobs today are
      tied to a query that represents a forecast or a materialized view.


      The jobs API provides an interface for interacting with the jobs table,
      which stores various operations involving reading or writing data. This
      API allows users to retrieve detailed information about specific jobs,
      including cost forecasts, data forecasts, NQL forecasts and materialized
      views.
  - name: Mappings
    description: >-
      A mapping is a transformation from a dataset to an attribute. Defining a
      mapping between a dataset and an attribute makes the dataset eligible to
      participate in subscriptions where a buyer is purchasing the target
      attribute.
  - name: Model Inference
    description: Model Inference
  - name: Models
    description: >-
      Machine learning models for training and inference.


      Models can be stored in HuggingFace or Narrative repositories and have
      configurable

      collaborator permissions for training and inference access.


      The `models` API allows you to list, retrieve, and update models
      accessible to your company.
  - name: NQL
    description: >-
      Narrative Query Language (NQL) is a specialized, SQL-inspired language
      designed to query and manipulate data within the Narrative platform. While
      it looks and feels much like standard SQL, it offers extended
      functionality and syntax that let you leverage platform-specific
      features—such as referencing datasets by their IDs, creating materialized
      views, or generating forecasts—without having to manage the complexities
      of different query engines behind the scenes. NQL queries can ultimately
      compile down to multiple underlying engines (e.g., Snowflake, Spark) to
      execute your requests efficiently in the Narrative ecosystem.
  - name: Payment Methods
    description: Payment methods used to purchase data
  - name: Products
    description: Internal routes used to offer datastream as products
  - name: Profiles
    description: >-
      App profiles are associated with an installation. They represent a
      reference to a configuration that the app can use to save confidential
      information outside of Narrative's control.

      Profiles are currently used to configure settings for connector apps.
  - name: Resources
    description: >-
      Narrative gives you access to managed resources, like your own AWS S3
      bucket, so that you can effortlessly buy and sell data on the platform.


      The `resources` API allows you to manage your resources.
  - name: Schema Inference
    description: >-
      The `schema-inference` API analyzes submitted files to automatically infer
      and return their structure as a dataset schema.
  - name: Schema Presets
    description: >-
      The `schema-presets` API allows you to list the available schema presets,
      get detailed information about a specific one and manage its life cycle.


      You can create a schema preset from scratch or create one based on an
      existing one, administrators can create platform wide available (public)
      schema preset.
  - name: Subscriptions
    description: >-
      In the Narrative Data Collaboration Platform a subscription represents a
      set of rules dictating the commercial terms related to the licensing of
      data.


      The `subscriptions` API allows you to set and get information about
      `subscription` objects owned by the authenticated account.
  - name: Uploads
    description: >-
      The `uploads` API allows you to send files to Narrative and use them to
      perform tasks like creating a list or adding data to a dataset.
  - name: Usage
    description: >-
      The `usage` API enables the recording of usage events associated with a
      product.
  - name: Workflows
    description: >-
      The `workflows` API allows you to create, schedule, trigger, and archive
      workflows.

      Workflows are defined using a serverlessworkflow YAML specification.
paths:
  /agents/runs/{id}:
    parameters:
      - in: path
        name: id
        required: true
        schema:
          $ref: '#/components/schemas/RunId'
        description: The run's UUID.
    get:
      tags:
        - Agent Conversations
      summary: Get a run's current state
      description: >-
        Returns the run's current state — status, iterations used so far, token
        usage,

        submitted inference job IDs, the model's final answer (if completed),
        pending tool

        calls (if requires_action), or the error (if failed).


        ## Polling


        Runs are asynchronous. After `POST /agents/conversations/{id}/runs` you
        poll this

        endpoint until you see a terminal status (`completed`,
        `requires_action`, or

        `failed`). A reasonable polling cadence:


        - Start with 2-second polls — most simple runs complete in a single
        iteration
          (5–15 seconds wall-clock).
        - Back off to 4–8 seconds for longer-running runs (multi-iteration tool
        loops).

        - Hard-cap at maybe 5 minutes — if a run hasn't terminated by then
        either something
          is wrong (check `submitted_inference_job_ids` in the data plane's `jobs` table) or
          the workflow timed out and will land `failed` shortly.

        ## Which fields are populated when


        | `status` | Populated fields |

        |---|---|

        | `pending` | `id`, `conversation_id`, `client_op_id`,
        `effective_config`, `started_at` |

        | `running` | above + `submitted_inference_job_ids` (one per iteration
        completed) |

        | `completed` | above + `iterations_used`, `usage`, exactly one of
        `final_text` / `final_structured_output`, `completed_at` |

        | `requires_action` | above + `iterations_used`, `usage`,
        `pending_tool_calls`, `completed_at` |

        | `failed` | above + `error`, possibly partial
        `iterations_used`/`usage`, `completed_at` |


        `effective_config` is **always** populated — it's the fully-merged
        config used for

        this run (conversation defaults + this run's `config_override`). Helpful
        for

        confirming the model saw what you expected.


        ## Run vs. inference iteration


        Each run runs N iterations, where N ≤ `effective_config.max_iterations`.
        Each

        iteration is one inference job submitted to the data plane (one Bedrock
        or Cortex

        API call). `submitted_inference_job_ids` carries the platform's
        `jobs.id` for each

        iteration — use those to drill into the raw model request/response in
        the data

        plane's logs / job table.


        `iterations_used` and `submitted_inference_job_ids.length` match for any
        terminal

        state.


        ## Error structure


        On `status: "failed"` the `error` field carries:


        - `type` — opaque incident code (e.g. `AgentLoopMaxIterationsExceeded`,
          `AgentLoopInvalidEffectiveConfig`, `UnknownTool`). Stable across versions, used
          for log correlation.
        - `message` — human-readable detail.

        - `title` and `docs_url` — caller-facing presentation looked up from the
        platform's
          [error catalog](https://docs.narrative.io/reference/architecture/agent-conversations/errors/unexpected).
          Absent if the API doesn't recognize the `type` (usually because the workflow
          workers have been upgraded ahead of the API); in that case rely on `type` and
          `message`.

        Note: this endpoint always returns 200 for a known run — even one with
        `status:

        "failed"`. The HTTP-level error path (RFC 7807) only applies when the
        call itself

        fails (token invalid, run not found, etc.).


        ## Scope: per-user, not per-company


        Runs are scoped to the **`(company_id, user_id)`** pair that created
        them. Returns

        404 for "run does not exist", "run belongs to a different company", and
        "run was

        created by a different user in the same company" alike — the API does
        not

        distinguish them to avoid leaking existence.


        ## Permission


        `agent_conversations` resource with `read` verb.


        ## Example: completed run


        ```json

        {
          "id": "82eb9cb7-619e-46bb-ac1c-8a32b0112c1c",
          "conversation_id": "bc2505b7-068d-44ed-8055-a6f6ffe54ab1",
          "company_id": 1,
          "user_id": 407,
          "client_op_id": "696b022c-e86d-4b3e-b6d7-ceb7eb1a495e",
          "status": "completed",
          "tool_choice": null,
          "effective_config": { "...": "..." },
          "iterations_used": 1,
          "usage": { "prompt_tokens": 169, "completion_tokens": 8, "total_tokens": 177 },
          "submitted_inference_job_ids": ["e94c6eab-019f-4e96-bb47-049fa60e7988"],
          "pending_tool_calls": [],
          "final_text": "4",
          "final_structured_output": null,
          "error": null,
          "started_at": "2026-05-18T13:21:30.355180Z",
          "completed_at": "2026-05-18T13:21:51.983952Z"
        }

        ```


        ## Example: completed structured-output run


        ```json

        {
          "id": "8dda70ab-9f81-4613-a3c9-68b3b584e82d",
          "status": "completed",
          "iterations_used": 1,
          "final_text": null,
          "final_structured_output": {
            "event": {
              "type": "login",
              "user_id": "u-123",
              "session_duration_seconds": 1800
            }
          },
          ...
        }

        ```


        ## Example: requires_action run


        ```json

        {
          "id": "19082f49-0280-4e32-a8b4-7df8dea9dbed",
          "status": "requires_action",
          "iterations_used": 1,
          "pending_tool_calls": [{
            "tool_use_id": "tooluse_DWXPKZ50JDGib5GmShyUgJ",
            "name": "confirm_booking",
            "arguments": { "proposed_slot": "tomorrow afternoon" }
          }],
          "final_text": null,
          "final_structured_output": null,
          ...
        }

        ```


        Resume by posting a new run with `payload.kind: "tool_outputs"` carrying
        the same

        `tool_use_id`.


        ## Example: failed run


        ```json

        {
          "id": "...",
          "status": "failed",
          "iterations_used": null,
          "usage": null,
          "final_text": null,
          "final_structured_output": null,
          "error": {
            "type": "AgentLoopMaxIterationsExceeded",
            "message": "max iterations exceeded after 5 iterations",
            "title": "Max Iterations Exceeded",
            "docs_url": "https://docs.narrative.io/reference/architecture/agent-conversations/errors/max-iterations-exceeded"
          },
          ...
        }

        ```
      operationId: getAgentRun
      responses:
        '200':
          description: >-
            Run state. `status` indicates which lifecycle position the run is
            in; populated

            fields vary accordingly (see description).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunResponse'
        '401':
          description: Missing or invalid bearer token.
        '403':
          description: Token does not have `agent_conversations:read` permission.
        '404':
          description: >-
            Run does not exist, belongs to a different company than the token's,
            or was

            created by a different user in the same company.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RFCError'
      security:
        - BearerAuth: []
components:
  schemas:
    RunId:
      description: >-
        UUID identifying a single run. Returned by `POST
        /agents/conversations/{id}/runs` and

        used in `GET /agents/runs/{id}` to poll progress.
      type: string
      format: uuid
      example: 82eb9cb7-619e-46bb-ac1c-8a32b0112c1c
    RunResponse:
      description: >-
        Run state as returned by `POST /agents/conversations/{id}/runs`
        (Accepted, 202) and

        `GET /agents/runs/{id}` (OK, 200). Which optional fields are populated
        depends on

        `status`:


        - `completed` → `iterations_used`, `usage`,
        `submitted_inference_job_ids`, and exactly
          one of `final_text` / `final_structured_output`. The two are mutually exclusive: text-mode
          runs (no `output_format_schema` supplied) populate `final_text`; structured-mode runs
          populate `final_structured_output` with the caller-schema-conforming JSON.
        - `requires_action` → `pending_tool_calls`, `iterations_used`, `usage`,
          `submitted_inference_job_ids`.
        - `failed` → `error`, possibly partial
        `iterations_used`/`usage`/`submitted_inference_job_ids`.

        - `pending` / `running` → only the at-creation fields (`id`,
        `conversation_id`,
          `started_at`, etc.) plus `submitted_inference_job_ids` if any iterations have
          started.
      type: object
      required:
        - id
        - conversation_id
        - company_id
        - user_id
        - client_op_id
        - status
        - effective_config
        - submitted_inference_job_ids
        - pending_tool_calls
        - started_at
        - live
      properties:
        id:
          $ref: '#/components/schemas/RunId'
        conversation_id:
          $ref: '#/components/schemas/ConversationId'
        company_id:
          type: integer
          example: 1
        user_id:
          type: integer
          example: 407
        client_op_id:
          $ref: '#/components/schemas/ClientOpId'
        status:
          $ref: '#/components/schemas/RunStatus'
        tool_choice:
          $ref: '#/components/schemas/ToolChoice'
        effective_config:
          allOf:
            - $ref: '#/components/schemas/ConversationDefaults'
          description: >-
            The fully-merged config that was used to run this turn —
            conversation `defaults`

            with `config_override` applied. Echoed back so you can see exactly
            what the model

            saw, especially helpful when debugging unexpected behavior caused by
            overrides.
        iterations_used:
          type:
            - integer
            - 'null'
          minimum: 0
          description: >-
            Number of inference iterations this run completed. Populated on
            terminal states.

            Equal to `submitted_inference_job_ids.length` for the same run.
          example: 6
        usage:
          oneOf:
            - $ref: '#/components/schemas/InferenceUsage'
            - type: 'null'
        submitted_inference_job_ids:
          type: array
          description: >-
            Inference job IDs (one per iteration) for cross-system tracing. Each
            ID is a row

            in the platform's `jobs` table — use it to pull the raw model
            request/response

            if you need to debug a specific iteration.
          items:
            type: string
            format: uuid
        pending_tool_calls:
          type: array
          description: >-
            Tool calls the run is waiting for the caller to answer. Empty unless
            `status` is

            `requires_action`.
          items:
            $ref: '#/components/schemas/PendingToolCall'
        final_text:
          type:
            - string
            - 'null'
          description: >-
            The model's final answer in plain text. Populated on `status:
            completed` when the

            caller did NOT supply an `output_format_schema` (text mode).
            Mutually exclusive with

            `final_structured_output`.
        final_structured_output:
          description: >-
            The model's final answer as a JSON object conforming to the caller's

            `output_format_schema`. Populated on `status: completed` when the
            caller supplied an

            `output_format_schema` on the conversation defaults or run override
            (structured

            mode). The shape is the caller's schema verbatim — no top-level
            `text` field is

            required or implied. Mutually exclusive with `final_text`.
        error:
          oneOf:
            - $ref: '#/components/schemas/RunError'
            - type: 'null'
          description: 'Populated only on `status: failed`.'
        started_at:
          type: string
          format: date-time
          example: '2026-05-18T13:21:30.355180Z'
        completed_at:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            When the run reached a terminal status. Null while in `pending` or
            `running`.
        live:
          allOf:
            - $ref: '#/components/schemas/RunLive'
          description: >-
            The conversation's current, still-mutating state (e.g. its
            auto-generated name).

            Populated on every read, independent of `status`.
    RFCError:
      description: >-
        RFC 7807 Problem Details. Returned with `Content-Type: application/json`
        for every

        4xx/5xx response on `/agents/*`.


        **Field semantics:**


        - `type` — stable URL to the docs page describing this error class.
        Treat it as the
          machine-readable identifier; the same URL is referenced by `RunError.docs_url` on
          failed runs. Optional on 500 errors that don't map to a documented class.
        - `title` — short human-readable summary.

        - `status` — HTTP status code echoed in the body (so clients that read
        only the body
          can still dispatch on status).
        - `detail` — request-specific detail. Includes which alias was
        malformed, which
          `tool_use_id` was missing, etc.
        - `instance` — the API surface group (`/agents` for all agent
        endpoints). Stable —
          it's the prefix you call, not the full path.
        - `log_id` — UUID correlated with server logs. Always include this when
        reporting an
          issue to support.
        - `debug` — usually `null`. Reserved for richer payloads in specific
        failure modes.


        Common error pages indexed by `type`:


        | HTTP | Common cause | Docs page |

        |------|--------------|-----------|

        | 400 | Bad request body, validation failure | various — see `type` |

        | 404 | Resource not found, or owned by a different company |
        `/conversation-not-found`, `/agent-run-not-found` |

        | 409 | Conversation version moved while you were preparing the run |
        `/version-conflict` |

        | 500 | Internal error (schema drift, workflow start failure) |
        `/invalid-stored-field`, `/workflow-start-failed` |
      type: object
      required:
        - title
        - status
        - log_id
      properties:
        type:
          type:
            - string
            - 'null'
          format: uri
          example: >-
            https://docs.narrative.io/reference/architecture/agent-conversations/errors/invalid-tool-alias
        title:
          type: string
          example: Invalid Tool Alias
        status:
          type: integer
          example: 400
        detail:
          type: string
          example: >-
            invalid tool aliases (must match ^[a-zA-Z][a-zA-Z0-9]{0,7}$):
            with_underscore
        instance:
          type: string
          example: /agents
        log_id:
          type: string
          format: uuid
          example: 1f6e5d4c-3b2a-1098-7654-3210fedcba98
        debug:
          type:
            - object
            - 'null'
      example:
        type: >-
          https://docs.narrative.io/reference/architecture/agent-conversations/errors/invalid-tool-alias
        title: Invalid Tool Alias
        status: 400
        detail: >-
          invalid tool aliases (must match ^[a-zA-Z][a-zA-Z0-9]{0,7}$):
          with_underscore
        instance: /agents
        log_id: 1f6e5d4c-3b2a-1098-7654-3210fedcba98
        debug: null
    ConversationId:
      description: >-
        UUID identifying a conversation. Returned from `POST
        /agents/conversations` and used

        in every other agent endpoint that operates on this conversation.
      type: string
      format: uuid
      example: bc2505b7-068d-44ed-8055-a6f6ffe54ab1
    ClientOpId:
      description: >-
        A UUID **you generate** for each `POST .../runs` call. Acts as an
        idempotency key:

        re-sending the same `client_op_id` against the same conversation returns
        the

        original run row unchanged. This lets you retry network blips, request
        timeouts, etc.

        without accidentally starting a second workflow.


        **Scope:** `(conversation_id, client_op_id)` is the uniqueness key. You
        can reuse the

        same `client_op_id` across different conversations; the platform doesn't
        deduplicate

        cross-conversation.
      type: string
      format: uuid
      example: 696b022c-e86d-4b3e-b6d7-ceb7eb1a495e
    RunStatus:
      description: >-
        Where the run is in its lifecycle. Three terminal states (`completed`,

        `requires_action`, `failed`) — you stop polling when you see any of
        them. The two

        in-flight states (`pending`, `running`) mean "keep polling."


        - `pending` — run row inserted by the API but the workflow hasn't picked
        it up yet.
          Usually < 1 second; if a run stays here for tens of seconds the workflow workers
          may be down.
        - `running` — workflow is mid-execution. One "running" you see roughly
        corresponds to
          one inference iteration; you might cycle through this state several times for a
          multi-iteration tool-use loop.
        - `completed` — model produced a final answer. Exactly one of
        `final_text` /
          `final_structured_output` is populated depending on whether the caller supplied an
          `output_format_schema` on the conversation defaults or run override.
        - `requires_action` — model called a client-side tool.
        `pending_tool_calls` is
          populated; resume by posting a new run with `payload.kind: tool_outputs`.
        - `failed` — non-recoverable error. `error.type`, `error.message`,
        `error.title`,
          `error.docs_url` are populated. See the
          [error catalog](https://docs.narrative.io/reference/architecture/agent-conversations/errors/unexpected)
          for the per-type meaning. A run that was deliberately **cancelled** also lands here, tagged
          with `error.type: AgentLoopCancelled` so it is distinguishable from a genuine failure.
      type: string
      enum:
        - pending
        - running
        - completed
        - requires_action
        - failed
    ToolChoice:
      description: >-
        Per-run policy that biases the model toward (or away from) using tools
        on the **first

        iteration** of the run. From iteration 2 onward the model is back on
        `{"kind":

        "auto"}` regardless.


        **Per-run, not per-conversation:** every new run picks its own
        `tool_choice`. To

        re-force a particular tool on every follow-up run (for example, always
        asking the user

        for confirmation), set it on each `POST .../runs` body.


        Three shapes, discriminated by `kind`:
      oneOf:
        - title: Auto
          type: object
          required:
            - kind
          properties:
            kind:
              type: string
              enum:
                - auto
          description: >-
            The model decides whether to use a tool. **Default behavior** when
            `tool_choice`

            is omitted entirely.
          example:
            kind: auto
        - title: Any
          type: object
          required:
            - kind
          properties:
            kind:
              type: string
              enum:
                - any
          description: >-
            The model **must** call some tool on iteration 1 — it cannot emit a
            plain text

            answer. Useful when your prompt is a question that's only answerable
            by tool use.
          example:
            kind: any
        - title: SpecificTool
          type: object
          required:
            - kind
            - name
          properties:
            kind:
              type: string
              enum:
                - specific_tool
            name:
              type: string
              description: >-
                The bare tool name — never the wire form. For MCP-pinned tools
                combine with

                `mcp_alias`. For caller-declared tools, omit `mcp_alias`.
            mcp_alias:
              type:
                - string
                - 'null'
              description: >-
                The MCP server's alias when pinning a server-side tool. When
                present, the

                platform stitches `{mcp_alias}-{name}` into the wire name the
                model sees, and

                validates that the alias is a registered MCP server with that
                tool in its

                catalog. Omit (or set to `null`) for caller-declared tools.
              pattern: ^[a-zA-Z][a-zA-Z0-9]{0,7}$
          description: >-
            The model **must** call this specific tool on iteration 1. Useful
            for human-

            in-the-loop flows where you want to force a `requires_action`
            terminal state

            with a known shape.


            The platform validates name resolution synchronously:

            - With `mcp_alias`: alias must be registered, and `name` must be in
            that server's
              declared tool catalog. Misses raise
              [Unknown Tool Choice MCP Alias](https://docs.narrative.io/reference/architecture/agent-conversations/errors/unknown-tool-choice-mcp-alias)
              or
              [Unknown Tool Choice Name](https://docs.narrative.io/reference/architecture/agent-conversations/errors/unknown-tool-choice-name).
            - Without `mcp_alias`: `name` must be in the caller-declared
            `tools[]`. Misses
              raise the same `Unknown Tool Choice Name`.
          example:
            kind: specific_tool
            name: confirm_booking
    ConversationDefaults:
      description: >-
        The configuration applied to every run on this conversation by default.
        Each field

        can be overridden per-run via `config_override` on the `POST .../runs`
        body, **except

        `system_prompt`** which is fixed at conversation creation time.


        For `mcp_servers` and `tools`, overrides **replace the whole list**, not
        individual

        entries. There is no per-server or per-tool merge — set the complete
        catalog you want

        for that run.
      type: object
      required:
        - model
        - data_plane_id
        - execution_cluster
      properties:
        model:
          type: string
          description: >-
            The language model identifier. The platform exposes a fixed set;
            check the

            [Model Inference
            reference](https://docs.narrative.io/reference/model-inference)

            for current supported values.
          example: anthropic.claude-opus-4.6
        data_plane_id:
          type: string
          format: uuid
          description: >-
            UUID of the data plane (compute environment) that hosts the
            inference job

            executor. Each company has at least one data plane. Get it from your
            platform

            admin or `GET /data-planes`.
          example: f79cbdae-4848-47ca-95e8-69588364d185
        execution_cluster:
          type: string
          enum:
            - shared
            - dedicated
          description: >-
            Which job-executor pool dispatches the inference call to AWS Bedrock
            or Snowflake

            Cortex. The executor doesn't run the model itself — that happens in
            the external

            service — it only routes the HTTP request.


            **Use `shared` for almost every case.** `dedicated` is only relevant
            if your

            company runs a dedicated executor pool for isolation reasons.
          example: shared
        compute_pool_id:
          type: string
          format: uuid
          description: >-
            Optional compute pool override. Only relevant for
            `execution_cluster: dedicated`

            — pinpoints a specific compute pool inside that cluster.
        max_iterations:
          type: integer
          minimum: 1
          default: 3
          description: >-
            Maximum number of inference rounds the workflow may perform before
            failing with

            [Max Iterations
            Exceeded](https://docs.narrative.io/reference/architecture/agent-conversations/errors/max-iterations-exceeded).

            Each iteration is one inference job (one Bedrock/Cortex call).
            Multi-step

            research flows often need 8–15; a one-shot question needs 1–2
            (default 3 gives

            you some headroom).
          example: 8
        max_tokens:
          type: integer
          minimum: 1
          default: 2048
          description: >-
            Cap on the model's reply length **per iteration** (does not include
            the prompt).

            Bedrock-side enforced. If the model hits this limit mid-JSON, the
            response will

            fail to validate against `output_format_schema` —

            [Schema Decode
            Failed](https://docs.narrative.io/reference/architecture/agent-conversations/errors/schema-decode-failed).
          example: 2048
        temperature:
          type: number
          minimum: 0
          maximum: 1
          default: 0
          description: >-
            Sampling temperature. `0.0` is deterministic-ish (best for
            structured / factual

            answers); higher values introduce randomness (helpful for
            brainstorming).
          example: 0
        output_format_schema:
          type: object
          description: >-
            JSON Schema describing the final answer's structure. The platform
            extracts a

            `text` field from the model's reply for `final_text` on the terminal
            run.


            **Supports a subset of Draft 2020-12** — the same subset Bedrock
            structured

            output accepts. Not supported: `oneOf`, `anyOf`, `allOf`, `not`,
            `$ref`,

            `$defs`, `if/then/else`, `pattern`, `format`. Supported: `type`,
            `properties`,

            `required`, `enum`, `additionalProperties: false`,
            `minimum`/`maximum` on

            numbers, `minLength`/`maxLength` on strings, `minItems`/`maxItems`
            on arrays.


            See

            [JSON Schema
            Reference](https://docs.narrative.io/reference/model-inference/json-schema-reference)

            for the canonical supported-feature list.
          example:
            type: object
            additionalProperties: false
            required:
              - text
            properties:
              text:
                type: string
        mcp_servers:
          type: array
          default: []
          description: >-
            List of MCP servers and their tools the model can call server-side.
            Each

            server's tools appear to the model with the `{alias}-` prefix. Empty
            list means

            "no MCP tools." Wholesale-replaced when overridden in
            `config_override`.
          items:
            $ref: '#/components/schemas/McpServerConfig'
        tools:
          type: array
          default: []
          description: >-
            List of caller-declared tools. When the model calls one of these,
            the run pauses

            at `requires_action` and the platform expects you to start a
            follow-up run with

            `payload.kind: tool_outputs`. Caller-declared tool `name`s have no
            alias prefix

            and must not contain a dash. Wholesale-replaced when overridden in

            `config_override`.
          items:
            $ref: '#/components/schemas/ToolSpec'
    InferenceUsage:
      description: >-
        Token usage totals across every inference iteration in this run. Used
        for billing

        and capacity planning. Note that `prompt_tokens` grows with each
        iteration because

        each round re-sends the full conversation history to the model.
      type: object
      required:
        - prompt_tokens
        - completion_tokens
        - total_tokens
      properties:
        prompt_tokens:
          type: integer
          minimum: 0
          example: 14842
        completion_tokens:
          type: integer
          minimum: 0
          example: 510
        total_tokens:
          type: integer
          minimum: 0
          example: 15352
    PendingToolCall:
      description: >-
        A tool call from the model that's waiting for **you** to answer.
        Surfaces on

        `status: requires_action` runs. Resume by posting a new run with
        `payload.kind:

        tool_outputs` and matching `outputs[].tool_use_id`.
      type: object
      required:
        - tool_use_id
        - name
        - arguments
      properties:
        tool_use_id:
          type: string
          description: Use this verbatim as `outputs[].tool_use_id` when resuming the run.
          example: tooluse_DWXPKZ50JDGib5GmShyUgJ
        name:
          type: string
          description: >-
            The wire-form name of the tool the model is calling. For
            caller-declared tools

            this is the bare `name` (dash-free) — the only shape that surfaces
            here, since

            MCP-resolved calls are settled inline by the platform.
          example: confirm_booking
        arguments:
          type: object
          description: The arguments the model produced. Matches the tool's `input_schema`.
          example:
            proposed_slot: tomorrow afternoon
    RunError:
      description: >-
        Populated on `status: failed` runs. Use `type` for log correlation and

        automated dispatch; show `title` and `message` to humans; link to
        `docs_url` for

        actionable explanations.
      type: object
      required:
        - type
        - message
      properties:
        type:
          type: string
          description: >-
            Stable internal incident code (e.g.
            `AgentLoopMaxIterationsExceeded`,

            `AgentLoopInvalidEffectiveConfig`, `UnknownTool`,
            `AgentLoopCancelled`).

            Future-stable — these are the keys log dashboards and support
            tooling

            correlate on. `AgentLoopCancelled` specifically marks a deliberately

            cancelled run rather than a genuine error.
          example: AgentLoopMaxIterationsExceeded
        message:
          type: string
          description: Human-readable detail string emitted by the failing component.
          example: max iterations exceeded after 5 iterations
        title:
          type: string
          description: >-
            Caller-facing short title looked up from the platform's error
            catalog. Absent if

            the API doesn't recognize the `type` (unusual; only happens if the
            workflow has

            been upgraded ahead of the API).
          example: Max Iterations Exceeded
        docs_url:
          type: string
          format: uri
          description: >-
            Link to the docs page explaining this error class — what triggered
            it and how to

            recover. Absent on unrecognized types.
          example: >-
            https://docs.narrative.io/reference/architecture/agent-conversations/errors/max-iterations-exceeded
    RunLive:
      description: >-
        Mutable, "live" view of the run's conversation — state that can change
        *after* the run

        row was written, so any fresh `GET /agents/runs/{id}` reflects the
        latest value without a

        separate conversation or messages poll. Always present on a run
        response.
      type: object
      required:
        - messages
      properties:
        current_name:
          type:
            - string
            - 'null'
          description: >-
            The conversation's current display name, or null if it has none yet.
            The platform

            auto-generates a name from the first user message shortly after the
            first run is

            created (an async flow), so a name that was null when the run
            started can appear on a

            later read. A name the caller set explicitly is never overwritten.
          example: Tomorrow Afternoon Meeting
        messages:
          type: array
          description: >-
            The run's produced turns so far, streamed while the run is
            **non-terminal** so a chat

            client can show tool execution live from its existing run poll.
            **Empty once the run is

            terminal** — the same turns are then committed and authoritative via

            `GET /agents/conversations/{id}/messages`. De-dupe the live tail
            against the committed

            messages by `tool_use_id`.
          items:
            $ref: '#/components/schemas/LiveMessage'
    McpServerConfig:
      description: >-
        A Model Context Protocol (MCP) server the platform will call **on your
        behalf** during

        a run. The platform discovers the server's tool catalog at run start via
        the JSON-RPC

        `tools/list` method — you do **not** declare individual tools here. When
        the model

        emits a call to `{alias}-{tool_name}`, the platform makes the
        `tools/call` request,

        parses the response, persists the tool result, and feeds it back into
        the next

        inference round, all inside the same run.


        The server must implement [Model Context
        Protocol](https://modelcontextprotocol.io/)

        over HTTP with JSON-RPC 2.0 (both `tools/list` and `tools/call`).


        **Authentication.** Public servers and Narrative-owned MCPs need no auth
        field. For an

        external server that requires user authorization, first connect it via

        `POST /mcp-connections` (OAuth) and pass the resulting id as
        `connection_id` here — the

        platform attaches and refreshes that connection's bearer token
        server-side at call time.

        The token never appears in the payload or run history.


        **Discovery happens per run.** Each new run re-fetches `tools/list` —
        there is no

        catalog caching between runs. If a server adds, removes, or changes a
        tool, the next

        run picks it up automatically.


        **Error handling:** transient transport errors (5xx, network) during
        discovery are

        surfaced as

        [MCP Discovery
        Failed](https://docs.narrative.io/reference/architecture/agent-conversations/errors/mcp-discovery-failed).

        `tools/call` errors follow the same classification as before:

        [MCP error
        pages](https://docs.narrative.io/reference/architecture/agent-conversations/errors/mcp-unknown-tool).
      type: object
      required:
        - alias
        - url
      properties:
        alias:
          $ref: '#/components/schemas/ToolAlias'
        url:
          type: string
          format: uri
          description: >-
            Fully-qualified HTTPS URL to the MCP server's JSON-RPC endpoint. The
            platform's

            outbound workers must be able to reach this URL — for private MCP
            servers, ensure

            the URL is reachable from the company's data plane.
          example: https://docs.narrative.io/mcp
        description:
          type: string
          description: >-
            Optional free-form description, exposed in the assembled tool
            catalog the model sees.
          example: Public Mintlify-hosted Narrative docs MCP server
        connection_id:
          type: string
          format: uuid
          description: >-
            Reference to a registered external-MCP OAuth connection (from `POST
            /mcp-connections`).

            Set this for an external server that requires user authorization:
            the platform resolves

            and refreshes that connection's bearer token server-side at call
            time — never in the

            payload or run history. Omit for public servers or Narrative-owned
            MCPs. The connection

            must belong to the calling user and be in `connected` status.
            Optional; defaults to none.
          example: b3f1c2a4-5d6e-47f8-9a0b-1c2d3e4f5a6b
    ToolSpec:
      description: >-
        A single tool definition. Mirrors the relevant fields from the
        underlying inference

        contract (Bedrock/Cortex).


        **For MCP tools (discovered at run start from `mcp_servers[]`
        entries):** the model sees the bare

        `name` prefixed with the parent server's `alias` and a dash (so a tool
        `search` on a server with

        `alias: "docs"` becomes `docs-search` on the wire). The wire-name length
        cap is

        `len(alias) + 1 + len(name) ≤ 64` (Bedrock).


        **For caller-declared tools (declared under top-level `tools[]`):** the
        model sees the

        bare `name` directly. The name must **not contain a dash** — the dash is
        reserved as

        the MCP alias separator and is the routing discriminator at call time.
        See

        [Invalid Caller-Declared Tool
        Name](https://docs.narrative.io/reference/architecture/agent-conversations/errors/invalid-caller-tool-name).


        **`input_schema` constraints:** must be a subset of JSON Schema Draft
        2020-12. Features

        like `oneOf`, `anyOf`, `allOf`, `not`, `$ref`, `$defs`, `if/then/else`,
        `pattern`, and

        `format` are **not supported** — the platform forwards the schema to the
        model

        provider, which rejects unsupported features. See

        [JSON Schema
        Reference](https://docs.narrative.io/reference/model-inference/json-schema-reference)

        for the supported subset.


        **Wire-name length:** total wire name (whether bare or `{alias}-{name}`)
        must be

        ≤ 64 characters (Bedrock limit). See

        [Tool Wire Name Too
        Long](https://docs.narrative.io/reference/architecture/agent-conversations/errors/tool-name-too-long).
      type: object
      required:
        - name
        - description
        - input_schema
      properties:
        name:
          type: string
          description: >-
            The tool's bare name. For MCP tools the model sees
            `{parent_alias}-{name}`; for

            caller-declared tools the model sees `name` directly.
            Caller-declared names must

            not contain a dash.
          example: search_narrative_i_o_knowledge_base
        description:
          type: string
          description: >-
            Human-readable description the model uses to decide when to call
            this tool.

            Keep it focused — vague descriptions cause the model to call the
            tool when it

            shouldn't, or skip it when it should.
          example: Search the Narrative.io documentation knowledge base.
        input_schema:
          type: object
          description: >-
            JSON Schema describing the tool's input arguments. The model
            produces an arguments

            object matching this schema for every call. Use
            `additionalProperties: false` and

            `required` aggressively — tighter schemas reduce model mistakes.
          example:
            type: object
            additionalProperties: false
            required:
              - query
            properties:
              query:
                type: string
        strict:
          type: boolean
          description: >-
            Whether to enforce the input schema strictly. Defaults to `true`.
            Leave it true

            for production — turning it off lets the model send arguments that
            don't validate,

            which is almost never what you want.
          default: true
    LiveMessage:
      description: >-
        One provisional, in-flight turn under [RunLive.messages](#runlive). Same
        content shape as a

        committed `MessageDto`, but carries a run-local `turn_index` instead of
        a `sequence_no` — these

        turns aren't in the committed log yet, so they have no committed
        position. The `tool_use` /

        `tool_result` blocks carry the same `tool_use_id`s that later land in
        the committed

        `content_blocks`, so you can de-dupe the live tail against `GET
        .../messages` once the run is

        terminal.
      type: object
      required:
        - turn_index
        - role
        - content_blocks
      properties:
        turn_index:
          type: integer
          minimum: 0
          description: >-
            Per-run ordering of live turns (assistant tool_use turn, then its
            tool_result turn, per

            iteration). Independent of `sequence_no`; use it only to order
            `live.messages`.
          example: 0
        role:
          $ref: '#/components/schemas/MessageRole'
        content_blocks:
          type: array
          items:
            $ref: '#/components/schemas/ContentBlock'
    ToolAlias:
      description: >-
        A 1–8 character namespace prefix for an MCP server's tools. The platform
        stitches

        `{alias}-{tool_name}` into the wire name the model sees, so the alias is
        how every

        MCP-resolved tool call gets routed back to the right server at execution
        time.


        **Rules:**

        - Must match the regex `^[a-zA-Z][a-zA-Z0-9]{0,7}$` — 1–8 characters
        total, starts
          with an ASCII letter, contains only ASCII letters and digits.
        - **No underscores**, **no dashes**, **no other punctuation**. Dashes
        are reserved as
          the alias↔name separator.
        - Must be **unique across `mcp_servers`** within a single conversation.
        The platform
          validates this on `POST /agents/conversations`.

        Caller-declared tools (in `tools[]`) have no alias — the model sees
        their bare `name`

        on the wire. The dash in MCP wire names is the routing discriminator: a
        dash-prefixed

        name comes from an MCP server; a dash-free name is caller-declared and
        triggers

        `requires_action`.


        See the [Invalid Tool
        Alias](https://docs.narrative.io/reference/architecture/agent-conversations/errors/invalid-tool-alias)

        and [Duplicate Tool
        Alias](https://docs.narrative.io/reference/architecture/agent-conversations/errors/duplicate-tool-alias)

        error pages for the exact validation behavior.
      type: string
      pattern: ^[a-zA-Z][a-zA-Z0-9]{0,7}$
      minLength: 1
      maxLength: 8
      example: docs
    MessageRole:
      description: >-
        Who produced this message.


        - `user` — the caller's input. Either a `user_message` payload, or a
        synthesized
          user-role turn carrying `tool_result` blocks when continuing from a
          `requires_action` run (Bedrock's chat-completion model requires tool results to
          live on a user-role turn).
        - `assistant` — the model's output. Either a plain answer (`text`
        blocks) or a
          tool-call request (`tool_use` blocks).
        - `tool` — synthesized turn that carries `tool_result` blocks from
        server-side tool
          calls. Conceptually distinct from `user` even though the underlying protocol may
          collapse them.
      type: string
      enum:
        - user
        - assistant
        - tool
    ContentBlock:
      description: >-
        A single block inside a message. Messages carry an ordered list of
        blocks. Three

        variants discriminated by `type`:


        - `text` — plain text content. The dominant variant for user messages
        and final
          assistant answers.
        - `tool_use` — the model requesting a tool call. Carries the call's
        `tool_use_id`
          (used to match it with the subsequent result), the fully-aliased `name`, and the
          `arguments` the model produced.
        - `tool_result` — the response to a `tool_use`. References the same
        `tool_use_id`
          and carries nested content blocks with the actual result text. `is_error` flags
          tool failures so the model can decide how to react.

        The discriminator field is `type`. Use it to dispatch in your client.
      oneOf:
        - title: Text
          type: object
          required:
            - type
            - text
          properties:
            type:
              type: string
              enum:
                - text
            text:
              type: string
          example:
            type: text
            text: What is 2 + 2?
        - title: ToolUse
          type: object
          required:
            - type
            - tool_use_id
            - name
            - arguments
          properties:
            type:
              type: string
              enum:
                - tool_use
            tool_use_id:
              type: string
              description: >-
                Server-assigned identifier the model produced when emitting the
                tool call.

                Use this to match a `tool_result` with its `tool_use`, and to
                fill

                `outputs[].tool_use_id` when resuming a `requires_action` run.
              example: tooluse_DWXPKZ50JDGib5GmShyUgJ
            name:
              type: string
              description: >-
                Fully-aliased tool name (`{alias}-{tool_name}`) — the same
                string the model

                saw in its tool catalog. The alias prefix is how the platform
                routes the call

                back to its definition.
              example: docs-search_narrative_i_o_knowledge_base
            arguments:
              type: object
              description: >-
                Arguments object produced by the model. Must conform to the
                tool's

                `input_schema` — if the model produced something that doesn't
                validate, the

                run terminates with the

                [MCP Tool Argument Validation
                Failed](https://docs.narrative.io/reference/architecture/agent-conversations/errors/mcp-tool-validation)

                error for server-side tools, or surfaces in `pending_tool_calls`
                as-is for

                client-side tools.
              example:
                query: rate limiting
        - title: ToolResult
          type: object
          required:
            - type
            - tool_use_id
            - content
            - is_error
          properties:
            type:
              type: string
              enum:
                - tool_result
            tool_use_id:
              type: string
              description: >-
                The `tool_use_id` from the matching `tool_use` block on the
                prior assistant turn.
              example: tooluse_DWXPKZ50JDGib5GmShyUgJ
            content:
              type: array
              description: >-
                Nested content blocks carrying the actual result. Almost always
                a single

                `text` block; the platform splits long results into multiple
                text blocks when

                the underlying MCP server returns multiple chunks.
              items:
                $ref: '#/components/schemas/ContentBlock'
            is_error:
              type: boolean
              description: >-
                Whether the tool call failed. The model decides how to react to
                errors —

                retry, ask the user, fall through to a partial answer, etc. Note
                that an

                MCP server returning a non-2xx response that the platform can
                still parse

                counts as `is_error: false` (the tool *succeeded* in returning a
                result, even

                if that result reports an underlying failure).
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer

````