Skip to content
Get Started

Agent API

Backbone Mode

Run the Agent API as a bare LLM backend: mode:"model", the builtin_tools allowlist, and the full tool_choice contract.

Backbone mode turns POST /v1/responses into a bare inference backend — an OpenAI-compatible LLM with client function tools, but no server-side agent runtime, tools, planning, or stored state. Use it when your own agent framework (LangChain, openai-agents, a custom loop) is the orchestrator and Mirobody is “the model.”

The default (mode: "agent") is the whole Mirobody agent: server-side runtime, built-in health-data tools, planning, and stored conversations.

All /v1 endpoints share one base URL — pick the cluster your account uses:

https://api.mirobody.ai/v1 # Global
https://api.mirobody.cn/v1 # China

Japan and EU clusters are in preparation — see Regions. Model providers and pricing can differ by region, so read GET /v1/models from the cluster you call.

{ "mode": "agent" | "model" } // default "agent"
mode:"agent" (default)mode:"model" (backbone)
Runtimeplanning, sub-agents, code eval, virtual filesystemsingle bare-model inference
Server toolsbuilt-in domain tools (trim with builtin_tools)none
System promptfull agent base (~10k tokens)minimal safety base (<100 tokens)
Stateprevious_response_id / session_id threadsstateless (both → 400)
Continuationstateful resume or stateless full replaystateless full replay only
Client toolshandoff via function_call (server-issued call_id)bound directly to the model (call_id preserved)
MCP toolssupported (server-executed)400 (no server tool loop)
Server-side thread stateyes (deleted at request end when store=false)none
text.format400 (not supported)supported

With store=true, model mode still persists the response object (GET /v1/responses/{id} works), but the conversation is tagged as model-mode: a later previous_response_id against it returns an explicit 400 (“replay the transcript to continue”) rather than silently resuming an empty thread.

Terminal window
curl https://api.mirobody.ai/v1/responses \
-H "Authorization: Bearer $MIROBODY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "mirobody-flash",
"mode": "model",
"builtin_tools": "none",
"input": "Summarize the attached lab panel.",
"user": "alice"
}'
{ "builtin_tools": "auto" | "none" | ["query_health_data", ...] } // default "auto"

Controls the server-side domain-tool family — the health, clinical-record, and external-evidence tools:

query_health_data · list_clinical_records · list_family_members · search_medical_evidence · read_source

The external-evidence surface accepts only search_medical_evidence and read_source. Arbitrary URL fetching is not available: read_source accepts refs returned by search (pmid:, pmc:, nct:, or doi:), not model-constructed URLs.

ValueEffect
"auto" (default)All domain tools available — current behavior.
"none"Domain tools all hidden. Required when your backbone caller brings its own data or tools — otherwise the model prefers to query the (empty) Mirobody Subject and skips your client tool.
["name", ...]Allowlist. An unknown name returns 400 invalid_value and lists the available set.

The server-side orchestration primitives (write_todos, filesystem, task, eval) belong to agent mode itself, outside this parameter’s scope — they may still appear in tool_steps. For a zero server-tool trace, use mode:"model".

tool_choice follows OpenAI semantics, with model mode adding hard guarantees the agent runtime cannot make:

tool_choicemode:"model"mode:"agent" (default)
omitted / "auto"Model decidesModel decides
"none"Plain text (auto-drops into model mode)Same, when stateless; with previous_response_id/session_id400
"required"Guarantees the output has at least one client function_call400 unsupported_parameter (the agent runtime can’t force a client-tool call)
{"type":"function","name":X}Guarantees only X is called (stray calls pruned)Accepted but best-effort (not forced)
required / named + empty tools400 invalid_value, param="tool_choice"Same

required / a named tool is a hard guarantee, not a hint — if it can’t be honored you get a 502, never a silent downgrade. In streaming, a forced call is synthesized into the standard event sequence (response.output_item.addedresponse.function_call_arguments.delta/.doneresponse.output_item.done), identical to the non-streaming behavior.

This is verified against LangChain create_agent with both ToolStrategy(...) (which auto-sends tool_choice:"required") and ProviderStrategy(...).

Provider error classification (model mode)

Section titled “Provider error classification (model mode)”

In model mode, provider exceptions are classified by retryability instead of a blanket 502:

Provider sideReturnedMeaning
400 / 404 / 413 / 422 (params, over-length)400 invalid_request_errorThe provider’s actionable message is passed through (truncated). Do not retry.
429429 rate_limit_errorRetry-After passed through or synthesized.
401 / 403 (platform-side credentials / quota)502 upstream_errorA platform fault, not your request — no internal detail leaked.
5xx / timeout / transport502 upstream_errorError type only; full text is logged with an X-Request-Id.