Skip to content

Seeding

The seeding module provides infrastructure for reproducible benchmark runs. Seeds are derived deterministically from hierarchical paths, ensuring that adding or removing components doesn't affect seeds for other components.

Guide available

For practical usage examples and best practices, see the Seeding Guide.

The abstract base class that defines the seeding interface. Implement this to create custom seeding strategies.

View source

SeedGenerator

Bases: ABC, ConfigurableMixin

Abstract base class for seed generation.

Subclass this to implement custom seeding strategies (e.g., database lookup, different hash algorithms, external seed services).

The default implementation is DefaultSeedGenerator, which uses SHA-256 hashing and provides additional convenience methods like child() for hierarchical namespacing.

Implementations must be thread-safe. The recommended pattern is to create isolated state in for_task() so each task repetition has its own generator instance.

When global_seed is None, seeding is disabled and derive_seed() returns None. This allows seeds to flow through to model adapters which already accept Optional[int].

Subclasses must implement:

  • global_seed - Property returning the root seed (or None if disabled)
  • derive_seed() - Derive a seed for a named component (returns None if disabled)
  • for_task() - Create a generator scoped to a specific task
  • for_repetition() - Create a generator scoped to a specific repetition
  • seed_log - Property returning all derived seeds

global_seed abstractmethod property

global_seed: Optional[int]

Root seed for the entire benchmark run, or None if seeding is disabled.

seed_log abstractmethod property

seed_log: Dict[str, int]

Return all seeds derived by this generator and its children.

RETURNS DESCRIPTION
Dict[str, int]

Dictionary mapping component paths to their derived seeds.

derive_seed abstractmethod

derive_seed(
    name: str, per_repetition: bool = True
) -> Optional[int]

Derive a seed for a named component.

PARAMETER DESCRIPTION
name

Component identifier (e.g., "agent_x", "environment/tool_weather"). Use "/" for hierarchical paths if desired.

TYPE: str

per_repetition

If True, seed varies per repetition. If False, seed is constant across repetitions of the same task.

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
Optional[int]

Deterministic seed derived from the generator's state and name,

Optional[int]

or None if global_seed is None (seeding disabled).

RAISES DESCRIPTION
SeedingError

If global_seed is set but required context (task_id, rep_index) is not set.

for_repetition abstractmethod

for_repetition(rep_index: int) -> Self

Create a generator scoped to a specific repetition.

PARAMETER DESCRIPTION
rep_index

The repetition index (0-based).

TYPE: int

RETURNS DESCRIPTION
Self

New generator with rep_index set, preserving task scope and log.

for_task abstractmethod

for_task(task_id: str) -> Self

Create a generator scoped to a specific task.

This creates a fresh generator with its own seed log. Call this once per task to isolate seed tracking between tasks.

PARAMETER DESCRIPTION
task_id

The task identifier.

TYPE: str

RETURNS DESCRIPTION
Self

New generator with task_id set and fresh log.

gather_config

gather_config() -> Dict[str, Any]

Gather configuration for tracing integration.

Output fields:

  • type - Component class name
  • gathered_at - ISO timestamp
  • seeds - Dictionary of all derived seeds
RETURNS DESCRIPTION
Dict[str, Any]

Dictionary containing seed generator configuration.

View source

DefaultSeedGenerator

Bases: SeedGenerator

Default hash-based seed generator using SHA-256.

Derives deterministic seeds from hierarchical paths. Thread-safe and immutable after construction (derives seeds via pure functions).

When global_seed is None, seeding is disabled and derive_seed() returns None. This allows seeds to flow directly to model adapters which already accept Optional[int].

Provides child() method for hierarchical namespacing (not part of the ABC). Override _compute_seed() to customize the hash algorithm while keeping the rest of the infrastructure (logging, scoping, validation).

All child generators share the same seed log for unified tracking.

Example
# Create root generator with seeding enabled
gen = DefaultSeedGenerator(global_seed=42)

# Or disable seeding (derive_seed returns None)
gen = DefaultSeedGenerator(global_seed=None)

# Scope to task and repetition
task_gen = gen.for_task("task_001").for_repetition(0)

# Use child() for hierarchical namespacing - creates paths like "agents/orchestrator"
agent_gen = task_gen.child("agents")
orchestrator_seed = agent_gen.derive_seed("orchestrator")  # Path: "agents/orchestrator"
baseline_seed = agent_gen.derive_seed("baseline", per_repetition=False)  # Constant

# Pass seed directly to your agent
agent = MyAgent(seed=orchestrator_seed)  # Works with None
Thread Safety

DefaultSeedGenerator is thread-safe by design through isolation:

  1. Isolated logs per task: for_task() creates a fresh seed log, so different tasks running in parallel threads don't share state.

  2. Root generator is read-only: The root generator only stores the global_seed and is never mutated after construction.

  3. Children share parent's log: Within a task, child() and for_repetition() share the same seed log. This is safe because a single task/repetition runs in a single thread.

