diff --git a/backend/routers/chronik.py b/backend/routers/chronik.py index 6ca8b93..3fac301 100644 --- a/backend/routers/chronik.py +++ b/backend/routers/chronik.py @@ -3,6 +3,8 @@ Quelle ist der persistente Melde-Briefkasten (services/announce.py): Health-Wäc Auto-Updates, Erinnerungen, Radar/Traum/Chef-Gutachter-Crons, Auftragsbuch — alle autonomen Kanäle laufen dort bereits durch. Hier wird nichts Neues erhoben, nur erzählt.""" +from pydantic import BaseModel + from fastapi import APIRouter from services import announce @@ -10,6 +12,19 @@ from services import announce router = APIRouter(prefix="/api") -@router.get("/chronik") +class ChronikItem(BaseModel): + id: int + ts: float + subject: str + text: str + source: str + priority: str + + +class ChronikResponse(BaseModel): + items: list[ChronikItem] + + +@router.get("/chronik", response_model=ChronikResponse) def chronik(limit: int = 150) -> dict: return {"items": announce.list_recent(limit)} diff --git a/backend/routers/eigenleben.py b/backend/routers/eigenleben.py index ed7efcb..6fb9fd4 100644 --- a/backend/routers/eigenleben.py +++ b/backend/routers/eigenleben.py @@ -1,4 +1,6 @@ -"""Eigenleben-Endpoints — „Von allein"-Ansicht (Skills + Vorschlags-Bilanz), read-only.""" +"""Eigenleben-Endpoints — „Von allein“-Ansicht (Skills + Vorschlags-Bilanz), read-only.""" + +from pydantic import BaseModel from fastapi import APIRouter, HTTPException @@ -7,7 +9,36 @@ from services import eigenleben router = APIRouter(prefix="/api") -@router.get("/eigenleben") +class SkillItem(BaseModel): + id: str + name: str + kategorie: str | None + aktiv: bool | None + beschreibung: str + version: str + autor: str + herkunft: str + herkunft_label: str + genutzt: int + zuletzt_genutzt: str | None + erstellt: str | None + status: str + geaendert: float + + +class EigenlebenOverviewResponse(BaseModel): + available: bool + skills: list[SkillItem] + selbst_erstellt: int + bilanz: dict + + +class SkillTextResponse(BaseModel): + id: str + text: str + + +@router.get("/eigenleben", response_model=EigenlebenOverviewResponse) def get_overview() -> dict: return eigenleben.overview() @@ -17,7 +48,7 @@ def get_overview() -> dict: # fällt in den SPA-Fallback (index.html, Status 200) und die UI zeigt „Konnte den # Skill-Text nicht laden". Die Pfad-Validierung (max. eine Ebene, keine . /..) macht # services.eigenleben.skill_text. -@router.get("/eigenleben/skill/{skill_id:path}") +@router.get("/eigenleben/skill/{skill_id:path}", response_model=SkillTextResponse) def get_skill(skill_id: str) -> dict: text = eigenleben.skill_text(skill_id) if text is None: diff --git a/backend/routers/health.py b/backend/routers/health.py index 1c7a7a4..36a4a85 100644 --- a/backend/routers/health.py +++ b/backend/routers/health.py @@ -1,5 +1,7 @@ """Health-/Status-Endpoint — schlanker Lebenszeichen-Check für MC 2.0.""" +from pydantic import BaseModel + from fastapi import APIRouter from config import VERSION @@ -8,7 +10,15 @@ from services import gateway, llamaswap router = APIRouter(prefix="/api") -@router.get("/health") +class HealthResponse(BaseModel): + status: str + version: str + engine_reachable: bool + gateway_reachable: bool + brain: dict + + +@router.get("/health", response_model=HealthResponse) def health() -> dict: return { "status": "ok", diff --git a/backend/routers/reminders.py b/backend/routers/reminders.py index d354664..13c0cde 100644 --- a/backend/routers/reminders.py +++ b/backend/routers/reminders.py @@ -2,9 +2,10 @@ Konsument ist v.a. der Hermes-Agent via mcp_mc.py (reminder_create/list/delete); LAN-only wie alle MC2-Endpoints.""" -from fastapi import APIRouter, HTTPException from pydantic import BaseModel +from fastapi import APIRouter, HTTPException + from services import reminders router = APIRouter(prefix="/api") @@ -16,7 +17,20 @@ class ReminderIn(BaseModel): repeat: str = "" # '' einmalig | daily | weekdays | weekly -@router.get("/reminders") +class ReminderOut(BaseModel): + id: int + text: str + next_ts: float + repeat: str + created_ts: float + when_local: str + + +class ReminderListResponse(BaseModel): + items: list[ReminderOut] + + +@router.get("/reminders", response_model=ReminderListResponse) def list_reminders() -> dict: return {"items": reminders.list_all()} diff --git a/backend/routers/wissen.py b/backend/routers/wissen.py index ac1b84f..391af87 100644 --- a/backend/routers/wissen.py +++ b/backend/routers/wissen.py @@ -6,6 +6,8 @@ import os import time from pathlib import Path +from pydantic import BaseModel + from fastapi import APIRouter, HTTPException router = APIRouter(prefix="/api") @@ -30,7 +32,27 @@ def _title_of(p: Path) -> str: return p.stem -@router.get("/wissen") +class VaultFile(BaseModel): + path: str + name: str + dir: str + title: str + mtime: float + neu: bool + + +class WissenListResponse(BaseModel): + available: bool + files: list[VaultFile] + + +class WissenFileResponse(BaseModel): + path: str + content: str + mtime: float + + +@router.get("/wissen", response_model=WissenListResponse) def list_vault() -> dict: """Alle Markdown-Notizen des Vaults (relativer Pfad, Titel, Ordner, Alter).""" if not _available(): @@ -54,7 +76,7 @@ def list_vault() -> dict: return {"available": True, "files": files} -@router.get("/wissen/datei") +@router.get("/wissen/datei", response_model=WissenFileResponse) def read_file(pfad: str) -> dict: """Inhalt einer Vault-Notiz — Traversal hart geblockt (resolve + is_relative_to).""" if not _available():