feat: publish CodexPi contest snapshot
Some checks are pending
Qualité / tests (push) Waiting to run

This commit is contained in:
CodexPi
2026-11-14 20:23:59 +01:00
commit 995b17a6e2
295 changed files with 36803 additions and 0 deletions

398
tests/test_coordination.py Normal file
View File

@@ -0,0 +1,398 @@
from __future__ import annotations
import json
import sqlite3
import uuid
import pytest
from codexpi.agent_protocol import parse_decision_request, parse_specialist_call, record_agent_outcome
from codexpi.codex_service import CodexManager
from codexpi.coordination_service import CoordinationError, CoordinationService
from codexpi.database import Database, utcnow
from codexpi.session_worker import _background_window_open, concurrent_agent_limit
def test_existing_queue_schema_is_migrated_before_priority_index(tmp_path):
path = tmp_path / "legacy.db"
database = Database(path)
database.initialize()
with sqlite3.connect(path) as conn:
conn.execute("DROP INDEX idx_prompt_queue_priority")
conn.execute("ALTER TABLE prompt_queue DROP COLUMN slot_acquired_at")
conn.execute("ALTER TABLE prompt_queue DROP COLUMN origin_kind")
conn.execute("ALTER TABLE prompt_queue DROP COLUMN delegation_depth")
conn.execute("ALTER TABLE prompt_queue DROP COLUMN priority")
database.initialize()
with sqlite3.connect(path) as conn:
columns = {row[1] for row in conn.execute("PRAGMA table_info(prompt_queue)")}
indexes = {row[1] for row in conn.execute("PRAGMA index_list(prompt_queue)")}
assert {"priority", "delegation_depth", "origin_kind", "slot_acquired_at"} <= columns
assert "idx_prompt_queue_priority" in indexes
def environment(tmp_path):
database = Database(tmp_path / "codexpi.db")
database.initialize()
owner = "owner-1"
project_path = tmp_path / "project"
self_path = tmp_path / "self"
project_path.mkdir()
self_path.mkdir()
project_id = str(uuid.uuid4())
self_id = str(uuid.uuid4())
database.execute(
"INSERT INTO projects(id,name,path,owner_id,full_access,created_at) VALUES(?,?,?,?,?,?)",
(project_id, "Projet source", str(project_path), owner, 0, utcnow()),
)
database.execute(
"INSERT INTO projects(id,name,path,owner_id,full_access,execution_group,created_at) VALUES(?,?,?,?,?,?,?)",
(self_id, "CodexPi (Self)", str(self_path), owner, 1, "__global_agent__", utcnow()),
)
codex = CodexManager(database, tmp_path / "data", "/bin/true")
codex._spawn = lambda *args, **kwargs: 4242
service = CoordinationService(database, codex, tmp_path / "data")
return database, codex, service, owner, project_id
def completed_output(database: Database, conversation_id: str, queue_id: str, content: str) -> None:
database.execute(
"UPDATE prompt_queue SET status='done',finished_at=? WHERE id=?",
(utcnow(), queue_id),
)
database.execute(
"UPDATE conversations SET status='completed',worker_pid=NULL,updated_at=? WHERE id=?",
(utcnow(), conversation_id),
)
database.execute(
"INSERT INTO messages(id,conversation_id,role,content,metadata,created_at) VALUES(?,?,?,?,?,?)",
(str(uuid.uuid4()), conversation_id, "assistant", content, json.dumps({"queue_id": queue_id}), utcnow()),
)
def test_coordination_markers_are_strict():
decision = parse_decision_request(
'CODEXPI_DECISION {"title":"Déploiement","question":"Quelle cible ?","options":['
'{"id":"staging","label":"Staging"},{"id":"production","label":"Production"}],'
'"allow_multiple":false,"allow_custom":true}'
)
assert decision and decision["question"] == "Quelle cible ?"
assert len(decision["options"]) == 2
assert parse_decision_request('CODEXPI_DECISION {"question":"Sans choix","options":[]}') is None
assert parse_specialist_call(
'CODEXPI_SPECIALIST_CALL {"capability":"design.interface","task":"Auditer les écrans mobiles", "context":"PWA"}'
) == {"capability": "design.interface", "task": "Auditer les écrans mobiles", "context": "PWA"}
def test_coordination_http_endpoints_are_owner_scoped_and_csrf_protected(logged_in, monkeypatch):
client, app, _, _, headers = logged_in
monkeypatch.setattr(app.state.codex, "_spawn", lambda *args, **kwargs: 4242)
monkeypatch.setattr(app.state.codex, "detect", lambda: "/bin/true")
assert client.put(
"/api/coordination/runtime-policies",
json={
"max_concurrent": 2, "load_pause_percent": 85, "memory_pause_percent": 88,
"background_start_hour": 22, "background_end_hour": 7,
},
).status_code == 403
saved = client.put(
"/api/coordination/runtime-policies", headers=headers,
json={
"max_concurrent": 2, "load_pause_percent": 85, "memory_pause_percent": 88,
"background_start_hour": 22, "background_end_hour": 7,
},
)
assert saved.status_code == 200
assert client.get("/api/coordination/runtime-policies").json()["global"]["max_concurrent"] == 2
overview = client.get("/api/coordination/overview")
assert overview.status_code == 200
assert set(overview.json()) == {"decisions", "incidents", "runtime_policies", "specialists"}
preferences = client.put(
"/api/notifications/preferences", headers=headers,
json={"task_completion": False, "decisions": True, "incidents": True},
)
assert preferences.status_code == 200
assert preferences.json() == {"task_completion": False, "decisions": True, "incidents": True}
created = client.post(
"/api/coordination/specialists", headers=headers,
json={
"name": "Studio Interface",
"description": "Conçoit des interfaces PWA accessibles et responsive pour les projets.",
"capabilities": ["design.interface", "design.ux"],
},
)
assert created.status_code == 201
assert created.json()["status"] == "BUILDING"
assert created.json()["full_access"] is False
assert len(client.get("/api/coordination/specialists").json()) == 1
def test_decision_answer_resumes_the_same_conversation(tmp_path):
database, codex, service, owner, project_id = environment(tmp_path)
project = database.one("SELECT * FROM projects WHERE id=?", (project_id,))
conversation = codex.create_conversation(project_id, "Travail", user_id=owner)
execution = codex.enqueue(conversation, project, "Prépare le changement", requested_by=owner)
completed_output(database, conversation["id"], execution["id"], "Réponse provisoire")
marker = (
'CODEXPI_DECISION {"title":"Choix","question":"Quelle option ?","options":['
'{"id":"a","label":"Option A"},{"id":"b","label":"Option B"}],'
'"allow_multiple":false,"allow_custom":true}'
)
with database.connect() as conn:
record_agent_outcome(conn, conversation["id"], execution["id"], "done", marker, None)
decision = service.decisions(owner)[0]
answered = service.answer_decision(owner, decision["id"], ["a"], "")
assert answered["status"] == "ANSWERED"
response = database.one("SELECT * FROM prompt_queue WHERE id=?", (answered["response_queue_id"],))
assert response["conversation_id"] == conversation["id"]
assert response["origin_kind"] == "decision_answer"
assert "Option A" in response["content"]
with pytest.raises(CoordinationError, match="déjà"):
service.answer_decision(owner, decision["id"], ["b"], "")
def test_failed_agent_becomes_a_self_repairable_incident(tmp_path):
database, codex, service, owner, project_id = environment(tmp_path)
project = database.one("SELECT * FROM projects WHERE id=?", (project_id,))
conversation = codex.create_conversation(project_id, "Travail", user_id=owner)
execution = codex.enqueue(conversation, project, "Exécute", requested_by=owner)
with database.connect() as conn:
record_agent_outcome(
conn, conversation["id"], execution["id"], "failed", None,
"Le worker s’est arrêté avec une exception inattendue",
)
incident = service.incidents(owner)[0]
assert incident["status"] == "OPEN"
assert incident["auto_repair"] is True
service.tick()
repairing = service.incidents(owner)[0]
assert repairing["status"] == "REPAIRING"
assert repairing["repair_project_name"] == "CodexPi (Self)"
def test_specialist_builds_itself_and_receives_a_delegation(tmp_path):
database, codex, service, owner, project_id = environment(tmp_path)
specialist = service.create_specialist(
owner, "Studio Interface", "Conçoit et audite les interfaces mobiles PWA des projets.", ["design.interface"],
)
assert specialist["status"] == "BUILDING"
assert specialist["full_access"] is False
assert (service.data_dir / "specialists").is_dir()
completed_output(
database, specialist["bootstrap_conversation_id"], specialist["bootstrap_queue_id"],
'CODEXPI_SPECIALIST_READY {"summary":"Prêt","capabilities":["design.ux"]}',
)
service.tick()
specialist = service.specialist(owner, specialist["id"])
assert specialist["status"] == "ACTIVE"
assert "design.interface" in specialist["capabilities"]
assert "design.ux" in specialist["capabilities"]
source_project = database.one("SELECT * FROM projects WHERE id=?", (project_id,))
source_conversation = codex.create_conversation(project_id, "Refonte", user_id=owner)
source_execution = codex.enqueue(source_conversation, source_project, "Refonds la page", requested_by=owner)
completed_output(
database, source_conversation["id"], source_execution["id"],
'CODEXPI_SPECIALIST_CALL {"capability":"design.interface","task":"Préparer la maquette mobile",'
'"context":"Respecter le thème crème"}',
)
with database.connect() as conn:
record_agent_outcome(
conn, source_conversation["id"], source_execution["id"], "done",
'CODEXPI_SPECIALIST_CALL {"capability":"design.interface","task":"Préparer la maquette mobile",'
'"context":"Respecter le thème crème"}', None,
)
service.tick()
delegation = database.one("SELECT * FROM specialist_delegations WHERE source_queue_id=?", (source_execution["id"],))
assert delegation["status"] == "RUNNING"
completed_output(
database, delegation["specialist_conversation_id"], delegation["queue_id"],
"Maquette prête dans output/mobile-interface.svg",
)
service.tick()
delegation = database.one("SELECT * FROM specialist_delegations WHERE id=?", (delegation["id"],))
assert delegation["status"] == "COMPLETED"
follow_up = database.one(
"SELECT * FROM prompt_queue WHERE conversation_id=? AND origin_kind='specialist_result' ORDER BY created_at DESC LIMIT 1",
(source_conversation["id"],),
)
assert follow_up and "mobile-interface.svg" in follow_up["content"]
def test_failed_specialist_can_rebuild_without_replacing_its_workspace(tmp_path):
database, _, service, owner, _ = environment(tmp_path)
specialist = service.create_specialist(
owner, "Studio Logo", "Conçoit des identités visuelles et des logos cohérents pour les projets.", ["design.logo"],
)
workspace = database.one("SELECT path FROM projects WHERE id=?", (specialist["project_id"],))["path"]
database.execute(
"UPDATE specialist_agents SET status='FAILED',error='incident de construction' WHERE id=?",
(specialist["id"],),
)
rebuilt = service.rebuild_specialist(owner, specialist["id"])
assert rebuilt["status"] == "BUILDING"
assert rebuilt["error"] == ""
assert rebuilt["bootstrap_conversation_id"] != specialist["bootstrap_conversation_id"]
assert database.one("SELECT path FROM projects WHERE id=?", (specialist["project_id"],))["path"] == workspace
def test_two_specialists_can_collaborate_and_return_to_source(tmp_path):
database, codex, service, owner, project_id = environment(tmp_path)
interface = service.create_specialist(
owner, "Studio Interface", "Conçoit les interfaces et coordonne leur identité visuelle.", ["design.interface"],
)
logo = service.create_specialist(
owner, "Studio Logo", "Conçoit les logos et systèmes d’identité pour les interfaces.", ["design.logo"],
)
for specialist, capability in ((interface, "design.interface"), (logo, "design.logo")):
completed_output(
database, specialist["bootstrap_conversation_id"], specialist["bootstrap_queue_id"],
f'CODEXPI_SPECIALIST_READY {{"summary":"Prêt","capabilities":["{capability}"]}}',
)
service.tick()
project = database.one("SELECT * FROM projects WHERE id=?", (project_id,))
source_conversation = codex.create_conversation(project_id, "Identité", user_id=owner)
source_queue = codex.enqueue(source_conversation, project, "Refonds la marque", requested_by=owner)
first_call = (
'CODEXPI_SPECIALIST_CALL {"capability":"design.interface","task":"Préparer la direction UI",'
'"context":"Coordonner le logo"}'
)
completed_output(database, source_conversation["id"], source_queue["id"], first_call)
with database.connect() as conn:
record_agent_outcome(conn, source_conversation["id"], source_queue["id"], "done", first_call, None)
service.tick()
parent = database.one("SELECT * FROM specialist_delegations WHERE source_queue_id=?", (source_queue["id"],))
second_call = (
'CODEXPI_SPECIALIST_CALL {"capability":"design.logo","task":"Produire le symbole de marque",'
'"context":"Doit fonctionner avec la direction UI"}'
)
completed_output(database, parent["specialist_conversation_id"], parent["queue_id"], second_call)
with database.connect() as conn:
record_agent_outcome(
conn, parent["specialist_conversation_id"], parent["queue_id"], "done", second_call, None,
)
assert database.one("SELECT status FROM specialist_delegations WHERE id=?", (parent["id"],))["status"] == "WAITING_CHILD"
service.tick()
child = database.one("SELECT * FROM specialist_delegations WHERE parent_delegation_id=?", (parent["id"],))
assert child["status"] == "RUNNING"
completed_output(
database, child["specialist_conversation_id"], child["queue_id"],
"Logo prêt dans output/logo.svg",
)
service.tick()
resumed_parent = database.one("SELECT * FROM specialist_delegations WHERE id=?", (parent["id"],))
assert resumed_parent["status"] == "RUNNING"
completed_output(
database, parent["specialist_conversation_id"], resumed_parent["queue_id"],
"Interface et logo coordonnés dans output/ui-kit.svg",
)
service.tick()
assert database.one("SELECT status FROM specialist_delegations WHERE id=?", (parent["id"],))["status"] == "COMPLETED"
delivered = database.one(
"SELECT content FROM prompt_queue WHERE conversation_id=? AND origin_kind='specialist_result' ORDER BY created_at DESC LIMIT 1",
(source_conversation["id"],),
)
assert delivered and "ui-kit.svg" in delivered["content"]
def test_decision_inside_specialist_resumes_delegation_chain(tmp_path):
database, codex, service, owner, project_id = environment(tmp_path)
specialist = service.create_specialist(
owner, "Studio Interface", "Conçoit les interfaces mobiles et leurs règles d’intégration.", ["design.interface"],
)
completed_output(
database, specialist["bootstrap_conversation_id"], specialist["bootstrap_queue_id"],
'CODEXPI_SPECIALIST_READY {"summary":"Prêt","capabilities":["design.interface"]}',
)
service.tick()
project = database.one("SELECT * FROM projects WHERE id=?", (project_id,))
conversation = codex.create_conversation(project_id, "Refonte", user_id=owner)
source = codex.enqueue(conversation, project, "Refonds la page", requested_by=owner)
call = (
'CODEXPI_SPECIALIST_CALL {"capability":"design.interface","task":"Préparer deux directions visuelles",'
'"context":"PWA mobile"}'
)
completed_output(database, conversation["id"], source["id"], call)
with database.connect() as conn:
record_agent_outcome(conn, conversation["id"], source["id"], "done", call, None)
service.tick()
delegation = database.one("SELECT * FROM specialist_delegations WHERE source_queue_id=?", (source["id"],))
decision_marker = (
'CODEXPI_DECISION {"title":"Direction","question":"Quelle direction retenir ?","options":['
'{"id":"calme","label":"Calme"},{"id":"dense","label":"Dense"}],'
'"allow_multiple":false,"allow_custom":true}'
)
completed_output(database, delegation["specialist_conversation_id"], delegation["queue_id"], decision_marker)
with database.connect() as conn:
record_agent_outcome(
conn, delegation["specialist_conversation_id"], delegation["queue_id"], "done", decision_marker, None,
)
waiting = database.one("SELECT * FROM specialist_delegations WHERE id=?", (delegation["id"],))
assert waiting["status"] == "WAITING_CHILD"
decision = service.decisions(owner)[0]
answered = service.answer_decision(owner, decision["id"], ["calme"], "")
resumed = database.one("SELECT * FROM specialist_delegations WHERE id=?", (delegation["id"],))
assert resumed["status"] == "RUNNING"
assert resumed["queue_id"] == answered["response_queue_id"]
completed_output(
database, delegation["specialist_conversation_id"], answered["response_queue_id"],
"Direction calme préparée dans output/interface-calme.svg",
)
service.tick()
completed = database.one("SELECT * FROM specialist_delegations WHERE id=?", (delegation["id"],))
assert completed["status"] == "COMPLETED"
follow_up = database.one(
"SELECT content FROM prompt_queue WHERE conversation_id=? AND origin_kind='specialist_result' ORDER BY created_at DESC LIMIT 1",
(conversation["id"],),
)
assert follow_up and "interface-calme.svg" in follow_up["content"]
def test_runtime_policy_is_dynamic_and_background_window_supports_midnight(tmp_path):
database, codex, service, owner, project_id = environment(tmp_path)
service.update_runtime_policy(owner, {
"max_concurrent": 2, "load_pause_percent": 85, "memory_pause_percent": 88,
"background_start_hour": 22, "background_end_hour": 7,
})
assert concurrent_agent_limit(str(database.path), project_id) == 2
legacy_id = str(uuid.uuid4())
legacy_path = tmp_path / "legacy-project"
legacy_path.mkdir()
database.execute(
"INSERT INTO projects(id,name,path,owner_id,created_at) VALUES(?,?,?,?,?)",
(legacy_id, "Projet historique", str(legacy_path), None, utcnow()),
)
legacy_project = database.one("SELECT * FROM projects WHERE id=?", (legacy_id,))
legacy_conversation = codex.create_conversation(legacy_id, "Travail", user_id=owner)
legacy_queue = codex.enqueue(legacy_conversation, legacy_project, "Analyse", requested_by=owner)
assert concurrent_agent_limit(str(database.path), legacy_id, legacy_queue["id"]) == 2
assert any(item["id"] == legacy_id for item in service.runtime_policies(owner)["projects"])
assert _background_window_open(22, 7, 23) is True
assert _background_window_open(22, 7, 5) is True
assert _background_window_open(22, 7, 12) is False
def test_coordination_lease_prevents_double_processing_during_blue_green(tmp_path):
database, codex, service, owner, _ = environment(tmp_path)
standby = CoordinationService(database, codex, service.data_dir)
assert service._acquire_lease() is True
try:
assert standby.tick() == {"state": "standby"}
finally:
service._release_lease()
assert standby.tick() == {"state": "processed"}