> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://respan.ai/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://respan.ai/docs/_mcp/server.

# Mirascope (tracing)

> Trace Mirascope 2.x model calls, streams, context calls, and toolkit execution with Respan.

[Mirascope](https://mirascope.com/) is a Python toolkit for building LLM applications with a unified model API, structured outputs, streaming, and typed tools. `respan-instrumentation-mirascope` traces Mirascope 2.x model operations as canonical Respan chat spans and toolkit execution as tool spans.

Synchronous and asynchronous calls are supported. Streaming spans stay open until the underlying stream is consumed, so their timing, output, usage, and iterator errors describe the complete stream.

#### Set up Respan

Create an account at [platform.respan.ai](https://platform.respan.ai) and grab an [API key](https://platform.respan.ai/platform/gateway/api-keys).

Run `npx @respan/cli setup` to set up with your coding agent.

#### Example projects

* [Python package README](https://github.com/RespanAI/respan/tree/main/python-sdks/instrumentations/respan-instrumentation-mirascope)
* [Runnable Mirascope examples](https://github.com/respanai/respan-example-projects/tree/main/python/tracing/mirascope)

## Setup

#### Install packages

```bash
pip install respan-ai respan-instrumentation-mirascope "mirascope[openai]"
```

#### Set environment variables

```bash
export RESPAN_API_KEY="YOUR_RESPAN_API_KEY"
export OPENAI_API_KEY="YOUR_OPENAI_API_KEY"
```

Use the credential required by your selected Mirascope provider when it is not OpenAI.

#### Initialize and call a model

```python
from mirascope import llm
from respan import Respan
from respan_instrumentation_mirascope import MirascopeInstrumentor

respan = Respan(
    app_name="mirascope-support-agent",
    instrumentations=[MirascopeInstrumentor()],
)
model = llm.Model("openai/gpt-4o-mini")

try:
    response = model.call("Explain distributed tracing in one sentence.")
    print(response.text())
finally:
    respan.shutdown()
```

#### View your trace

Open the [Traces page](https://platform.respan.ai/platform/traces) to inspect the Mirascope chat span, provider, model, messages, usage, and status.

## Supported operations

| Mirascope surface                       | Respan log type | Lifecycle                                                    |
| --------------------------------------- | --------------- | ------------------------------------------------------------ |
| `Model.call` and `Model.call_async`     | `chat`          | Ends when the call returns or raises.                        |
| Context-aware model calls               | `chat`          | Preserves the active Respan parent context.                  |
| `Model.stream` and `Model.stream_async` | `chat`          | Ends when the stream is consumed, fails, or is abandoned.    |
| Toolkit execution                       | `tool`          | Captures the tool name, arguments, result, and error status. |

Model calls include prompts, completions, tool definitions and calls, model and provider identifiers, and token usage when the provider response supplies them. Errors are re-raised unchanged after the span records OpenTelemetry error status, `status_code`, and `error.message`.

## Stream model output

The stream span finishes when `text_stream()` is exhausted:

```python
from mirascope import llm

model = llm.Model("openai/gpt-4o-mini")
response = model.stream("Count from one to three.")

for text in response.text_stream():
    print(text, end="")
```

For an asynchronous stream, await `stream_async()` and consume its text stream with `async for`:

```python
from mirascope import llm


async def stream_answer() -> str:
    model = llm.Model("openai/gpt-4o-mini")
    response = await model.stream_async("Count from four to six.")
    parts = []
    async for text in response.text_stream():
        parts.append(text)
    return "".join(parts)
```

## Trace tool execution

Tools passed to a model call are captured on the chat span. When Mirascope executes a returned tool call, the execution becomes a child tool span.

```python
import math

from mirascope import llm


@llm.tool
def square_root(number: float) -> float:
    """Calculate the square root of a number."""
    return math.sqrt(number)


model = llm.Model("openai/gpt-4o-mini")
response = model.call(
    "Use the tool to calculate the square root of 144.",
    tools=[square_root],
)
results = response.execute_tools() if response.tool_calls else []
print(results)
```

## Configuration

| Parameter             | Type           | Default | Description                                                       |
| --------------------- | -------------- | ------- | ----------------------------------------------------------------- |
| `capture_content`     | `bool`         | `True`  | Capture model messages, tool definitions, arguments, and outputs. |
| `instrumentations`    | `list`         | `[]`    | Pass `[MirascopeInstrumentor()]` to activate Mirascope tracing.   |
| `api_key`             | `str \| None`  | `None`  | Falls back to `RESPAN_API_KEY`.                                   |
| `base_url`            | `str \| None`  | `None`  | Falls back to `RESPAN_BASE_URL`.                                  |
| `customer_identifier` | `str \| None`  | `None`  | Default customer identifier for all emitted spans.                |
| `metadata`            | `dict \| None` | `None`  | Default metadata attached to all emitted spans.                   |

### Disable content capture

```python
from respan import Respan
from respan_instrumentation_mirascope import MirascopeInstrumentor

respan = Respan(
    instrumentations=[MirascopeInstrumentor(capture_content=False)],
)
```

With capture disabled, messages, tool definitions, arguments, and model outputs are omitted. Provider, model, usage, timing, status, and exception type remain available.

## Add trace context

```python
from respan import Respan

with Respan.propagate_attributes(
    customer_identifier="user_123",
    thread_identifier="conversation_abc",
    trace_group_identifier="mirascope_support_workflow",
    metadata={"plan": "pro"},
):
    response = model.call("Draft a concise answer to this support request.")
```

Do not combine this adapter with `mirascope.ops.instrument_llm()` unless you intentionally want two independent telemetry pipelines for each operation.