Skip to content

Test agent programs

Test application logic without relying on a live model. ScriptedModel returns a predetermined sequence of actions and records every request it receives.

Test a direct result

from dataclasses import dataclass

from pilota import FinalResult, ScriptedModel, agent


@dataclass
class Classification:
    label: str
    confidence: float


def test_classifies_incident() -> None:
    model = ScriptedModel(
        [FinalResult({"label": "database", "confidence": 0.91})]
    )

    result = agent(
        "Classify the incident",
        model=model,
        context={"title": "Primary database is unavailable"},
        returns=Classification,
    )

    assert result == Classification(label="database", confidence=0.91)

Test tool interaction

Script tool calls and the final result in order:

from pilota import (
    Editor,
    FinalResult,
    InMemoryWorkspace,
    ScriptedModel,
    ToolCall,
    run_agent,
)


def test_agent_updates_file() -> None:
    workspace = InMemoryWorkspace({"version.txt": "1\n"})
    model = ScriptedModel(
        [
            ToolCall(
                id="write-version",
                name="editor",
                arguments={
                    "operation": "write",
                    "path": "version.txt",
                    "content": "2\n",
                },
            ),
            FinalResult("Updated version.txt"),
        ]
    )

    execution = run_agent(
        "Set the version to 2",
        model=model,
        workspace=workspace,
        tools=[Editor()],
        returns=str,
    )

    assert workspace.read_text("version.txt") == "2\n"
    assert [(item.operation, str(item.path)) for item in execution.artifacts] == [
        ("modified", "version.txt")
    ]

Assert request wiring

request = model.requests[0]

assert request.task == "Set the version to 2"
assert request.context == {}
assert [tool.name for tool in request.tools] == ["editor"]
assert request.result_schema["type"] == "string"

After a tool call, the next recorded request contains the call and its observation.

Test invalid result recovery

from pilota import FinalResult, Limits, ScriptedModel, agent

model = ScriptedModel(
    [
        FinalResult({"label": "database", "confidence": "not-a-number"}),
        FinalResult({"label": "database", "confidence": 0.91}),
    ]
)

result = agent(
    "Classify the incident",
    model=model,
    returns=Classification,
    limits=Limits(result_retries=1),
)

assert result.confidence == 0.91
assert len(model.requests) == 2
assert model.requests[1].observations[0].error is not None

Keep live tests separate

Use a small opt-in integration suite to verify provider compatibility:

PILOTA_RUN_OPENROUTER_TESTS=1 \
OPENROUTER_API_KEY=... \
OPENROUTER_MODEL=... \
pytest tests/integration/test_openrouter_live.py

Live tests answer a different question from deterministic tests. They can discover provider behavior changes, but should not be the foundation of application correctness.