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

# Run Agents

> Execute AI agents in Orq.ai. Send messages, pass variables, attach files, continue tasks, and trace executions through the AI Studio, API, or Orq MCP.

Execute agents already configured. For building and configuring agents, see [Build Agents](/docs/ai-studio/ai-engineering/build-agents).

## Run Agents

<Note>For Python and Node.js client libraries, see [Orq SDKs](/reference/client-libraries).</Note>

Send a message to an agent using the Responses API:

<Tabs>
  <Tab title="API & SDK" icon="code">
    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/router/responses \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
        "model": "agent/my-agent",
        "input": "Help me plan a microservices architecture for our e-commerce platform."
      }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      from orq_ai_sdk import Orq
      import os

      with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
          response = orq.responses.create(
              model="agent/my-agent",
              input="Help me plan a microservices architecture for our e-commerce platform.",
          )
          print(response)
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      import { Orq } from '@orq-ai/node';

      const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

      const response = await orq.responses.create({
        model: 'agent/my-agent',
        input: 'Help me plan a microservices architecture for our e-commerce platform.',
      });

      console.log(response);
      ```
    </CodeGroup>
  </Tab>

  <Tab title="MCP" icon="https://mintcdn.com/orqai/i7ZhKI7LFRfXU7ox/images/logos/mcp.svg?fit=max&auto=format&n=i7ZhKI7LFRfXU7ox&q=85&s=cef7916eb5fe1f6bb97541398d3f7639" width="16" height="16" data-path="images/logos/mcp.svg">
    ```prompt wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
    Invoke "my-agent" with: Help me plan a microservices architecture for our e-commerce platform.
    ```

    The assistant uses `invoke_agent` with `model: "agent/my-agent"` and returns the completed response.
  </Tab>
</Tabs>

The call waits for the agent to finish and returns a completed response object:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "resp_01K6D8QESESZ6SAXQPJPFQXPFT",
  "object": "response",
  "model": "agent/my-agent",
  "status": "completed",
  "output": [
    {
      "type": "message",
      "role": "assistant",
      "content": [{ "type": "output_text", "text": "Here's a microservices architecture..." }]
    }
  ],
  "usage": {
    "input_tokens": 120,
    "output_tokens": 340,
    "total_tokens": 460
  },
  "created_at": 1727694875
}
```

### Streaming

Set `stream: true` to receive incremental output as server-sent events. The response arrives in chunks as the Agent produces it.

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -N -X POST https://api.orq.ai/v3/router/responses \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "agent/my-agent",
      "input": "Help me plan a microservices architecture.",
      "stream": true
    }'
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  from orq_ai_sdk import Orq
  import os

  with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
      res = orq.responses.create(
          model="agent/my-agent",
          input="Help me plan a microservices architecture.",
          stream=True,
      )
      with res as event_stream:
          for item in event_stream:
              event = item.data
              if event and event.type == "response.output_text.delta":
                  print(event.delta, end="", flush=True)
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import { Orq } from '@orq-ai/node';

  const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

  const stream = await orq.responses.create({
    model: 'agent/my-agent',
    input: 'Help me plan a microservices architecture.',
    stream: true,
  });

  for await (const chunk of stream) {
    const event = chunk.data;
    if (event?.type === 'response.output_text.delta') {
      process.stdout.write(event.delta);
    } else if (event?.type === 'response.failed') {
      console.error('Stream failed:', event.response.error);
    }
  }
  ```
</CodeGroup>

The stream emits server-sent events as the agent produces output:

| Event                        | When                       | Key field        | Notes                                                       |
| ---------------------------- | -------------------------- | ---------------- | ----------------------------------------------------------- |
| `response.created`           | Stream opens               | `id`             | Pass as `previous_response_id` to continue the conversation |
| `response.output_text.delta` | Each text chunk            | `delta`          | Append to build the full output                             |
| `response.output_text.done`  | Text generation complete   | `text`           | Full accumulated text                                       |
| `response.completed`         | Agent finishes             | `status`         | Value is `"completed"`                                      |
| `response.failed`            | Agent encountered an error | `response.error` | Full error details; `response.status` is `"failed"`         |

<Tip>See the full [Create Response API reference](/reference/responses/create-response).</Tip>

### Pass Variables

Pass variables in the `variables` field of the execution request:

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.orq.ai/v3/router/responses \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "agent/my-agent",
      "input": "I need help with my account.",
      "variables": {
        "user_name": "John Smith",
        "user_role": "admin",
        "company_name": "Acme Corp"
      }
    }'
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  from orq_ai_sdk import Orq
  import os

  with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
      response = orq.responses.create(
          model="agent/my-agent",
          input="I need help with my account.",
          variables={
              "user_name": "John Smith",
              "user_role": "admin",
              "company_name": "Acme Corp",
          },
      )
      print(response.output[0]["content"][0]["text"])
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import { Orq } from '@orq-ai/node';

  const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

  const response = await orq.responses.create({
    model: 'agent/my-agent',
    input: 'I need help with my account.',
    variables: {
      user_name: 'John Smith',
      user_role: 'admin',
      company_name: 'Acme Corp',
    },
  });

  console.log(response.output?.[0]?.content?.[0]?.text);
  ```
</CodeGroup>

To define which variables the agent uses and configure templating, see [Build Agents: Variables and Templates](/docs/ai-studio/ai-engineering/build-agents#variables-and-templates).

### Attach Files

Attach files in the `content` array of an input message item:

* **Images**: Via URL (`image_url`). For base64-encoded images, also set `mime_type` (e.g. `image/jpeg`).
* **PDFs**: Data URI only (`file_data`). Pass the file as `data:application/pdf;base64,<base64-data>`. URL links are not supported for PDFs.

<Warning>
  Verify the chosen model supports the file types in use. Vision models are required for image and PDF processing.
</Warning>

**Attach an image via URL:**

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.orq.ai/v3/router/responses \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
    "model": "agent/image-classifier",
    "input": [
      {
        "role": "user",
        "content": [
          {
            "type": "input_text",
            "text": "What can you see in this image?"
          },
          {
            "type": "input_image",
            "image_url": "https://example.com/image.jpg",
            "detail": "auto"
          }
        ]
      }
    ]
  }'
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  from orq_ai_sdk import Orq
  import os

  with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
      response = orq.responses.create(
          model="agent/image-classifier",
          input=[
              {
                  "role": "user",
                  "content": [
                      {"type": "input_text", "text": "What can you see in this image?"},
                      {
                          "type": "input_image",
                          "image_url": "https://example.com/image.jpg",
                          "detail": "auto",
                      },
                  ],
              }
          ],
      )
      print(response)
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import { Orq } from '@orq-ai/node';

  const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

  const response = await orq.responses.create({
    model: 'agent/image-classifier',
    input: [
      {
        role: 'user',
        content: [
          { type: 'input_text', text: 'What can you see in this image?' },
          {
            type: 'input_image',
            imageUrl: 'https://example.com/image.jpg',
            detail: 'auto',
          },
        ],
      },
    ],
  });

  console.log(response);
  ```
</CodeGroup>

**Attach a PDF via base64:**

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  PDF_B64="data:application/pdf;base64,$(base64 path/to/document.pdf | tr -d '\n')"

  curl -X POST https://api.orq.ai/v3/router/responses \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{
    \"model\": \"agent/my-agent\",
    \"input\": [
      {
        \"role\": \"user\",
        \"content\": [
          { \"type\": \"input_text\", \"text\": \"Summarize this document.\" },
          {
            \"type\": \"input_file\",
            \"filename\": \"document.pdf\",
            \"file_data\": \"$PDF_B64\"
          }
        ]
      }
    ]
  }"
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import base64
  from orq_ai_sdk import Orq
  import os

  with open("path/to/document.pdf", "rb") as f:
      pdf_data_uri = "data:application/pdf;base64," + base64.b64encode(f.read()).decode()

  with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
      response = orq.responses.create(
          model="agent/my-agent",
          input=[
              {
                  "role": "user",
                  "content": [
                      {"type": "input_text", "text": "Summarize this document."},
                      {
                          "type": "input_file",
                          "filename": "document.pdf",
                          "file_data": pdf_data_uri,
                      },
                  ],
              }
          ],
      )
      print(response)
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import { Orq } from '@orq-ai/node';
  import { readFileSync } from 'fs';

  const pdfDataUri =
    'data:application/pdf;base64,' +
    readFileSync('path/to/document.pdf').toString('base64');

  const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

  const response = await orq.responses.create({
    model: 'agent/my-agent',
    input: [
      {
        role: 'user',
        content: [
          { type: 'input_text', text: 'Summarize this document.' },
          {
            type: 'input_file',
            filename: 'document.pdf',
            fileData: pdfDataUri,
          },
        ],
      },
    ],
  });

  console.log(response);
  ```
</CodeGroup>

<Tip>See the full [Create Response API reference](/reference/responses/create-response).</Tip>

### Continue a Conversation

