The open-source testing framework for AI agents.
Project description
TrajAI
The open-source testing framework for AI agents.
TrajAI lets you write deterministic tests for non-deterministic AI agents. Mock tools, capture execution trajectories, and assert on what your agent did — not just what it said.
Quick Start
pip install trajai
# test_agent.py
from trajai.mock import MockToolkit
def my_agent(input: str, tools: dict):
order = tools["lookup_order"]({"order_id": "123"})
if order["status"] == "delivered":
refund = tools["process_refund"]({"order_id": "123", "amount": 50.0})
return f"Refund processed: {refund['confirmation']}"
return "Order not yet delivered"
def test_refund_flow():
toolkit = MockToolkit()
toolkit.mock("lookup_order", return_value={"status": "delivered"})
toolkit.mock("process_refund", return_value={"confirmation": "RF-456", "success": True})
result = toolkit.run_callable(my_agent, "Refund order 123")
assert result.tool_was_called("lookup_order")
assert result.tool_called_before("lookup_order", "process_refund")
assert result.output_contains("RF-456")
pytest test_agent.py -v
Why TrajAI?
Testing AI agents is hard. LLMs are non-deterministic, tool calls have side effects, and there's no standard way to assert on agent behavior. Teams end up with fragile integration tests that hit real APIs, cost money, and break randomly.
TrajAI fixes this:
- Mock tools, not LLMs. Your agent runs with real LLM calls but mocked tools. No side effects, deterministic tool responses.
- Assert on behavior. Test what the agent did (which tools it called, in what order, with what arguments) — not just its final text output.
- Handle non-determinism. Run tests N times and assert on pass rates. "This agent calls the right tools 95% of the time" is a valid, useful test.
- Framework support. Works with LangGraph, CrewAI, OpenAI Agents SDK, or any Python callable.
Core Concepts
MockToolkit
The central API. Register mock tools, run your agent, get results.
toolkit = MockToolkit()
toolkit.mock("search", return_value={"results": [...]})
toolkit.mock("send_email", return_value={"sent": True})
Assertions
Both boolean and assert-style APIs for testing agent behavior:
result = toolkit.run_callable(agent, "Find and email the report")
# Boolean API — use with assert
assert result.tool_was_called("search")
assert result.tool_called_before("search", "send_email")
assert result.tool_call_count("search", 1)
# Assert API — raises TrajAIAssertionError with formatted trajectory on failure
result.assert_tool_was_called("search")
result.assert_output_contains("report")
Trajectory
Every agent run produces a Trajectory — a chronological record of all tool calls, LLM calls, and state changes. When assertions fail, the full trajectory is pretty-printed in the error message.
Statistical Testing
Handle LLM non-determinism by running tests multiple times:
from trajai.runner import statistical
@statistical(n=10, threshold=0.9)
def test_agent_uses_correct_tools():
toolkit = MockToolkit()
toolkit.mock("lookup", return_value={"id": "123"})
result = toolkit.run_callable(agent, "Look up order 123")
assert result.tool_was_called("lookup")
Framework Support
| Framework | Install | Status |
|---|---|---|
| Any Python callable | pip install trajai |
Stable |
| LangGraph | pip install trajai[langgraph] |
Stable |
| CrewAI | pip install trajai[crewai] |
Stable |
| OpenAI Agents SDK | pip install trajai[openai-agents] |
Stable |
Framework-specific adapters handle tool injection and trajectory collection automatically:
# LangGraph — auto-detects and injects mocks
result = toolkit.run(my_langgraph_agent, "Refund order 123")
# Generic callable — you wire the tools
result = toolkit.run_callable(my_function, "Refund order 123")
Mock Strategies
# Static return value
toolkit.mock("get_weather", return_value={"temp": 72, "unit": "F"})
# Sequence — different value on each call
toolkit.mock("check_status", sequence=[
{"status": "pending"},
{"status": "shipped"},
{"status": "delivered"},
])
# Side effect — custom function
toolkit.mock("calculate", side_effect=lambda args: args["a"] + args["b"])
# Error — simulate failures
toolkit.mock("flaky_api", side_effect=ConnectionError("timeout"))
# Conditional — return based on arguments
toolkit.mock("lookup", conditional={
lambda args: args.get("id") == "1": {"name": "Alice"},
lambda args: args.get("id") == "2": {"name": "Bob"},
})
Documentation
- Quick Start Guide — Get running in 5 minutes
- Assertion Reference — Every assertion method with examples
- Framework Adapters — LangGraph, CrewAI, OpenAI Agents setup
- Statistical Testing — Handle non-determinism
- Configuration — Full config reference
- CI Integration — GitHub Actions, GitLab CI, CircleCI
Examples
Self-contained example projects in the examples/ directory:
generic_chatbot/— Simple chatbot with basic assertionsrefund_agent/— Multi-step refund workflow with ordering constraintsresearch_agent/— Research agent with statistical testing
Contributing
See CONTRIBUTING.md for development setup, coding standards, and how to submit changes.
License
MIT License. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file trajai-0.1.0.tar.gz.
File metadata
- Download URL: trajai-0.1.0.tar.gz
- Upload date:
- Size: 120.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22e3610340969c63d0ca6a40e6b6d696bd40842452cd175c0d03d32ea5ba78b1
|
|
| MD5 |
76988e4112b464569d37fcc732508c5a
|
|
| BLAKE2b-256 |
8965b4485c3d56af23ac5134bc90f73c8cc7bb8af1fe2b9b071ea4cce771b8dc
|
Provenance
The following attestation bundles were made for trajai-0.1.0.tar.gz:
Publisher:
release.yml on Kaboom2025/TrajAI
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trajai-0.1.0.tar.gz -
Subject digest:
22e3610340969c63d0ca6a40e6b6d696bd40842452cd175c0d03d32ea5ba78b1 - Sigstore transparency entry: 995147976
- Sigstore integration time:
-
Permalink:
Kaboom2025/TrajAI@93dbca8e126abd8e73b9a2730861f3d67f29c89a -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Kaboom2025
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@93dbca8e126abd8e73b9a2730861f3d67f29c89a -
Trigger Event:
push
-
Statement type:
File details
Details for the file trajai-0.1.0-py3-none-any.whl.
File metadata
- Download URL: trajai-0.1.0-py3-none-any.whl
- Upload date:
- Size: 43.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67a3f36c85ef15d6bf1d97176a47e0f9f6d42c4168cb4e3a4e82b73632996558
|
|
| MD5 |
ad27f31efc8bcb500f8e08396e87b767
|
|
| BLAKE2b-256 |
cf651047dac28b7ea3ab1eb7a25ec4b0a354d6fc208b15373bfc78d796c6b482
|
Provenance
The following attestation bundles were made for trajai-0.1.0-py3-none-any.whl:
Publisher:
release.yml on Kaboom2025/TrajAI
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trajai-0.1.0-py3-none-any.whl -
Subject digest:
67a3f36c85ef15d6bf1d97176a47e0f9f6d42c4168cb4e3a4e82b73632996558 - Sigstore transparency entry: 995147979
- Sigstore integration time:
-
Permalink:
Kaboom2025/TrajAI@93dbca8e126abd8e73b9a2730861f3d67f29c89a -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Kaboom2025
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@93dbca8e126abd8e73b9a2730861f3d67f29c89a -
Trigger Event:
push
-
Statement type: