agent_urban_planning.RunMetadata

class RunMetadata(run_id=<factory>, timestamp=<factory>, scenario_name=None, policy_name=None, seed=None, llm_provider=None, llm_model=None, llm_temperature=None, llm_concurrency=None, total_llm_calls=0, cached_llm_calls=0, cache_hit_rate=0.0, total_input_tokens=0, total_output_tokens=0, wall_clock_seconds=0.0, estimated_cost_usd=0.0, llm_retry_count=0, llm_failed_calls=0, llm_success_rate=1.0, clustering_algo='none', num_archetypes=None, samples_per_archetype=1, within_cluster_assignment='deterministic', cluster_features=<factory>, cluster_assignments=None, price_elasticity_used=None, damping_final=None, market_iterations_actual=None, convergence_achieved=None, decision_engine_name=None, notes=None)[source]

Bases: object

Reproducibility metadata for a single simulation run.

Captures everything needed to make a run reproducible from the output JSON: scenario / policy / seed, LLM provider details, performance counters (call count, cache hit rate, wall-clock time), clustering configuration (algorithm + k + assignments), and an estimated USD cost based on a static per-model price table. Every field is optional so this can be incrementally populated during a run. The result is JSON-serializable and saved alongside the SimulationResults.

Examples

>>> from agent_urban_planning import RunMetadata
>>> md = RunMetadata(scenario_name="berlin", policy_name="counterfactual")
>>> md.to_dict()["scenario_name"]
'berlin'
Parameters:
  • run_id (str)

  • timestamp (str)

  • scenario_name (str | None)

  • policy_name (str | None)

  • seed (int | None)

  • llm_provider (str | None)

  • llm_model (str | None)

  • llm_temperature (float | None)

  • llm_concurrency (int | None)

  • total_llm_calls (int)

  • cached_llm_calls (int)

  • cache_hit_rate (float)

  • total_input_tokens (int)

  • total_output_tokens (int)

  • wall_clock_seconds (float)

  • estimated_cost_usd (float)

  • llm_retry_count (int)

  • llm_failed_calls (int)

  • llm_success_rate (float)

  • clustering_algo (str)

  • num_archetypes (int | None)

  • samples_per_archetype (int)

  • within_cluster_assignment (str)

  • cluster_features (list[str])

  • cluster_assignments (dict[int, int] | None)

  • price_elasticity_used (float | None)

  • damping_final (float | None)

  • market_iterations_actual (int | None)

  • convergence_achieved (bool | None)

  • decision_engine_name (str | None)

  • notes (str | None)

run_id: str
timestamp: str
scenario_name: str | None = None
policy_name: str | None = None
seed: int | None = None
llm_provider: str | None = None
llm_model: str | None = None
llm_temperature: float | None = None
llm_concurrency: int | None = None
total_llm_calls: int = 0
cached_llm_calls: int = 0
cache_hit_rate: float = 0.0
total_input_tokens: int = 0
total_output_tokens: int = 0
wall_clock_seconds: float = 0.0
estimated_cost_usd: float = 0.0
llm_retry_count: int = 0
llm_failed_calls: int = 0
llm_success_rate: float = 1.0
clustering_algo: str = 'none'
num_archetypes: int | None = None
samples_per_archetype: int = 1
within_cluster_assignment: str = 'deterministic'
cluster_features: list[str]
cluster_assignments: dict[int, int] | None = None
price_elasticity_used: float | None = None
damping_final: float | None = None
market_iterations_actual: int | None = None
convergence_achieved: bool | None = None
decision_engine_name: str | None = None
notes: str | None = None
update_cost()[source]

Recompute estimated_cost_usd from the static cost table.

Uses llm_provider + llm_model + token counters to look up per-1k-token rates and compute the rough USD cost.

Returns:

None. Mutates self.estimated_cost_usd.

Examples

>>> from agent_urban_planning import RunMetadata
>>> md = RunMetadata(llm_provider="openai", llm_model="gpt-4o-mini",
...                  total_input_tokens=1000, total_output_tokens=500)
>>> md.update_cost()
>>> md.estimated_cost_usd > 0
True
update_cache_hit_rate()[source]

Recompute cache_hit_rate from cached and uncached call counters.

Returns:

None. Mutates self.cache_hit_rate.

Examples

>>> from agent_urban_planning import RunMetadata
>>> md = RunMetadata(total_llm_calls=8, cached_llm_calls=2)
>>> md.update_cache_hit_rate()
>>> round(md.cache_hit_rate, 1)
0.2
update_llm_success_rate()[source]

Compute LLM success rate from successful and failed counters.

In pure LLM mode this SHOULD be 1.0 — any value less than 1 means some agents’ decisions could not be made by the LLM. By design the simulation aborts rather than falling back to utility, so a < 1 value only occurs from manual failure injection or an incomplete run.

Returns:

None. Mutates self.llm_success_rate.

Examples

>>> from agent_urban_planning import RunMetadata
>>> md = RunMetadata(total_llm_calls=99, llm_failed_calls=1)
>>> md.update_llm_success_rate()
>>> round(md.llm_success_rate, 2)
0.99
to_dict()[source]

Return a JSON-serializable dict of every field.

Converts int keys in cluster_assignments to strings so the result round-trips through json.dumps.

Return type:

dict[str, Any]

Returns:

dict ready for serialization.

Examples

>>> from agent_urban_planning import RunMetadata
>>> md = RunMetadata(scenario_name="x")
>>> md.to_dict()["scenario_name"]
'x'
to_json(indent=2)[source]

Serialize to an indented JSON string.

Parameters:

indent (int) – Number of spaces of indentation. Defaults to 2.

Return type:

str

Returns:

JSON string.

Examples

>>> from agent_urban_planning import RunMetadata
>>> md = RunMetadata(scenario_name="x")
>>> '"scenario_name"' in md.to_json()
True
classmethod from_dict(data)[source]

Build a RunMetadata from its serialized dict form.

Parameters:

data (dict[str, Any]) – Dict shaped like the output of to_dict().

Return type:

RunMetadata

Returns:

A new RunMetadata with cluster_assignments int keys restored.

Examples

>>> from agent_urban_planning import RunMetadata
>>> md = RunMetadata(scenario_name="x")
>>> RunMetadata.from_dict(md.to_dict()).scenario_name
'x'
classmethod from_json(s)[source]

Build a RunMetadata from a JSON string.

Parameters:

s (str) – JSON string previously produced by to_json().

Return type:

RunMetadata

Returns:

A new RunMetadata.

Examples

>>> from agent_urban_planning import RunMetadata
>>> md = RunMetadata(scenario_name="x")
>>> RunMetadata.from_json(md.to_json()).scenario_name
'x'
save(path)[source]

Write this metadata to path as JSON.

Creates parent directories as needed.

Parameters:

path – Path-like target.

Returns:

None.

Examples

>>> from agent_urban_planning import RunMetadata
>>> # md.save("output/run.json")
classmethod load(path)[source]

Load a RunMetadata from a JSON file.

Parameters:

path – Path-like file source.

Return type:

RunMetadata

Returns:

The deserialized RunMetadata.

Examples

>>> from agent_urban_planning import RunMetadata
>>> # md = RunMetadata.load("output/run.json")