290 lines
8.3 KiB
Python
290 lines
8.3 KiB
Python
"""Alle API-Routen. Fachlogik wirft ValueError/FileNotFoundError,
|
|
hier wird auf 400/404/409 gemappt."""
|
|
|
|
from fastapi import APIRouter, HTTPException
|
|
|
|
import agents
|
|
import auftrag
|
|
import chat
|
|
import features
|
|
import projekte
|
|
import planung
|
|
import pruefung
|
|
import recherche
|
|
import verzeichnis
|
|
|
|
router = APIRouter(prefix="/api")
|
|
|
|
|
|
@router.get("/health")
|
|
async def health():
|
|
return {"ok": True}
|
|
|
|
|
|
@router.get("/projekte")
|
|
async def projekte_liste():
|
|
return projekte.liste()
|
|
|
|
|
|
@router.post("/projekte")
|
|
async def projekt_anlegen(body: dict):
|
|
name = (body.get("name") or "").strip()
|
|
try:
|
|
projekte.anlegen(name)
|
|
except ValueError as e:
|
|
raise HTTPException(409 if "existiert" in str(e) else 400, str(e))
|
|
return {"name": name}
|
|
|
|
|
|
@router.put("/projekte/{name}")
|
|
async def projekt_umbenennen(name: str, body: dict):
|
|
neu = (body.get("name") or "").strip()
|
|
try:
|
|
projekte.umbenennen(name, neu)
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(409 if "existiert" in str(e) else 400, str(e))
|
|
return {"name": neu}
|
|
|
|
|
|
@router.delete("/projekte/{name}")
|
|
async def projekt_loeschen(name: str):
|
|
try:
|
|
projekte.loeschen(name)
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(400, str(e))
|
|
return {"ok": True}
|
|
|
|
|
|
@router.get("/projekte/{name}/features")
|
|
async def features_liste(name: str, sicht: str = "planung"):
|
|
"""`sicht=uebersicht` liest den Projektstand, sonst die Arbeitskopie.
|
|
|
|
Ohne laufende Planung sind beide dasselbe Verzeichnis.
|
|
"""
|
|
try:
|
|
return features.liste(name, nur_stand=sicht == "uebersicht")
|
|
except (FileNotFoundError, ValueError) as e:
|
|
raise HTTPException(404, str(e))
|
|
|
|
|
|
@router.post("/projekte/{name}/features")
|
|
async def feature_anlegen(name: str, body: dict):
|
|
try:
|
|
return features.anlegen(name, body.get("roh") or "")
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(400, str(e))
|
|
|
|
|
|
@router.put("/projekte/{name}/features/{id}")
|
|
async def feature_speichern(name: str, id: str, body: dict):
|
|
try:
|
|
return features.speichern(name, id, body.get("roh") or "")
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(400, str(e))
|
|
|
|
|
|
@router.post("/projekte/{name}/pruefung")
|
|
async def pruefung_starten(name: str, body: dict | None = None):
|
|
art = (body or {}).get("art") or "stil"
|
|
try:
|
|
return await pruefung.starte(name, art)
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
except pruefung.LaeuftBereits as e:
|
|
raise HTTPException(409, str(e)) # 409 heißt genau das und sonst nichts
|
|
except ValueError as e:
|
|
raise HTTPException(400, str(e))
|
|
|
|
|
|
@router.get("/projekte/{name}/pruefung")
|
|
async def pruefung_status(name: str):
|
|
return pruefung.status(name)
|
|
|
|
|
|
@router.get("/projekte/{name}/planung")
|
|
async def planung_stand(name: str):
|
|
try:
|
|
return planung.stand(name)
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
|
|
|
|
@router.post("/projekte/{name}/planung")
|
|
async def planung_starten(name: str):
|
|
try:
|
|
planung.starte(name)
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(409, str(e))
|
|
return planung.stand(name)
|
|
|
|
|
|
@router.post("/projekte/{name}/planung/umsetzen")
|
|
async def planung_umsetzen(name: str):
|
|
"""Mit Arbeitsverzeichnis implementiert ein Agent die Änderungen; die Planung
|
|
bleibt stehen und wird erst nach seinem Erfolg übernommen. Ohne Verzeichnis
|
|
oder ohne Änderungen wird sofort übernommen."""
|
|
try:
|
|
anweisung, schritte = auftrag.bau_auftrag(name)
|
|
agent = auftrag.starte(name, anweisung, schritte)
|
|
if not agent:
|
|
planung.setze_um(name)
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(409, str(e))
|
|
return {"ok": True, "agent": agent}
|
|
|
|
|
|
@router.get("/projekte/{name}/auftrag")
|
|
async def auftrag_status(name: str):
|
|
return auftrag.status(name)
|
|
|
|
|
|
@router.get("/system/ordner")
|
|
async def ordner_liste(pfad: str = ""):
|
|
"""Zum Durchblättern im Verzeichnis-Dialog — listet nur, schreibt nie."""
|
|
try:
|
|
return verzeichnis.ordner(pfad)
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(400, str(e))
|
|
|
|
|
|
@router.get("/projekte/{name}/verzeichnis")
|
|
async def verzeichnis_lesen(name: str):
|
|
try:
|
|
return {"pfad": verzeichnis.lies(name)}
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
|
|
|
|
@router.put("/projekte/{name}/verzeichnis")
|
|
async def verzeichnis_setzen(name: str, body: dict):
|
|
pfad = (body.get("pfad") or "").strip()
|
|
try:
|
|
if not pfad:
|
|
verzeichnis.loesche(name)
|
|
return {"pfad": ""}
|
|
return {"pfad": verzeichnis.setze(name, pfad)}
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(400, str(e))
|
|
|
|
|
|
@router.delete("/projekte/{name}/planung")
|
|
async def planung_abbrechen(name: str):
|
|
# Solange der Agent auf der Planung arbeitet, darf sie ihm niemand wegziehen
|
|
if auftrag.status(name)["laeuft"]:
|
|
raise HTTPException(409, "Der Agent arbeitet noch an dieser Planung")
|
|
try:
|
|
planung.brich_ab(name)
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
return {"ok": True}
|
|
|
|
|
|
@router.post("/projekte/{name}/planung/zuruecksetzen")
|
|
async def planung_zuruecksetzen(name: str, body: dict):
|
|
if auftrag.status(name)["laeuft"]:
|
|
raise HTTPException(409, "Der Agent arbeitet noch an dieser Planung")
|
|
try:
|
|
planung.zuruecksetzen(name, (body or {}).get("titel") or "")
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(409, str(e))
|
|
return planung.stand(name)
|
|
|
|
|
|
@router.delete("/projekte/{name}/pruefung")
|
|
async def pruefung_beenden(name: str):
|
|
pruefung.beende(name)
|
|
return {"ok": True}
|
|
|
|
|
|
@router.delete("/projekte/{name}/features/{id}")
|
|
async def feature_loeschen(name: str, id: str):
|
|
try:
|
|
features.loeschen(name, id)
|
|
except (FileNotFoundError, ValueError) as e:
|
|
raise HTTPException(404, str(e))
|
|
return {"ok": True}
|
|
|
|
|
|
@router.get("/projekte/{name}/chat")
|
|
async def chat_verlauf(name: str):
|
|
try:
|
|
return {"verlauf": chat.verlauf(name)}
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
|
|
|
|
@router.post("/projekte/{name}/chat")
|
|
async def chat_frage(name: str, body: dict):
|
|
try:
|
|
return await chat.frage(name, body.get("text") or "")
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
except agents.NichtKonfiguriert as e:
|
|
raise HTTPException(400, str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(400, str(e))
|
|
|
|
|
|
@router.delete("/projekte/{name}/chat")
|
|
async def chat_leeren(name: str):
|
|
try:
|
|
chat.leeren(name)
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
return {"ok": True}
|
|
|
|
|
|
@router.get("/projekte/{name}/recherche")
|
|
async def recherche_faeden(name: str):
|
|
try:
|
|
return {"faeden": recherche.liste(name)}
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
|
|
|
|
@router.post("/projekte/{name}/recherche")
|
|
async def recherche_anlegen(name: str):
|
|
try:
|
|
return recherche.anlegen(name)
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
|
|
|
|
@router.post("/projekte/{name}/recherche/{id}")
|
|
async def recherche_frage(name: str, id: str, body: dict):
|
|
try:
|
|
return await recherche.frage(name, id, body.get("text") or "")
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
except agents.NichtKonfiguriert as e:
|
|
raise HTTPException(400, str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(400, str(e))
|
|
|
|
|
|
@router.delete("/projekte/{name}/recherche/{id}")
|
|
async def recherche_loeschen(name: str, id: str):
|
|
try:
|
|
recherche.loeschen(name, id)
|
|
except FileNotFoundError as e:
|
|
raise HTTPException(404, str(e))
|
|
return {"ok": True}
|