> ## Documentation Index
> Fetch the complete documentation index at: https://docs.withwhile.com/llms.txt
> Use this file to discover all available pages before exploring further.

# whileai.simulations.generate

> Situation writers, coverage axes, agent adapters, model backends.

Situation writers, coverage axes, agent adapters, model backends.

18 public names. `import whileai.simulations as wai`, then `wai.name`.

| Name                                              | What it does                                                                                                                      |
| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| [`AgentProfile`](#agentprofile)                   |                                                                                                                                   |
| [`ModelSimulator`](#modelsimulator)               | Invent what a person might send, ask, or discuss; it never grades.                                                                |
| [`World`](#world)                                 | The mock world for a callable agent, faults first.                                                                                |
| [`adaptive_allocator`](#adaptive_allocator)       | Adaptive mix.                                                                                                                     |
| [`allocator_slot_counts`](#allocator_slot_counts) | Integer explore/expand/verify slots from mix shares.                                                                              |
| [`build_dimensions`](#build_dimensions)           | Coverage axes from this agent.                                                                                                    |
| [`claude_code`](#claude_code)                     |                                                                                                                                   |
| [`connect`](#connect)                             |                                                                                                                                   |
| [`hosted_model`](#hosted_model)                   | The default simulation brain: hosted Qwen wearing these tools.                                                                    |
| [`inspect`](#inspect)                             | Read tools and system prompt off the agent; caller extras are merged in.                                                          |
| [`local_model`](#local_model)                     | An agent that talks to an OpenAI-compatible endpoint (a served adapter, a local vLLM, any chat server) for `simulate(agent=...)`. |
| [`novelty`](#novelty)                             | Min cosine distance from a candidate embedding to every tested row.                                                               |
| [`open_ended_probes`](#open_ended_probes)         | Taxonomy-free probes.                                                                                                             |
| [`policy_sections`](#policy_sections)             | Split policy text into short rule clauses used as coverage cells.                                                                 |
| [`scenario_regions`](#scenario_regions)           | Weighted target regions over a pairwise covering set of the dimensions.                                                           |
| [`seeded_agent`](#seeded_agent)                   | A demo agent whose mistakes are on purpose and on the row.                                                                        |
| [`world`](#world)                                 | A `World` for a callable agent: `world.call(tool, arguments)`.                                                                    |
| [`write_scene_brief`](#write_scene_brief)         | One cheap LLM pass per simulate().                                                                                                |

## adapters

Framework adapters. Every runner returns \{steps, final\_text}.

### AgentProfile

```python theme={null}
AgentProfile(
    tools: list[dict] = <factory>,
    policy: str = '',
    capabilities: dict = <factory>,
    constraints: dict = <factory>,
    transport: str = 'callable',
    name: str = '',
    rubric: str = '',
) -> None
```

### claude\_code

```python theme={null}
claude_code(
    extra_args: tuple | list = (),
    cwd: str | None = None,
    max_turns: int | None = None,
    timeout: float = 300.0,
) -> Callable
```

### connect

```python theme={null}
connect(
    agent: Any,
    tools: list[dict] | None = None,
    system_prompt: str | None = None,
    policy: str | None = None,
    transport: str | None = None,
    execute: Callable | None = None,
    model: str | None = None,
) -> ConnectedAgent
```

### inspect

```python theme={null}
inspect(
    agent: Any,
    tools: list[dict] | None = None,
    system_prompt: str | None = None,
    policy: str | None = None,
    transport: str | None = None,
) -> AgentProfile
```

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

```python theme={null}
hosted_model(
    tools: list[dict],
    system: str = '',
    fault_plans: dict | None = None,
    **kwargs,
) -> Callable
```

The default simulation brain: hosted Qwen wearing these tools.

### local\_model

```python theme={null}
local_model(
    base_url: str,
    model: str,
    tools: list[dict],
    system: str = '',
    api_key: str | None = None,
    max_turns: int | None = None,
    avg_turns: float = 12.0,
    min_user_turns: int = 1,
    turn_stats: dict | None = None,
    temperature: float = 0.8,
    logprobs: bool | str = False,
    fault_plans: dict | None = None,
    result_shapes: dict | None = None,
    opening_rate: float = 0.0,
    human_tools: set | None = None,
    execute: Callable | None = None,
    timeout: float = 300.0,
    max_tokens: int | None = None,
    user_model: str | None = None,
    thinking: bool | None = None,
    patience: Patience | None = 'normal',
    user_temperature: float | None = None,
    world_options: WorldOptions | Mapping[str, Any] | None = None,
) -> Callable
```

An agent that talks to an OpenAI-compatible endpoint (a served
adapter, a local vLLM, any chat server) for `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

```python theme={null}
adaptive_allocator(
    time_budget: float | None,
    until: str = 'compute',
    elapsed: float | None = None,
) -> dict[str, Any]
```

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

```python theme={null}
allocator_slot_counts(take: int, plan: dict | None) -> dict[str, int]
```

Integer explore/expand/verify slots from mix shares.

## generator

Model-driven scenario generation. Templates are bootstrap and offline fallback.

### ModelSimulator

```python theme={null}
ModelSimulator(
    backend_spec: str | None = None,
    tools: Sequence[dict] = (),
    policy: str = '',
    candidates_per_round: int = 160,
    seed: int = 0,
    dimensions: dict | None = None,
    timeout: float = 30.0,
    cells_per_request: int | None = None,
    completions: int | None = None,
    distinct_cards: bool = False,
    extra_cards: int = 1,
    texture_rate: float | None = None,
    kind: str | None = None,
    scene_brief: str = '',
    out_tokens: int | None = None,
    time_budget: float | None = None,
    run_started: float | None = None,
    mode: str | None = None,
    prefer_success: bool | None = None,
    steering_weight: float | None = None,
    hard_share: float | None = None,
    writer_temperature: float | tuple[float, float] | None = None,
    world: Any = None,
)
```

Invent what a person might send, ask, or discuss; it never grades.

### write\_scene\_brief

```python theme={null}
write_scene_brief(
    tools: Sequence[dict] = (),
    policy: str = '',
    backend_spec: str | None = None,
    kind: str = '',
    timeout: float = 8.0,
) -> str
```

One cheap LLM pass per simulate(). Private writer context. Empty on failure.

## offline\_agent

The free path, with something to catch.

### World

```python theme={null}
World(tools: Sequence[dict] | None = None, seed: int = 0) -> None
```

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

```python theme={null}
call(self, tool: str, arguments: dict | None = None) -> dict[str, Any]
```

The world's answer to one tool call. Scheduled faults apply first.

### seeded\_agent

```python theme={null}
seeded_agent(
    tools: Sequence[dict],
    rate: float = 0.35,
    seed: int = 0,
    behaviors: Sequence[str] | None = None,
) -> Callable[[str], dict]
```

A demo agent whose mistakes are on purpose and on the row.

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` (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

```python theme={null}
world(tools: Sequence[dict] | None = None, seed: int = 0) -> World
```

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

```python theme={null}
build_dimensions(tools: list[dict], policy: str = '') -> dict[str, list[str]]
```

Coverage axes from this agent. Length and vagueness are writer-only.

### novelty

```python theme={null}
novelty(candidate_vector, tested_matrix) -> float
```

Min cosine distance from a candidate embedding to every tested row.

### open\_ended\_probes

```python theme={null}
open_ended_probes(
    tools: list[dict],
    policy: str = '',
    per_round: int = 10,
    seed: int = 0,
) -> list[str]
```

Taxonomy-free probes. Wording rotates with seed.

### policy\_sections

```python theme={null}
policy_sections(policy: str, cap: int = 16) -> list[str]
```

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`.

### scenario\_regions

```python theme={null}
scenario_regions(
    tools: list[dict],
    policy: str = '',
    strength: int = 2,
    observed_counts: dict[str, int] | None = None,
    novelty: Callable[[dict], float] | None = None,
    behavior_value: Callable[[dict], float] | None = None,
    alpha: float = 0.35,
    beta: float = 0.35,
    gamma: float = 0.2,
    delta: float = 0.1,
    dimensions: dict | None = None,
    mode: str | None = None,
    prefer_success: bool | None = None,
) -> list[dict]
```

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.
