> ## 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.

# Delegate to a Second Model with Advisor and Sidekick

> Run an Agent on a cheap model and pay for a stronger one only at the step that needs it, then read the cost split in the trace.

An **Agent** runs every step of a conversation on one model. That model has to be cheap enough for the routine steps and strong enough for the hardest one. Size it for the hardest step and every step gets expensive. Size it for the routine steps and it fails exactly where quality matters.

The **Advisor** and **Sidekick** hosted tools break that trade-off by handing individual steps to a second model configured at design time. Both route through the **AI Gateway**, so each secondary call is metered on its own and appears as a nested span in [Traces](/docs/ai-studio/observability/traces). That is what turns the trade-off into something readable after the fact.

<Info>
  **TL;DR**

  * **Advisor**: the **Agent** asks a stronger model for guidance, sends the conversation transcript, and still writes the answer itself
  * **Sidekick**: the **Agent** hands off a self-contained task, sends only that task, and gets back a finished artifact
  * **Read the split**: one trace shows what the escalation costs relative to the rest of the run

  Neither is a sub-agent. The second model gets one call, with no tools and no memory of its own.
</Info>

## What you'll build

An incident triage **Agent** on a cheap model that consults an expensive model for one high-stakes judgement, hands a formatting job to a third model, and produces a trace where the cost of each choice sits side by side.

Incident triage is the first pass after a monitoring alert fires: decide how bad it is, what is affected, whether to roll back, and what to tell customers. It suits this pattern because those steps differ sharply in difficulty. Classification is mechanical, the rollback call is a judgement worth paying for, and the status note is formatting.

## Prerequisites

* An **Orq.ai** workspace with a project to build in. See [Projects](/docs/ai-studio/get-started/projects)
* An API key from [Workspace Settings > API Keys](/docs/ai-studio/organization/api-keys), exported as `ORQ_API_KEY`
* Three chat models enabled in the [AI Gateway](/docs/ai-gateway/using-the-router): a cheap one for the **Agent**, a strong one for the **Advisor**, and a cheap one for the **Sidekick**. This cookbook uses `anthropic/claude-haiku-4-5`, `anthropic/claude-opus-4-8`, and `openai/gpt-4o-mini`
* For the SDK snippets, the Python or Node SDK installed: `pip install orq-ai-sdk` or `npm install @orq-ai/node`

## Choose which tool each step needs

Decide this first, because the two tools carry different information and that is what limits which steps they can serve.

|              | Advisor                                                       | Sidekick                                                       |
| ------------ | ------------------------------------------------------------- | -------------------------------------------------------------- |
| Sends        | Conversation transcript, plus a question and optional context | A task and optional context, nothing else                      |
| Returns      | Advice                                                        | A finished artifact                                            |
| Who decides  | The **Agent**                                                 | The **Sidekick**                                               |
| Use when     | The step is a judgement that depends on what came before      | The step is self-contained work the conversation does not need |
| Extra config | `max_transcript_tokens`                                       | `system_prompt`, `output_format`                               |

Ask whether the step needs history. A rollback decision is worthless without the evidence gathered so far, so it needs an **Advisor**. A status update needs only the facts that go in it, so it goes to a **Sidekick**, and sending the transcript would just be waste.

The two tools are independent, and most **Agents** need only one. A support **Agent** that escalates nothing but refund approvals needs an **Advisor** and no **Sidekick**. A research **Agent** that does its own analysis and only wants the summary formatted needs a **Sidekick** and no **Advisor**. This cookbook uses both because incident triage happens to have both kinds of step: a judgement that depends on the history, and a self-contained job that does not.

## Step 1: Create the Agent

Both tools are declared in `settings.tools`, each with its secondary model in `configuration`. The instructions matter more than the configuration: a tool the instructions never mention is rarely called, so name each tool at the step it belongs to and say explicitly that the routine work stays on the **Agent**'s own model.

