Skip to main content

pytest assertions that verify OpenTelemetry spans conform to the gen_ai semantic conventions.

Project description

pytest-genai-semconv

Pytest assertions that verify emitted OpenTelemetry spans conform to the OpenTelemetry GenAI semantic conventions (gen_ai.*).

Instrumentation libraries emit gen_ai spans; pytest-genai-semconv lets you prove, in a unit or CI test, that those spans carry the right attributes, with the right value types, and the right span kinds — before they reach a backend.

from pytest_genai_semconv import assert_chat_span, assert_plan_span

def test_my_agent_emits_compliant_spans(genai_spans):
    run_my_agent()  # your code, instrumented with OpenTelemetry

    chat = genai_spans.spans_for_operation("chat")[0]
    assert_chat_span(chat, request_model="gpt-4")

    plan = genai_spans.spans_for_operation("plan")[0]
    assert_plan_span(plan, agent_name="research_agent")

Installation

pip install pytest-genai-semconv

The package depends on opentelemetry-api, opentelemetry-sdk, and pytest.

Relationship to the official OpenTelemetry GenAI conventions

The GenAI semantic conventions live in open-telemetry/semantic-conventions-genai. That repository is the source of truth for the spec, and it also ships a reference/ project (semconv-genai-reference) that drives real LLM client libraries against a mock server and validates the captured telemetry with OTel Weaver, producing a cross-library compliance matrix.

pytest-genai-semconv is complementary, not a replacement for that work:

semantic-conventions-genai/reference/ pytest-genai-semconv
Purpose Survey which real libraries emit which attributes Assert your own spans in your own test suite
Mechanism Runs scenarios against a mock server, validates via Weaver In-process pytest assertions over captured spans
Consumed as A repo tool run via uv scripts A pip install-able pytest plugin
Audience OTel maintainers / ecosystem reporting Instrumentation and application authors writing CI tests

In short: the upstream reference project answers "which libraries comply?"; this package answers "do the spans my code emits comply, and will my CI catch it if that regresses?" — a pytest-native check that is not currently packaged for installation elsewhere.

Quickstart

The package ships a pytest plugin that registers a genai_spans fixture. The fixture installs an in-memory OpenTelemetry span exporter for the duration of a single test and captures every span your instrumented code emits.

from opentelemetry import trace

from pytest_genai_semconv import (
    assert_genai_span_compliant,
    assert_execute_tool_span,
)


def test_tool_span_is_compliant(genai_spans):
    tracer = trace.get_tracer("my-app")
    with tracer.start_as_current_span(
        "execute_tool get_weather",
        kind=trace.SpanKind.INTERNAL,
        attributes={
            "gen_ai.operation.name": "execute_tool",
            "gen_ai.tool.name": "get_weather",
        },
    ):
        ...

    span = genai_spans.finished_spans()[0]

    # Generic check: valid operation name, correct attribute types, required
    # attributes present.
    assert_genai_span_compliant(span)

    # Operation-specific check with an expected value.
    assert_execute_tool_span(span, tool_name="get_weather")

When a span is not compliant, the assertion fails with a message that names every offending attribute:

Span 'chat gpt-4' is not gen_ai-compliant:
  - missing required attribute gen_ai.provider.name for gen_ai.inference.client spans
  - gen_ai.usage.input_tokens must be an int, got str

Public API

Symbol Purpose
genai_spans (fixture) In-memory span exporter; .finished_spans(), .spans_for_operation(name), .clear().
assert_genai_span_compliant(span) Generic gen_ai compliance check (all operations).
assert_chat_span(span, *, request_model=None) chat inference span.
assert_plan_span(span, *, agent_name=None) plan span (gen_ai.plan.internal, kind INTERNAL).
assert_invoke_agent_span(span, *, agent_name=None) invoke_agent span (client requires gen_ai.provider.name).
assert_execute_tool_span(span, *, tool_name=None) execute_tool span (requires gen_ai.tool.name).
GenAISpanComplianceError Raised on any violation; exposes .violations.

The assertions accept any span-like object exposing name, kind, and an attributes mapping — exactly what the OpenTelemetry SDK in-memory exporter returns, so they work directly on the fixture's captured spans.

What is checked