<Tabs>
  <Tab title="API & SDK" icon="code">
    After receiving a response, continue the conversation by passing the previously received response `id` as `previous_response_id` in the next request. The agent maintains full context from previous exchanges.

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/router/responses \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
        "model": "agent/my-agent",
        "previous_response_id": "resp_01K6D8QESESZ6SAXQPJPFQXPFT",
        "input": "Can you expand on the challenges section?"
      }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      from orq_ai_sdk import Orq
      import os

      with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
          response = orq.responses.create(
              model="agent/my-agent",
              previous_response_id="resp_01K6D8QESESZ6SAXQPJPFQXPFT",
              input="Can you expand on the challenges section?",
          )
          print(response)
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      import { Orq } from '@orq-ai/node';

      const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

      const response = await orq.responses.create({
        model: 'agent/my-agent',
        previousResponseId: 'resp_01K6D8QESESZ6SAXQPJPFQXPFT',
        input: 'Can you expand on the challenges section?',
      });

      console.log(response);
      ```
    </CodeGroup>

    The continuation returns a new response `id` for the extended conversation. The agent retains full context from all prior turns.

    <Tip>See the full [Create Response API reference](/reference/responses/create-response).</Tip>
  </Tab>

  <Tab title="MCP" icon="https://mintcdn.com/orqai/i7ZhKI7LFRfXU7ox/images/logos/mcp.svg?fit=max&auto=format&n=i7ZhKI7LFRfXU7ox&q=85&s=cef7916eb5fe1f6bb97541398d3f7639" width="16" height="16" data-path="images/logos/mcp.svg">
    Pass the response ID from the prior invocation. The assistant uses `invoke_agent` with `previous_response_id` set to that ID:

    ```prompt wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
    Continue that conversation and ask: Can you expand on the challenges section?
    ```

    The assistant uses `invoke_agent` with `previous_response_id` set to the ID from the prior response.
  </Tab>
</Tabs>

### Use Memory Stores

To call the Agent with a memory store, we'll use the [Responses API](/reference/responses/create-response) with an Embedded message and Linked memory.

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.orq.ai/v3/router/responses \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
    "model": "agent/agent-memories",
    "memory": {
      "entity_id": "customer_456"
    },
    "input": "Do you remember what is my name?"
  }'
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  from orq_ai_sdk import Orq
  import os

  with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
      response = orq.responses.create(
          model="agent/agent-memories",
          memory={
              "entity_id": "customer_456"
          },
          input="Do you remember what is my name?",
      )
      print(response)
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import { Orq } from '@orq-ai/node';

  const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

  const response = await orq.responses.create({
    model: 'agent/agent-memories',
    memory: {
      entityId: 'customer_456',
    },
    input: 'Do you remember what is my name?',
  });

  console.log(response);
  ```
</CodeGroup>

<Tip>
  Multiple memory stores per call are supported. Ensure the `entity_id` sent during the calls maps the same way to all previously declared memory stores during agent creation.
</Tip>

### Attach Metadata

Attach arbitrary key-value pairs to a response using the `metadata` field. Metadata is stored on the response and visible in traces. Use it to tag runs by session, user, environment, or any other dimension useful for filtering in **Observability**. Values must be strings.

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.orq.ai/v3/router/responses \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
    "model": "agent/my-agent",
    "input": "Summarize the latest product updates.",
    "metadata": {
      "session_id": "sess_abc123",
      "user_id": "user_456",
      "environment": "production"
    }
  }'
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  from orq_ai_sdk import Orq
  import os

  with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
      response = orq.responses.create(
          model="agent/my-agent",
          input="Summarize the latest product updates.",
          metadata={
              "session_id": "sess_abc123",
              "user_id": "user_456",
              "environment": "production",
          },
      )
      print(response.metadata)
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import { Orq } from '@orq-ai/node';

  const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

  const response = await orq.responses.create({
    model: 'agent/my-agent',
    input: 'Summarize the latest product updates.',
    metadata: {
      session_id: 'sess_abc123',
      user_id: 'user_456',
      environment: 'production',
    },
  });

  console.log(response.metadata);
  ```
</CodeGroup>

The metadata is returned on the response object:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "metadata": {
    "session_id": "sess_abc123",
    "user_id": "user_456",
    "environment": "production"
  }
}
```

### Use Tools

Pass tools in the `tools` array of any Responses API call. Multiple tools of different types can appear in the same request.

| Tool type      | What it does                                                                                                          |
| -------------- | --------------------------------------------------------------------------------------------------------------------- |
| **Function**   | Define a custom schema. The model decides when to call it; the application executes and returns the result.           |
| **MCP Server** | Connect to an MCP-compatible server. **Orq.ai** fetches the tool catalog and routes calls to the server.              |
| **HTTP**       | Call an external REST endpoint. **Orq.ai** executes the request; no application-side logic needed.                    |
| **Built-ins**  | Platform-managed tools (`orq:google_search`, `orq:web_scraper`, `orq:current_date`) with no setup or execution logic. |

Each tool type supports **Inline** (definition embedded in the request) or **Pre-saved** (created once in Studio, referenced by ID). HTTP and Built-ins are pre-saved or platform-managed only.

