"""Projects management and state CRUD router.""" from __future__ import annotations from fastapi import APIRouter, HTTPException from pydantic import BaseModel, Field from agentic_core.agents import known_info_snapshot from agentic_core.schemas import ProjectContext from ..deps import services router = APIRouter(prefix="/api/projects", tags=["Projects"]) class CreateProjectRequest(BaseModel): business_idea: str = Field(min_length=1) def load_project(project_id: str) -> ProjectContext: context = services.project_store.load(project_id) if context is None: raise HTTPException(status_code=404, detail=f"Project {project_id!r} not found") return context def save_project(context: ProjectContext) -> None: services.project_store.save(context) def project_response(context: ProjectContext, discovery: dict | None = None) -> dict: return { "project_id": context.project_id, "status": context.status, "business_idea": context.business_idea, "summary": project_summary(context), "known_information": known_info_snapshot(context), "transcript": [turn.model_dump() for turn in context.transcript], "discovery": discovery, } def project_summary(context: ProjectContext) -> dict: return { "problem": context.problem, "target_users": context.target_users, "user_roles": context.user_roles, "business_goals": context.business_goals, "core_features": context.core_features, "constraints": context.constraints, "integrations": context.integrations, "technology_preferences": context.technology_preferences, } @router.get("") async def list_projects(): """List all project IDs stored in the system.""" return {"projects": services.project_store.list_ids()} @router.post("", status_code=201) async def create_project(request: CreateProjectRequest): """Create a project and run the first discovery turn.""" context = services.project_store.create(request.business_idea) output = await services.orchestrator.discovery_turn(context, request.business_idea) save_project(context) return project_response(context, output.model_dump()) @router.get("/{project_id}") async def get_project(project_id: str): """Fetch full project state, context, and summary.""" context = load_project(project_id) return project_response(context) @router.delete("/{project_id}") async def delete_project(project_id: str): """Delete a project state from persistent SQLite store.""" deleted = services.project_store.delete(project_id) if not deleted: raise HTTPException(status_code=404, detail=f"Project {project_id!r} not found") return {"status": "deleted", "project_id": project_id} @router.get("/{project_id}/runs") async def get_project_runs(project_id: str): """Fetch per-agent execution logs and telemetry records for a project.""" load_project(project_id) records = services.tracker.list(project_id) return {"project_id": project_id, "runs": [r.model_dump() for r in records]}