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