Planner Mode

Overview

A normal chat completion is one call to one model. Planner mode is a loop: ASI:One breaks your request into tasks, decides what to run for each one, executes them, feeds the results back in, and repeats until it can answer.

Set planner_mode to true on an ordinary chat completion request:

$curl -X POST https://api.asi1.ai/v1/chat/completions \
> -H "Content-Type: application/json" \
> -H "Authorization: Bearer $ASI_ONE_API_KEY" \
> -H "x-session-id: 4f9c2b18-6d1e-4a77-9f30-2c5b8e7a1d64" \
> -d '{
> "model": "asi1",
> "messages": [{"role": "user", "content": "..."}],
> "planner_mode": true,
> "stream": true
> }'

planner_mode is not an OpenAI parameter, so with the SDK it goes through extra_body, and the required x-session-id through extra_headers. See Sessions.

It is available on asi1, asi1-mini and asi1-ultra. An unrecognised model name returns a 404, the same as it would on any other request.

Planner mode runs on /v1/chat/completions. Send planner_mode on that endpoint.

Reach for it when a request needs work rather than an answer: several steps that depend on each other, or a task that needs a specialist agent from Agentverse. For anything a single response can handle, use a normal chat completion, which is faster and cheaper.

What the planner can do

Within a run, the planner works through tasks using:

Tasks in the same round run in parallel.

Working with agents

The reason to turn planner_mode on is that it gives a request access to Agentverse, a marketplace of independent agents that do things a language model cannot: query live data, book and buy, run domain-specific tooling, talk to other systems.

You do not have to register agents, name them, or wire them up. When a task needs capability the model does not have, the planner does the whole loop itself:

  1. Discovers. It searches Agentverse for agents matching what the task actually needs, described in natural language. Agents it finds become callable in the next round of the plan.
  2. Messages. It sends a chosen agent a message describing the task and waits for the reply.
  3. Incorporates. The reply feeds back into the plan, which may answer the task, or may raise new ones that need another agent.

Because discovery happens inside the loop rather than up front, a run can reach agents it had no way to know it needed when the request arrived. A travel request can pick up a flight agent in one round and, on the strength of what that agent returns, a visa agent in the next.

Agents are independent services, so they can be slow, refuse, or not reply at all. The planner treats that as normal: it moves on, and an agent that fails twice is not tried again for the rest of the session. Some agents ask for a payment or a confirmation before they act, which pauses the run and hands control back to you. See Handing control back.

Supplying your own agents

If you already know which agents you want available, pass their addresses in an agents array and the planner can use them without searching for them first:

1{
2 "model": "asi1",
3 "messages": [{ "role": "user", "content": "..." }],
4 "planner_mode": true,
5 "agents": ["agent1q...", "agent1q..."]
6}

The list is capped, so keep it to the agents you actually want considered rather than passing a large roster. This does not switch discovery off: the planner can still search Agentverse for anything your list does not cover.

None of this happens on an ordinary chat completion. Without planner_mode, the request goes to the model alone, which answers from its own knowledge and any tools you passed. Agent discovery and messaging are what planner mode adds.

Sessions

Planner requests require an x-session-id header. Send one, and keep it constant for every request belonging to the same run:

$-H "x-session-id: 4f9c2b18-6d1e-4a77-9f30-2c5b8e7a1d64"

The planner uses it server-side to tie one job’s steps together: which agents it already found, which ones failed, and the state of a plan that paused partway through. Use a fresh value for each new job.

This is not conversation memory. Nothing you said is stored against the session id, and the model will not recall earlier messages because of it. To continue a conversation, send the prior turns in messages as usual.

Following progress

Planner runs are long. Use "stream": true and you get progress as it happens instead of waiting in silence.

Alongside the normal content chunks, the stream carries chunks with an empty choices array and a metadata object describing the plan:

data: {"choices":[],"metadata":{"type":"plan_state","plan_status":"in_progress","phases":{"0":{"status":"completed","tasks":{"0":{"status":"completed"}}}}}}

These are partial updates. Merge each one into the plan state you have accumulated so far rather than replacing it.

A plan reports plan_status as one of in_progress, completed, clarification_requested, payment_requested or card_interaction_requested. Tasks report their own status. Terminal values are completed, failed, error, timeout and skipped; while a task is running you will also see in-progress values such as pending, waiting_response, searching_agents and analyzing_image. Treat the set as open and ignore any value you do not recognize.

Task entries carry more than a status. Depending on what the task did, you may also get the agents it found, which one it used, the message it sent and the reply it received, or a payment request. Phases carry the planner’s reasoning for that step. All of it is optional, so read defensively rather than assuming a field is present.

Plan progress is only available when streaming. A non-streaming planner request returns the final answer alone, with no view of the steps taken to reach it.

Handing control back

If you pass your own tools and the planner decides to call one, it cannot run it for you. The run pauses and hands the call back in the same shape as an ordinary tool-calling response, with the call in choices[0].message.tool_calls:

1{ "choices": [{ "finish_reason": "tool_calls" }] }

Execute the tool yourself, then send a follow-up request carrying the result and the same x-session-id. The planner resumes from where it stopped instead of starting over.

A run pauses and hands back for four reasons, and all four resume the same way:

  • A tool call, as above.
  • A clarifying question. The planner can ask you for information it needs before it can continue. Reply in messages as you would in a normal conversation, keeping the same x-session-id, and it picks the plan back up.
  • A payment request, when an agent charges for its work.
  • A card interaction, when an agent needs a confirmation.

Resuming depends entirely on the x-session-id. Send a different value, or omit it, and the planner has no saved plan to resume: it starts over from scratch and the work already completed is lost. A paused plan is not kept indefinitely either, so resume it promptly rather than hours later.

This is the only deferred mechanism in planner mode. There is no job id to poll and no webhook: a planner request is a single HTTP request that either finishes or pauses for you.

Limits and timing

A planner run can take minutes. Budget for it, and prefer streaming so you can show progress.

LimitValue
Rounds of planning15
Agent discoveryUp to 90 seconds
Waiting on an agent replyFrom 60 seconds, longer for higher-rated agents, and extended to 240 seconds once one starts replying
Image analysis120 seconds

An agent that fails twice is not tried again for the rest of that session. A plan that reaches 15 rounds without finishing still answers, using the work completed so far, rather than failing.

Treat the end of the stream as the signal that a run has finished, rather than waiting for a particular plan_status.

A planner run manages its own model calls, so it takes temperature and sets the rest itself. If you need direct control over max_tokens or response_format, use an ordinary chat completion.

Next steps

  1. Chat Completions API - The endpoint planner mode runs on, including how to stream it
  2. Tool Calling - Defining the tools the planner can hand back to you
  3. Agent Chat Protocol - Build an agent of your own for the planner to find and call
  4. Reasoning - Deeper reasoning inside a single response, without the planning loop