<AccordionGroup>
  <Accordion title="Function" icon="lambda">
    Define a custom function schema. The model decides when to call it, fills the parameters, and returns a `function_call` output item. Choose **Inline** to embed the schema in the request, or **Pre-saved** to reuse a schema stored in Studio.

    <Tabs>
      <Tab title="Inline" icon="code">
        Define a function schema inline. The model decides when to call it, fills the parameters, and returns a `function_call` output item. The application executes the function and sends the result back.

        **Step 1: Send the request with a function tool:**

        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
          curl -X POST https://api.orq.ai/v3/router/responses \
            -H "Authorization: Bearer $ORQ_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{
              "model": "agent/my-agent",
              "input": "What is the weather in Paris?",
              "tools": [{
                "type": "function",
                "name": "get_weather",
                "description": "Returns the current weather for a city.",
                "parameters": {
                  "type": "object",
                  "properties": {
                    "city": { "type": "string", "description": "City name" }
                  },
                  "required": ["city"]
                }
              }]
            }'
          ```

          ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
          from orq_ai_sdk import Orq
          import os

          orq = Orq(api_key=os.environ["ORQ_API_KEY"])

          response = orq.responses.create(
              model="agent/my-agent",
              input="What is the weather in Paris?",
              tools=[{
                  "type": "function",
                  "name": "get_weather",
                  "description": "Returns the current weather for a city.",
                  "parameters": {
                      "type": "object",
                      "properties": {
                          "city": {"type": "string", "description": "City name"},
                      },
                      "required": ["city"],
                  },
              }],
          )
          ```

          ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
          import { Orq } from "@orq-ai/node";

          const orq = new Orq({ apiKey: process.env.ORQ_API_KEY });

          const response = await orq.responses.create({
            model: "agent/my-agent",
            input: "What is the weather in Paris?",
            tools: [{
              type: "function",
              name: "get_weather",
              description: "Returns the current weather for a city.",
              parameters: {
                type: "object",
                properties: {
                  city: { type: "string", description: "City name" },
                },
                required: ["city"],
              },
            }],
          });
          ```
        </CodeGroup>

        The response contains a `function_call` output item when the model decides to use the tool:

        ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
        {
          "id": "resp_abc123",
          "status": "completed",
          "output": [{
            "type": "function_call",
            "name": "get_weather",
            "arguments": "{\"city\": \"Paris\"}",
            "call_id": "call_xyz789"
          }]
        }
        ```

        <Tip>
          The model only emits a `function_call` item when it decides to use the tool. Check `output[0].type === "function_call"` before proceeding to Step 2; if the model answered directly, read the text from `response.output[0].content[0].text` instead. Pass `tool_choice: "required"` to force a tool call.
        </Tip>

        **Step 2: Execute the function and return the result:**

        Pass `previous_response_id` and a `function_call_output` input item with the matching `call_id`. Include the same `tools` array so the model can make additional calls if needed.

        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
          curl -X POST https://api.orq.ai/v3/router/responses \
            -H "Authorization: Bearer $ORQ_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{
              "model": "agent/my-agent",
              "previous_response_id": "resp_abc123",
              "input": [{
                "type": "function_call_output",
                "call_id": "call_xyz789",
                "output": "{\"temperature\": 22, \"unit\": \"celsius\", \"condition\": \"sunny\"}"
              }],
              "tools": [{
                "type": "function",
                "name": "get_weather",
                "description": "Returns the current weather for a city.",
                "parameters": {
                  "type": "object",
                  "properties": {
                    "city": { "type": "string", "description": "City name" }
                  },
                  "required": ["city"]
                }
              }]
            }'
          ```

          ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
          import json

          # Execute the function locally
          result = {"temperature": 22, "unit": "celsius", "condition": "sunny"}

          final = orq.responses.create(
              model="agent/my-agent",
              previous_response_id=response.id,
              input=[{
                  "type": "function_call_output",
                  "call_id": response.output[0]["call_id"],
                  "output": json.dumps(result),
              }],
              tools=[{
                  "type": "function",
                  "name": "get_weather",
                  "description": "Returns the current weather for a city.",
                  "parameters": {
                      "type": "object",
                      "properties": {
                          "city": {"type": "string", "description": "City name"},
                      },
                      "required": ["city"],
                  },
              }],
          )
          print(final.output[0]["content"][0]["text"])
          ```

          ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
          // Execute the function locally
          const result = { temperature: 22, unit: "celsius", condition: "sunny" };

          const final = await orq.responses.create({
            model: "agent/my-agent",
            previousResponseId: response.id,
            input: [{
              type: "function_call_output",
              callId: (response.output[0] as any).call_id,
              output: JSON.stringify(result),
            }],
            tools: [{
              type: "function",
              name: "get_weather",
              description: "Returns the current weather for a city.",
              parameters: {
                type: "object",
                properties: {
                  city: { type: "string", description: "City name" },
                },
                required: ["city"],
              },
            }],
          });
          console.log(final.output?.[0]?.content?.[0]?.text);
          ```
        </CodeGroup>

        **Function tool fields:**

        | Field         | Type    | Required | Description                                                                                                |
        | ------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------- |
        | `type`        | string  | yes      | `"function"`                                                                                               |
        | `name`        | string  | yes      | Function name. Returned in the `function_call` output item so the application knows which function to run. |
        | `description` | string  | no       | What the function does. Helps the model decide when to call it.                                            |
        | `parameters`  | object  | no       | JSON Schema object describing the function's parameters.                                                   |
        | `strict`      | boolean | no       | Enforce strict parameter validation against the schema.                                                    |
      </Tab>

      <Tab title="Pre-saved" icon="bookmark">
        Reference a function tool saved in **Studio** using `orq:function` and its `tool_id`. The schema is retrieved from the platform at call time, but the application is still responsible for executing the function and sending back the result via `function_call_output`, identical to the Inline tab two-step cycle above. The only difference is the schema lives in Studio instead of in the request.

        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
          curl -X POST https://api.orq.ai/v3/router/responses \
            -H "Authorization: Bearer $ORQ_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{
              "model": "agent/my-agent",
              "input": "What is the weather in Paris?",
              "tools": [{
                "type": "orq:function",
                "tool_id": "tool_01ABC..."
              }]
            }'
          ```

          ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
          from orq_ai_sdk import Orq
          import os

          orq = Orq(api_key=os.environ["ORQ_API_KEY"])

          response = orq.responses.create(
              model="agent/my-agent",
              input="What is the weather in Paris?",
              tools=[{"type": "orq:function", "tool_id": "tool_01ABC..."}],
          )
          # output[0]["type"] == "function_call"; execute locally and send function_call_output as in the Inline tab above
          ```

          ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
          import { Orq } from "@orq-ai/node";

          const orq = new Orq({ apiKey: process.env.ORQ_API_KEY });

          const response = await orq.responses.create({
            model: "agent/my-agent",
            input: "What is the weather in Paris?",
            tools: [{ type: "orq:function", toolId: "tool_01ABC..." }],
          });
          // output[0].type === "function_call"; execute locally and send function_call_output as in the Inline tab above
          ```
        </CodeGroup>

        To create and manage function tools, see [Create Tools](/docs/tools/overview).
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="MCP Server" icon="https://mintcdn.com/orqai/i7ZhKI7LFRfXU7ox/images/logos/mcp.svg?fit=max&auto=format&n=i7ZhKI7LFRfXU7ox&q=85&s=cef7916eb5fe1f6bb97541398d3f7639" width="16" height="16" data-path="images/logos/mcp.svg">
    Connect to any [MCP](https://modelcontextprotocol.io/)-compatible server. This lets the agent read from and write to external services like Linear, Slack, or GitHub without writing any integration code. Choose **Inline** to supply the server URL per-request, or **Pre-saved** to reference a saved server by key with credentials stored on the platform.

    <Tabs>
      <Tab title="Inline" icon="code">
        Supply the MCP server URL directly in the request. The tool catalog is fetched from the server on each call. Use for one-off calls or when the server has not yet been saved under Tools. Provide `server_url` (inline) or `key` (pre-saved), not both.

        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
          curl -X POST https://api.orq.ai/v3/router/responses \
            -H "Authorization: Bearer $ORQ_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{
              "model": "agent/my-agent",
              "input": "List the teams in Linear",
              "tools": [{
                "type": "mcp",
                "server_url": "https://mcp.linear.app/mcp",
                "server_description": "Linear issue tracker",
                "headers": {
                  "Authorization": "Bearer lin_api_..."
                }
              }]
            }'
          ```

          ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
          from orq_ai_sdk import Orq
          import os

          orq = Orq(api_key=os.environ["ORQ_API_KEY"])

          response = orq.responses.create(
              model="agent/my-agent",
              input="List the teams in Linear",
              tools=[{
                  "type": "mcp",
                  "server_url": "https://mcp.linear.app/mcp",
                  "server_description": "Linear issue tracker",
                  "headers": {"Authorization": "Bearer lin_api_..."},
              }],
          )
          print(response.output[0]["content"][0]["text"])
          ```

          ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
          import { Orq } from "@orq-ai/node";

          const orq = new Orq({ apiKey: process.env.ORQ_API_KEY });

          const response = await orq.responses.create({
            model: "agent/my-agent",
            input: "List the teams in Linear",
            tools: [{
              type: "mcp",
              serverUrl: "https://mcp.linear.app/mcp",
              serverDescription: "Linear issue tracker",
              headers: { Authorization: "Bearer lin_api_..." },
            }],
          });
          console.log(response.output?.[0]?.content?.[0]?.text);
          ```
        </CodeGroup>

        **Per-request credentials**

        Use `{{variable}}` placeholders in headers and supply values at call time. The `secret: true` wrapper keeps token values out of traces and logs:

        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
          curl -X POST https://api.orq.ai/v3/router/responses \
            -H "Authorization: Bearer $ORQ_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{
              "model": "agent/my-agent",
              "input": "List the teams in Linear",
              "tools": [{
                "type": "mcp",
                "server_url": "https://mcp.linear.app/mcp",
                "headers": { "Authorization": "Bearer {{linear_token}}" }
              }],
              "variables": {
                "linear_token": { "secret": true, "value": "lin_api_..." }
              }
            }'
          ```

          ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
          response = orq.responses.create(
              model="agent/my-agent",
              input="List the teams in Linear",
              tools=[{
                  "type": "mcp",
                  "server_url": "https://mcp.linear.app/mcp",
                  "headers": {"Authorization": "Bearer {{linear_token}}"},
              }],
              variables={"linear_token": {"secret": True, "value": "lin_api_..."}},
          )
          print(response.output[0]["content"][0]["text"])
          ```

          ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
          const response = await orq.responses.create({
            model: "agent/my-agent",
            input: "List the teams in Linear",
            tools: [{
              type: "mcp",
              serverUrl: "https://mcp.linear.app/mcp",
              headers: { Authorization: "Bearer {{linear_token}}" },
            }],
            variables: { linear_token: { secret: true, value: "lin_api_..." } },
          });
          console.log(response.output?.[0]?.content?.[0]?.text);
          ```
        </CodeGroup>

        <Warning>
          `server_url` must use `http` or `https` and be reachable from **Orq.ai**. URLs whose host resolves to a loopback, link-local, private (RFC 1918), unspecified, or cloud-metadata address are rejected.
        </Warning>
      </Tab>

      <Tab title="Pre-saved" icon="bookmark">
        Save the MCP server once in [Studio](/docs/tools/overview) or via the [Create Tool API](/reference/tools/create-tool), then reference it by `key`. The tool catalog is cached at save time: no round-trip to the server on each call.

        <Note>
          Replace `my-agent` with the agent key and `linear_mcp` with the key of the MCP tool saved in **Studio**. If either key does not exist in the workspace, the request returns `400`.
        </Note>

        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
          curl -X POST https://api.orq.ai/v3/router/responses \
            -H "Authorization: Bearer $ORQ_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{
              "model": "agent/my-agent",
              "input": "List the teams in Linear",
              "tools": [{ "type": "mcp", "key": "linear_mcp" }]
            }'
          ```

          ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
          from orq_ai_sdk import Orq
          import os

          orq = Orq(api_key=os.environ["ORQ_API_KEY"])

          response = orq.responses.create(
              model="agent/my-agent",
              input="List the teams in Linear",
              tools=[{"type": "mcp", "key": "linear_mcp"}],
          )
          print(response.output[0]["content"][0]["text"])
          ```

          ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
          import { Orq } from "@orq-ai/node";

          const orq = new Orq({ apiKey: process.env.ORQ_API_KEY });

          const response = await orq.responses.create({
            model: "agent/my-agent",
            input: "List the teams in Linear",
            tools: [{ type: "mcp", key: "linear_mcp" }],
          });
          console.log(response.output?.[0]?.content?.[0]?.text);
          ```
        </CodeGroup>

        **Encrypted headers**

        Mark sensitive headers as `encrypted: true` when creating the tool in **Studio**. Values are stored with workspace-scoped encryption, decrypted on each call, and redacted from traces:

        ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
        "headers": {
          "Authorization": { "value": "Bearer sk-live-...", "encrypted": true }
        }
        ```

        **Per-request credentials**

        Store a `{{variable}}` placeholder in the tool's headers, then supply the value per call. Use `secret: true` to keep the token out of traces:

        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
          curl -X POST https://api.orq.ai/v3/router/responses \
            -H "Authorization: Bearer $ORQ_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{
              "model": "agent/my-agent",
              "input": "List the teams in Linear",
              "tools": [{ "type": "mcp", "key": "linear_mcp" }],
              "variables": {
                "linear_token": { "secret": true, "value": "lin_api_..." }
              }
            }'
          ```

          ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
          response = orq.responses.create(
              model="agent/my-agent",
              input="List the teams in Linear",
              tools=[{"type": "mcp", "key": "linear_mcp"}],
              variables={"linear_token": {"secret": True, "value": "lin_api_..."}},
          )
          print(response.output[0]["content"][0]["text"])
          ```

          ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
          const response = await orq.responses.create({
            model: "agent/my-agent",
            input: "List the teams in Linear",
            tools: [{ type: "mcp", key: "linear_mcp" }],
            variables: { linear_token: { secret: true, value: "lin_api_..." } },
          });
          console.log(response.output?.[0]?.content?.[0]?.text);
          ```
        </CodeGroup>

        **Multiple servers in one call**

        Each entry in `tools` is independent. Mix server keys and types freely:

        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
          curl -X POST https://api.orq.ai/v3/router/responses \
            -H "Authorization: Bearer $ORQ_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{
              "model": "agent/my-agent",
              "input": "Find tickets from yesterday in Linear and the related Slack threads.",
              "tools": [
                { "type": "mcp", "key": "linear_mcp" },
                { "type": "mcp", "key": "slack_mcp" }
              ]
            }'
          ```

          ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
          response = orq.responses.create(
              model="agent/my-agent",
              input="Find tickets from yesterday in Linear and the related Slack threads.",
              tools=[
                  {"type": "mcp", "key": "linear_mcp"},
                  {"type": "mcp", "key": "slack_mcp"},
              ],
          )
          print(response.output[0]["content"][0]["text"])
          ```

          ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
          const response = await orq.responses.create({
            model: "agent/my-agent",
            input: "Find tickets from yesterday in Linear and the related Slack threads.",
            tools: [
              { type: "mcp", key: "linear_mcp" },
              { type: "mcp", key: "slack_mcp" },
            ],
          });
          console.log(response.output?.[0]?.content?.[0]?.text);
          ```
        </CodeGroup>

        If the remote server adds new tools, refresh the saved tool in **Studio** to update the cached catalog.
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="HTTP" icon="globe">
    Reference an HTTP tool saved in **Studio** using `orq:http` and its `tool_id`. **Orq.ai** executes the HTTP request against the configured endpoint and returns the result to the model. No execution logic needed in the application.

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/router/responses \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "agent/my-agent",
          "input": "Get the latest order status for customer 42.",
          "tools": [{
            "type": "orq:http",
            "tool_id": "tool_01XYZ..."
          }]
        }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      from orq_ai_sdk import Orq
      import os

      orq = Orq(api_key=os.environ["ORQ_API_KEY"])

      response = orq.responses.create(
          model="agent/my-agent",
          input="Get the latest order status for customer 42.",
          tools=[{"type": "orq:http", "tool_id": "tool_01XYZ..."}],
      )
      print(response.output[0]["content"][0]["text"])
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      import { Orq } from "@orq-ai/node";

      const orq = new Orq({ apiKey: process.env.ORQ_API_KEY });

      const response = await orq.responses.create({
        model: "agent/my-agent",
        input: "Get the latest order status for customer 42.",
        tools: [{ type: "orq:http", toolId: "tool_01XYZ..." }],
      });
      console.log(response.output?.[0]?.content?.[0]?.text);
      ```
    </CodeGroup>

    To create and manage HTTP tools, see [Create Tools](/docs/tools/overview).
  </Accordion>

  <Accordion title="Built-ins" icon="bolt">
    **Orq.ai** includes platform-managed tools that require no configuration. Reference them by `type` alone. No credentials or execution logic needed in the application.

    | `type`              | Description                                       |
    | ------------------- | ------------------------------------------------- |
    | `orq:current_date`  | Returns the current UTC date and time.            |
    | `orq:google_search` | Performs a Google search and returns top results. |
    | `orq:web_scraper`   | Fetches and extracts text content from a URL.     |

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/router/responses \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "agent/my-agent",
          "input": "What are the top AI news stories right now?",
          "tools": [
            { "type": "orq:current_date" },
            { "type": "orq:google_search" }
          ]
        }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      from orq_ai_sdk import Orq
      import os

      orq = Orq(api_key=os.environ["ORQ_API_KEY"])

      response = orq.responses.create(
          model="agent/my-agent",
          input="What are the top AI news stories right now?",
          tools=[
              {"type": "orq:current_date"},
              {"type": "orq:google_search"},
          ],
      )
      print(response.output[0]["content"][0]["text"])
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      import { Orq } from "@orq-ai/node";

      const orq = new Orq({ apiKey: process.env.ORQ_API_KEY });

      const response = await orq.responses.create({
        model: "agent/my-agent",
        input: "What are the top AI news stories right now?",
        tools: [
          { type: "orq:current_date" },
          { type: "orq:google_search" },
        ],
      });
      console.log(response.output?.[0]?.content?.[0]?.text);
      ```
    </CodeGroup>

    Built-in tools execute automatically on **Orq.ai** infrastructure. Results are fed back to the model within the same request; no `function_call_output` round-trip needed.
  </Accordion>
