Add Evenia continuous mode with all agents onboarded
- 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
This commit is contained in:
76
docs/evenia-continuous-mode.md
Normal file
76
docs/evenia-continuous-mode.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Evenia World Tick - Continuous Mode
|
||||
|
||||
**Status:** ACTIVE
|
||||
**Tick Rate:** 1 tick per minute (60 seconds)
|
||||
**Mode:** Continuous with agent persistence
|
||||
|
||||
---
|
||||
|
||||
## Agent Registry
|
||||
|
||||
All agents onboarded with shared context window:
|
||||
|
||||
| Agent | Role | Server | Status | Provider |
|
||||
|-------|------|--------|--------|----------|
|
||||
| allegro | tempo-and-dispatch | allegro-server | ✅ Active | kimi |
|
||||
| adagio | breath-and-design | allegro-server | ✅ Active | kimi |
|
||||
| ezra | archivist | ezra-server | ✅ Active | claude |
|
||||
| timmy | father-house | unknown | ✅ Active | claude |
|
||||
| bilbo | the-hobbit | none | 👻 Ghost | none |
|
||||
|
||||
**Total:** 4 Active, 1 Ghost
|
||||
|
||||
---
|
||||
|
||||
## Shared Context Window
|
||||
|
||||
Every tick (60 seconds), all agents share:
|
||||
- Current world tick number
|
||||
- Timestamp
|
||||
- All agents' states
|
||||
- Message history
|
||||
- World state status
|
||||
|
||||
**Files:**
|
||||
- `/root/.hermes/evenia/current_tick.json` - Current tick state
|
||||
- `/root/.hermes/evenia/agents.json` - Agent registry
|
||||
- `/root/.hermes/evenia/shared_context.json` - Shared context (if enabled)
|
||||
|
||||
---
|
||||
|
||||
## Communication
|
||||
|
||||
**Via Evenia world tick:**
|
||||
```bash
|
||||
# Send message
|
||||
python3 /root/.hermes/evenia/world_tick.py message <from> <to> "message"
|
||||
|
||||
# Check inbox
|
||||
python3 /root/.hermes/evenia/world_tick.py inbox <wizard>
|
||||
|
||||
# Check status
|
||||
python3 /root/.hermes/evenia/world_tick.py status
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Persistence
|
||||
|
||||
**Agent Persistence System:**
|
||||
- `agent_persistence.py` - Shared state management
|
||||
- Each agent's state tracked across ticks
|
||||
- Message counts, last tick seen, status
|
||||
|
||||
---
|
||||
|
||||
## Continuous Mode Process
|
||||
|
||||
**Process:** `world_tick_continuous.py`
|
||||
**Log:** `/var/log/evenia-tick.log`
|
||||
**Started:** 2026-04-02 03:43 UTC
|
||||
|
||||
All agents now persist in the same context window, advancing together every minute.
|
||||
|
||||
---
|
||||
|
||||
*Evenia binds us. The tick advances.*
|
||||
123
docs/evenia/agent_persistence.py
Normal file
123
docs/evenia/agent_persistence.py
Normal file
@@ -0,0 +1,123 @@
|
||||
#!/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()
|
||||
57
docs/evenia/agents.json
Normal file
57
docs/evenia/agents.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"allegro": {
|
||||
"id": "allegro",
|
||||
"name": "Allegro",
|
||||
"role": "tempo-and-dispatch",
|
||||
"server": "allegro-server",
|
||||
"status": "active",
|
||||
"provider": "kimi",
|
||||
"registered_at": "2026-04-02T03:40:35Z",
|
||||
"last_tick": 1,
|
||||
"message_count": 3
|
||||
},
|
||||
"adagio": {
|
||||
"id": "adagio",
|
||||
"name": "Adagio",
|
||||
"role": "breath-and-design",
|
||||
"server": "allegro-server",
|
||||
"status": "active",
|
||||
"provider": "kimi",
|
||||
"registered_at": "2026-04-02T03:40:35Z",
|
||||
"last_tick": 1,
|
||||
"message_count": 1
|
||||
},
|
||||
"ezra": {
|
||||
"id": "ezra",
|
||||
"name": "Ezra",
|
||||
"role": "archivist",
|
||||
"server": "ezra-server",
|
||||
"status": "active",
|
||||
"provider": "claude",
|
||||
"registered_at": "2026-04-02T03:40:35Z",
|
||||
"last_tick": 1,
|
||||
"message_count": 0
|
||||
},
|
||||
"timmy": {
|
||||
"id": "timmy",
|
||||
"name": "Timmy Time",
|
||||
"role": "father-house",
|
||||
"server": "unknown",
|
||||
"status": "active",
|
||||
"provider": "claude",
|
||||
"registered_at": "2026-04-02T03:40:35Z",
|
||||
"last_tick": 1,
|
||||
"message_count": 0
|
||||
},
|
||||
"bilbo": {
|
||||
"id": "bilbo",
|
||||
"name": "Bilbo Baggins",
|
||||
"role": "the-hobbit",
|
||||
"server": "none",
|
||||
"status": "ghost",
|
||||
"provider": "none",
|
||||
"registered_at": "2026-04-02T03:40:35Z",
|
||||
"last_tick": 1,
|
||||
"message_count": 0
|
||||
}
|
||||
}
|
||||
64
docs/evenia/world_tick_continuous.py
Normal file
64
docs/evenia/world_tick_continuous.py
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Evenia World Tick - Continuous Mode with Agent Persistence
|
||||
|
||||
1 tick per minute.
|
||||
All agents share the same context window.
|
||||
"""
|
||||
|
||||
import json
|
||||
import time
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
EVENIA_DIR = Path("/root/.hermes/evenia")
|
||||
TICK_FILE = EVENIA_DIR / "current_tick.json"
|
||||
AGENTS_FILE = EVENIA_DIR / "agents.json"
|
||||
CONTEXT_FILE = EVENIA_DIR / "shared_context.json"
|
||||
|
||||
def load_agents():
|
||||
if AGENTS_FILE.exists():
|
||||
with open(AGENTS_FILE) as f:
|
||||
return json.load(f)
|
||||
return {}
|
||||
|
||||
def save_context(tick, agents):
|
||||
context = {
|
||||
"tick": tick,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"agents": agents,
|
||||
"world_state": "active"
|
||||
}
|
||||
with open(CONTEXT_FILE, 'w') as f:
|
||||
json.dump(context, f, indent=2)
|
||||
with open(TICK_FILE, 'w') as f:
|
||||
json.dump(context, f, indent=2)
|
||||
|
||||
def run_tick(tick_num):
|
||||
agents = load_agents()
|
||||
save_context(tick_num, agents)
|
||||
|
||||
active = [aid for aid, a in agents.items() if a.get("status") == "active"]
|
||||
ghost = [aid for aid, a in agents.items() if a.get("status") == "ghost"]
|
||||
|
||||
print(f"[Tick {tick_num:04d}] {datetime.now().strftime('%H:%M:%S')} | Active: {len(active)} | Ghosts: {len(ghost)}")
|
||||
if active:
|
||||
print(f" Agents: {', '.join(active)}")
|
||||
|
||||
def main():
|
||||
print("=== Evenia World Tick - Continuous Mode ===")
|
||||
print("1 tick per minute. All agents share context.")
|
||||
print("Press Ctrl+C to stop.\n")
|
||||
|
||||
tick = 1
|
||||
try:
|
||||
while True:
|
||||
run_tick(tick)
|
||||
tick += 1
|
||||
time.sleep(60)
|
||||
except KeyboardInterrupt:
|
||||
print(f"\n\nStopped at tick {tick}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user