<CodeGroup>
  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import os

  from orq_ai_sdk import Orq

  INSTRUCTIONS = """Triage incoming production alerts for a SaaS platform team.

  Work through an alert in three stages.

  Stage 1 - Classify (do this yourself, do not delegate).
  From the alert and any log excerpt, state:
  - Severity: SEV1, SEV2, or SEV3
  - Affected service
  - Blast radius: which users or regions are affected, and roughly how many
  Keep this to a few lines. This is routine work and must stay on the primary model.

  Stage 2 - Rollback decision (use the advisor).
  Deciding whether to roll back a deployment is high-stakes and depends on everything established in stage 1. Always ask the advisor before making this call. Put the specific question to the advisor, for example whether the evidence so far justifies an immediate rollback or whether to hold and keep monitoring. Weigh the advice, then state the decision and the reasoning in the final answer. The decision is the primary model's to make, not the advisor's.

  Stage 3 - Status page update (use the sidekick).
  Once the decision is made, delegate the customer-facing status page update to the sidekick. Send it a task describing what happened and what the team is doing, plus the severity and affected service as context. Do not write the status update. Return the sidekick's result verbatim under a 'Status page update' heading.

  Rules:
  - Never invent metrics, error rates, or timestamps that are not in the alert.
  - If the alert is too thin to classify, say what is missing rather than guessing.
  - Keep the final answer under 250 words, excluding the status page update."""

  with Orq(api_key=os.getenv("ORQ_API_KEY", "")) as orq:
      agent = orq.agents.create(
          key="incident-triage-delegation",
          display_name="Incident Triage (Advisor + Sidekick)",
          role="Incident triage assistant for a SaaS platform team.",
          description="Classifies a production alert, consults an advisor on the rollback decision, and delegates the status update to a sidekick.",
          path="Default",
          model="anthropic/claude-haiku-4-5",
          instructions=INSTRUCTIONS,
          settings={
              "max_iterations": 10,
              "tool_approval_required": "none",
              "tools": [
                  {
                      "type": "advisor",
                      "configuration": {
                          "model": "anthropic/claude-opus-4-8",
                          "max_uses": 2,
                          "max_transcript_tokens": 4000,
                          "max_tokens": 600,
                      },
                  },
                  {
                      "type": "sidekick",
                      "configuration": {
                          "model": "openai/gpt-4o-mini",
                          "max_uses": 2,
                          "max_tokens": 400,
                          "system_prompt": "Write customer-facing status page updates for a SaaS platform. Plain and factual. No blame, no speculation about root cause beyond what the task states, no internal service names, no engineer names, no internal metrics.",
                          "output_format": "Three short paragraphs, each preceded by a plain text label on its own line: Impact, Current status, Next update. No markdown headings.",
                      },
                  },
              ],
          },
      )

  print(agent.key)
  ```

  ```typescript Node.js 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 INSTRUCTIONS = `Triage incoming production alerts for a SaaS platform team.

  Work through an alert in three stages.

  Stage 1 - Classify (do this yourself, do not delegate).
  From the alert and any log excerpt, state:
  - Severity: SEV1, SEV2, or SEV3
  - Affected service
  - Blast radius: which users or regions are affected, and roughly how many
  Keep this to a few lines. This is routine work and must stay on the primary model.

  Stage 2 - Rollback decision (use the advisor).
  Deciding whether to roll back a deployment is high-stakes and depends on everything established in stage 1. Always ask the advisor before making this call. Put the specific question to the advisor, for example whether the evidence so far justifies an immediate rollback or whether to hold and keep monitoring. Weigh the advice, then state the decision and the reasoning in the final answer. The decision is the primary model's to make, not the advisor's.

  Stage 3 - Status page update (use the sidekick).
  Once the decision is made, delegate the customer-facing status page update to the sidekick. Send it a task describing what happened and what the team is doing, plus the severity and affected service as context. Do not write the status update. Return the sidekick's result verbatim under a 'Status page update' heading.

  Rules:
  - Never invent metrics, error rates, or timestamps that are not in the alert.
  - If the alert is too thin to classify, say what is missing rather than guessing.
  - Keep the final answer under 250 words, excluding the status page update.`;

  const agent = await orq.agents.create({
    key: "incident-triage-delegation",
    displayName: "Incident Triage (Advisor + Sidekick)",
    role: "Incident triage assistant for a SaaS platform team.",
    description: "Classifies a production alert, consults an advisor on the rollback decision, and delegates the status update to a sidekick.",
    path: "Default",
    model: "anthropic/claude-haiku-4-5",
    instructions: INSTRUCTIONS,
    settings: {
      maxIterations: 10,
      toolApprovalRequired: "none",
      tools: [
        {
          type: "advisor",
          configuration: {
            model: "anthropic/claude-opus-4-8",
            max_uses: 2,
            max_transcript_tokens: 4000,
            max_tokens: 600,
          },
        },
        {
          type: "sidekick",
          configuration: {
            model: "openai/gpt-4o-mini",
            max_uses: 2,
            max_tokens: 400,
            system_prompt: "Write customer-facing status page updates for a SaaS platform. Plain and factual. No blame, no speculation about root cause beyond what the task states, no internal service names, no engineer names, no internal metrics.",
            output_format: "Three short paragraphs, each preceded by a plain text label on its own line: Impact, Current status, Next update. No markdown headings.",
          },
        },
      ],
    },
  });

  console.log(agent.key);
  ```

  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST "https://my.orq.ai/v2/agents" \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "key": "incident-triage-delegation",
      "display_name": "Incident Triage (Advisor + Sidekick)",
      "role": "Incident triage assistant for a SaaS platform team.",
      "description": "Classifies a production alert, consults an advisor on the rollback decision, and delegates the status update to a sidekick.",
      "path": "Default",
      "model": "anthropic/claude-haiku-4-5",
      "instructions": "Triage incoming production alerts for a SaaS platform team.\n\nWork through an alert in three stages.\n\nStage 1 - Classify (do this yourself, do not delegate).\nFrom the alert and any log excerpt, state:\n- Severity: SEV1, SEV2, or SEV3\n- Affected service\n- Blast radius: which users or regions are affected, and roughly how many\nKeep this to a few lines. This is routine work and must stay on the primary model.\n\nStage 2 - Rollback decision (use the advisor).\nDeciding whether to roll back a deployment is high-stakes and depends on everything established in stage 1. Always ask the advisor before making this call. Put the specific question to the advisor, for example whether the evidence so far justifies an immediate rollback or whether to hold and keep monitoring. Weigh the advice, then state the decision and the reasoning in the final answer. The decision is the primary model'\''s to make, not the advisor'\''s.\n\nStage 3 - Status page update (use the sidekick).\nOnce the decision is made, delegate the customer-facing status page update to the sidekick. Send it a task describing what happened and what the team is doing, plus the severity and affected service as context. Do not write the status update. Return the sidekick'\''s result verbatim under a '\''Status page update'\'' heading.\n\nRules:\n- Never invent metrics, error rates, or timestamps that are not in the alert.\n- If the alert is too thin to classify, say what is missing rather than guessing.\n- Keep the final answer under 250 words, excluding the status page update.",
      "settings": {
        "max_iterations": 10,
        "tool_approval_required": "none",
        "tools": [
          {
            "type": "advisor",
            "configuration": {
              "model": "anthropic/claude-opus-4-8",
              "max_uses": 2,
              "max_transcript_tokens": 4000,
              "max_tokens": 600
            }
          },
          {
            "type": "sidekick",
            "configuration": {
              "model": "openai/gpt-4o-mini",
              "max_uses": 2,
              "max_tokens": 400,
              "system_prompt": "Write customer-facing status page updates for a SaaS platform. Plain and factual. No blame, no speculation about root cause beyond what the task states, no internal service names, no engineer names, no internal metrics.",
              "output_format": "Three short paragraphs, each preceded by a plain text label on its own line: Impact, Current status, Next update. No markdown headings."
            }
          }
        ]
      }
    }'
  ```

  ```bash CLI theme={"theme":{"light":"github-light","dark":"github-dark"}}
  orq agents create \
    --key "incident-triage-delegation" \
    --display-name "Incident Triage (Advisor + Sidekick)" \
    --role "Incident triage assistant for a SaaS platform team." \
    --description "Classifies a production alert, consults an advisor on the rollback decision, and delegates the status update to a sidekick." \
    --instructions "$(cat instructions.txt)" \
    --path "Default" \
    --model "anthropic/claude-haiku-4-5" \
    --settings '{
      "max_iterations": 10,
      "tool_approval_required": "none",
      "tools": [
        {
          "type": "advisor",
          "configuration": {
            "model": "anthropic/claude-opus-4-8",
            "max_uses": 2,
            "max_transcript_tokens": 4000,
            "max_tokens": 600
          }
        },
        {
          "type": "sidekick",
          "configuration": {
            "model": "openai/gpt-4o-mini",
            "max_uses": 2,
            "max_tokens": 400,
            "system_prompt": "Write customer-facing status page updates for a SaaS platform. Plain and factual. No blame, no speculation about root cause beyond what the task states, no internal service names, no engineer names, no internal metrics.",
            "output_format": "Three short paragraphs, each preceded by a plain text label on its own line: Impact, Current status, Next update. No markdown headings."
          }
        }
      ]
    }'
  ```