</AccordionGroup>

#### Control Tool Calls

Controls whether and which tool the model calls. Applies to all tool types.

<AccordionGroup>
  <Accordion title="Auto: Model Decides" icon="shuffle">
    Default when tools are present. The model decides on each turn whether to call a tool or answer directly. Use this for conversational agents where tool use is situational.

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/router/responses \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "agent/my-agent",
          "input": "What is the weather in Paris?",
          "tools": [{
            "type": "function",
            "name": "get_weather",
            "description": "Returns the current weather for a city.",
            "parameters": {
              "type": "object",
              "properties": { "city": { "type": "string" } },
              "required": ["city"]
            }
          }],
          "tool_choice": "auto"
        }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      response = orq.responses.create(
          model="agent/my-agent",
          input="What is the weather in Paris?",
          tools=[{
              "type": "function",
              "name": "get_weather",
              "description": "Returns the current weather for a city.",
              "parameters": {
                  "type": "object",
                  "properties": {"city": {"type": "string"}},
                  "required": ["city"],
              },
          }],
          tool_choice="auto",
      )
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      const response = await orq.responses.create({
        model: "agent/my-agent",
        input: "What is the weather in Paris?",
        tools: [{
          type: "function",
          name: "get_weather",
          description: "Returns the current weather for a city.",
          parameters: {
            type: "object",
            properties: { city: { type: "string" } },
            required: ["city"],
          },
        }],
        toolChoice: "auto",
      });
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Required: Always Call a Tool" icon="circle-check">
    The model must call at least one tool before producing a final response. Use when a tool call is always necessary: for example, a retrieval step before every answer.

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/router/responses \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "agent/my-agent",
          "input": "What is the weather in Paris?",
          "tools": [{
            "type": "function",
            "name": "get_weather",
            "description": "Returns the current weather for a city.",
            "parameters": {
              "type": "object",
              "properties": { "city": { "type": "string" } },
              "required": ["city"]
            }
          }],
          "tool_choice": "required"
        }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      response = orq.responses.create(
          model="agent/my-agent",
          input="What is the weather in Paris?",
          tools=[{
              "type": "function",
              "name": "get_weather",
              "description": "Returns the current weather for a city.",
              "parameters": {
                  "type": "object",
                  "properties": {"city": {"type": "string"}},
                  "required": ["city"],
              },
          }],
          tool_choice="required",
      )
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      const response = await orq.responses.create({
        model: "agent/my-agent",
        input: "What is the weather in Paris?",
        tools: [{
          type: "function",
          name: "get_weather",
          description: "Returns the current weather for a city.",
          parameters: {
            type: "object",
            properties: { city: { type: "string" } },
            required: ["city"],
          },
        }],
        toolChoice: "required",
      });
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="None: Disable Tools" icon="ban">
    The model must not call any tool. Tools remain present in the request (the model can see their schemas) but cannot invoke them. Use to temporarily disable tools without removing them from the request.

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/router/responses \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "agent/my-agent",
          "input": "What is the weather in Paris?",
          "tools": [{
            "type": "function",
            "name": "get_weather",
            "description": "Returns the current weather for a city.",
            "parameters": {
              "type": "object",
              "properties": { "city": { "type": "string" } },
              "required": ["city"]
            }
          }],
          "tool_choice": "none"
        }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      response = orq.responses.create(
          model="agent/my-agent",
          input="What is the weather in Paris?",
          tools=[{
              "type": "function",
              "name": "get_weather",
              "description": "Returns the current weather for a city.",
              "parameters": {
                  "type": "object",
                  "properties": {"city": {"type": "string"}},
                  "required": ["city"],
              },
          }],
          tool_choice="none",
      )
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      const response = await orq.responses.create({
        model: "agent/my-agent",
        input: "What is the weather in Paris?",
        tools: [{
          type: "function",
          name: "get_weather",
          description: "Returns the current weather for a city.",
          parameters: {
            type: "object",
            properties: { city: { type: "string" } },
            required: ["city"],
          },
        }],
        toolChoice: "none",
      });
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Specific Function: Force One Tool" icon="lambda">
    Force the model to call one named function. Pass `{ "type": "function", "name": "<function name>" }`, replacing `<function name>` with the exact `name` from the tool definition. Use when the application must extract structured data from a known function schema.

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/router/responses \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "agent/my-agent",
          "input": "What is the weather in Paris?",
          "tools": [{
            "type": "function",
            "name": "get_weather",
            "description": "Returns the current weather for a city.",
            "parameters": {
              "type": "object",
              "properties": { "city": { "type": "string" } },
              "required": ["city"]
            }
          }],
          "tool_choice": { "type": "function", "name": "get_weather" }
        }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      response = orq.responses.create(
          model="agent/my-agent",
          input="What is the weather in Paris?",
          tools=[{
              "type": "function",
              "name": "get_weather",
              "description": "Returns the current weather for a city.",
              "parameters": {
                  "type": "object",
                  "properties": {"city": {"type": "string"}},
                  "required": ["city"],
              },
          }],
          tool_choice={"type": "function", "name": "get_weather"},
      )
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      const response = await orq.responses.create({
        model: "agent/my-agent",
        input: "What is the weather in Paris?",
        tools: [{
          type: "function",
          name: "get_weather",
          description: "Returns the current weather for a city.",
          parameters: {
            type: "object",
            properties: { city: { type: "string" } },
            required: ["city"],
          },
        }],
        toolChoice: { type: "function", name: "get_weather" },
      });
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>

#### Filter Tools

MCP servers can expose dozens of tools. Use `allowed_tools` on any MCP entry (inline or pre-saved) to narrow what the model sees. Tools outside the filter are invisible to the model and cannot be invoked. `allowed_tools` applies only to MCP tools; it has no effect on function, HTTP, or built-in tools.

