The WorldSerializer provides a robust mechanism to save the entire state of a World — including all entities and their components — into a structured format like JSON, and reload it later.
The WorldSerializer class offers several methods for serializing and deserializing World states:
WorldSerializer.to_dict(world: World) -> dict: Converts aWorldinstance into a serializable dictionary.WorldSerializer.from_dict(data: dict, providers: dict[str, LLMProvider], tool_handlers: dict[str, Callable]) -> World: Reconstructs aWorldfrom a dictionary.WorldSerializer.save(world: World, path: Path | str): Directly saves theWorldto a JSON file.WorldSerializer.load(path: Path | str, providers: dict[str, LLMProvider], tool_handlers: dict[str, Callable]) -> World: Directly loads aWorldfrom a JSON file.
The serialization process relies on the COMPONENT_REGISTRY, which maps component class names to their corresponding types for correct deserialization.
Some fields within components are naturally non-serializable, such as live LLM provider instances or tool handler callables.
LLMComponent.provider: Replaced with"<non-serializable>"during serialization.ToolRegistryComponent.handlers: Replaced with"<non-serializable>"during serialization.
When loading a World, you must provide a dictionary of providers (mapping model names to LLMProvider instances) and tool_handlers (mapping tool names to their corresponding callable functions). The WorldSerializer uses these to re-inject the necessary live objects back into the components.
The following example demonstrates a complete save-and-load cycle:
import asyncio
from pathlib import Path
from ecs_agent.core import World
from ecs_agent.components import LLMComponent, ConversationComponent
from ecs_agent.providers import OpenAIProvider
from ecs_agent.serialization import WorldSerializer
async def main():
# 1. Create and setup the original world
world = World()
agent_id = world.create_entity()
provider = OpenAIProvider(api_key="...", model="qwen3.5-plus")
world.add_component(agent_id, LLMComponent(provider=provider, model="qwen3.5-plus"))
world.add_component(agent_id, ConversationComponent(messages=[]))
# 2. Save to JSON
state_path = Path("agent_state.json")
WorldSerializer.save(world, state_path)
print(f"World state saved to {state_path}")
# 3. Load back from JSON
# Note: We must re-provide the live LLM provider and tool handlers (if any)
loaded_world = WorldSerializer.load(
state_path,
providers={"qwen3.5-plus": provider},
tool_handlers={}
)
print("World state loaded back successfully.")
if __name__ == "__main__":
asyncio.run(main())- Private Internals: The
WorldSerializerdirectly accesses privateWorldinternals (world._components._components) to efficiently iterate and extract state. - Dependency Management: Deserialization requires all necessary providers and tool handlers to be available at load time. If a component references a provider that is not included in the
providersmap, the field will remain as"<non-serializable>", which may lead to errors when the agent attempts to use it.