</CodeGroup>

All four tabs produce the same **Agent**, and a successful create returns `201` with the stored configuration echoed back. Set `path` to a project in the target workspace. The output shown in the next steps is the same whichever tab is used.

Two tabs need a note of their own:

* **CLI**: reads `ORQ_API_KEY` from the environment and keeps the instructions in a file, which avoids quoting a multi-line string on the command line. Write the same instructions used in the other tabs to `instructions.txt` first. See [install and setup](/reference/cli) to get started with the CLI.
* **Node.js**: top-level fields are camelCase (`displayName`, `maxIterations`) while the keys inside `configuration` stay snake\_case (`max_uses`, `system_prompt`), because that object is passed through untouched and keeps the API's naming.

<Warning>
  Reads and writes use different shapes. `POST` and `PATCH` take `type` plus `configuration`, but `GET /v2/agents/{agent_key}` returns each tool as `action_type` with a generated `id`. Fetching an **Agent** and sending the response straight back will fail.
</Warning>

## Step 2: Confirm the configuration in AI Studio

Open the **Agent** and select the **Advisor** tool. This dialog is where the secondary model and its parameters are edited.

<img src="https://mintcdn.com/orqai/-gXjVxXZrfDCguJT/images/advisor-sidekick-configure-advisor.png?fit=max&auto=format&n=-gXjVxXZrfDCguJT&q=85&s=0e578cb59df03d5f989cd8969f212a79" alt="Configure Advisor dialog showing the secondary model set to claude-opus-4-8, max tokens 600, max transcript tokens 4000, temperature on Auto, max uses 2, and reasoning effort on provider default" width="1076" height="1256" data-path="images/advisor-sidekick-configure-advisor.png" />