<AccordionGroup>
  <Accordion title="tool_names: Expose Named Tools Only" icon="list">
    Expose only the listed tools by name. The model cannot see or call any tool not in the list.

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/router/responses \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "agent/my-agent",
          "input": "List the open Engineering issues.",
          "tools": [{
            "type": "mcp",
            "key": "linear_mcp",
            "allowed_tools": { "tool_names": ["list_teams", "list_issues"] }
          }]
        }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      response = orq.responses.create(
          model="agent/my-agent",
          input="List the open Engineering issues.",
          tools=[{
              "type": "mcp",
              "key": "linear_mcp",
              "allowed_tools": {"tool_names": ["list_teams", "list_issues"]},
          }],
      )
      print(response.output[0]["content"][0]["text"])
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      const response = await orq.responses.create({
        model: "agent/my-agent",
        input: "List the open Engineering issues.",
        tools: [{
          type: "mcp",
          key: "linear_mcp",
          allowedTools: { toolNames: ["list_teams", "list_issues"] },
        }],
      });
      console.log(response.output?.[0]?.content?.[0]?.text);
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="read_only: Non-mutating Tools Only" icon="eye">
    Expose only tools the server marks as `readOnlyHint: true`. Use to prevent the model from calling any mutating operations. The server must annotate tools with `readOnlyHint` for this filter to have effect.

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/router/responses \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "agent/my-agent",
          "input": "Summarise the open issues in the Engineering team.",
          "tools": [{
            "type": "mcp",
            "key": "linear_mcp",
            "allowed_tools": { "read_only": true }
          }]
        }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      response = orq.responses.create(
          model="agent/my-agent",
          input="Summarise the open issues in the Engineering team.",
          tools=[{
              "type": "mcp",
              "key": "linear_mcp",
              "allowed_tools": {"read_only": True},
          }],
      )
      print(response.output[0]["content"][0]["text"])
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      const response = await orq.responses.create({
        model: "agent/my-agent",
        input: "Summarise the open issues in the Engineering team.",
        tools: [{
          type: "mcp",
          key: "linear_mcp",
          allowedTools: { readOnly: true },
        }],
      });
      console.log(response.output?.[0]?.content?.[0]?.text);
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Combined: Name and Read-only Filter" icon="filter">
    Intersection filter: expose only tools that are both read-only AND in the named list.

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/router/responses \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "model": "agent/my-agent",
          "input": "List the open Engineering issues.",
          "tools": [{
            "type": "mcp",
            "key": "linear_mcp",
            "allowed_tools": { "read_only": true, "tool_names": ["list_teams", "list_issues"] }
          }]
        }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      response = orq.responses.create(
          model="agent/my-agent",
          input="List the open Engineering issues.",
          tools=[{
              "type": "mcp",
              "key": "linear_mcp",
              "allowed_tools": {"read_only": True, "tool_names": ["list_teams", "list_issues"]},
          }],
      )
      print(response.output[0]["content"][0]["text"])
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      const response = await orq.responses.create({
        model: "agent/my-agent",
        input: "List the open Engineering issues.",
        tools: [{
          type: "mcp",
          key: "linear_mcp",
          allowedTools: { readOnly: true, toolNames: ["list_teams", "list_issues"] },
        }],
      });
      console.log(response.output?.[0]?.content?.[0]?.text);
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>

#### Streaming Events

Set `stream: true` on any request with tools. See [Streaming](#streaming) for setup and base event shapes. For function tools, act on `response.output_item.done`: it carries the complete `function_call` item with `arguments` and `call_id` ready for Step 2. MCP server calls also emit three additional events:

| Event                           | When                                               |
| ------------------------------- | -------------------------------------------------- |
| `response.mcp_call.in_progress` | MCP tool starts executing.                         |
| `response.mcp_call.completed`   | MCP tool returned a result.                        |
| `response.mcp_call.failed`      | MCP tool raised an error or the connection failed. |

MCP output items use `type: "mcp_call"`. Function tool output items use `type: "function_call"`. Match on `type` when processing output on the client.

#### Observability

Every tool invocation appears in traces as a child span of the agent loop.

**All tool spans:**

| Attribute                    | Description                                                   |
| ---------------------------- | ------------------------------------------------------------- |
| `gen_ai.tool.name`           | The tool name the model called.                               |
| `gen_ai.tool.type`           | `mcp`, `function`, `http`, or `code`.                         |
| `gen_ai.tool.call.id`        | The call ID matching the output item in the stored response.  |
| `gen_ai.tool.call.arguments` | JSON-encoded arguments passed to the tool (secrets redacted). |

**MCP spans only:**

| Attribute         | Description                                                        |
| ----------------- | ------------------------------------------------------------------ |
| `server.address`  | The MCP server URL.                                                |
| `mcp.session.id`  | The pre-saved tool key, or the inline server URL for ad-hoc calls. |
| `mcp.method.name` | Always `tools/call`.                                               |

#### Error Reference

<AccordionGroup>
  <Accordion title="Rejected server_url" icon="circle-exclamation">
    HTTP `400`, `type: "invalid_request"`

    The `server_url` uses a bad scheme or resolves to a disallowed address (loopback, link-local, private RFC 1918, unspecified, or cloud-metadata).

    ```text wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
    MCP server URL must not point to loopback, link-local, private, or unspecified addresses
    ```
  </Accordion>

  <Accordion title="Pre-saved Key Not Found" icon="circle-exclamation">
    HTTP `400`, `type: "invalid_request"`

    The `key` passed in the request does not match any tool saved in the workspace.

    ```text wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
    failed to resolve MCP server "foo": tool not found
    ```
  </Accordion>

  <Accordion title="Server Refused the Handshake" icon="circle-exclamation">
    HTTP `400`, `type: "invalid_request"`

    The MCP server rejected the connection during the initialization handshake.

    ```text wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
    mcp connect to "foo" failed: ...
    ```
  </Accordion>

  <Accordion title="Server Unreachable or Bad Response" icon="circle-exclamation">
    HTTP `400`, `type: "invalid_request"`

    The MCP server was not reachable or returned a malformed response during tool discovery.

    ```text wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
    mcp list tools from "foo" failed: ...
    ```
  </Accordion>

  <Accordion title="Server-side Failure" icon="circle-exclamation">
    HTTP `500`, `type: "internal_error"`

    An unexpected error occurred on the **Orq.ai** side. Retry with exponential backoff.
  </Accordion>

  <Accordion title="Tool-call Execution Failure" icon="circle-exclamation">
    HTTP `200`, output item with `status: "failed"`

    The tool call was routed successfully but the tool itself raised an error. The overall HTTP response is `200` because the request succeeded; inspect `output[n].output` for the error detail.
  </Accordion>
</AccordionGroup>

#### Limits

| Limit                    | Value                               |
| ------------------------ | ----------------------------------- |
| Supported MCP transports | Streamable HTTP (preferred) and SSE |
| Tool discovery per call  | 250 tools across all MCP servers    |
| Per-tool call timeout    | 10 minutes                          |
| Encrypted header size    | 16 KB per header value              |

## Schedule Agents

Run an agent on a recurring cadence without holding open an HTTP connection. Each scheduled run follows the same execution path, tracing, and billing as a direct API call.

### Create a Schedule

<Tabs>
  <Tab title="AI Studio" icon="https://mintcdn.com/orqai/My16MDKJXrKALEHC/images/logos/ai-studio-round.svg?fit=max&auto=format&n=My16MDKJXrKALEHC&q=85&s=ac04dd509320d58ab9701cb6d6137733" width="100" height="100" data-path="images/logos/ai-studio-round.svg">
    Open the agent and go to the **Schedules** tab. Click <kbd className="key"><Icon icon="circle-plus" color="#fff" /> New schedule</kbd> to open the form.

    <Frame caption="Create a new schedule from the Schedules tab on an agent.">
      <img src="https://mintcdn.com/orqai/o8naf68UePQ9lM4H/images/schedule-create.png?fit=max&auto=format&n=o8naf68UePQ9lM4H&q=85&s=b38ccf61636595895af8291da0f08726" alt="Agent schedule creation form showing Name, Frequency toggle with Hourly, Daily, and Weekly options, Time, Summary, Input, Variables, and Metadata fields." width="682" height="959" data-path="images/schedule-create.png" />
    </Frame>

    | Field            | Description                                                                                                     |
    | ---------------- | --------------------------------------------------------------------------------------------------------------- |
    | **Name**         | A display label for the schedule in the UI. Required. Not sent to the agent.                                    |
    | **Frequency**    | **Hourly**, **Daily**, or **Weekly**.                                                                           |
    | **Time**         | The hour the schedule fires, in local time. Shown for Daily and Weekly.                                         |
    | **Pick the day** | Day of the week to fire. Shown for Weekly only.                                                                 |
    | **Summary**      | Auto-generated human-readable description of the schedule.                                                      |
    | **Input**        | The user message sent to the agent on each firing. Required, since every agent invocation needs a user message. |
    | **Variables**    | Key-value pairs passed to the agent on each run. See below.                                                     |
    | **Metadata**     | Key-value pairs attached to every response this schedule generates. See below.                                  |

    **Variables**

    Use the **Variables** section to define values that the agent needs on each run. Variables are sent alongside the input as a distinct payload field, and can be consumed by the agent's instructions, any configured tool, or a subagent wherever the variable is wired up.

    <Note>
      For example, a support agent with an HTTP tool that looks up a customer in an external system can receive `customer_id=1234` from the schedule and use it to query the right record on every run. See the screenshot below.
    </Note>

    Variables cannot be referenced inside the **Input** field itself. Wire them into the agent's instructions, a tool, or a subagent instead.

    **Metadata**

    Use the **Metadata** section to attach arbitrary key-value pairs to every response generated by this schedule. Metadata is not passed to the agent: it is stored on the trace and can be used to filter traces in **Observability**, identify which schedule triggered a run, or tag responses for downstream processing.

    Click **Create** to activate the schedule. It starts firing at the next matching time.

    <Frame caption="A created schedule showing configured variables and metadata.">
      <img src="https://mintcdn.com/orqai/o8naf68UePQ9lM4H/images/agent-schedule-created.png?fit=max&auto=format&n=o8naf68UePQ9lM4H&q=85&s=dc73fb24c40c0f5b447e6a1f1a1b4143" alt="A saved agent schedule entry showing the schedule name, frequency, next run time, and the configured variables and metadata key-value pairs." width="1747" height="1195" data-path="images/agent-schedule-created.png" />
    </Frame>
  </Tab>

  <Tab title="API & SDK" icon="code">
    Only `cron` schedules are supported. Expressions use the 6-field format: `sec min hour dom month dow`. Three patterns are accepted:

    | Pattern | Expression             | Example                                  |
    | ------- | ---------------------- | ---------------------------------------- |
    | Hourly  | `0 0 * * * *`          | Fires every hour                         |
    | Daily   | `0 0 <hour> * * *`     | `0 0 9 * * *` (9:00 AM UTC daily)        |
    | Weekly  | `0 0 <hour> * * <day>` | `0 0 9 * * 1` (9:00 AM UTC every Monday) |

    `<day>` is `0` (Sunday) through `6` (Saturday). All times are stored in UTC; the UI displays them in user's local timezone.

    <Warning>
      Only `cron` is accepted. Seconds and minutes must be `0`, dom and month must be `*`, and the weekday field must be a single integer `0`-`6` or `*` (names like `mon` and ranges like `1-5` are rejected). To run an agent in response to an event rather than a clock, invoke it directly via the [Run API](/docs/ai-studio/ai-engineering/run-agents).

      Expressions that do not match a supported pattern return `400` with `"code": "invalid_expression"`. The `message` field describes the specific violation, for example `invalid schedule expression: day-of-month and month fields must be '*'`
    </Warning>

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/agents/ops_digest/schedules \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "type": "cron",
          "expression": "0 0 9 * * *",
          "display_name": "Morning briefing",
          "payload": {
            "input": "Generate the morning briefing for {{region}}",
            "variables": { "region": "EMEA" }
          }
        }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      from orq_ai_sdk import Orq
      import os

      with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
          schedule = orq.schedules.create(
              agent_key="ops_digest",
              type_="cron",
              expression="0 0 9 * * *",
              display_name="Morning briefing",
              payload={
                  "input": "Generate the morning briefing for {{region}}",
                  "variables": {"region": "EMEA"},
              },
          )
          print(schedule)
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      import { Orq } from '@orq-ai/node';

      const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

      const schedule = await orq.schedules.create({
        agentKey: 'ops_digest',
        requestBody: {
          type: 'cron',
          expression: '0 0 9 * * *',
          displayName: 'Morning briefing',
          payload: {
            input: 'Generate the morning briefing for {{region}}',
            variables: { region: 'EMEA' },
          },
        },
      });

      console.log(schedule);
      ```
    </CodeGroup>

    <Info>The TypeScript SDK uses camelCase keys (`agentKey`, `requestBody`) and nests the request body under `requestBody`, while the Python SDK uses flat keyword arguments. Both map to the same wire format.</Info>

    `payload` is required. Response (schedule records use `_id` rather than `id`):

    ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
    {
      "_id": "01KPN29WWKSK0VDPJNTKZPVNRB",
      "agent_key": "ops_digest",
      "type": "cron",
      "expression": "0 0 9 * * *",
      "display_name": "Morning briefing",
      "is_active": true,
      "generation": 1,
      "payload": {
        "input": "Generate the morning briefing for {{region}}",
        "variables": { "region": "EMEA" }
      },
      "trigger_count": 0,
      "created": "2026-04-20T10:00:00Z",
      "updated": "2026-04-20T10:00:00Z"
    }
    ```

    **Schedule fields:**

    | Field          | Type   | Description                                                                          |
    | -------------- | ------ | ------------------------------------------------------------------------------------ |
    | `display_name` | string | Optional. Label shown in the UI Schedules tab.                                       |
    | `type`         | string | Must be `cron`.                                                                      |
    | `expression`   | string | 6-field cron expression matching one of the three supported patterns.                |
    | `agent_tag`    | string | Pin the schedule to a specific agent version. Omit to always run the active version. |

    **Payload fields:**

    | Field              | Type            | Description                                                                                                                                                                                 |
    | ------------------ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `input`            | string or array | The instruction the agent runs on each firing. Same shape as the `input` field in the [Run API](/docs/ai-studio/ai-engineering/run-agents). Supports template variables via `{{variable}}`. |
    | `variables`        | object          | Template variable substitution. Use `{"secret": true, "value": "..."}` for secret values.                                                                                                   |
    | `memory_entity_id` | string          | Memory store entity to attach on each run.                                                                                                                                                  |
    | `metadata`         | object          | Opaque key/value pairs attached to every response this schedule generates.                                                                                                                  |

    `generation` increments each time `type` or `expression` changes and resets `trigger_count` to 0. Use it to distinguish firings before and after a cadence change.

    Use `agent_tag` (string) to pin the schedule to a specific agent version. Omit it to always use the active version:

    ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
    {
      "type": "cron",
      "expression": "0 0 9 * * *",
      "display_name": "Morning briefing",
      "agent_tag": "v2",
      "payload": { "input": "Generate the morning briefing for {{region}}" }
    }
    ```
  </Tab>
</Tabs>

### List & Retrieve

<Tabs>
  <Tab title="AI Studio" icon="https://mintcdn.com/orqai/My16MDKJXrKALEHC/images/logos/ai-studio-round.svg?fit=max&auto=format&n=My16MDKJXrKALEHC&q=85&s=ac04dd509320d58ab9701cb6d6137733" width="100" height="100" data-path="images/logos/ai-studio-round.svg">
    All schedules for the agent are listed in the **Schedules** tab. Click a schedule row to open its details, including trigger count and last fired time.
  </Tab>

  <Tab title="API & SDK" icon="code">
    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      # List all schedules
      curl https://api.orq.ai/v3/agents/ops_digest/schedules \
        -H "Authorization: Bearer $ORQ_API_KEY"

      # Get a single schedule
      curl https://api.orq.ai/v3/agents/ops_digest/schedules/{schedule_id} \
        -H "Authorization: Bearer $ORQ_API_KEY"
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      from orq_ai_sdk import Orq
      import os

      with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
          # List all schedules
          result = orq.schedules.list(agent_key="ops_digest")
          print(result.schedules)

          # Get a single schedule
          schedule = orq.schedules.retrieve(
              agent_key="ops_digest",
              schedule_id="{schedule_id}",
          )
          print(schedule)
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      import { Orq } from '@orq-ai/node';

      const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

      // List all schedules
      const result = await orq.schedules.list({ agentKey: 'ops_digest' });
      console.log(result.schedules);

      // Get a single schedule
      const schedule = await orq.schedules.retrieve({
        agentKey: 'ops_digest',
        scheduleId: '{schedule_id}',
      });
      console.log(schedule);
      ```
    </CodeGroup>

    List returns `{ "schedules": [...] }`, most recent first. The single-schedule response includes `trigger_count`, `last_triggered_at` (UTC timestamp string; `null` before the first firing), and `generation`.
  </Tab>
