from __future__ import annotations import os from fastapi import FastAPI from app.core.event_core import EventCore from app.core.handoff import HandoffMatrix from app.core.models import ( AuditEvent, BackupBundle, ControlProfile, ControlState, HandoffMode, LearningState, RuntimeState, StateEvent, ) from app.core.stores import FutureStores app = FastAPI( title="SillyHome Future API", description="SillyHome v2 event-core side project.", version="2.0.0-alpha.2", ) stores = FutureStores(os.getenv("SILLYHOME_FUTURE_STORE", ".future_store")) event_core = EventCore(stores) handoff = HandoffMatrix() @app.get("/health") def health() -> dict[str, str]: return {"status": "ok", "version": app.version} @app.post("/v2/events/state", response_model=list[AuditEvent]) def ingest_state_event(event: StateEvent) -> list[AuditEvent]: return event_core.process_state_event(event) @app.get("/v2/runtime", response_model=RuntimeState) def get_runtime() -> RuntimeState: return stores.runtime() @app.get("/v2/learning", response_model=LearningState) def get_learning() -> LearningState: return stores.learning() @app.put("/v2/learning", response_model=LearningState) def put_learning(state: LearningState) -> LearningState: return stores.save_learning(state) @app.get("/v2/control", response_model=ControlState) def get_control() -> ControlState: return stores.control() @app.put("/v2/control/{actuator_entity_id}", response_model=ControlProfile) def put_control(actuator_entity_id: str, profile: ControlProfile) -> ControlProfile: state = stores.control() state.profiles[actuator_entity_id] = profile stores.save_control(state) return profile @app.post("/v2/handoff/{actuator_entity_id}/assume", response_model=ControlProfile) def assume_control(actuator_entity_id: str) -> ControlProfile: state = stores.control() profile = state.profiles.get( actuator_entity_id, ControlProfile(actuator_entity_id=actuator_entity_id), ) updated = handoff.assume_control(profile) state.profiles[actuator_entity_id] = updated stores.save_control(state) return updated @app.post("/v2/handoff/{actuator_entity_id}/rollback", response_model=ControlProfile) def rollback_control(actuator_entity_id: str) -> ControlProfile: state = stores.control() profile = state.profiles.get( actuator_entity_id, ControlProfile(actuator_entity_id=actuator_entity_id), ) updated = handoff.rollback(profile) state.profiles[actuator_entity_id] = updated stores.save_control(state) return updated @app.get("/v2/handoff/{actuator_entity_id}", response_model=HandoffMode) def classify_handoff(actuator_entity_id: str) -> HandoffMode: profile = stores.control().profiles.get( actuator_entity_id, ControlProfile(actuator_entity_id=actuator_entity_id), ) return handoff.classify(profile) @app.get("/v2/backup/export", response_model=BackupBundle) def export_backup() -> BackupBundle: return stores.export_backup() @app.post("/v2/backup/restore") def restore_backup(bundle: BackupBundle) -> dict[str, str]: stores.restore_backup(bundle) return {"status": "restored"}