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

> ## Agent Instructions
> Install with `uv add whileai`; import as `import whileai as wai`.
> Run the offline path first (`simulator=False`, `wai.seeded_agent`, a callable judge); no key is needed for it.
> Report every pass rate with its interval and n, as `scored.pass_at` prints it.

# Connect your agent

> Where your model string and your key go: backend objects, configure once, override per call. The four ways to hand simulate() an agent, and how traces aim the run.

**What you learn:** backend objects, `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](/get-started/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.

```python theme={"theme":"vitesse-dark"}
import whileai as wai

wai.OpenAI("gpt-4.1-mini")                              # OpenAI(model='gpt-4.1-mini', key=OPENAI_API_KEY)
wai.OpenAI("gpt-4.1-mini", api_key="sk-...")            # OpenAI(model='gpt-4.1-mini', key=given)
wai.Anthropic("claude-haiku-4-5")                       # key=ANTHROPIC_API_KEY
wai.Fireworks("accounts/fireworks/models/llama-v3p1-8b-instruct")   # an open model Fireworks serves; key=FIREWORKS_API_KEY
wai.models.Bedrock("us.anthropic.claude-haiku-4-5-20251001-v1:0", region="us-west-2")  # key=AWS_BEARER_TOKEN_BEDROCK or AWS credentials
wai.Endpoint("Qwen/Qwen3-4B", url="http://localhost:8000/v1")   # any OpenAI-compatible server; key=none needed
wai.Ollama("llama3")                                    # key=none needed
wai.Hosted()                                            # the model While hosts, key=`wai login`
```

| Backend                                 | Talks to                                                                                         | Key                                                                                               |
| --------------------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
| `wai.OpenAI(model)`                     | OpenAI                                                                                           | `api_key=` or `OPENAI_API_KEY`                                                                    |
| `wai.Anthropic(model)`                  | Anthropic's Messages API                                                                         | `api_key=` or `ANTHROPIC_API_KEY`                                                                 |
| `wai.Fireworks(model)`                  | Fireworks, model ids as Fireworks names them (`accounts/fireworks/models/<name>`)                | `api_key=` or `FIREWORKS_API_KEY`                                                                 |
| `wai.models.Bedrock(model_id, region=)` | Amazon Bedrock's Converse API: a foundation model, an inference profile, or a model you imported | `api_key=` or `AWS_BEARER_TOKEN_BEDROCK`; else AWS credentials through boto3 (`whileai[bedrock]`) |
| `wai.Endpoint(model, url=)`             | vLLM, SGLang, TGI, LM Studio, a served adapter                                                   | `api_key=`, else `VLLM_API_KEY` or `OPENAI_API_KEY`; none for a local URL                         |
| `wai.Ollama(model)`                     | Ollama on this machine                                                                           | none                                                                                              |
| `wai.Hosted()`                          | The model While hosts                                                                            | `wai.configure(api_key=)`, `WHILEAI_API_KEY`, or `wai login`                                      |

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.

```python theme={"theme":"vitesse-dark"}
wai.configure(
    agent=wai.OpenAI("gpt-4.1-mini"),
    judge=wai.Anthropic("claude-haiku-4-5"),   # never the agent's model by default
    api_key="zp_...",                          # the While account key, for hosted models and the platform
)
print(wai.settings)

data = wai.simulate(tools=TOOLS, system_prompt=POLICY)           # gpt-4.1-mini
strict = data.grade(wai.Judge(rubric=RUBRIC))                    # claude-haiku-4-5

with wai.context(judge=wai.OpenAI("gpt-4.1")):
    second = data.grade(wai.Judge(rubric=RUBRIC))                # gpt-4.1, inside the block only
```

```text theme={"theme":"vitesse-dark"}
Settings(agent=openai:gpt-4.1-mini, judge=anthropic:claude-haiku-4-5, simulator=default (While hosted), api_key=set)
```

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

```python theme={"theme":"vitesse-dark"}
data = wai.simulate(wai.OpenAI("gpt-4.1-mini"), tools=TOOLS, system_prompt=POLICY)
```

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

```python theme={"theme":"vitesse-dark"}
def my_agent(message: str) -> dict:
    return {
        "steps": [
            {
                "tool": "get_order",
                "arguments": {"order_id": "4412"},
                "result": {"status": "shipped"},
            }
        ],
        "final_text": "Order 4412 shipped yesterday.",
    }

data = wai.simulate(my_agent, tools=TOOLS, system_prompt=POLICY)
```

A callable is played single-turn: one message in, one trajectory out. It
is the right shape for an agent you already run behind an HTTP handler or
a queue worker. Wrap the handler, return what it did.

<Tip>
  `wai.simulations.world(tools)` gives a callable agent the same mock world
  the engine uses, so a real tool call in your code can be answered by the
  sandbox (faults included) instead of by production.
</Tip>

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

```python theme={"theme":"vitesse-dark"}
agent = wai.simulations.local_model(
    "http://localhost:8000/v1",
    "Qwen/Qwen3-8B",
    tools=TOOLS,
    system=POLICY,
    thinking=False,  # reasoning bases: reply with the answer, not the trace
)
data = wai.simulate(agent, tools=TOOLS, system_prompt=POLICY)
```

`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](/reference/parameters) page.

### A spec string

The string form of a backend object, for configs and command lines.

```python theme={"theme":"vitesse-dark"}
data = wai.simulate("openai:gpt-4.1-mini", tools=TOOLS, system_prompt=POLICY)
```

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

```python theme={"theme":"vitesse-dark"}
data = wai.simulate(my_agent, tools=TOOLS, system_prompt=POLICY, traces="traces.jsonl")
```

`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](/reference/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".