</Tabs>

### Pause and Resume

<Tabs>
  <Tab title="AI Studio" icon="https://mintcdn.com/orqai/My16MDKJXrKALEHC/images/logos/ai-studio-round.svg?fit=max&auto=format&n=My16MDKJXrKALEHC&q=85&s=ac04dd509320d58ab9701cb6d6137733" width="100" height="100" data-path="images/logos/ai-studio-round.svg">
    Click <kbd><Icon icon="ellipsis" /></kbd> on the schedule row, then click <kbd className="key"><Icon icon="bolt" color="#fff" /> Enable</kbd> to toggle the schedule on or off. Field edits saved while paused take effect on the next active run.
  </Tab>

  <Tab title="API & SDK" icon="code">
    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      # Pause
      curl -X PATCH https://api.orq.ai/v3/agents/ops_digest/schedules/{schedule_id} \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{ "is_active": false }'

      # Resume
      curl -X PATCH https://api.orq.ai/v3/agents/ops_digest/schedules/{schedule_id} \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{ "is_active": true }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      from orq_ai_sdk import Orq
      import os

      with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
          # Pause
          orq.schedules.update(
              agent_key="ops_digest",
              schedule_id="{schedule_id}",
              is_active=False,
          )

          # Resume
          orq.schedules.update(
              agent_key="ops_digest",
              schedule_id="{schedule_id}",
              is_active=True,
          )
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      import { Orq } from '@orq-ai/node';

      const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

      // Pause
      await orq.schedules.update({
        agentKey: 'ops_digest',
        scheduleId: '{schedule_id}',
        requestBody: { isActive: false },
      });

      // Resume
      await orq.schedules.update({
        agentKey: 'ops_digest',
        scheduleId: '{schedule_id}',
        requestBody: { isActive: true },
      });
      ```
    </CodeGroup>

    Payload-only and `agent_tag`-only changes do not reset the firing cadence and apply to the next regular run. Changing `type` or `expression` shifts the cadence from the PATCH time and resets `trigger_count` to 0.

    **Lifecycle notes:**

    * **Missed firings**: Not replayed. If the service is unavailable when a schedule fires, that firing is lost. The schedule resumes on its next scheduled time once service is restored.
  </Tab>
</Tabs>

### Trigger On Demand

<Tabs>
  <Tab title="API & SDK" icon="code">
    Runs the schedule's payload immediately without affecting its regular cadence. Useful for smoke-testing a new schedule or manually re-running a missed execution.

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v3/agents/ops_digest/schedules/{schedule_id}/execution \
        -H "Authorization: Bearer $ORQ_API_KEY"
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      from orq_ai_sdk import Orq
      import os

      with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
          orq.schedules.trigger(
              agent_key="ops_digest",
              schedule_id="{schedule_id}",
          )
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      import { Orq } from '@orq-ai/node';

      const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

      await orq.schedules.trigger({
        agentKey: 'ops_digest',
        scheduleId: '{schedule_id}',
      });
      ```
    </CodeGroup>

    Returns `202 Accepted` with:

    ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
    {
      "status": "triggered",
      "schedule_id": "01KPN29WWKSK0VDPJNTKZPVNRB"
    }
    ```

    The run appears in traces as a `schedule.<agent_key>` leading span roughly 10 seconds later, carrying `orq.schedule_id` and the full agent execution chain. Schedule-driven cost and token usage appear in usage reports alongside HTTP-invoked runs. Inactive schedules return `400 schedule_inactive`.
  </Tab>
</Tabs>

### Delete

<Tabs>
  <Tab title="AI Studio" icon="https://mintcdn.com/orqai/My16MDKJXrKALEHC/images/logos/ai-studio-round.svg?fit=max&auto=format&n=My16MDKJXrKALEHC&q=85&s=ac04dd509320d58ab9701cb6d6137733" width="100" height="100" data-path="images/logos/ai-studio-round.svg">
    Click <kbd><Icon icon="ellipsis" /></kbd> on the schedule row, then click **Delete**. The action is immediate and permanent.
  </Tab>

  <Tab title="API & SDK" icon="code">
    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X DELETE https://api.orq.ai/v3/agents/ops_digest/schedules/{schedule_id} \
        -H "Authorization: Bearer $ORQ_API_KEY"
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      from orq_ai_sdk import Orq
      import os

      with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
          orq.schedules.delete(
              agent_key="ops_digest",
              schedule_id="{schedule_id}",
          )
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      import { Orq } from '@orq-ai/node';

      const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

      await orq.schedules.delete({
        agentKey: 'ops_digest',
        scheduleId: '{schedule_id}',
      });
      ```
    </CodeGroup>

    Returns `204 No Content`. Deleting the agent itself removes all its schedules automatically.
  </Tab>