Parallel execution example::

Thread 1 (task A, rep 0):
  task_gen_A = root.for_task("A").for_repetition(0)  # Fresh log
  child = task_gen_A.child("env")                     # Shares task_gen_A's log

Thread 2 (task B, rep 0):
  task_gen_B = root.for_task("B").for_repetition(0)  # Different fresh log
  child = task_gen_B.child("env")                     # Shares task_gen_B's log

If implementing a custom SeedGenerator subclass, ensure similar thread isolation by creating fresh state in for_task().

global_seed property

global_seed: Optional[int]

Root seed for the entire benchmark run, or None if seeding is disabled.

seed_log property

seed_log: Dict[str, int]

Return all seeds derived by this generator and its children.

RETURNS DESCRIPTION
Dict[str, int]

Copy of the seed log dictionary for safety.

__init__

__init__(
    global_seed: Optional[int] = None,
    task_id: Optional[str] = None,
    rep_index: Optional[int] = None,
    path_prefix: str = "",
    _shared_log: Optional[Dict[str, int]] = None,
)

Initialize a DefaultSeedGenerator.

PARAMETER DESCRIPTION
global_seed

Root seed for the entire benchmark run, or None to disable seeding. When None, derive_seed() returns None for all components.

TYPE: Optional[int] DEFAULT: None

task_id

Current task identifier (set via for_task()).

TYPE: Optional[str] DEFAULT: None

rep_index

Current repetition index (set via for_repetition()).

TYPE: Optional[int] DEFAULT: None

path_prefix

Accumulated path from parent generators.

TYPE: str DEFAULT: ''

_shared_log

Internal. Shared dict for logging all derived seeds. Do not pass this directly; it's managed by child() and for_task().

TYPE: Optional[Dict[str, int]] DEFAULT: None

child

child(name: str) -> Self

Create a child generator scoped to a component.

The child inherits context (global_seed, task_id, rep_index) and extends the path. All children share the same seed log.

This method is specific to DefaultSeedGenerator and not part of the ABC.

PARAMETER DESCRIPTION
name

Component name to add to the path.

TYPE: str

RETURNS DESCRIPTION
Self

New DefaultSeedGenerator with extended path, sharing the same log.

Example
env_gen = seed_generator.child("environment")
tools_gen = env_gen.child("tools")
weather_seed = tools_gen.derive_seed("weather")  # Path: "environment/tools/weather"

derive_seed

derive_seed(
    name: str, per_repetition: bool = True
) -> Optional[int]

Derive a seed for a named component.

PARAMETER DESCRIPTION
name

Component identifier (e.g., "agent_x", "tool_weather").

TYPE: str

per_repetition

If True, seed varies per repetition. If False, seed is constant across repetitions of the same task.

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
Optional[int]

Deterministic seed derived from (global_seed, task_id, [rep_index], path, name),

Optional[int]

or None if global_seed is None (seeding disabled).

RAISES DESCRIPTION
SeedingError

If global_seed is set but task_id is not set (call for_task() first), or if per_repetition=True and rep_index is not set.

for_repetition

for_repetition(rep_index: int) -> Self

Create a generator scoped to a specific repetition.

Preserves the task scope and seed log. Seeds derived with per_repetition=True will include the rep_index in the hash.

PARAMETER DESCRIPTION
rep_index

The repetition index (0-based).

TYPE: int

RETURNS DESCRIPTION
Self

New DefaultSeedGenerator with rep_index set, preserving task scope and log.

for_task

for_task(task_id: str) -> Self

Create a generator scoped to a specific task.

Creates a fresh seed log for this task. Each task should have its own generator created via this method.

PARAMETER DESCRIPTION
task_id

The task identifier.

TYPE: str

RETURNS DESCRIPTION
Self

New DefaultSeedGenerator with task_id set and fresh log.

gather_config

gather_config() -> Dict[str, Any]

Gather configuration for tracing integration.

Output fields:

  • type - Component class name
  • gathered_at - ISO timestamp
  • global_seed - The root seed (or None if disabled)
  • task_id - Current task ID (if set)
  • rep_index - Current repetition index (if set)
  • seeds - Dictionary of all derived seeds (empty if seeding disabled)
RETURNS DESCRIPTION
Dict[str, Any]

Dictionary containing seed generator configuration.

View source

SeedingError

Bases: Exception

Raised when seeding is misconfigured or unsupported.

Examples:

  • Calling derive_seed() before for_task() sets the task context
  • Calling derive_seed(per_repetition=True) before for_repetition() sets the rep context
  • Model adapter doesn't support seeding but seed was provided