Skip to main content
Available for: Python and TypeScript.
Wrap your OpenAI client with wrapOpenAI() (TypeScript) or patch the openai module with patch_openai() (Python). Every chat.completions.create call your existing code makes is traced automatically — no changes to call sites required.
Only chat.completions.create is instrumented today — this covers standard chat and streaming chat calls, including function/tool calling. embeddings.create, the Responses API, and other OpenAI endpoints (images, audio, moderations) are not currently traced by either SDK.

Installation

Setup

In TypeScript, wrapOpenAI() returns a wrapped client instance — pass it to any function that makes OpenAI calls, and use it exactly like the original client. In Python, patch_openai() monkey-patches openai.resources.chat.completions.Completions.create in place, so openai.OpenAI() (constructed after patching) is traced automatically with no wrapping step.

Example

Zespan captures this call as a span with model, prompt tokens, completion tokens, latency, and cost.

What gets captured

Prompt and completion text is stored by default, with PII redaction applied before transmission. Set storePrompts: false (store_prompts=False in Python) in zespan.init() to disable prompt/completion storage entirely.

Streaming

Both wrappers support streaming. Token counts and tool calls are accumulated from the stream chunks, and time-to-first-token (ttft_ms) is recorded on the first chunk.

Tool and function calls

Pass tools as usual. Zespan records the tool definitions from the request and, once the model responds, the names and arguments of any tools it decided to call — for both streaming and non-streaming calls, in both languages.

Guardrails

Pass guardrails: true (guardrails=True in Python) to run pre- and post-call content checks against your configured guardrail policies.
A guardrail that blocks content throws (Python: raises) GuardrailBlockedError — catch it to return a safe fallback instead of letting the exception propagate. See Guardrails for the full configuration options (pre/post/failClosed), the GuardrailBlockedError shape, and how to call guardrail checks directly outside of a wrapped call.

Error handling

On failure, both wrappers re-throw (Python: re-raise) the original OpenAI SDK error after recording an error-status event with error_message — your existing try/catch (try/except) around the call keeps working unchanged.
A few behaviors are worth knowing about:
  • Status classification. TypeScript inspects err.status and reports rate_limited for HTTP 429 and timeout for HTTP 408 (in addition to error for everything else, and guardrail_blocked as the error_code when a GuardrailBlockedError is thrown). The Python wrapper does not currently classify errors this way — every exception is recorded with status error.
  • Guardrail blocks. In TypeScript, a guardrail block still enqueues an error-status event (with error_code: "guardrail_blocked") before re-throwing. In Python, GuardrailBlockedError is re-raised immediately without an error event being recorded.
  • Config-driven resilience. Retries, timeouts, concurrency limits, fallback models, and A/B testing are not options you pass to wrapOpenAI()/patch_openai() directly — they’re project-level rules pushed from the Zespan dashboard via config propagation and applied automatically to every call. The TypeScript wrapper applies all of these (model override, A/B test, retry with backoff, timeout, concurrency limiting, and fallback-on-error). The Python wrapper currently applies model override, A/B testing, and fallback-on-error, but not retry, timeout, or concurrency limiting.

Next steps

  • Guardrails — full guardrail configuration and GuardrailBlockedError reference
  • Config propagation — how model overrides, fallbacks, retries, and timeouts get pushed to running apps
  • Agent tracing — wrap multi-step agent logic
  • Manual spans — add custom spans around non-LLM operations
  • PII redaction — automatically redact sensitive data before storage