</Tabs>

### Examples

<Tabs>
  <Tab title="API & SDK" icon="code">
    <AccordionGroup>
      <Accordion title="Daily morning briefing (9 AM UTC)" icon="sun">
        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
          curl -X POST https://api.orq.ai/v3/agents/ops_digest/schedules \
            -H "Authorization: Bearer $ORQ_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{
              "type": "cron",
              "expression": "0 0 9 * * *",
              "display_name": "Daily morning briefing",
              "agent_tag": "v2",
              "payload": {
                "input": "Generate the morning briefing for {{region}}",
                "variables": { "region": "EMEA" },
                "metadata": { "run_source": "daily-briefing" }
              }
            }'
          ```

          ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
          from orq_ai_sdk import Orq
          import os

          with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
              schedule = orq.schedules.create(
                  agent_key="ops_digest",
                  type_="cron",
                  expression="0 0 9 * * *",
                  display_name="Daily morning briefing",
                  agent_tag="v2",
                  payload={
                      "input": "Generate the morning briefing for {{region}}",
                      "variables": {"region": "EMEA"},
                      "metadata": {"run_source": "daily-briefing"},
                  },
              )
              print(schedule)
          ```

          ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
          import { Orq } from '@orq-ai/node';

          const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

          const schedule = await orq.schedules.create({
            agentKey: 'ops_digest',
            requestBody: {
              type: 'cron',
              expression: '0 0 9 * * *',
              displayName: 'Daily morning briefing',
              agentTag: 'v2',
              payload: {
                input: 'Generate the morning briefing for {{region}}',
                variables: { region: 'EMEA' },
                metadata: { run_source: 'daily-briefing' },
              },
            },
          });

          console.log(schedule);
          ```
        </CodeGroup>
      </Accordion>

      <Accordion title="Hourly background summarizer (with memory)" icon="brain">
        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
          curl -X POST https://api.orq.ai/v3/agents/knowledge_indexer/schedules \
            -H "Authorization: Bearer $ORQ_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{
              "type": "cron",
              "expression": "0 0 * * * *",
              "display_name": "Hourly knowledge indexer",
              "payload": {
                "input": "Fetch new entries and update the knowledge base",
                "memory_entity_id": "mem_entity_123"
              }
            }'
          ```

          ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
          from orq_ai_sdk import Orq
          import os

          with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
              schedule = orq.schedules.create(
                  agent_key="knowledge_indexer",
                  type_="cron",
                  expression="0 0 * * * *",
                  display_name="Hourly knowledge indexer",
                  payload={
                      "input": "Fetch new entries and update the knowledge base",
                      "memory_entity_id": "mem_entity_123",
                  },
              )
              print(schedule)
          ```

          ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
          import { Orq } from '@orq-ai/node';

          const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

          const schedule = await orq.schedules.create({
            agentKey: 'knowledge_indexer',
            requestBody: {
              type: 'cron',
              expression: '0 0 * * * *',
              displayName: 'Hourly knowledge indexer',
              payload: {
                input: 'Fetch new entries and update the knowledge base',
                memoryEntityId: 'mem_entity_123',
              },
            },
          });

          console.log(schedule);
          ```
        </CodeGroup>

        `memory_entity_id` attaches a [Memory Store](/docs/ai-studio/ai-engineering/knowledge-bases-memory-stores#memory-stores) entity to every run. The agent can read from and write to the store on each firing, accumulating context across executions.
      </Accordion>

      <Accordion title="Scheduled run with secret variables" icon="lock">
        <CodeGroup>
          ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
          curl -X POST https://api.orq.ai/v3/agents/daily_sync/schedules \
            -H "Authorization: Bearer $ORQ_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{
              "type": "cron",
              "expression": "0 0 3 * * *",
              "display_name": "Nightly warehouse sync",
              "payload": {
                "input": "Sync new rows from {{table}} to the analytics warehouse",
                "variables": {
                  "table": "orders",
                  "warehouse_token": { "secret": true, "value": "sk-secret-123" }
                }
              }
            }'
          ```

          ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
          from orq_ai_sdk import Orq
          import os

          with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
              schedule = orq.schedules.create(
                  agent_key="daily_sync",
                  type_="cron",
                  expression="0 0 3 * * *",
                  display_name="Nightly warehouse sync",
                  payload={
                      "input": "Sync new rows from {{table}} to the analytics warehouse",
                      "variables": {
                          "table": "orders",
                          "warehouse_token": {"secret": True, "value": "sk-secret-123"},
                      },
                  },
              )
              print(schedule)
          ```

          ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
          import { Orq } from '@orq-ai/node';

          const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

          const schedule = await orq.schedules.create({
            agentKey: 'daily_sync',
            requestBody: {
              type: 'cron',
              expression: '0 0 3 * * *',
              displayName: 'Nightly warehouse sync',
              payload: {
                input: 'Sync new rows from {{table}} to the analytics warehouse',
                variables: {
                  table: 'orders',
                  warehouse_token: { secret: true, value: 'sk-secret-123' },
                },
              },
            },
          });

          console.log(schedule);
          ```
        </CodeGroup>

        Secret values are redacted from traces and stripped from the stored payload's observable form.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

## Agent and Task States

<Tabs>
  <Tab title="AI Studio" icon="https://mintcdn.com/orqai/My16MDKJXrKALEHC/images/logos/ai-studio-round.svg?fit=max&auto=format&n=My16MDKJXrKALEHC&q=85&s=ac04dd509320d58ab9701cb6d6137733" width="100" height="100" data-path="images/logos/ai-studio-round.svg">
    <Warning>
      Agent execution can take a long time. If the agent appears to be hanging, it is most likely still running. Wait and check the panel again later.
    </Warning>

    **Agent states:**

    | State             | Description                                                    |
    | ----------------- | -------------------------------------------------------------- |
    | Active            | Execution in progress; continuation requests blocked           |
    | Inactive          | Waiting for user input or tool results; ready for continuation |
    | Error             | Execution failed; continuation blocked                         |
    | Approval Required | Tool execution requires manual approval (coming soon)          |

    **Task states:**

    | State          | Description                            |
    | -------------- | -------------------------------------- |
    | Submitted      | Task created and queued for execution  |
    | Working        | Agent actively processing              |
    | Input Required | Waiting for user input or tool results |
    | Completed      | Task finished successfully             |
    | Failed         | Task encountered an error              |
    | Canceled       | Task was manually canceled             |
  </Tab>

  <Tab title="API & SDK" icon="code">
    **Response status values:**

    | Status        | Description                    |
    | ------------- | ------------------------------ |
    | `in_progress` | Agent is actively processing   |
    | `completed`   | Response finished successfully |
    | `failed`      | Response encountered an error  |

    The `status` field is returned on every response object from `POST /v3/router/responses`. See the [Create Response API reference](/reference/responses/create-response) for the full response shape.
  </Tab>

  <Tab title="MCP" icon="https://mintcdn.com/orqai/i7ZhKI7LFRfXU7ox/images/logos/mcp.svg?fit=max&auto=format&n=i7ZhKI7LFRfXU7ox&q=85&s=cef7916eb5fe1f6bb97541398d3f7639" width="16" height="16" data-path="images/logos/mcp.svg">
    **Inspect task states through traces:**

    ```prompt wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
    Show me the last 10 traces for "support-bot" and summarize their completion states
    ```

    The assistant uses `list_traces` filtered to the agent and surfaces the state distribution.
  </Tab>
</Tabs>

## Multi-Agent Workflows

<Tabs>
  <Tab title="AI Studio" icon="https://mintcdn.com/orqai/My16MDKJXrKALEHC/images/logos/ai-studio-round.svg?fit=max&auto=format&n=My16MDKJXrKALEHC&q=85&s=ac04dd509320d58ab9701cb6d6137733" width="100" height="100" data-path="images/logos/ai-studio-round.svg">
    Multi-agent workflows are configured at the agent level. Each agent in a team is created individually, then the orchestrator references sub-agents through its `team_of_agents` configuration.

    The **Description** field on each sub-agent is critical: orchestrators use it to decide when to delegate.

    <Info>
      To configure multi-agent setups, see [Build Agents: Instructions](/docs/ai-studio/ai-engineering/build-agents#configure-instructions) for how to write descriptions that enable effective delegation.
    </Info>
  </Tab>

  <Tab title="API & SDK" icon="code">
    Multi-agent workflows use a hierarchical system:

    * **Orchestrator**: Main agent that delegates tasks using `call_sub_agent`.
    * **Sub-agents**: Specialized agents for specific functions.
    * **Delegation**: Automatic routing based on sub-agent descriptions and capabilities.

    **Step 1: Create sub-agents.**

    Create each specialized agent individually. The `description` field drives orchestrator delegation decisions.

    **Step 2: Create the orchestrator.**

    Reference sub-agents in the `team_of_agents` array. Include `retrieve_agents` and `call_sub_agent` tools.

    <CodeGroup>
      ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -X POST https://api.orq.ai/v2/agents \
        -H "Authorization: Bearer $ORQ_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
        "key": "orchestrator",
        "role": "Task Coordinator",
        "description": "Coordinates specialized agents to handle diverse user requests",
        "instructions": "Answer the user using your sub-agents. Use retrieve_agents to discover available agents, then call_sub_agent to delegate tasks based on their capabilities.",
        "settings": {
          "max_iterations": 15,
          "max_execution_time": 600,
          "tools": [
            { "type": "retrieve_agents" },
            { "type": "call_sub_agent" }
          ]
        },
        "model": "openai/gpt-4o",
        "path": "Default/agents",
        "team_of_agents": [
          { "key": "specialist-a", "role": "Handles domain A" },
          { "key": "specialist-b", "role": "Handles domain B" }
        ]
      }'
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
      from orq_ai_sdk import Orq
      import os

      with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
          orchestrator = orq.agents.create(
              key="orchestrator",
              role="Task Coordinator",
              description="Coordinates specialized agents to handle diverse user requests",
              instructions="Answer the user using your sub-agents. Use retrieve_agents to discover available agents, then call_sub_agent to delegate tasks based on their capabilities.",
              path="Default/agents",
              model="openai/gpt-4o",
              settings={
                  "max_iterations": 15,
                  "max_execution_time": 600,
                  "tools": [
                      {"type": "retrieve_agents"},
                      {"type": "call_sub_agent"}
                  ]
              },
              team_of_agents=[
                  {"key": "specialist-a", "role": "Handles domain A"},
                  {"key": "specialist-b", "role": "Handles domain B"}
              ]
          )
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
      import { Orq } from '@orq-ai/node';

      const orq = new Orq({ apiKey: process.env['ORQ_API_KEY'] ?? '' });

      const orchestrator = await orq.agents.create({
        key: 'orchestrator',
        role: 'Task Coordinator',
        description: 'Coordinates specialized agents to handle diverse user requests',
        instructions: 'Answer the user using your sub-agents. Use retrieve_agents to discover available agents, then call_sub_agent to delegate tasks based on their capabilities.',
        path: 'Default/agents',
        model: 'openai/gpt-4o',
        settings: {
          maxIterations: 15,
          maxExecutionTime: 600,
          tools: [
            { type: 'retrieve_agents' },
            { type: 'call_sub_agent' }
          ]
        },
        teamOfAgents: [
          { key: 'specialist-a', role: 'Handles domain A' },
          { key: 'specialist-b', role: 'Handles domain B' }
        ]
      });
      ```
    </CodeGroup>

    **Step 3: Invoke the orchestrator.**

    Invoke the orchestrator the same way as any other agent. It handles delegation internally.

    <Warning>
      Orchestrator agents must include `retrieve_agents` to discover sub-agents before delegating. Add explicit instructions: "Use `retrieve_agents` to see what specialized agents are available, then `call_sub_agent` to delegate."
    </Warning>

    <Tip>Update the orchestrator at any time with [`PATCH /v2/agents/{key}`](/reference/agents/update-agent) to add or remove sub-agents from `team_of_agents`.</Tip>
  </Tab>

  <Tab title="MCP" icon="https://mintcdn.com/orqai/i7ZhKI7LFRfXU7ox/images/logos/mcp.svg?fit=max&auto=format&n=i7ZhKI7LFRfXU7ox&q=85&s=cef7916eb5fe1f6bb97541398d3f7639" width="16" height="16" data-path="images/logos/mcp.svg">
    **Find all agents available as sub-agents:**

    ```prompt wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
    Search for all agents in the Default/agents project
    ```

    The assistant uses `search_entities` with `type: "agent"` to list available agents.

    ***

    **Set up an orchestrator:**

    ```prompt wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
    Create an orchestrator agent that coordinates "youth-agent" and "formal-agent" for tone-matched responses
    ```

    The assistant uses `create_agent` with the `team_of_agents` array and `retrieve_agents` / `call_sub_agent` tools.
  </Tab>
