---
title: prefactor_core.span_context module
editUrl: true
head: []
template: doc
sidebar:
  hidden: false
  attrs: {}
pagefind: true
draft: false
---

# prefactor_core.span_context module

Span context for automatic lifecycle management.

The SpanContext provides an interface for updating span data during execution
and ensures proper cleanup when the span completes.

### *class* prefactor_core.span_context.SpanContext(temp_id: str, span_manager: [SpanManager](prefactor_core.managers.md#prefactor_core.managers.SpanManager), default_payload: dict[str, Any] | None = None)

Bases: `object`

Context for an active span.

Returned by `instance.span()` / `client.span()` context managers.

Spans follow a three-phase lifecycle:

1. **Enter context** — span is prepared locally (no HTTP call yet).
2. **\`\`await span.start(payload)\`\`** — POSTs the span to the API as
   `active` with the given params payload.
3. **\`\`await span.complete(result)\`\`** (or `.fail()` / `.cancel()`)
   — finishes the span with the appropriate terminal status.

`cancelled` before start is handled via `pending → cancelled`; once
started, the span transitions from `active` to a terminal status.

If `start()` or a finish method is omitted, the context manager calls
them automatically on exit (auto-start uses `default_payload`; the
default finish status is `complete`), so explicit calls are opt-in.

Example:

```default
async with instance.span("agent:llm_call") as span:
    await span.start({"model": "claude-3-5-sonnet", "prompt": "Hi"})
    try:
        response = await call_llm(...)
        await span.complete({"response": response, "tokens": 42})
    except Exception as exc:
        await span.fail({"error": str(exc)})

# Skip start entirely to cancel before any work begins:
async with instance.span("agent:retrieval") as span:
    if not needed:
        await span.cancel()
    else:
        await span.start({"query": "..."})
        ...
```

#### *async* cancel() → None

Finish the span with `cancelled` status.

Can be called before or after `start()`. If `start()` has not
been called yet, the span is posted as `pending` then immediately
cancelled — the API only accepts cancellation from the `pending`
state, so this is always a valid sequence.

#### *async* complete(result: dict[str, Any] | None = None) → None

Finish the span with `complete` status.

* **Parameters:**
  **result** – Optional result payload to attach to the span.

#### *async* fail(result: dict[str, Any] | None = None) → None

Finish the span with `failed` status.

* **Parameters:**
  **result** – Optional result payload (e.g. error details).

#### *async* finish() → None

Finish the span using whichever status was last set (default: `complete`).

Called automatically when exiting the context manager. Can also be
called manually; subsequent calls are no-ops.

#### *property* id *: str*

Get the span ID.

Before `start()` is called this returns the temporary local ID.
After `start()` it returns the API-generated ID.

* **Returns:**
  The span identifier.

#### set_result(data: dict[str, Any]) → None

Store result data to be sent when the span finishes.

The data is merged and sent as `result_payload` when the span
finishes. Calling this does **not** finish the span.

* **Parameters:**
  **data** – Dictionary of result data for the span.

#### *async* start(payload: dict[str, Any] | None = None) → None

Post the span to the API as `active` with the given params payload.

This triggers `POST /api/v1/agent_spans`. The span is created as
`pending` so that any terminal status (`complete`, `failed`,
`cancelled`) is a valid transition via the finish endpoint. Must be
called at most once; subsequent calls are no-ops.

* **Parameters:**
  **payload** – Optional params/inputs for the span (e.g. model name,
  prompt text, tool input). Stored as the span’s `payload`
  field in the API.