import whileai.simulations as wai, then wai.name.
adapters
Framework adapters. Every runner returns {steps, final_text}.AgentProfile
whileai/simulations/generate/adapters.py.
claude_code
whileai/simulations/generate/adapters.py.
connect
whileai/simulations/generate/adapters.py.
inspect
whileai/simulations/generate/adapters.py.
Read tools and system prompt off the agent; caller extras are merged in.
agents
OpenAI-compatible chat loop for hosted and local simulation backends.hosted_model
whileai/simulations/generate/agents.py.
The default simulation brain: hosted Qwen wearing these tools.
local_model
whileai/simulations/generate/agents.py.
Build an agent that talks to any OpenAI-compatible endpoint for simulate(agent=...).
Reach for it when the policy under test is a served model: a trained
adapter behind vLLM, a local server, any chat endpoint. It returns a
callable that plays the multi-turn agent (tool calls, the simulated
user, faults) against model at base_url with tools and the
system prompt, and every rollout comes back as a row.
base_url,model,api_key: where the model is served and what to call it.thinking: for reasoning bases such as Qwen3.Falsesendschat_template_kwargs={"enable_thinking": False}so the reply is the answer, not the reasoning, the way the hosted Qwen path already does;Trueasks 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) oruser_modelsits on the same endpoint, so the customer is asked not to reason either; auser_modelon another endpoint keeps that server’s default. Either way<think>markup never reachesstep["text"],final_text, or a user turn (step["user"]and themessageshistory): 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. The run reports those undersearch["user_think"]:user_turns,strippedandunclosedas counts,stripped_shareandunclosed_shareas shares of the user turns, zeros when none.result_shapes: pins what a tool returns, as{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.0lands in roughly 600 to 1200,90.0in 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_idin, sameinvoice_idout). 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, as{message: {tool_name: {"mode": "timeout", "rate": 1.0}}}, keyed by the exact user message, withmodeone oftimeout,malformed,staleorpermission_deniedandratethe chance the fault fires on a call. The plan may also carryworld_state,stance,toneandtexture, which are popped off and shape the world and the simulated user for that ask.simulate()writes these itself fromfault_rate=; pass your own only to replay a known plan (tasks=does this for you).timeout: 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 indata.warningswith the fix (raisetimeout=, or send one throwaway request first so the endpoint is warm).patience: a level name (PATIENCE_LEVELS,"normal"by default) 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 (seePATIENCE_HAZARDS).user_modelanduser_temperature: the simulated person’s model (the agent’s own by default) and the sampling temperature of every simulated-user line, follow-ups (USER_TURN_TEMPERATURE) and human-tool answers (HUMAN_TOOL_TEMPERATURE) alike;Nonekeeps those two defaults.world_options: the mock world’s dials (aWorldOptionsor the same fields as a dict: fault modes, hit counts, name pools, …);simulate(advanced={"world": {...}})lands here.Noneis the defaults indefaults.py.execute: your own world(tool, arguments) -> resultin place of the mock one.max_turns/avg_turns(12.0) cap and shape the conversation length;avg_turns=1is one user line and one reply, and the follow-up branch never runs;temperature(0.8),max_tokensandlogprobsare the agent’s own sampling, recorded on every row.
diversity
Sparse generic writer knobs and annealing helpers.adaptive_allocator
whileai/simulations/generate/diversity.py.
Adaptive mix. Short remaining clock is messier; saturation walks more cards.
Shares are explore / expand / verify. n_req and k are caps so expand and
verify can actually run. Not a pinned n=1 k=1 policy.
allocator_slot_counts
whileai/simulations/generate/diversity.py.
Integer explore/expand/verify slots from mix shares.
generator
Model-driven scenario generation. Templates are bootstrap and offline fallback.ModelSimulator
whileai/simulations/generate/generator.py.
Invent what a person might send, ask, or discuss; it never grades.
write_scene_brief
whileai/simulations/generate/generator.py.
One cheap LLM pass per simulate(). Private writer context. Empty on failure.
offline_agent
The free path, with something to catch.World
whileai/simulations/generate/offline_agent.py.
The mock world for a callable agent, faults first.
Built once; 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
whileai/simulations/generate/offline_agent.py.
Build a demo agent whose mistakes are on purpose and recorded on the row.
Reach for it to try the whole loop offline, with no key and no model:
it gives a run something to catch, and each row says what was
planted, so a grader or a marker can be checked against the truth. It
returns a callable message -> trajectory for simulate(agent=...).
Honest by default: it picks the tool the ask names, calls it through
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: 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.
tools: the tool schemas the agent may call.rate(SEEDED_RATE, 0.35): the share of rollouts with one planted mistake, high enough that a 20-row demo run catches every behavior kind at least once; a convention, not a real failure rate.seed(0): fixes which rollouts misbehave and how.behaviors(SEEDED_BEHAVIORS): the subset of mistakes to draw from.
world
whileai/simulations/generate/offline_agent.py.
A 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
whileai/simulations/generate/scenarios.py.
Coverage axes from this agent. Length and vagueness are writer-only.
rule_cap is the most policy clauses on the rule axis: the grid’s
RULE_CAP by default, None for every clause (what a report over
an existing suite passes, RULE_AXIS_CAP_REPORT).
novelty
whileai/simulations/generate/scenarios.py.
Min cosine distance from a candidate embedding to every tested row.
open_ended_probes
whileai/simulations/generate/scenarios.py.
Taxonomy-free probes. Wording rotates with seed.
policy_sections
whileai/simulations/generate/scenarios.py.
Split policy text into short rule clauses used as coverage cells.
Identity / system-prompt preambles are not clauses. A long unsplit
paragraph is dropped rather than truncated mid-word into rule.
cap is the most clauses returned, in document order; None is
every clause. rule_axis says how many a cap left out.
scenario_regions
whileai/simulations/generate/scenarios.py.
Weighted target regions over a pairwise covering set of the dimensions.
prefer_success defaults off in mode="rl" so fault cells survive
for covering-grid RL data. Explicit True/False always wins.