Skip to main content

veval-sdk

Python SDK for Veval — trace, evaluate, and test AI agents.

Install

pip install veval-sdk

Quick start

Wrap your agent with run_async to send a trace to the Veval dashboard:

import asyncio
from veval import VevalSdk, VevalOptions, VevalExecutionContext

sdk = VevalSdk(VevalOptions(api_key="veval-..."))

async def my_agent(ctx: VevalExecutionContext) -> str:
    result = await ctx.track_step_async(
        name="call-llm",
        input=ctx.input,
        step=lambda: call_my_llm(ctx.input),
    )
    return result

output = asyncio.run(sdk.run_async("my-agent", my_agent, input="Hello"))

Every call to track_step_async records the step name, input, output, timing, and any metadata you attach.

Tracking steps

Use the StepHandle to attach token counts, cost, and model name:

async def agent(ctx: VevalExecutionContext) -> str:
    async def llm_call(handle):
        response = await call_my_llm(ctx.input)
        handle.set_meta("tokens_in", response.usage.input_tokens)
        handle.set_meta("tokens_out", response.usage.output_tokens)
        handle.set_meta("cost_usd", response.usage.cost)
        handle.set_meta("type", "llm")
        handle.set_meta("model", "claude-opus-4-6")
        return response.text

    return await ctx.track_step_async("call-llm", ctx.input, llm_call)

Assertions

Use TraceAssert to validate behaviour at the trace level:

from veval import TraceAssert

assertions = [
    TraceAssert.no_errors(),
    TraceAssert.max_steps(10),
    TraceAssert.step_exists("call-llm"),
    TraceAssert.max_cost(0.05),
    TraceAssert.max_duration(30_000),
    TraceAssert.output_contains("success"),
    TraceAssert.tool_called("web-search"),
]

Scenarios

Run a named scenario against a list of test items and assertions:

from veval import ScenarioItem

items = [
    ScenarioItem(name="basic greeting", input="Hello"),
    ScenarioItem(name="edge case", input=""),
]

result = asyncio.run(
    sdk.run_scenario_async("smoke-test", my_agent, assertions, items=items)
)

print(f"Passed: {result.pass_count}/{len(result.results)}")
for r in result.results:
    if not r.passed:
        print(f"  FAIL {r.item.name}: {r.failures}")

A trace-backed item (ScenarioItem(trace_id=...)) replays live: steps recorded with set_meta("type", "llm") call the model with your current prompt, so a prompt regression fails the item, and every other step returns its recorded output, so tools never reach a real system. Set mock_model_steps=True on the item, or pass mock_model_steps=True to run_scenario_async for every item (including ones loaded from the dashboard), for a free, fully mocked replay that checks code changes but can't see prompt changes. VevalTestSdk always replays trace-backed items mocked. ReplayOptions(live_model_steps=True) does the same for replay_async.

You can also pull items from the Veval dashboard by omitting items:

result = asyncio.run(sdk.run_scenario_async("smoke-test", my_agent, assertions))

Replay and snapshot testing

Load a previously recorded trace and replay it with mocked LLM responses — no real calls, deterministic results:

trace = asyncio.run(sdk.get_trace_async("tr_abc123"))

replay = asyncio.run(sdk.replay_async(
    trace,
    my_agent,
    ReplayOptions(mock_llm_responses=True, assertions=assertions),
))

print("Passed" if replay.passed else replay.failures)

Each call gets the recorded step with the same name and an identical input, or else the next unused one in recorded order, reported as diverged in replay.fidelity. A step with no recording raises instead of calling live, and a recorded step the agent never calls fails the replay.

Store a known-good run — every step with its input and output — and detect when a new run drifts from it: a changed prompt or tool argument, a step added, dropped, repeated, or reordered:

# Save a baseline from a recorded trace. The trace is pinned, so retention never deletes it.
asyncio.run(sdk.save_snapshot_async("my-baseline", "tr_abc123"))

