Skip to main content

to11ai-sdk

Python SDK for to11.ai — the AI engineering platform for prompt management, tracing, and evals.

Use it to render managed prompts at runtime, wire your provider client (OpenAI, Anthropic, …) to the to11 gateway with the right auth/trace headers, and group model calls into sessions, conversations, and turns for tracing. Synchronous, snake_case, Python 3.10+. Only runtime dependency: Pydantic.

Installation

pip install to11ai-sdk
# or: uv add to11ai-sdk  ·  poetry add to11ai-sdk

The SDK's only runtime dependency is Pydantic. The provider client libraries used in the examples below (openai, anthropic) are not dependencies — install whichever you use yourself, e.g. pip install openai.

Upgrading from 1.x

2.0 reshapes prompt access around a single render() call and trims the public surface to what we keep stable. prompts.resolve() is gone, the per-call env argument is now label, and routing rules are no longer exported. See Migrating from 1.x to 2.0 for the full list of renames and removals.

Quick start

Create a client, render a prompt for the current environment, and send it through the gateway with your normal provider client:

import os
from to11ai_sdk import create_client
from openai import OpenAI

to11 = create_client(
    # Each also resolves from an env var, so on a server you can pass nothing:
    base_url=os.environ.get("TO11_API_URL"),        # -> https://api.to11.ai
    api_key=os.environ.get("TO11_API_KEY"),         # -> TO11_API_KEY
    project_id=os.environ.get("TO11_PROJECT_ID"),   # -> TO11_PROJECT_ID
    env=os.environ.get("TO11_ENV"),                 # "prod", "staging", … -> TO11_ENV
)

# Fetch a released prompt for the client's project + environment, shaped for OpenAI.
prompt = to11.prompts.render("welcome-message", variables={"name": "Ada"}, format="openai")

# Point your provider client at the gateway and send it.
openai = OpenAI(**to11.openai_options())
completion = openai.chat.completions.create(
    **prompt["config"],
    messages=prompt["messages"],
    extra_headers=to11.turn().headers(prompt),  # auth + trace id + prompt provenance
)

prompt["config"] carries the model parameters, prompt["messages"] the rendered messages, and turn().headers(prompt) the headers that authenticate the gateway call and record which prompt produced the trace.

Configuring the client

create_client(...) takes keyword-only args. Each URL/credential resolves option → environment variable → built-in default, so a server app can construct it from the environment alone:

Argument Resolves from Default
base_url option → TO11_API_URL https://api.to11.ai
gateway_url option → TO11_GATEWAY_URL https://gw.to11.ai
api_key option → TO11_API_KEY — (required)
project_id option → TO11_PROJECT_ID —
env option → TO11_ENV — (lowercase-kebab, 1–63 chars)
provider_api_key option — (BYOK; carried by openai_options()/anthropic_options())
format option — ("openai" | "anthropic"; omit for the neutral result)
on_unknown_role option "drop"
timeout_s / max_retries option 30.0 / 3
behavior_overrides option None

The client exposes the resolved values as read-only attributes — to11.base_url, to11.gateway_url, to11.api_key, to11.project_id, and to11.env. Use the non-secret ones (base_url/gateway_url/project_id/env) for diagnostics; api_key is exposed to build manual auth headers — treat it as a secret and never log it. provider_api_key (BYOK) is deliberately not exposed back off the client.

Fetching prompts

prompts.render(slug, ...) resolves the released prompt for the client's project_id + env in one request. Set format (on the client or per call) to get a result shaped for that provider; omit it for the provider-neutral result.