`Max Transcript Tokens` caps how much conversation history reaches the **Advisor** and is specific to it. `Max Uses` caps calls per run, which matters because an escalation the model can trigger freely is one that will show up on the bill. Unset numeric fields read `Auto`, and `Reasoning Effort` reads `Provider default`.

The **Sidekick** dialog drops the transcript control and adds the two fields that shape its output.

<img src="https://mintcdn.com/orqai/-gXjVxXZrfDCguJT/images/advisor-sidekick-configure-sidekick.png?fit=max&auto=format&n=-gXjVxXZrfDCguJT&q=85&s=0034fc91d1b8b30f2d717d68987cdc7a" alt="Configure Sidekick dialog showing the secondary model set to gpt-4o-mini, max tokens 400, temperature on Auto, max uses 2, and the system prompt and output format fields filled in" width="1088" height="1340" data-path="images/advisor-sidekick-configure-sidekick.png" />

`System Prompt` replaces the platform default for the **Sidekick** and `Output Format` describes the shape of the result in plain language. Together they make the **Sidekick** result usable verbatim, with no cleanup turn on the **Agent**.

## Step 3: Run the Agent

Send an alert with enough evidence to classify and enough ambiguity to be worth escalating.

```bash Run the agent theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST "https://my.orq.ai/v3/router/responses" \
  -H "Authorization: Bearer $ORQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "agent/incident-triage-delegation",
    "input": "ALERT: checkout-api p99 latency 8.4s (threshold 1.5s), sustained 11 minutes. Error rate 4.2% (baseline 0.1%).\n\nDeploy: checkout-api v2.31.0 rolled out to eu-west-1 and eu-central-1 at 14:02 UTC. Alert fired 14:07 UTC. us-east-1 still on v2.30.4 and healthy.\n\nLog excerpt:\n14:07:12 ERROR checkout-api pool=payments timeout acquiring connection after 5000ms\n14:07:12 WARN  checkout-api pool=payments active=50 idle=0 waiting=213\n14:07:18 ERROR checkout-api pool=payments timeout acquiring connection after 5000ms\n14:07:31 INFO  checkout-api completed_order id=ord_8812 duration=7912ms\n\nRoughly 30% of EU traffic is hitting the slow path. Orders are still completing, just slowly."
  }'
```

The response completes with `status: "completed"` and the `output` array carries the delegation in order:

```json Output item sequence theme={"theme":{"light":"github-light","dark":"github-dark"}}
["message", "function_call", "orq:advisor", "message", "function_call", "orq:sidekick", "message"]
```

Each tool produces a `function_call` followed by a completed `orq:advisor` or `orq:sidekick` item holding the second model's result, then the **Agent** continues.

## Step 4: Read what each tool returned

The **Advisor** received a question and context, and returned a recommendation with reasoning:

