Configuration¶
API key¶
Both agents reach a model through OpenRouter, so
TriageSim needs an API key before any simulation will run. It is read once, at
import time, from the OPENROUTER_API_KEY environment variable.
Do not commit your key
Add .env to your .gitignore. An OpenRouter key is a billing credential.
Because the key is resolved when triagesim.config is first imported, setting
os.environ after importing the package has no effect. Set it before your
first import, or use a .env file.
Choosing a model¶
Any OpenRouter model identifier works. The model is supplied per LLM backend, which means the nurse and the patient can run on different models:
from triagesim.agents import OpenRouterLLM
from triagesim.core import NurseOutput, PatientOutput
nurse_llm = OpenRouterLLM(model_name="anthropic/claude-sonnet-4-5",
output_type=NurseOutput)
patient_llm = OpenRouterLLM(model_name="google/gemini-3-pro-preview",
output_type=PatientOutput)
Each backend is bound to exactly one output schema, so a nurse backend cannot be handed to a patient agent. This is deliberate: it makes an invalid pairing a construction-time error rather than a parsing failure mid-run.
Structured output is enforced by pydantic-ai, so the model must support
tool-calling or JSON mode. Models that only emit free text will fail
validation.
Feature flags¶
Two settings live in triagesim.config:
| Name | Default | Effect |
|---|---|---|
OPENROUTER_API_KEY | from environment | Credential used by OpenRouterLLM. |
ENABLE_LLM_DETECTORS | False | Enables LLM fallback when the rule-based detectors cannot identify a requested vital or a belief update from the nurse's text. |
By default TriageSim extracts requested vitals with keyword rules — "pulse"
and "heart rate" both map to heartrate, "bp" to sbp, and so on. Turning
on ENABLE_LLM_DETECTORS adds a model call whenever those rules find nothing,
which is more robust but slower and more expensive.
A separate, per-run flag controls LLM-backed belief updates:
Note
RunnerConfig.enable_llm defaults to False. The dialogue itself is always
model-driven; this flag only governs whether the belief updater may call a
model in addition to its deterministic rules.
Reproducibility¶
Pass a seed to RunnerConfig to seed Python's global RNG for the run, and to
sample_patient_personas / sample_nurse_personas to fix persona selection:
This makes persona sampling and any internal random choices deterministic. It does not make the language model deterministic — remote sampling is outside TriageSim's control, so repeated runs with the same seed will still differ in wording.