Adam Bandel


Agent World Simulator

May 2025
Type: game
Code: 9k lines
Files: 159
Active: May 2025 — May 2025
Stack:
PythonPygamehttpxOpenRouter APIPyYAML
Tags:
aisimulationdeveloper-tools

Overview

Agent World Simulator is an experimental Python sandbox where autonomous LLM-powered agents can dynamically expand their own capabilities through code generation. The standout feature is the “Angel System”—an AI-powered code generator that creates new Python ability classes on-the-fly when agents request capabilities they don’t possess.

The simulation uses an Entity-Component-System (ECS) architecture combined with behavior trees and LLM-driven reasoning. Agents perceive their environment, make decisions, and can even learn by observing abilities used by other agents. All assets are procedurally generated, and the entire system runs as a single Python process with no external dependencies beyond an optional LLM API key.

Screenshots

World View

CLI Interaction

Problem

Traditional game AI is constrained by pre-programmed behaviors. Agents can only use abilities developers explicitly coded. This project explores a radical alternative: what if agents could identify gaps in their capabilities and request entirely new abilities generated by an LLM?

This creates a testbed for emergent AI behavior research, where complex strategies can develop organically. The challenge is making LLM-generated code safe, integrating it seamlessly at runtime, and maintaining determinism for debugging and replay.

Approach

The solution combines a robust ECS game architecture with async LLM integration and hot-reloadable Python modules.

Stack

Challenges

Outcomes

The Angel System successfully generates working Python ability classes from natural language descriptions. Agents can request “I need to attack from a distance” and receive a generated ranged attack ability that integrates with the combat system.

Key learnings:

Implementation Notes

Angel System Flow

When an agent requests an ability it doesn’t have:

# 1. Check the Vault for existing abilities
vault_match = get_vault_index().lookup(description)
if vault_match:
    self._grant_to_agent(agent_id, vault_match)
    return {"status": "success", "ability_class_name": vault_match}

# 2. Generate new ability via LLM
prompt = self._build_angel_code_generation_prompt(
    description,
    templates.get_world_constraints_for_angel(),
    templates.get_code_scaffolds_for_angel(),
)
generated_code = llm.request(prompt, model=llm.angel_generation_model)

# 3. Write to disk and hot-reload
write_ability_file(generated_code)
ability_system.reload_abilities()

Ability Base Class

All abilities—built-in, vault, and generated—inherit from a simple abstract interface:

class Ability(ABC):
    @property
    @abstractmethod
    def energy_cost(self) -> int: ...

    @property
    @abstractmethod
    def cooldown(self) -> int: ...

    @abstractmethod
    def can_use(self, caster_id: int, world: Any, target_id: Optional[int] = None) -> bool: ...

    @abstractmethod
    def execute(self, caster_id: int, world: Any, target_id: Optional[int] = None) -> None: ...

Agent Decision Pipeline

PerceptionSystem → visible_entities, visible_ability_uses
       ↓
prompt_builder → LLM context with agent state, goals, and observations
       ↓
LLMManager.request() → queued async call to OpenRouter
       ↓
AIReasoningSystem → parse response into Action objects
       ↓
ActionQueue → validated actions for execution
       ↓
ActionExecutionSystem → ability checks, combat, Angel requests

Configuration

world:
  size: [100, 100]
  tick_rate: 10
  paused_for_angel_timeout_seconds: 60

llm:
  mode: offline  # offline | echo | live
  agent_decision_model: <model_id>
  angel_generation_model: <model_id>

View on GitHub →


Related Posts

No posts yet.