feat: agent coordination system (workflows, locks, components, messages)
Adds /api/coord/* endpoints for real-time cross-session coordination: - coord_workflows: named units of work per project - coord_work_items: tasks within workflows with dependency chains - coord_session_locks: exclusive resource locks with auto-expiry (TTL) - coord_component_states: live component state per project (upsert) - coord_messages: cross-session messaging and broadcasts - /api/coord/status: cross-project snapshot endpoint Replaces PROJECT_STATE.md as the coordination layer for Claude sessions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
63
api/services/coord_component_service.py
Normal file
63
api/services/coord_component_service.py
Normal file
@@ -0,0 +1,63 @@
|
||||
"""Service layer for CoordComponentState."""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import HTTPException, status
|
||||
from sqlalchemy.dialects.mysql import insert
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from api.models.coord_component_state import CoordComponentState
|
||||
from api.schemas.coord_component_state import CoordComponentStateUpsert
|
||||
|
||||
|
||||
def get_component_states(
|
||||
db: Session,
|
||||
project_key: Optional[str] = None,
|
||||
) -> list[CoordComponentState]:
|
||||
"""Return all component states, optionally filtered by project."""
|
||||
q = db.query(CoordComponentState)
|
||||
if project_key:
|
||||
q = q.filter(CoordComponentState.project_key == project_key)
|
||||
return q.order_by(CoordComponentState.project_key, CoordComponentState.component).all()
|
||||
|
||||
|
||||
def upsert_component_state(
|
||||
db: Session,
|
||||
project_key: str,
|
||||
component: str,
|
||||
data: CoordComponentStateUpsert,
|
||||
) -> CoordComponentState:
|
||||
"""Insert or update a component state using MariaDB ON DUPLICATE KEY UPDATE."""
|
||||
try:
|
||||
stmt = insert(CoordComponentState).values(
|
||||
project_key=project_key,
|
||||
component=component,
|
||||
state=data.state,
|
||||
version=data.version,
|
||||
notes=data.notes,
|
||||
updated_by=data.updated_by,
|
||||
)
|
||||
stmt = stmt.on_duplicate_key_update(
|
||||
state=stmt.inserted.state,
|
||||
version=stmt.inserted.version,
|
||||
notes=stmt.inserted.notes,
|
||||
updated_by=stmt.inserted.updated_by,
|
||||
)
|
||||
db.execute(stmt)
|
||||
db.commit()
|
||||
|
||||
record = (
|
||||
db.query(CoordComponentState)
|
||||
.filter(
|
||||
CoordComponentState.project_key == project_key,
|
||||
CoordComponentState.component == component,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
return record
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to upsert component state: {e}"
|
||||
)
|
||||
Reference in New Issue
Block a user