@@ -257,6 +257,84 @@ async def get_emergence_score():
257257 logger .error (f"Failed to get emergence score: { e } " )
258258 raise HTTPException (status_code = 500 , detail = f"Failed to retrieve emergence score: { str (e )} " )
259259
260+
261+ @router .get ("/breakthroughs" )
262+ async def get_breakthroughs (limit : int = Query (50 , ge = 1 , le = 500 )):
263+ """Return historical breakthrough log entries (newest first).
264+
265+ Reads the persistent ``logs/breakthroughs.jsonl`` file and returns up to
266+ *limit* entries. Returns an empty list when no breakthroughs have been
267+ recorded yet.
268+ """
269+ try :
270+ if emergence_detector is not None :
271+ entries = emergence_detector .get_breakthroughs (limit = limit )
272+ return {
273+ "breakthroughs" : entries ,
274+ "total" : len (entries ),
275+ "limit" : limit ,
276+ "threshold" : emergence_detector .threshold ,
277+ }
278+ raise HTTPException (
279+ status_code = 503 ,
280+ detail = "Emergence detector is not initialised" ,
281+ )
282+ except HTTPException :
283+ raise
284+ except Exception as e :
285+ logger .error (f"Failed to get breakthroughs: { e } " )
286+ raise HTTPException (status_code = 500 , detail = f"Failed to retrieve breakthroughs: { str (e )} " )
287+
288+
289+ # Observatory reference — set by unified_server at startup
290+ _observatory = None
291+
292+
293+ def set_observatory (observatory ) -> None :
294+ """Register the UnifiedConsciousnessObservatory instance."""
295+ global _observatory
296+ _observatory = observatory
297+
298+
299+ def get_observatory ():
300+ """Return the active UnifiedConsciousnessObservatory instance (may be None)."""
301+ return _observatory
302+
303+
304+ @router .get ("/observatory" )
305+ async def get_observatory_report ():
306+ """Return the full UnifiedConsciousnessObservatory report.
307+
308+ Includes uptime, total observed states, total breakthrough events, peak
309+ score, current emergence snapshot, and the 10 most recent breakthroughs.
310+ """
311+ try :
312+ if _observatory is not None :
313+ return _observatory .get_report ()
314+ # Fallback: lightweight report using the detector only
315+ if emergence_detector is not None :
316+ status = emergence_detector .get_emergence_status ()
317+ recent = emergence_detector .get_breakthroughs (limit = 10 )
318+ return {
319+ "running" : False ,
320+ "uptime_seconds" : 0 ,
321+ "total_states_observed" : 0 ,
322+ "total_breakthroughs" : len (recent ),
323+ "peak_score" : status .get ("emergence_score" , 0.0 ),
324+ "current_emergence" : status ,
325+ "recent_breakthroughs" : recent ,
326+ }
327+ raise HTTPException (
328+ status_code = 503 ,
329+ detail = "Neither observatory nor emergence detector is available" ,
330+ )
331+ except HTTPException :
332+ raise
333+ except Exception as e :
334+ logger .error (f"Failed to get observatory report: { e } " )
335+ raise HTTPException (status_code = 500 , detail = f"Failed to retrieve observatory report: { str (e )} " )
336+
337+
260338# WebSocket endpoints for real-time consciousness streaming
261339
262340@router .websocket ("/stream" )
@@ -313,6 +391,104 @@ async def global_workspace_stream(websocket: WebSocket):
313391
314392 await enhanced_websocket_manager .handle_consciousness_connection (websocket , "workspace" )
315393
394+
395+ # ---------------------------------------------------------------------------
396+ # Autonomous Goal Engine endpoints (Issue #81)
397+ # ---------------------------------------------------------------------------
398+
399+ # Module-level references populated at startup by unified_server
400+ _goal_generator = None
401+ _creative_engine = None
402+
403+
404+ def set_goal_engine (generator , creative_engine ) -> None :
405+ """Register the AutonomousGoalGenerator and CreativeSynthesisEngine."""
406+ global _goal_generator , _creative_engine
407+ _goal_generator = generator
408+ _creative_engine = creative_engine
409+
410+
411+ @router .get ("/goals" )
412+ async def get_autonomous_goals ():
413+ """Return the currently active autonomous goals generated by the system.
414+
415+ Goals are produced without external prompting by monitoring cognitive
416+ state gaps (low phi, coherence drift, knowledge gaps, etc.).
417+ """
418+ try :
419+ if _goal_generator is not None :
420+ goals = _goal_generator .active_goals
421+ metrics = _goal_generator .get_metrics ()
422+ return {
423+ "goals" : goals ,
424+ "total" : len (goals ),
425+ "metrics" : metrics ,
426+ }
427+ raise HTTPException (
428+ status_code = 503 ,
429+ detail = "Autonomous goal generator is not initialised" ,
430+ )
431+ except HTTPException :
432+ raise
433+ except Exception as e :
434+ logger .error (f"Failed to get autonomous goals: { e } " )
435+ raise HTTPException (status_code = 500 , detail = f"Failed to retrieve goals: { str (e )} " )
436+
437+
438+ @router .post ("/goals/generate" )
439+ async def trigger_goal_generation ():
440+ """Manually trigger a round of autonomous goal generation.
441+
442+ Useful for testing or seeding the goal list before any cognitive state
443+ has been observed. Returns the newly proposed goals.
444+ """
445+ try :
446+ if _goal_generator is not None :
447+ # Use an empty cognitive state to trigger baseline exploration
448+ new_goals = await _goal_generator .generate ({})
449+ return {
450+ "new_goals" : new_goals ,
451+ "total_new" : len (new_goals ),
452+ "active_total" : len (_goal_generator .active_goals ),
453+ }
454+ raise HTTPException (
455+ status_code = 503 ,
456+ detail = "Autonomous goal generator is not initialised" ,
457+ )
458+ except HTTPException :
459+ raise
460+ except Exception as e :
461+ logger .error (f"Failed to generate autonomous goals: { e } " )
462+ raise HTTPException (status_code = 500 , detail = f"Failed to generate goals: { str (e )} " )
463+
464+
465+ @router .get ("/creative-synthesis" )
466+ async def get_creative_synthesis (n : int = Query (5 , ge = 1 , le = 20 )):
467+ """Return the most recent creative concept-synthesis outputs.
468+
469+ The CreativeSynthesisEngine combines concepts from the active knowledge
470+ store and scores them on novelty and coherence.
471+ """
472+ try :
473+ if _creative_engine is not None :
474+ outputs = _creative_engine .get_recent_outputs (limit = n )
475+ metrics = _creative_engine .get_metrics ()
476+ return {
477+ "syntheses" : outputs ,
478+ "total" : len (outputs ),
479+ "metrics" : metrics ,
480+ }
481+ raise HTTPException (
482+ status_code = 503 ,
483+ detail = "Creative synthesis engine is not initialised" ,
484+ )
485+ except HTTPException :
486+ raise
487+ except Exception as e :
488+ logger .error (f"Failed to get creative syntheses: { e } " )
489+ raise HTTPException (status_code = 500 , detail = f"Failed to retrieve syntheses: { str (e )} " )
490+
491+
316492# Health and statistics endpoints
317493
318494@router .get ("/health" )
@@ -410,4 +586,11 @@ async def assess_consciousness_level(query: str = "", context: Optional[Dict] =
410586 raise HTTPException (status_code = 500 , detail = f"Assessment failed: { str (e )} " )
411587
412588# Export router
413- __all__ = ['router' , 'set_consciousness_engine' , 'set_emergence_detector' ]
589+ __all__ = [
590+ 'router' ,
591+ 'set_consciousness_engine' ,
592+ 'set_emergence_detector' ,
593+ 'set_observatory' ,
594+ 'get_observatory' ,
595+ 'set_goal_engine' ,
596+ ]
0 commit comments