</Tabs>

## Traces

<Tabs>
  <Tab title="AI Studio" icon="https://mintcdn.com/orqai/My16MDKJXrKALEHC/images/logos/ai-studio-round.svg?fit=max&auto=format&n=My16MDKJXrKALEHC&q=85&s=ac04dd509320d58ab9701cb6d6137733" width="100" height="100" data-path="images/logos/ai-studio-round.svg">
    The **Traces** tab in the agent page shows execution logs filtered to the agent automatically.

    <Frame caption="Agent-specific traces with automatic filtering.">
      <img src="https://mintcdn.com/orqai/hGdKybmgjhwDfaBt/images/agent-traces-tab.png?fit=max&auto=format&n=hGdKybmgjhwDfaBt&q=85&s=273887082ceb068e11ea26c07e7240af" alt="Traces tab for the bank_creditcard_agent showing a list of invoke-agent runs with timestamps, duration, and cost, filtered to this agent." width="3362" height="1970" data-path="images/agent-traces-tab.png" />
    </Frame>

    **Trace data includes:**

    * Execution history with timestamps
    * Input and output for each call
    * Token usage and cost per execution
    * Execution duration and performance metrics
    * Errors and debugging information
    * Tool calls executed (function, HTTP, code, or MCP calls)
    * Knowledge retrieval results and RAG context
    * Memory store interactions
  </Tab>

  <Tab title="API & SDK" icon="code">
    All agent executions are automatically traced. Access traces in the **AI Studio** or via the [Traces API](/docs/ai-studio/observability/traces).

    For programmatic trace access, see the [Observability documentation](/docs/ai-studio/observability/traces).
  </Tab>

  <Tab title="MCP" icon="https://mintcdn.com/orqai/i7ZhKI7LFRfXU7ox/images/logos/mcp.svg?fit=max&auto=format&n=i7ZhKI7LFRfXU7ox&q=85&s=cef7916eb5fe1f6bb97541398d3f7639" width="16" height="16" data-path="images/logos/mcp.svg">
    **List recent traces for an agent:**

    ```prompt wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
    Show me the last 20 traces for "support-bot" sorted by most recent
    ```

    The assistant uses `list_traces` with a filter on the agent key.

    ***

    **Inspect a specific trace:**

    ```prompt wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
    Show me the full span details for trace ID 01K6D8QESESZ6SAXQPJPFQXPFT
    ```

    The assistant uses `list_spans` to retrieve the full execution tree for that trace.

    ***

    **Debug errors:**

    ```prompt wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
    Find all failed traces for "support-bot" from the last 24 hours and summarize the errors
    ```

    The assistant uses `list_traces` filtered by `status:=ERROR` and time range, then `get_span` on relevant spans to surface root causes.
  </Tab>
</Tabs>

### Trace Views

Each trace can be inspected in three views:

<Tabs>
  <Tab title="Trace" icon="diagram-project">
    The **Trace** view shows the full execution tree for a single agent run. Each step is displayed hierarchically, including LLM calls, tool invocations, knowledge retrievals, and memory interactions.

    <Frame>
      <img src="https://mintcdn.com/orqai/o4CxH4xK7MCteqsT/images/agent-traces.png?fit=max&auto=format&n=o4CxH4xK7MCteqsT&q=85&s=c9ff9068c81f135879cd15a1654cb027" alt="Trace view showing the single-product-agent span tree with nested invoke-agent, gpt-4o chat-completion, and current_date spans, with properties panel on the right." width="1506" height="925" data-path="images/agent-traces.png" />
    </Frame>
  </Tab>

  <Tab title="Thread" icon="messages">
    The **Thread** view presents the execution as a conversation thread, showing the sequence of messages exchanged between the user, the agent, and any tools.

    <Frame>
      <img src="https://mintcdn.com/orqai/hYJ46ZNib1CGRiid/images/agent-traces-thread.png?fit=max&auto=format&n=hYJ46ZNib1CGRiid&q=85&s=6b2904b134eee8a2a6a4f37751e5be41" alt="Thread view showing the conversation turn with user message, tool executions (current_date called multiple times), and assistant responses." width="1161" height="1176" data-path="images/agent-traces-thread.png" />
    </Frame>
  </Tab>

  <Tab title="Timeline" icon="chart-gantt">
    The **Timeline** view shows execution steps plotted against time, making it easy to identify bottlenecks and understand parallel vs sequential operations.

    <Frame>
      <img src="https://mintcdn.com/orqai/hYJ46ZNib1CGRiid/images/agent-traces-timeline.png?fit=max&auto=format&n=hYJ46ZNib1CGRiid&q=85&s=727f7c4a29aa23a55b81126c612c384d" alt="Timeline view showing agent spans as horizontal bars across a 10-second axis, with invoke-agent, chat-completion, and current_date calls visualized sequentially." width="1165" height="1176" data-path="images/agent-traces-timeline.png" />
    </Frame>
  </Tab>
</Tabs>

### Creating Custom Views

Save frequently used filter combinations as reusable views:

1. Set the desired filters.
2. Click <kbd><Icon icon="eye" /> All Rows</kbd> (top right).
3. Select <kbd><Icon icon="plus" /> Create New View</kbd>.
4. Give the view a title.
5. Optionally check **Set view private** (default is shared with project members).

<Tip>
  For advanced filtering and cross-agent analysis, see [Traces](/docs/ai-studio/observability/traces).
</Tip>