# In tests: an assertion like any other. A missing baseline fails; it never passes silently.
replay = asyncio.run(sdk.replay_async(trace, my_agent, ReplayOptions(
    mock_llm_responses=True,
    assertions=[TraceAssert.matches_snapshot(sdk, "my-baseline")],
    compare_with_recording=SnapshotOptions(),  # also fail if steps/inputs drift from the trace
)))

# Or compare directly, and record the result in the dashboard.
baseline = asyncio.run(sdk.get_snapshot_async("my-baseline"))
diff = asyncio.run(sdk.compare_snapshot_async("my-baseline", baseline, ctx))
if diff.has_changes:
    print(diff.summary())  # every change, with a line diff of changed inputs

Test SDK

VevalTestSdk is a drop-in replacement that blocks real LLM calls, making it safe to use in unit tests. It still reports to the dashboard.

from veval import VevalTestSdk

sdk = VevalTestSdk(options).with_replay(trace)
output = asyncio.run(sdk.run_async("my-agent", my_agent, input="test input"))

API reference

VevalOptions

Parameter Type Default Description
api_key str "" Your Veval API key — it also determines the workspace
project_id str "" Deprecated and ignored; will be removed
flush_interval_ms int 5000 Batch flush interval
flush_batch_size int 50 Max traces per flush
raise_on_send_failure bool False Raise VevalSendError when a trace or scenario run can't be stored. Off by default: the failure is logged as a warning on the veval logger with the HTTP status. Turn it on in tests and CI

VevalSdk

Method Description
run_async(name, callback, input) Run agent and send trace
get_trace_async(trace_id) Fetch a recorded trace
save_snapshot_async(name, trace_id_or_ctx) Store a named baseline (pins the trace)
get_snapshot_async(name) Load the latest stored baseline
load_snapshot_async(trace_id) Build a snapshot from a trace (not pinned)
compare_snapshot_async(name, snapshot, ctx, options) Diff a run against a baseline and record it
replay_async(trace, callback, options) Replay trace with mocked outputs
run_scenario_async(name, agent, assertions, items) Run a test scenario

TraceAssert built-ins

Assertion Description
no_errors() All steps must succeed
max_steps(n) Total step count must not exceed n
step_exists(name) A step with this name must appear
max_cost(usd) Total cost must not exceed usd
max_duration(ms) Total step duration must not exceed ms
output_contains(text) At least one step output must contain text
tool_called(name) A tool step with this name must appear

Custom assertions implement async ITraceAssertion.evaluate_async(ctx) -> Optional[str] — return None to pass or an error string to fail.

Requirements

  • Python 3.10+
  • No third-party dependencies

Metadata

Release files for veval-sdk 1.3.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 veval-sdk 1.3.0
File Size Uploaded Provenance
veval_sdk-1.3.0.tar.gz 31.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for veval-sdk 1.3.0
File Interpreter ABI Platform
veval_sdk-1.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 60.6 kB

Release files / veval_sdk-1.3.0.tar.gz

Download URL veval_sdk-1.3.0.tar.gz
Size 31.1 kB
Tags Source
SHA-256 checksum
How to use checksums
535d6cfbd64e450139a0bd3ed41db495f3c70592fc98706bc9c8fe22f5b351d0
BLAKE2b-256 checksum
How to use checksums
c892e3445676eb0c6367a861cef7ede5887466637adf92b878947c553d2a2d71
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / veval_sdk-1.3.0-py3-none-any.whl

Download URL veval_sdk-1.3.0-py3-none-any.whl
Size 29.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b7b6ee62d01dd1ebd57b5547a6203b77a519da4f05ac6c0c935f0943a30bc1f6
BLAKE2b-256 checksum
How to use checksums
94ff20be7350beb1c61c761b7d7f6e9c190b949e13d1187bfdf2a473d11871ea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Security for veval-sdk 1.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for veval_sdk-1.3.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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