aec-benchaec-bench

Interactive Worlds

An Interactive World is a causal task environment. The agent observes the current situation, takes an action, and receives the next observation. An accepted action can change later evidence and the final evaluation.

Use this model when a sequence of decisions matters. If one submitted file or bounded workspace is enough, use an artefact task. If the stages are known in advance and the host controls evidence release, use a finite lifecycle.

Find and load a world

Use the aec_bench.worlds facade to discover registered worlds and build provider-neutral tasks:

from aec_bench import worlds

available = worlds.list()
matches = worlds.find("seepage")
dam = worlds.get("dam-seepage-monitoring")
profiles = worlds.profiles(dam.id)

task = worlds.task(
    dam.id,
    profile="synthetic-rising-seepage",
    instruction="Monitor the dam and respond as conditions evolve.",
)
loaded_profile = worlds.load_profile(task)

worlds.list() shows every registered world, worlds.find() searches them, and worlds.get() loads an exact world ID. A profile selects one fixed scenario for that world.

The built-in catalogue contains:

World IDProfilesCapabilities
dam-seepage-monitoringsynthetic-rising-seepageMinimum world contract
wastewater-pump-station-stewardship.v1pump-station-reference-system.asw-8-rs1.v1, pump-station-reference-system.asw-8-rs2.v1Branching, host controls, persistence

Define a world task in files

A WorldTask combines an instruction with an exact registered world build and scenario profile. This keeps the task reproducible even if the world catalogue changes later. Provider settings and live execution state stay outside the task.

For a portable task package, store the objective in instruction.md and the exact references in world.toml:

tasks/civil/dam-monitoring/
├── instruction.md
└── world.toml
[world]
task_world_id = "dam-seepage-monitoring"
entry_point = "<registered entry point>"
artifact_sha256 = "<registered world build SHA-256>"

[profile]
task_world_id = "dam-seepage-monitoring"
profile_id = "synthetic-rising-seepage"
profile_content_sha256 = "<registered profile SHA-256>"

[metadata]
domain = "civil"
category = "monitoring"
difficulty = "medium"
lifecycle = "active"
visibility = "public"
tags = ["dam", "monitoring", "seepage", "synthetic"]

Load it with worlds.load_world_task(instance_dir, tasks_root). Loading rejects an unknown world, a stale build, a stale profile, or metadata that does not match the registered profile.

What every world owns

A world contribution owns five things:

PartPurpose
StateOne authoritative representation of the current engineering situation
ObservationThe part of the current situation that the agent is allowed to see
ActionA validated task-owned decision or request
TransitionA deterministic accepted change or a rejection that leaves state unchanged
EvaluationThe task-owned interpretation of final state, trajectory, and verified evidence

The registered definition binds this behaviour to an exact code build and scenario profile.

The dam and pump worlds share the world core and one Prime actor-session implementation. Each task owner defines its own state, journey, controls, persistence, verification, and evaluation.

Authoring path

  1. Define exact scenario inputs and one authoritative state.
  2. Project only actor-visible facts into the observation.
  3. Implement deterministic initialisation, transitions, rejection, verification, and evaluation.
  4. Create an exact world build and content-pinned profile loader.
  5. Register the definition once at the catalogue composition boundary.
  6. Add the complete trial function only when a supported provider route exists.
  7. Prove deterministic behaviour, safe rejection, terminal handling, evidence retention, and boundary round trips.

Store episode IDs, step indexes, provider data, repository paths, and content digests as execution or evidence metadata outside domain state. Add host controls, durable recovery, branching, or provider packaging only when the task needs them.

What counts as one trial

A trial covers the complete journey from the selected scenario to verified final evidence. It can contain several actions or provider sessions.

A complete world trial selects the profile, runs the actor journey, closes the provider session, verifies task-owned evidence, evaluates the result, retains referenced artefacts, and returns one TrialRecord. Returned artefact references remain valid after temporary session directories are removed.

The complete public application functions are asynchronous:

  • run_dam_seepage_trial() for the dam world;
  • run_pump_station_trial() for a Prime pump journey;
  • run_pump_station_harbor_trial() for a Harbor pump journey; and
  • run_world_experiment() for ordered execution and optional record persistence.

Plan trials directly with the one public planner:

from functools import partial
from pathlib import Path

from aec_bench.harness.world_routing import run_selected_world, validate_world_routes
from aec_bench.harness.world_trials import run_world_experiment
from aec_bench.trials import plan_trials

trials = plan_trials(
    "dam-study",
    tasks=[task],
    agents=[agent],
    repetitions=3,
)
validate_world_routes([task], trials)

records = await run_world_experiment(
    tasks=[task],
    trials=trials,
    run_trial=partial(run_selected_world, work_root=Path("artefacts/world-runs")),
)

run_world_experiment() preserves the declared trial order and validates that each returned record matches its task and plan. Unsupported world and provider combinations fail before execution begins.

Current complete routes are:

WorldProvider path
Dam-seepage monitoringPrime Agent
Pump-station stewardshipPrime Agent
Pump-station stewardshipDeepSeek harness through Harbor

Provider adapters translate execution protocols. The dam and pump task owners define their task-specific behavior.

Who controls the world

The world owns engineering meaning. The actor host owns the provider-facing decision exchange.

World ownerActor and execution boundary
Domain state and valid actionsOpaque decision association
Actor-visible observationProvider session and transcript
Accepted transition or rejectionRecording and accepted-step advancement
Domain terminationLimits and runtime truncation
Verification and evaluation inputsTrial construction after the live transition

An invalid action leaves state unchanged. A stale decision is rejected before it reaches task logic. Domain termination and host truncation are separate facts.

Host controls are separate from agent actions. The host alone can pause, rewind, branch, or otherwise control the run.

Branching

worlds.branch_world() creates child branches through the existing rollout-control boundary and the pump branch port. worlds.tasks_for_branches() maps those branches to tasks for later planning.

Branch creation materialises child branches and leaves the parent unchanged. Separate application operations execute, evaluate, select, or merge those children.

CLI

Discover and inspect worlds:

aec-bench task world list
aec-bench task world find seepage
aec-bench task world show dam-seepage-monitoring
aec-bench task world profiles dam-seepage-monitoring

Plan and run one registered task:

aec-bench task world run dam-seepage-monitoring \
  --profile synthetic-rising-seepage \
  --instruction "Monitor the dam and respond as conditions evolve." \
  --model <provider/model> \
  --dry-run

Pump-specific application commands are under one nested path:

aec-bench task world pump-station --help
aec-bench task world pump-station verify --help
aec-bench task world pump-station branch --help
aec-bench task world pump-station evaluate --help

Use top-level aec-bench run for a dataset-backed experiment that can contain artefact and world tasks. See Datasets and the CLI Reference.

See Architecture for ownership and Scoring for evaluation authority.

On this page