configure once, the four ways to hand simulate() an agent, and how traces aim the run. Needs: WHILEAI_API_KEY or wai login for the hosted model, or the provider’s key; simulator=False with a callable needs nothing. Takes: ten minutes.
simulate() needs to know what the agent can do (its tools and system
prompt) and how to run it. TOOLS on this page is a list of @wai.tool
functions, as on the quickstart; schema dicts
work in the same list. This page is the second part: which model,
behind which endpoint, on which key.
Every block below reaches a model, so each one needs a key: WHILEAI_API_KEY
in the environment (or wai login) for the hosted model, and
OPENAI_API_KEY or ANTHROPIC_API_KEY for a block that names that provider.
Adding simulator=False and your own callable agent runs the same call
offline.
Which model, on which key
A backend object names a provider, a model and a key. Print it and it says where the call goes.
A key given on a backend is kept for that provider, so every call to that
provider in the process finds it. The spec strings the objects stand for
(
openai:<model>, anthropic:<model>, fireworks:<model>, bedrock:<model-id>[@<region>],
vllm:<model>@<url>, ollama:<model>) still work anywhere a backend does.
Set it once, override per call
Three roles: the agent under test, the judge, and the simulator that writes the user’s messages.configure sets them for the process. A
keyword on the call wins over configure; a context block wins inside
the block; the environment is read only when none of those say.
Four ways to hand simulate() the agent
A backend object
No wrapper at all. The SDK builds the agent from the tools and system prompt you pass and plays it multi-turn: it sends the system prompt and tools, answers each tool call from the mock world, and lets a separate model play the customer.agent= takes the same backend object configure(agent=) takes, and a
key given on it (wai.OpenAI("gpt-4.1-mini", api_key="sk-...")) reaches
that provider the same way. Leave agent= out and the run uses what
configure set, else the model While hosts on the key from wai login. Useful for a policy that does
not have an agent yet: pass only system_prompt= and tools= and see how
a capable open model behaves under it. The judge is never the model it is
judging: the hosted judge is a different family from the hosted agent.
A callable
Any function that takes the user’s message and returns the tool calls it made and what it finally said.An endpoint with knobs
wai.Endpoint covers a served model. When you need the engine’s
per-agent knobs (a reasoning base that should reply without its trace,
pinned tool results, scheduled faults), build the agent with
local_model and pass the callable.
result_shapes= pins what a tool returns so a policy branch is actually
reached; fault_plans= schedules which tool fails on which ask. Both are
on the parameters page.
A spec string
The string form of a backend object, for configs and command lines.typesafe:<model> is TypeSafe’s Jev, on TYPESAFE_API_KEY. It is a
judge only: spec= on grade, never agent=.
Aim the run with traces
Without traces, the coverage grid comes from the tools and policy alone (a cold start). With them, it aims at the situations the agent actually met: the tools called, the faults seen, the world states. Any generated row that near-copies a source trace is dropped, so held-out traces stay out of training.traces= takes rows or a JSONL path. wai.simulations.load_traces
normalizes the common shapes (OpenAI messages, tool_trace,
final/output) to the one the engine reads, and
wai.simulations.rows_from_otel reads an OpenTelemetry batch. Traces
reproduce situations, not wording failures: an unsupported claim or an
estimate not labelled as one has no world-visible trigger, so put a grader
in the loop for those (grader=, on the
what to run page).
Seeds
seeds= is a list of opening asks the writer keeps and varies. Every
seed is run. With a callable agent whose world has real ids (order
numbers, account names), put those ids in the seeds or in the tool
descriptions, or the writer invents ids and every rollout is “not found”.