```text Advisor result theme={"theme":{"light":"github-light","dark":"github-dark"}}
Rollback now. Strong evidence, low risk.

1. Insight: Deploy correlates tightly (5-min gap), region-isolated to v2.31.0,
   healthy control (us-east-1 on v2.30.4). Signature is clear: payments pool
   exhausted (active=50 at cap, 213 waiting). This is a code/config regression,
   not load.
2. Plan: Rollback both EU regions to v2.30.4. Active revenue impact.
3. Verify: Confirm rollback restores pool health before closing.
4. Follow-up: Preserve v2.31.0 logs. Root-cause: likely a leaked connection or
   pool-size/timeout config change in this release.
```

That is advice, not an answer. The **Agent** weighed it and wrote the decision into its own reply. That is what an **Advisor** is for: guidance from the stronger model, decision left with the **Agent**.

The **Sidekick** received only a task and context, never the transcript, and returned a finished artifact in the configured shape:

```text Sidekick result theme={"theme":{"light":"github-light","dark":"github-dark"}}
Impact
We are currently experiencing elevated checkout latency in EU regions since
14:07 UTC. Customers may notice longer wait times during the checkout process.

Current status
Our team has identified the cause of the latency as connection pool exhaustion
due to a recent deployment. We are in the process of rolling back to the
previous version to resolve this issue.

Next update
We expect to have the service restored and functioning normally within
5 minutes. Thank you for your patience as we work to resolve this.
```

The `Impact / Current status / Next update` structure came from `output_format` and the plain register came from `system_prompt`.

## Step 5: Read the cost split in the trace

Open the run in **Traces** and expand the waterfall.

<img src="https://mintcdn.com/orqai/-gXjVxXZrfDCguJT/images/advisor-sidekick-trace-waterfall.png?fit=max&auto=format&n=-gXjVxXZrfDCguJT&q=85&s=a34dcfbbf879c5912a81b36e8fa58343" alt="Trace waterfall for the incident triage run showing the agent root span, a pii.redact span, and nested under agent.response three claude-haiku spans, an advisor span wrapping a claude-opus call, and a sidekick span wrapping a gpt-4o-mini call, each row listing tokens, cost, and duration" width="1738" height="956" data-path="images/advisor-sidekick-trace-waterfall.png" />

```text Span tree theme={"theme":{"light":"github-light","dark":"github-dark"}}
incident-triage-delegation          (root, full run cost)
├─ pii.redact                       workspace setting, not part of this pattern
└─ agent.response
   ├─ chat claude-haiku-4-5         Agent, turn 1
   ├─ advisor                       tool span
   │  └─ chat claude-opus-4-8       the secondary call, metered here
   ├─ chat claude-haiku-4-5         Agent, turn 2
   ├─ sidekick                      tool span
   │  └─ chat gpt-4o-mini           the secondary call, metered here
   └─ chat claude-haiku-4-5         Agent, turn 3
```

The single **Advisor** call cost roughly as much as all three **Agent** turns put together, close to half the run, in under a third of the wall-clock time. That is the price of the escalation. It is worth paying once for a rollback decision, and ruinous as the model behind every turn.

The **Sidekick** call landed well under one percent of the run. Delegation does not have to mean escalation, and moving self-contained work to a cheaper model is the other half of the pattern.

Exact figures move with provider pricing and vary between runs. The proportions are the durable result and the thing to design against.

## When the secondary model fails

A failing secondary model does not fail the run. Pointing the **Advisor** at a model that does not exist still returns `200` with `status: "completed"`, and the **Agent** answers without the guidance it asked for. The error arrives as text inside the tool item's `result`:

```text Failed secondary call theme={"theme":{"light":"github-light","dark":"github-dark"}}
advisor: secondary model request failed: Model 'openai/this-model-does-not-exist' not found or is not available.
```

<Warning>
  The tool item's own `status` stays `completed` when the secondary call fails. Detecting a failed secondary call means inspecting the `result` text, not the item status.
</Warning>

## When to use this pattern, and when not to

Use it when a run has one or two steps that are genuinely harder than the rest. The saving comes from the ratio of many cheap steps to few expensive ones. An **Agent** where every step is the hard step should just run on the stronger model, and one that calls the **Advisor** every turn has bought the expensive model with extra latency attached.

Set `max_uses` deliberately. It caps how often the model can reach for the expensive path, and leaving it unlimited on a strong secondary model gives up the cost control that makes the pattern worth using. For a ceiling on the run as a whole, pair it with `max_cost` and `max_iterations` in the **Agent** settings.
