Skip to content

Commit b7a7a79

Browse files
fahmiwolclaude
andcommitted
FEAT vol 17: CodeAct + MCP wrap + 1000 hands stub - Q3 P1 100% SHIP
User: 'itu masih ada sisa yg belum?' (CodeAct, MCP wrap, 1000 hands) NO PIVOT. 3 P2 deliverable closure. Q3 P1 sekarang 9/9 + 1 stub. Modul 1 - apps/brain_qa/brain_qa/codeact_adapter.py (~280 LOC): Per Wang et al 2024. Detect fenced/tagged Python block, AST validate, 14 forbidden patterns, execute via code_sandbox existing. Coexist dengan tool_synthesizer (vol 5): codeact ephemeral, synth permanent. Modul 2 - apps/brain_qa/brain_qa/mcp_server_wrap.py (~280 LOC): 17 SIDIX tools wrapped sebagai MCP server (Anthropic spec). 12 cognitive + 2 search + 1 memory + 1 audio + 1 code. 12 public + 5 admin-only. export_manifest() = standalone deploy ready. Modul 3 - apps/brain_qa/brain_qa/hands_orchestrator.py (~310 LOC): Vol 17 stub sequential, Q1 2027 full Celery+Redis parallel. Plan splitter (LLM atau heuristic), persona affinity 5 keywords, dispatcher sub-task per persona, AYMAN synthesizer. agent_serve.py 7 endpoint baru: POST /agent/codeact/process, GET /admin/codeact/stats GET /mcp/tools, GET /mcp/manifest, GET /admin/mcp/stats POST /agent/hands/orchestrate, GET /admin/hands/stats Validation: 3 modul import OK, syntax valid, live test passed. Q3 P1 SHIP 9/9 + stub: - Pilar 2 Critic + Tadabbur (vol 10) - Context Triple + Persona Router (vol 11) - Pilar 3 Nightly LoRA + Pilar 4 Trend RSS + Sensorial (vol 15) - CodeAct + MCP wrap (vol 17 today) - 1000 hands stub (vol 17, full Q1 2027) Compound: 17 vol 28+ commits ~7300 LOC ~76k kata docs 50 endpoint live. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 472b06c commit b7a7a79

4 files changed

Lines changed: 1339 additions & 1 deletion

File tree

apps/brain_qa/brain_qa/agent_serve.py

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)