For every span, assert_genai_span_compliant enforces:

  • gen_ai.operation.name is present and is a well-known operation value.
  • Value types — every recognised gen_ai.* attribute is type-checked against the convention registry (int, double, boolean, string, string[]); e.g. gen_ai.usage.input_tokens must be an int, gen_ai.request.temperature a number, gen_ai.request.stream a boolean.
  • Enumerated valuesgen_ai.operation.name, gen_ai.output.type, gen_ai.provider.name, and gen_ai.token.type must be well-known values.
  • Per-operation required attributes and span kind for the operations with a defined span profile (see coverage below); e.g. gen_ai.provider.name on chat/embeddings/create_agent client spans, gen_ai.tool.name on execute_tool spans, and INTERNAL kind on plan spans.

Conditionally-required and recommended attributes are intentionally not enforced as hard failures, matching the requirement levels in the spec.

Span coverage

Type and enum checks apply to all recognised gen_ai.* attributes on any span. Operation-specific span profiles (required attributes + allowed span kind) are enforced for these operations:

Operation Span type Profile enforced Named helper
chat, text_completion, generate_content gen_ai.inference.client assert_chat_span (chat)
embeddings gen_ai.embeddings.client
create_agent gen_ai.create_agent.client
invoke_agent gen_ai.invoke_agent.client / .internal assert_invoke_agent_span
execute_tool gen_ai.execute_tool.internal assert_execute_tool_span
invoke_workflow gen_ai.invoke_workflow.internal
plan gen_ai.plan.internal assert_plan_span
retrieval, memory operations ⬜ (generic type/enum only)

Operations without a span profile still get full attribute type and enum validation; only their operation-specific required-attribute and span-kind checks are not yet enforced. Extending profile coverage to retrieval and the memory operations is tracked for a future release.

Why this exists

The OpenTelemetry GenAI semantic conventions define how spans for LLM and agent operations — chat, embeddings, execute_tool, invoke_agent, create_agent, invoke_workflow, and plan — should be shaped. Instrumentation libraries are responsible for emitting spans that follow those conventions. Existing pytest tooling instruments code and captures spans; it does not check that the captured spans match the gen_ai conventions, and the upstream reference project validates libraries rather than offering an installable assertion helper for your own suite.

pytest-genai-semconv fills that gap. It operationalizes the conventions as executable assertions so instrumentation authors and application developers can guard against silent drift as the spec evolves.

In particular, it supports the plan operation and the gen_ai.plan.internal span, which represent an agent's planning / task decomposition phase. A plan span wraps the decision phase where an agent formulates a strategy before executing it; the LLM call that generates the plan is a child of the plan span, and the resulting tool or task spans are siblings under the same invoke_agent span. This library provides assert_plan_span to verify those spans directly, along with golden multi-agent trajectory fixtures that exercise invoke_workflowinvoke_agentplanchatexecute_tool end to end.

Attribute source of truth

The attribute names, value types, enum values, and per-operation requirements are derived from the OpenTelemetry GenAI semantic conventions model files (see src/pytest_genai_semconv/spec.py for the pinned source reference into open-telemetry/semantic-conventions-genai).

Development

python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest
ruff check src tests
ruff format --check src tests

License

Apache-2.0. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest_genai_semconv-0.1.0.tar.gz (25.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_genai_semconv-0.1.0-py3-none-any.whl (20.5 kB view details)

Uploaded Python 3

File details

Details for the file pytest_genai_semconv-0.1.0.tar.gz.

File metadata

  • Download URL: pytest_genai_semconv-0.1.0.tar.gz
  • Upload date:
  • Size: 25.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pytest_genai_semconv-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a1ef7e6230299d7e7f49b46a839493f70b44d3dc2cc57761ff01c326d7c0185b
MD5 73e614278fbc90190f1b31e55bb082a2
BLAKE2b-256 9441cdab6b920de557e9e3f8d9f9cf537e9205c987b9898e27a38358944f2300

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytest_genai_semconv-0.1.0.tar.gz:

Publisher: release.yml on Krishnachaitanyakc/pytest-genai-semconv

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pytest_genai_semconv-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pytest_genai_semconv-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1e8dbd91797de0985d1ba7ed90fb257e02e18890acabb46c11d9bf6fa84c1844
MD5 1089d9d4b0ce3e39f4b5ae84640a7209
BLAKE2b-256 410b6bdb7f2912b05378b20ac66978177fa930f5655f092a84e49e197da2b6fb

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytest_genai_semconv-0.1.0-py3-none-any.whl:

Publisher: release.yml on Krishnachaitanyakc/pytest-genai-semconv

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page