render resolves whatever version the current environment points at, the prompt your application serves changes the moment you release a new version in the dashboard, with no redeploy. A promotion or rollback takes effect on the next request.
The examples show both the TypeScript SDK (@to11ai/sdk) and the Python SDK (to11ai-sdk), which expose the same prompts surface (TypeScript in camelCase, Python in snake_case).
Create the client
The SDK’sprompts.* methods talk to the to11 API, the control plane. Create one client with the API base URL, your key, the project id, and the environment your application runs in, so render can default to them:
env set here is the default label for every render call; you can override it per call with label (env is just a label value). You can also omit env and let the SDK read the TO11_ENV environment variable (in the TypeScript SDK baseUrl/apiKey/projectId likewise default from TO11_API_URL/TO11_API_KEY/TO11_PROJECT_ID, so the explicit values above are optional). A render with no label resolvable — no per-call label, no client env, and no TO11_ENV — is an error, so a misconfigured deployment fails loudly instead of serving the wrong prompt.
Render a prompt
Callprompts.render with the prompt’s slug and the variables it needs:
variables object. A value fills the {{ placeholders }} it’s referenced in and can also drive conditions; a value the prompt marks non-renderable (like tier here) drives conditions but is never rendered. See Variables.
The result carries everything needed to call the model:
In Python the same fields use snake_case:
rendered.tool_choice, rendered.prompt_id.
The developer role
Blocks carry a role, and the author’s roles outrank the end user’s. Thedeveloper role is OpenAI’s name for that application-author layer. OpenAI describes a developer message as “instructions provided by the application developer, prioritized ahead of user messages,” and offers an analogy: a developer message is like a function definition that sets the rules and business logic, while a user message supplies the arguments those rules run against. Historically this layer was the system role, and many models still use that name; OpenAI’s newer models accept developer as a distinct role. See OpenAI’s text generation guide for the details.
A resolved prompt returns your authored roles as-is — a developer block comes back as a developer message. Converting that to what each provider expects is the SDK’s job:
- OpenAI accepts
developer(its modern name for the author layer), so it is passed through unchanged. - Anthropic has no
developerrole, so it goes in Anthropic’s top-levelsystemfield:toAnthropicSystem(to_anthropic_systemin Python) folds thesystemanddeveloperturns into that string, andtoAnthropicMessagesomits them from the message list.
developer blocks, and the SDK places them correctly for the provider you call.
Model configuration
The model id and generation settings (temperature, token limit) are authored on the version in the editor’s Config pane, separate from the rendered messages. Read them withgetVersion:
The TypeScript SDK defaults
projectId on every prompts.* method from the client (createClient({ projectId })), so you omit it per call. The Python SDK currently still takes project_id on each lifecycle/version call — parity is in progress.Send it to the model
Rendered messages, tools, and tool choice are provider-neutral. The SDK’sgateway entry point converts them to your provider’s request shape and supplies the gateway auth headers, so you call your normal provider client pointed at the gateway:
toOpenAIToolChoice returns undefined when the version leaves tool choice unset, letting the provider apply its own default. For the Anthropic request shape, use toAnthropicMessages / toAnthropicTools / toAnthropicToolChoice instead. The Python SDK exposes the same converters as to_openai_* / to_anthropic_*.
The control plane (
createClient({ baseUrl: TO11_API_URL, … })) is where you render prompts; the data plane (baseURL: TO11_GATEWAY_URL) is where the model call runs. They’re different hosts; pointing one at the other is a common setup mistake.Tools and tool choice
rendered.tools and rendered.toolChoice mirror the version’s Tools pane. A specific tool-choice that names a tool no longer present in the resolved version is dropped rather than sent, so a stale directive can’t force a call to a tool that isn’t offered.
Resolution and fallbacks
- Environment resolution.
renderresolves the single version the environment currently serves. For a weighted release, pass a stablesubject(a user or session id) so the same subject deterministically lands on the same variant;rendered.variantNametells you which one served. - Offline fallback. If you pass a
fallbackand the request fails on a network error, the SDK serves the fallback instead of throwing, so a control-plane blip degrades gracefully rather than taking your feature down.
Errors
render throws typed errors you can branch on: a missing prompt, no label supplied, a label that doesn’t exist, an unregistered label, or a policy violation among them. See the TypeScript SDK reference for the full list and their fields.
Migration notes
Both SDKs expose onlyrender(); the older label-addressed resolve() was removed in 2.0. Pass the label as label (which defaults to the client’s env) rather than a labels list. See the TypeScript and Python SDK references.
Earlier TypeScript SDK builds (0.8.x) accepted a separate
context argument on render. It’s been removed: pass those values in variables instead, turning off renderable on the ones that shouldn’t appear in the text. An old build still sending context is accepted without error, but the values are ignored, so blocks that gated on them stop gating until you migrate.Next steps
Authoring prompts
Build the variables, tools, and config that shape what you render.
TypeScript SDK
Full
prompts.* method and error reference.Versions & releases
Control which version an environment resolves to.
Observe traces
See the prompt and version stamped on each model call.