@@ -561,8 +561,11 @@ async def dispatch(self, request: Request, call_next): # type: ignore[override]
561561 nightly_lora , # noqa: F401 vol 15 — Pilar 3 closure
562562 sensorial_input , # noqa: F401 vol 15 — sensorial foundation
563563 creative_tools_registry , # noqa: F401 vol 16 — creative tool registry
564+ codeact_adapter , # noqa: F401 vol 17 — CodeAct executable
565+ mcp_server_wrap , # noqa: F401 vol 17 — MCP server expose
566+ hands_orchestrator , # noqa: F401 vol 17 — 1000 hands stub
564567 )
565- _startup_logger .info ("[startup] cognitive modules eager-loaded (vol 5-16 )" )
568+ _startup_logger .info ("[startup] cognitive modules eager-loaded (vol 5-17 )" )
566569 except Exception as e :
567570 _startup_logger .warning ("[startup] cognitive eager-load skipped: %s" , e )
568571
@@ -2360,6 +2363,123 @@ async def creative_update_status_endpoint(request: Request):
23602363 except Exception as e :
23612364 raise HTTPException (status_code = 500 , detail = f"update fail: { e } " )
23622365
2366+ # ════════════════════════════════════════════════════════════════════════
2367+ # CODEACT (vol 17, P2) — Executable Code Action vs JSON Tool Calls
2368+ # Per Wang et al. 2024 (huggingface.co/papers/2402.01030)
2369+ # ════════════════════════════════════════════════════════════════════════
2370+
2371+ @app .post ("/agent/codeact/process" , tags = ["Cognitive" ])
2372+ async def codeact_process_endpoint (request : Request ):
2373+ """Detect + validate + execute code action dari LLM output.
2374+ Body: {llm_output: "...```python\\ n...\\ n```", auto_execute?: True}"""
2375+ try :
2376+ body = await request .json ()
2377+ except Exception :
2378+ body = {}
2379+ llm_output = body .get ("llm_output" , "" )
2380+ if not llm_output :
2381+ raise HTTPException (status_code = 400 , detail = "llm_output wajib" )
2382+ try :
2383+ from . import codeact_adapter
2384+ return codeact_adapter .process_llm_output_for_codeact (
2385+ llm_output ,
2386+ auto_execute = bool (body .get ("auto_execute" , True )),
2387+ timeout_seconds = int (body .get ("timeout_seconds" , 10 )),
2388+ )
2389+ except Exception as e :
2390+ raise HTTPException (status_code = 500 , detail = f"codeact fail: { e } " )
2391+
2392+ @app .get ("/admin/codeact/stats" , tags = ["Cognitive" ])
2393+ def codeact_stats_endpoint (request : Request ):
2394+ """Stats CodeAct adapter (total/valid/executed/errors/avg_duration)."""
2395+ if not _admin_ok (request ):
2396+ raise HTTPException (status_code = 403 , detail = "Akses ditolak" )
2397+ try :
2398+ from . import codeact_adapter
2399+ return codeact_adapter .stats ()
2400+ except Exception as e :
2401+ raise HTTPException (status_code = 500 , detail = f"stats fail: { e } " )
2402+
2403+ # ════════════════════════════════════════════════════════════════════════
2404+ # MCP SERVER WRAP (vol 17, P2) — Expose SIDIX tools sebagai MCP server
2405+ # Per modelcontextprotocol.io spec
2406+ # ════════════════════════════════════════════════════════════════════════
2407+
2408+ @app .get ("/mcp/tools" , tags = ["MCP" ])
2409+ def mcp_list_tools_endpoint (request : Request , category : str = "" ):
2410+ """MCP standard tools/list. Public (non-admin tools only)."""
2411+ try :
2412+ from . import mcp_server_wrap
2413+ admin_ok = _admin_ok (request )
2414+ return {
2415+ "tools" : mcp_server_wrap .list_tools (category = category , admin_ok = admin_ok ),
2416+ }
2417+ except Exception as e :
2418+ raise HTTPException (status_code = 500 , detail = f"mcp list fail: { e } " )
2419+
2420+ @app .get ("/mcp/manifest" , tags = ["MCP" ])
2421+ def mcp_manifest_endpoint (request : Request ):
2422+ """Full MCP server manifest export — untuk register di Claude Desktop /
2423+ Cursor / smolagents / continue.dev."""
2424+ try :
2425+ from . import mcp_server_wrap
2426+ return mcp_server_wrap .export_manifest ()
2427+ except Exception as e :
2428+ raise HTTPException (status_code = 500 , detail = f"manifest fail: { e } " )
2429+
2430+ @app .get ("/admin/mcp/stats" , tags = ["MCP" ])
2431+ def mcp_stats_endpoint (request : Request ):
2432+ """MCP server stats untuk admin."""
2433+ if not _admin_ok (request ):
2434+ raise HTTPException (status_code = 403 , detail = "Akses ditolak" )
2435+ try :
2436+ from . import mcp_server_wrap
2437+ return mcp_server_wrap .stats ()
2438+ except Exception as e :
2439+ raise HTTPException (status_code = 500 , detail = f"stats fail: { e } " )
2440+
2441+ # ════════════════════════════════════════════════════════════════════════
2442+ # 1000 HANDS ORCHESTRATOR (vol 17 stub, Q1 2027 full)
2443+ # Multi-persona parallel sub-task dispatch + synthesis
2444+ # ════════════════════════════════════════════════════════════════════════
2445+
2446+ @app .post ("/agent/hands/orchestrate" , tags = ["Cognitive" ])
2447+ async def hands_orchestrate_endpoint (request : Request ):
2448+ """1000 hands orchestrator: split goal → dispatch per persona → synthesize.
2449+ Vol 17 = sequential stub (3-4 sub-task, 1-3 menit total).
2450+ Q1 2027 = real parallel via Celery+Redis.
2451+ Body: {user_goal, use_llm_split?: True}"""
2452+ if not _admin_ok (request ):
2453+ raise HTTPException (status_code = 403 , detail = "Akses ditolak (mahal, admin only saat stub)" )
2454+ try :
2455+ body = await request .json ()
2456+ except Exception :
2457+ body = {}
2458+ user_goal = (body .get ("user_goal" ) or "" ).strip ()
2459+ if not user_goal :
2460+ raise HTTPException (status_code = 400 , detail = "user_goal wajib" )
2461+ try :
2462+ from . import hands_orchestrator
2463+ from dataclasses import asdict
2464+ result = hands_orchestrator .orchestrate (
2465+ user_goal ,
2466+ use_llm_split = bool (body .get ("use_llm_split" , True )),
2467+ )
2468+ return {"ok" : True , "goal" : asdict (result )}
2469+ except Exception as e :
2470+ raise HTTPException (status_code = 500 , detail = f"orchestrate fail: { e } " )
2471+
2472+ @app .get ("/admin/hands/stats" , tags = ["Cognitive" ])
2473+ def hands_stats_endpoint (request : Request ):
2474+ """1000 hands orchestrator stats."""
2475+ if not _admin_ok (request ):
2476+ raise HTTPException (status_code = 403 , detail = "Akses ditolak" )
2477+ try :
2478+ from . import hands_orchestrator
2479+ return hands_orchestrator .stats ()
2480+ except Exception as e :
2481+ raise HTTPException (status_code = 500 , detail = f"stats fail: { e } " )
2482+
23632483 @app .get ("/agent/context-triple" , tags = ["Cognitive" ])
23642484 async def context_triple_endpoint (request : Request , user_id : str = "" , verbose : bool = False ):
23652485 """Derive zaman/makan/haal context triple untuk current request.
0 commit comments