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.
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 (orNoneif disabled)derive_seed()- Derive a seed for a named component (returnsNoneif disabled)for_task()- Create a generator scoped to a specific taskfor_repetition()- Create a generator scoped to a specific repetitionseed_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:
|
per_repetition
|
If True, seed varies per repetition. If False, seed is constant across repetitions of the same task.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Optional[int]
|
Deterministic seed derived from the generator's state and name, |
Optional[int]
|
or |
| RAISES | DESCRIPTION |
|---|---|
SeedingError
|
If |
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:
|
| 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:
|
| 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 namegathered_at- ISO timestampseeds- Dictionary of all derived seeds
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, Any]
|
Dictionary containing seed generator configuration. |
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:
-
Isolated logs per task:
for_task()creates a fresh seed log, so different tasks running in parallel threads don't share state. -
Root generator is read-only: The root generator only stores the global_seed and is never mutated after construction.
-
Children share parent's log: Within a task,
child()andfor_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
TYPE:
|
task_id
|
Current task identifier (set via
TYPE:
|
rep_index
|
Current repetition index (set via
TYPE:
|
path_prefix
|
Accumulated path from parent generators.
TYPE:
|
_shared_log
|
Internal. Shared dict for logging all derived seeds.
Do not pass this directly; it's managed by
TYPE:
|
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:
|
| 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:
|
per_repetition
|
If True, seed varies per repetition. If False, seed is constant across repetitions of the same task.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Optional[int]
|
Deterministic seed derived from (global_seed, task_id, [rep_index], path, name), |
Optional[int]
|
or |
| RAISES | DESCRIPTION |
|---|---|
SeedingError
|
If |
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:
|
| 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:
|
| 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 namegathered_at- ISO timestampglobal_seed- The root seed (orNoneif 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. |
SeedingError
Bases: Exception
Raised when seeding is misconfigured or unsupported.
Examples:
- Calling
derive_seed()beforefor_task()sets the task context - Calling
derive_seed(per_repetition=True)beforefor_repetition()sets the rep context - Model adapter doesn't support seeding but seed was provided