langwatch-scenario for Python and @langwatch/scenario for TypeScript. The loop is one scenario.run call inside a normal test, so it runs in CI with the rest of your suite. For what agent testing covers and the other ways to run it, see the agent testing overview. To start now, go to Install Scenario.
Why use a simulated user
A conversation you write out and replay passes because you wrote the user’s lines to fit your agent. Your customers word things in ways no fixture holds. A simulated user gets the situation instead of lines, and words it differently on every run. So a pass means the agent handles the situation, and the judge checks the outcome instead of an exact reply.1. Install Scenario
@langwatch/scenario and vitest instead; Scenarios in code has the TypeScript version of every step.
Scenario calls a model for the simulated user and the judge. Set that provider’s key, and your LangWatch key so every run shows up in LangWatch:
.env
load_dotenv() from python-dotenv, or export the variables in your shell.
2. Write the first test
An adapter tells Scenario how to call your agent. It receives the conversation so far and returns your agent’s reply. Thenscenario.run puts the three parties together:
test_refund_agent.py
-s you see the conversation in the terminal. If a criterion fails, result.reasoning says which one and why, and the test fails with it.
3. Script the turns that matter
Leave the conversation to the simulated user by default. When one moment matters, such as the first message or a tool the agent must call at a certain point, script it and let the simulation carry on from there:scenario.proceed() hands the rest of the conversation back to the simulated user and the judge.
4. Run it in CI and read the results
Because a scenario is a test, your CI already runs it, and the job fails when a scenario fails. Both the agent and the simulated user are models, so one green run can be luck. Before a release, run the suite more than once and read the pass rate. WithLANGWATCH_API_KEY set, every run appears on the Results tab in LangWatch with the full conversation, the judge’s reasoning per criterion and the pass rate over time.
When a production conversation goes wrong, copy how that user opened it into a new scenario’s description. The same mistake then fails a test before it reaches a customer again.
How this compares to other ways of testing agents
Evaluations still fit the steps inside the agent, such as retrieval or one prompt, and both run in the same LangWatch project. See Agent testing vs evaluations.
Questions about Scenario
Which model should play the user and the judge in Scenario
Start with a small, cheap model:scenario.configure(default_model=...) sets it for both roles. Pass a different model to UserSimulatorAgent or JudgeAgent when one role needs more.