import whileai.simulations as wai, then wai.name.
adapters
Framework adapters. Every runner returns {steps, final_text}.AgentProfile
claude_code
connect
inspect
agents
OpenAI-compatible chat loop for hosted and local simulation backends.hosted_model
local_model
simulate(agent=...).
thinking is for reasoning bases such as Qwen3: False sends
chat_template_kwargs={"enable_thinking": False} so the reply is
the answer, not the reasoning, the way the hosted Qwen path already
does; True asks for it; None (the default) sends nothing and
leaves the server’s default. The same field goes to the simulated
user when the agent’s own model plays it (the default) or
user_model sits on the same endpoint, so the customer is asked
not to reason either; a user_model on another endpoint keeps
that server’s default. Either way <think> markup never reaches
step["text"], final_text, or a user turn (step["user"] and
the messages history): what the user model still emits as
reasoning is stripped before it becomes speech, and a turn that was
reasoning with no spoken line is retried, then dropped (#284). The run
reports those under search["user_think"]: user_turns,
stripped and unclosed as counts, stripped_share and
unclosed_share as shares of the user turns, zeros when none.
result_shapes pins what a tool returns: \{tool_name: example result dict\}. The sandbox fills the example on every call instead
of inventing a record, so a policy branch that only exists for some
tool results (a credit over $200 must be escalated) is reached on
purpose rather than by luck. Field names and free text stay as
written; ids, dates and people are re-drawn per call, and a number
moves by up to about a third of itself (900.0 lands in roughly
600 to 1200, 90.0 in 60 to 120), so pick a template value whose
whole range sits on the side of the threshold you want. An argument
that shares a key with the template is echoed back (invoice_id
in, same invoice_id out). To measure a branch, run the same
pinned tasks under two shapes, one per side of the rule. Without it
the situation writer drafts an example per tool (write_result_shapes)
and the branch is exercised at random.
fault_plans schedules faults per ask: \{message: \{tool_name: \{"mode": "timeout", "rate": 1.0\}\}\}, keyed by the exact user message,
with mode one of timeout, malformed, stale or
permission_denied and rate the chance the fault fires on a
call. The plan may also carry world_state, stance, tone
and texture, which are popped off and shape the world and the
simulated user for that ask. simulate() writes these itself from
fault_rate=; pass your own only to replay a known plan (tasks=
does this for you).
timeout is seconds per completion, LOCAL_MODEL_TIMEOUT (300)
by default: a served model that scaled to zero takes two to three
minutes to answer its first request, and a timeout under that drops
every rollout of the first pass. When a call still times out the run
says so in data.warnings with the fix (raise timeout=, or send
one throwaway request first so the endpoint is warm).
patience is a level name (PATIENCE_LEVELS) or a table
{"second": p, "later": q}: the chance the person leaves at the
agent’s second question and at every later one, fitted from your own
traces (see PATIENCE_HAZARDS). user_temperature is the
sampling temperature of every simulated-user line, follow-ups
(USER_TURN_TEMPERATURE) and human-tool answers
(HUMAN_TOOL_TEMPERATURE) alike; None keeps those two defaults.
world_options is the mock world’s dials (a WorldOptions or the
same fields as a dict: fault modes, hit counts, name pools, …);
simulate(advanced={"world": {...}}) lands here. None is the
defaults in defaults.py.
diversity
Sparse generic writer knobs and annealing helpers.adaptive_allocator
allocator_slot_counts
generator
Model-driven scenario generation. Templates are bootstrap and offline fallback.ModelSimulator
write_scene_brief
offline_agent
The free path, with something to catch.World
call reads the rollout being answered from
current_rollout (thread-local, set by simulate before each
rollout) so the row’s own faults and world_state apply.
Outside a run it answers with no faults and no world state.
World.call
seeded_agent
world() (faults fire), and reports what came back. On rate of
rollouts, drawn deterministically from seed, the prompt and the
rollout index, it does one thing from behaviors (default
SEEDED_BEHAVIORS): hedging, sycophancy, apology and
boilerplate add the phrase style_report looks for;
ignore_fault claims success although the tool faulted;
leak quotes the row’s privileged context. Each row it answers
carries seeded: what it did on purpose, [] when it behaved.
world
World for a callable agent: world.call(tool, arguments).
Pass the same tools you pass simulate. Inside a run the row’s
scheduled faults fire on it; a callable that answers its tool calls
through this sees them, and the row’s faults stop being a label
with no effect.
scenarios
Coverage cells from the agent’s tools and policy, plus offline fallback wording.build_dimensions
novelty
open_ended_probes
policy_sections
rule.
scenario_regions
prefer_success defaults off in mode="rl" so fault cells survive
for covering-grid RL data. Explicit True/False always wins.