- 1 tick per minute, all agents share context window - 5 agents registered: allegro, adagio, ezra, timmy, bilbo - Agent persistence system for shared state - Continuous mode process running - Documentation: evenia-continuous-mode.md
124 lines
3.7 KiB
Python
124 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Evenia Agent Persistence System
|
|
|
|
Ensures all agents share the same context window every world tick.
|
|
Each agent reads the shared state at the start of each tick.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
EVENIA_DIR = Path("/root/.hermes/evenia")
|
|
PERSISTENCE_FILE = EVENIA_DIR / "shared_context.json"
|
|
AGENTS_STATE_FILE = EVENIA_DIR / "agents_state.json"
|
|
|
|
def load_shared_context():
|
|
"""Load the shared context for all agents."""
|
|
if PERSISTENCE_FILE.exists():
|
|
with open(PERSISTENCE_FILE) as f:
|
|
return json.load(f)
|
|
return {
|
|
"tick": 0,
|
|
"timestamp": datetime.now().isoformat(),
|
|
"world_state": {},
|
|
"active_agents": [],
|
|
"messages_this_tick": []
|
|
}
|
|
|
|
def save_shared_context(context):
|
|
"""Save the shared context."""
|
|
PERSISTENCE_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
with open(PERSISTENCE_FILE, 'w') as f:
|
|
json.dump(context, f, indent=2)
|
|
|
|
def get_agent_state(agent_id):
|
|
"""Get an agent's persistent state."""
|
|
if AGENTS_STATE_FILE.exists():
|
|
with open(AGENTS_STATE_FILE) as f:
|
|
states = json.load(f)
|
|
return states.get(agent_id, {})
|
|
return {}
|
|
|
|
def update_agent_state(agent_id, state_update):
|
|
"""Update an agent's state."""
|
|
states = {}
|
|
if AGENTS_STATE_FILE.exists():
|
|
with open(AGENTS_STATE_FILE) as f:
|
|
states = json.load(f)
|
|
|
|
if agent_id not in states:
|
|
states[agent_id] = {
|
|
"id": agent_id,
|
|
"first_seen": datetime.now().isoformat(),
|
|
"last_tick": 0,
|
|
"message_count": 0,
|
|
"status": "active"
|
|
}
|
|
|
|
states[agent_id].update(state_update)
|
|
states[agent_id]["last_updated"] = datetime.now().isoformat()
|
|
|
|
AGENTS_STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
with open(AGENTS_STATE_FILE, 'w') as f:
|
|
json.dump(states, f, indent=2)
|
|
|
|
def persist_tick_event(tick_num, event_data):
|
|
"""Persist an event to the shared tick history."""
|
|
context = load_shared_context()
|
|
|
|
if "tick_history" not in context:
|
|
context["tick_history"] = []
|
|
|
|
event_data["tick"] = tick_num
|
|
event_data["timestamp"] = datetime.now().isoformat()
|
|
|
|
context["tick_history"].append(event_data)
|
|
|
|
# Keep only last 100 ticks to prevent bloat
|
|
context["tick_history"] = context["tick_history"][-100:]
|
|
context["tick"] = tick_num
|
|
|
|
save_shared_context(context)
|
|
|
|
def get_context_for_agent(agent_id, current_tick):
|
|
"""Get the full context an agent should have at this tick."""
|
|
context = load_shared_context()
|
|
agent_state = get_agent_state(agent_id)
|
|
|
|
return {
|
|
"world_tick": current_tick,
|
|
"shared_context": context,
|
|
"my_state": agent_state,
|
|
"all_agents": list(load_agents_state().keys()) if AGENTS_STATE_FILE.exists() else [],
|
|
"timestamp": datetime.now().isoformat()
|
|
}
|
|
|
|
def load_agents_state():
|
|
"""Load all agents' states."""
|
|
if AGENTS_STATE_FILE.exists():
|
|
with open(AGENTS_STATE_FILE) as f:
|
|
return json.load(f)
|
|
return {}
|
|
|
|
def main():
|
|
"""Demo of persistence system."""
|
|
print("Evenia Agent Persistence System")
|
|
print("================================")
|
|
|
|
# Initialize context
|
|
context = load_shared_context()
|
|
print(f"Current tick: {context['tick']}")
|
|
print(f"Active agents: {context.get('active_agents', [])}")
|
|
|
|
# Update all registered agents
|
|
for agent_id in ["allegro", "adagio", "ezra", "timmy", "bilbo"]:
|
|
update_agent_state(agent_id, {"last_tick": context['tick']})
|
|
|
|
print("\nAll agents synchronized to shared context.")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|