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

# Rendering prompts

> Render a managed prompt, shape it per provider, or convert the neutral result.

`client.prompts.render(slug, **options)` resolves a prompt for the client's `project_id` and `env` in a single request. Set `format` — on the client or per call — to get a result shaped for that provider; omit it to get the neutral result. It is the primary runtime method.

```python theme={null}
client = create_client(env="production", format="openai")

prompt = client.prompts.render("welcome-message", variables={"name": "Ada"})
```

The keyword options are `format`, `label`, `subject`, `variables`, `fallback`, and `on_unknown_role`: `label` picks the label to resolve for this call (defaulting to the client's `env` — env is a label value), `format` overrides the client default, `subject` (a stable id) pins a weighted release to a variant, and `fallback` is served on a transient network or 5xx failure. The return shape is fixed by the call's `format`, not by the network outcome. Authored `developer` blocks render as-is; the SDK maps them per provider (OpenAI keeps `developer`, Anthropic folds them into `system`). `on_unknown_role` (`"drop"` default, `"warn"`, or `"error"`) sets how a message with an unrecognized role is handled during provider conversion — see [Unknown roles](#unknown-roles).

## Shaped result

With a `format`, `render` returns a dict you can spread straight into a provider request. `format="openai"` returns `{"messages", "config", "metadata"}`; `format="anthropic"` returns `{"system", "messages", "config", "metadata"}` — the authored system and developer instructions are folded into a top-level `system` string, which Anthropic takes as a separate request field. When the prompt authors tools, the result also carries provider-shaped `tools` and `tool_choice`.

| Key                     | Holds                                                                                                                                                                                        |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `system`                | **Anthropic only.** The folded system/developer instruction text, passed as Anthropic's top-level `system`. Omit it and you drop the authored instructions.                                  |
| `messages`              | The rendered messages, shaped for the provider.                                                                                                                                              |
| `config`                | Model parameters from the resolved version — `model`, `temperature`, `max_tokens`, and any other stored keys — passed through verbatim, so the dict spreads straight into `create()`.        |
| `tools` / `tool_choice` | Provider-shaped tool definitions and directive, present only when the prompt authors tools. Spread them into the request so a tool-using prompt isn't sent without its tools.                |
| `metadata`              | Provenance: `prompt_id`, `version`, `version_id`, `release_id`, `label` (the single label the prompt resolved through), `slug`, and `variant_name` when a weighted release served a variant. |

Spread the result into the request, and pass the whole result to `turn().headers(prompt)` for the provenance headers:

```python theme={null}
# OpenAI — tools/tool_choice are present only when the prompt authors tools
res = openai.chat.completions.create(
    **prompt["config"],
    messages=prompt["messages"],
    **({"tools": prompt["tools"]} if "tools" in prompt else {}),
    **({"tool_choice": prompt["tool_choice"]} if "tool_choice" in prompt else {}),
    extra_headers=client.turn().headers(prompt),
)
```

```python theme={null}
# Anthropic — pass the folded system alongside the messages
res = anthropic.messages.create(
    **prompt["config"],
    system=prompt["system"],
    messages=prompt["messages"],
    extra_headers=client.turn().headers(prompt),
)
```

## Neutral result and converters

Omit `format` (on both the client and the call) to get the neutral `RenderedPrompt` dataclass: `messages`, `tools`, `tool_choice`, `prompt_id`, `version`, `version_id`, `release_id`, `variant_name`, `content_hash`, `label`, `slug`, and `block_render_record`. The version's model config is exposed as `model_config_` — the trailing underscore avoids Pydantic's reserved `model_config` attribute. This is the path for a provider the shaper does not cover (Vercel AI, LangChain) or for driving one prompt through more than one provider.

The `to11ai_sdk.gateway` module converts a neutral result into a provider's request shape:

| Helper                                               | Purpose                                                                                                                                                             |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `to_openai_messages` / `to_anthropic_messages`       | Convert the neutral `messages` to the provider's message list. Both accept an `on_unknown_role` argument — see [Unknown roles](#unknown-roles).                     |
| `to_anthropic_system`                                | Fold the `system`/`developer` turns into Anthropic's top-level `system` string (they are omitted from `to_anthropic_messages`). Pair the two for an Anthropic call. |
| `to_openai_tools` / `to_anthropic_tools`             | Convert `tools` to the provider's tool schema.                                                                                                                      |
| `to_openai_tool_choice` / `to_anthropic_tool_choice` | Convert `tool_choice` to the provider's directive.                                                                                                                  |
| `gateway_auth_headers`                               | The `x-to11-*` headers that authenticate a gateway call.                                                                                                            |
| `gateway_prompt_headers`                             | Prompt provenance headers for a rendered prompt.                                                                                                                    |

`gateway_auth_headers` and `gateway_prompt_headers` are also importable from the main `to11ai_sdk` entry. With a `format`, `render` applies the message conversion for you, so most apps never call the converters directly.

```python theme={null}
from to11ai_sdk.gateway import to_openai_messages, to_openai_tools

rendered = client.prompts.render("weather-concierge", variables={"city": "NYC"})
res = openai.chat.completions.create(
    model="gpt-4o",
    messages=to_openai_messages(rendered.messages),
    tools=to_openai_tools(rendered.tools) if rendered.tools else None,
    extra_headers=client.turn().headers(rendered),
)
```

## Unknown roles

The message converters recognize `system`, `user`, `assistant`, `developer`, and `tool`. A message whose role is anything else is handled by the `on_unknown_role` policy — set it per call, on `create_client`, or on the converter directly:

| Mode               | Behavior                                                                                    |
| ------------------ | ------------------------------------------------------------------------------------------- |
| `"drop"` (default) | The message is omitted silently.                                                            |
| `"warn"`           | The message is omitted and a warning on the `to11ai_sdk` logger names the role and index.   |
| `"error"`          | Conversion raises `UnknownRoleError` (carrying `code="unknown_role"`, `role`, and `index`). |

```python theme={null}
# Fail loudly when a hand-built message array has an unrecognized role
messages = to_openai_messages(history, on_unknown_role="error")
```

A prompt rendered by to11 only ever carries known roles, so on `render()` this matters mainly when you convert your own message arrays (assembled conversation history, messages from another source). `on_unknown_role="error"` on `render()` is a way to assert that invariant explicitly.