prompt = to11.prompts.render(
    "weather-concierge",
    variables={"city": "New York", "units": "fahrenheit"},
    # label=...      # override the client's environment for this call
    # subject=...    # a stable id so a weighted release pins the same caller to a variant
    # fallback=...   # a previously-rendered RenderedPrompt served on a network error
    # format="openai" | "anthropic"
    # on_unknown_role="drop" | "warn" | "error"
)
  • With format the result is spread-ready: {"messages": ..., "config": ..., "metadata": ...} (config = the version's model params; metadata = prompt/version/release provenance). For Anthropic it also carries a top-level "system".
  • Without format you get the neutral RenderedPrompt: .messages, .tools, .tool_choice, .prompt_id, .version, .version_id, .release_id, .variant_name, .content_hash, .label, .slug, .block_render_record, .model_config_ (trailing underscore avoids Pydantic's reserved name).

Authored developer blocks come back as-is; the SDK maps them per provider (OpenAI keeps developer; Anthropic folds system/developer into the top-level system). on_unknown_role controls how an unrecognized role is handled during provider conversion.

Sending through the gateway

openai_options() / anthropic_options() return spread-ready kwargs (base_url, api_key, default_headers) for a provider client pointed at the gateway; default_headers carries the static tenant auth. Add turn().headers(prompt) per call for the trace id and prompt provenance:

from anthropic import Anthropic
anthropic = Anthropic(**to11.anthropic_options())

By default the gateway runs the call on the project's configured provider credential (managed). For BYOK, set provider_api_key on create_client.

Sessions, conversations & turns

Group model calls for tracing. to11.turn() uses the client's default session; create explicit ones with to11.session(id=None) / to11.conversation(id=None). turn().headers(prompt=None) emits the session/conversation ids + a fresh traceparent (plus prompt provenance when a rendered/shaped prompt is passed) — for the gateway call you make. (This is separate from the SDK's OTel-based traceparent on its own control-plane requests.)

Managing prompts, versions & labels

Beyond render(), the prompts namespace covers the control-plane lifecycle. All of these default project_id from the client — pass it per call only to override:

to11 = create_client(api_key="...", project_id="proj_abc123")

to11.prompts.list()                                        # uses the bound project_id
to11.prompts.get(prompt_id="prompt_1")
to11.prompts.get_version(prompt_id="prompt_1", version_number=3)
to11.prompts.move_label(prompt_id="prompt_1", label="production", version_id="ver_9", reason="promote")

Full set: create, list, get, update, archive, create_version, list_versions, get_version, move_label, list_labels, and the project-label registry (list_project_labels, create_project_label, get_project_label, update_project_label, delete_project_label, list_project_label_usages, list_label_events). to11.project_environments exposes the project-environments registry.

update_project_label(description=None) means "leave unchanged"; pass description="" to clear it.

Error handling

To11aiError is the base; catch it broadly or match a subclass:

from to11ai_sdk import To11aiRateLimitError, PromptNotFoundError

try:
    prompt = to11.prompts.render("welcome-message")
except To11aiRateLimitError as exc:
    ...  # exc.retry_after_seconds
except PromptNotFoundError:
    ...
Class When
To11aiApiError non-2xx API response (status_code, error_code, details)
To11aiAuthError 401/403
To11aiRateLimitError 429 (retry_after_seconds)
To11aiValidationError 400
To11aiNetworkError network failure / timeout
PromptNotFoundError · LabelNotFoundError · MissingLabelError · NoActiveReleaseError · PromptPolicyViolationError · PromptLabelNotRegisteredError typed prompt-resolution errors
UnknownRoleError an unrecognized message role with on_unknown_role="error"
To11aiResponseValidationError a 2xx body that fails schema validation

Documentation

Full reference: https://docs.to11.ai/reference/python-sdk. Licensed under MPL-2.0.

Metadata

Release files for to11ai-sdk 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for to11ai-sdk 2.0.0
File Size Uploaded
to11ai_sdk-2.0.0.tar.gz 121.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for to11ai-sdk 2.0.0
File Interpreter ABI Platform
to11ai_sdk-2.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 176.0 kB

Release files / to11ai_sdk-2.0.0.tar.gz

Download URL to11ai_sdk-2.0.0.tar.gz
Size 121.4 kB
Tags Source
SHA-256 checksum
How to use checksums
518219139bc772536b29859a2d5a23454bc1630b32dc77681003366f09abb31d
BLAKE2b-256 checksum
How to use checksums
392a7078329cef617a80ddaeb135dcfa3c1f2e781f30babf2536ec2582b25695
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / to11ai_sdk-2.0.0-py3-none-any.whl

Download URL to11ai_sdk-2.0.0-py3-none-any.whl
Size 54.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
20c09a27b9462a5f4df196779c090732ded1ee4e4cf03b11c04a922b15bb0013
BLAKE2b-256 checksum
How to use checksums
b79e322a94b119564fe70bcec8460fb05020e6857316258aaf9ae9a25155cebf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page