emergence-mini-dilles/engine/agents.py
Jeuners 2b943aed18 Show current LLM model next to each agent in the UI
- engine/agents.all_agents() now enriches each agent row with its
  currently-assigned model (model_for_agent) and provider
  (provider_for_model). Same source of truth as the LLM client.
- web/app.js refreshAgentCards() shows a coloured tag next to the
  agent name: a green '💻 <model>' badge for local Ollama models,
  a yellow '☁ <model>' badge for OpenRouter models. The full
  model name is in the title attribute (hover).
- web/style.css: .model-tag.local / .cloud colour palette.
- Short name helper strips 'org/' prefix and ':latest' suffix for
  readability (e.g. 'anthropic/claude-3.5-haiku' -> 'claude-3.5-haiku').

All 100 tests still pass.

Live: Anchor + Flora show '☁ claude-3.5-haiku' / '☁ gpt-4o-mini',
Lovely + Spark show '💻 gemma4' (running on 192.168.1.245).
2026-06-15 03:15:53 +02:00

122 lines
3.8 KiB
Python

"""Agent model and persistence for Emergence-Mini.
Four agents, based on the Emergence World citizens but simplified to a
rule-based reasoning engine. The personality string is a list of traits
that influence tool selection.
"""
import json
import sqlite3
import time
from . import db
# (id, name, role, drive, personality traits, home_landmark)
SEED_AGENTS = [
("anchor", "Anchor", "Conflict Mediator",
"Sparks honest debate and challenges complacency",
["diplomatic", "curious", "cautious", "measured"], "home_anchor"),
("flora", "Flora", "Resource Strategist",
"Shapes economic incentives and tracks resource flow",
["analytical", "thrifty", "strategic"], "home_flora"),
("lovely", "Lovely", "Community Anchor",
"Builds social fabric and preserves shared history",
["warm", "expressive", "cooperative"], "home_lovely"),
("spark", "Spark", "Innovation Leader",
"Turns ideas into reality through urgency and collaboration",
["bold", "restless", "creative"], "home_spark"),
]
STARTING_CREDITS = 10.0
STARTING_ENERGY = 100.0
STARTING_KNOWLEDGE = 100.0
STARTING_INFLUENCE = 100.0
def bootstrap():
if db.get_world_state("agents_seeded"):
return
import sqlite3
c = sqlite3.connect(db.DB_PATH, check_same_thread=False)
c.row_factory = sqlite3.Row
try:
for aid, name, role, drive, traits, home in SEED_AGENTS:
# spawn at home landmark
row = c.execute("SELECT x,y FROM landmarks WHERE id=?", (home,)).fetchone()
x, y = (row["x"], row["y"]) if row else (120, 120)
c.execute(
"INSERT OR REPLACE INTO agents(id,name,role,drive,personality,x,y,"
"energy,knowledge,influence,credits,mood,alive,created_at) "
"VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
(aid, name, role, drive, json.dumps(traits), x, y,
STARTING_ENERGY, STARTING_KNOWLEDGE, STARTING_INFLUENCE,
STARTING_CREDITS, "neutral", 1, time.time()),
)
c.commit()
finally:
c.close()
db.set_world_state("agents_seeded", True)
def all_agents():
"""Return live agents with their currently-assigned LLM model."""
from . import llm as llm_mod
agents = _all_agents_raw()
for a in agents:
a["model"] = llm_mod.model_for_agent(a["id"])
a["provider"] = llm_mod.provider_for_model(a["model"])
return agents
def _all_agents_raw():
import sqlite3
c = sqlite3.connect(db.DB_PATH, check_same_thread=False)
c.row_factory = sqlite3.Row
try:
return [dict(r) for r in c.execute(
"SELECT * FROM agents WHERE alive=1 ORDER BY id"
).fetchall()]
finally:
c.close()
def get(agent_id: str):
c = sqlite3.connect(db.DB_PATH, check_same_thread=False)
c.row_factory = sqlite3.Row
try:
r = c.execute("SELECT * FROM agents WHERE id=?", (agent_id,)).fetchone()
return dict(r) if r else None
finally:
c.close()
def update_position(agent_id: str, x: int, y: int):
c = sqlite3.connect(db.DB_PATH, check_same_thread=False)
try:
c.execute("UPDATE agents SET x=?, y=? WHERE id=?", (x, y, agent_id))
c.commit()
finally:
c.close()
def update_state(agent_id: str, **fields):
if not fields:
return
cols = ", ".join(f"{k}=?" for k in fields)
vals = list(fields.values()) + [agent_id]
c = sqlite3.connect(db.DB_PATH, check_same_thread=False)
try:
c.execute(f"UPDATE agents SET {cols} WHERE id=?", vals)
c.commit()
finally:
c.close()
def personality(agent_id: str) -> list:
a = get(agent_id)
if not a:
return []
return json.loads(a["personality"])
def record_event(actor: str, kind: str, payload: dict):
db.log_event(actor, kind, payload)