2026-02-09 21:51:42 -08:00
|
|
|
"""Session and prompt routes."""
|
|
|
|
|
|
|
|
|
|
import uuid
|
|
|
|
|
from typing import Any
|
|
|
|
|
|
|
|
|
|
from fastapi import APIRouter, HTTPException, WebSocket, WebSocketDisconnect
|
|
|
|
|
|
fix: deep GPU integration, fix all ruff/mypy issues, add .dockerignore
- Integrate GPU scoring inline into reasoning/multi_path.py (auto-uses GPU when available)
- Integrate GPU deduplication into multi_agent/consensus_engine.py
- Add semantic_search() method to memory/semantic_graph.py with GPU acceleration
- Integrate GPU training into self_improvement/training.py AutoTrainer
- Fix all 758 ruff lint issues (whitespace, import sorting, unused imports, ambiguous vars, undefined names)
- Fix all 40 mypy type errors across the codebase (no-any-return, union-attr, arg-type, etc.)
- Fix deprecated ruff config keys (select/ignore -> [tool.ruff.lint])
- Add .dockerignore to exclude .venv/, tests/, docs/ from Docker builds
- Add type hints and docstrings to verification/outcome.py
- Fix E402 import ordering in witness_agent.py
- Fix F821 undefined names in vector_pgvector.py and native.py
- Fix E741 ambiguous variable names in reflective.py and recommender.py
All 276 tests pass. 0 ruff errors. 0 mypy errors.
Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
2026-04-28 05:48:37 +00:00
|
|
|
from fusionagi.api.dependencies import (
|
|
|
|
|
get_event_bus,
|
|
|
|
|
get_orchestrator,
|
|
|
|
|
get_safety_pipeline,
|
|
|
|
|
get_session_store,
|
|
|
|
|
)
|
2026-02-09 21:51:42 -08:00
|
|
|
from fusionagi.api.websocket import handle_stream
|
fix: deep GPU integration, fix all ruff/mypy issues, add .dockerignore
- Integrate GPU scoring inline into reasoning/multi_path.py (auto-uses GPU when available)
- Integrate GPU deduplication into multi_agent/consensus_engine.py
- Add semantic_search() method to memory/semantic_graph.py with GPU acceleration
- Integrate GPU training into self_improvement/training.py AutoTrainer
- Fix all 758 ruff lint issues (whitespace, import sorting, unused imports, ambiguous vars, undefined names)
- Fix all 40 mypy type errors across the codebase (no-any-return, union-attr, arg-type, etc.)
- Fix deprecated ruff config keys (select/ignore -> [tool.ruff.lint])
- Add .dockerignore to exclude .venv/, tests/, docs/ from Docker builds
- Add type hints and docstrings to verification/outcome.py
- Fix E402 import ordering in witness_agent.py
- Fix F821 undefined names in vector_pgvector.py and native.py
- Fix E741 ambiguous variable names in reflective.py and recommender.py
All 276 tests pass. 0 ruff errors. 0 mypy errors.
Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
2026-04-28 05:48:37 +00:00
|
|
|
from fusionagi.core import (
|
|
|
|
|
extract_sources_from_head_outputs,
|
|
|
|
|
run_dvadasa,
|
|
|
|
|
select_heads_for_complexity,
|
|
|
|
|
)
|
|
|
|
|
from fusionagi.schemas.commands import UserIntent, parse_user_input
|
2026-02-09 21:51:42 -08:00
|
|
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _ensure_init():
|
|
|
|
|
from fusionagi.api.dependencies import ensure_initialized
|
|
|
|
|
ensure_initialized()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("")
|
|
|
|
|
def create_session(user_id: str | None = None) -> dict[str, Any]:
|
Full optimization: 38 improvements across frontend, backend, infrastructure, and docs
Frontend (17 items):
- Virtualized message list with batch loading
- CSS split with skeleton, drawer, search filter, message action styles
- Code splitting via React.lazy + Suspense for Admin/Ethics/Settings pages
- Skeleton loading components (Skeleton, SkeletonCard, SkeletonGrid)
- Debounced search/filter component (SearchFilter)
- Error boundary with fallback UI
- Keyboard shortcuts (Ctrl+K search, Ctrl+Enter send, Escape dismiss)
- Page transition animations (fade-in)
- PWA support (manifest.json + service worker)
- WebSocket auto-reconnect with exponential backoff (10 retries)
- Chat history persistence to localStorage (500 msg limit)
- Message edit/delete on hover
- Copy-to-clipboard on code blocks
- Mobile drawer (bottom-sheet for consensus panel)
- File upload support
- User preferences sync to backend
Testing (8 items):
- Component tests: Toast, Markdown, ChatMessage, Avatar, ErrorBoundary, Skeleton
- Hook tests: useChatHistory
- E2E smoke tests (5 tests)
- Accessibility audit utility
Backend (12 items):
- Vector memory with cosine similarity search
- TTS/STT adapter factory wiring
- Geometry kernel with orphan detection
- Tenant registry with CRUD operations
- Response cache with TTL
- Connection pool (async)
- Background task queue
- Health check endpoints (/health, /ready)
- Request tracing middleware (X-Request-ID)
- API key rotation mechanism
- Environment-based config (settings.py)
- API route documentation improvements
Infrastructure (4 items):
- Grafana dashboard template
- Database migration system
- Storybook configuration
Documentation (3 items):
- ADR-001: Advisory Governance Model
- ADR-002: Twelve-Head Architecture
- ADR-003: Consequence Engine
552 Python tests + 45 frontend tests passing, 0 ruff errors.
Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
2026-05-02 03:08:08 +00:00
|
|
|
"""Create a new FusionAGI session.
|
|
|
|
|
|
|
|
|
|
Returns a session_id that can be used for subsequent prompts.
|
|
|
|
|
Each session maintains its own conversation history and context.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
user_id: Optional user identifier for tenant-scoped sessions.
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
JSON with session_id and user_id.
|
|
|
|
|
"""
|
2026-02-09 21:51:42 -08:00
|
|
|
_ensure_init()
|
|
|
|
|
store = get_session_store()
|
|
|
|
|
if not store:
|
|
|
|
|
raise HTTPException(status_code=503, detail="Session store not initialized")
|
|
|
|
|
session_id = str(uuid.uuid4())
|
|
|
|
|
store.create(session_id, user_id)
|
|
|
|
|
return {"session_id": session_id, "user_id": user_id}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/{session_id}/prompt")
|
|
|
|
|
def submit_prompt(session_id: str, body: dict[str, Any]) -> dict[str, Any]:
|
Full optimization: 38 improvements across frontend, backend, infrastructure, and docs
Frontend (17 items):
- Virtualized message list with batch loading
- CSS split with skeleton, drawer, search filter, message action styles
- Code splitting via React.lazy + Suspense for Admin/Ethics/Settings pages
- Skeleton loading components (Skeleton, SkeletonCard, SkeletonGrid)
- Debounced search/filter component (SearchFilter)
- Error boundary with fallback UI
- Keyboard shortcuts (Ctrl+K search, Ctrl+Enter send, Escape dismiss)
- Page transition animations (fade-in)
- PWA support (manifest.json + service worker)
- WebSocket auto-reconnect with exponential backoff (10 retries)
- Chat history persistence to localStorage (500 msg limit)
- Message edit/delete on hover
- Copy-to-clipboard on code blocks
- Mobile drawer (bottom-sheet for consensus panel)
- File upload support
- User preferences sync to backend
Testing (8 items):
- Component tests: Toast, Markdown, ChatMessage, Avatar, ErrorBoundary, Skeleton
- Hook tests: useChatHistory
- E2E smoke tests (5 tests)
- Accessibility audit utility
Backend (12 items):
- Vector memory with cosine similarity search
- TTS/STT adapter factory wiring
- Geometry kernel with orphan detection
- Tenant registry with CRUD operations
- Response cache with TTL
- Connection pool (async)
- Background task queue
- Health check endpoints (/health, /ready)
- Request tracing middleware (X-Request-ID)
- API key rotation mechanism
- Environment-based config (settings.py)
- API route documentation improvements
Infrastructure (4 items):
- Grafana dashboard template
- Database migration system
- Storybook configuration
Documentation (3 items):
- ADR-001: Advisory Governance Model
- ADR-002: Twelve-Head Architecture
- ADR-003: Consequence Engine
552 Python tests + 45 frontend tests passing, 0 ruff errors.
Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
2026-05-02 03:08:08 +00:00
|
|
|
"""Submit a prompt to the 12-headed Dvādaśa pipeline.
|
|
|
|
|
|
|
|
|
|
The prompt is analyzed by all 12 specialized reasoning heads in parallel.
|
|
|
|
|
Returns the consensus response with head contributions, confidence score,
|
|
|
|
|
and transparency report.
|
|
|
|
|
|
|
|
|
|
Supports commands: /head <name>, /show dissent, /sources, /explain.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
session_id: Active session identifier.
|
|
|
|
|
body: JSON body with 'prompt' field.
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
FinalResponse with final_answer, head_contributions, confidence_score,
|
|
|
|
|
and transparency_report.
|
|
|
|
|
"""
|
2026-02-09 21:51:42 -08:00
|
|
|
_ensure_init()
|
|
|
|
|
store = get_session_store()
|
|
|
|
|
orch = get_orchestrator()
|
|
|
|
|
bus = get_event_bus()
|
|
|
|
|
if not store or not orch:
|
|
|
|
|
raise HTTPException(status_code=503, detail="Service not initialized")
|
|
|
|
|
|
|
|
|
|
sess = store.get(session_id)
|
|
|
|
|
if not sess:
|
|
|
|
|
raise HTTPException(status_code=404, detail="Session not found")
|
|
|
|
|
|
|
|
|
|
prompt = body.get("prompt", "")
|
|
|
|
|
parsed = parse_user_input(prompt)
|
|
|
|
|
|
|
|
|
|
if not prompt or not parsed.cleaned_prompt.strip():
|
|
|
|
|
if parsed.intent in (UserIntent.SHOW_DISSENT, UserIntent.RERUN_RISK, UserIntent.EXPLAIN_REASONING, UserIntent.SOURCES):
|
|
|
|
|
hist = sess.get("history", [])
|
|
|
|
|
if hist:
|
|
|
|
|
prompt = hist[-1].get("prompt", "")
|
|
|
|
|
if not prompt:
|
|
|
|
|
raise HTTPException(status_code=400, detail="No previous prompt; provide a prompt for this command")
|
|
|
|
|
else:
|
|
|
|
|
raise HTTPException(status_code=400, detail="prompt is required")
|
|
|
|
|
|
|
|
|
|
effective_prompt = parsed.cleaned_prompt.strip() or prompt
|
|
|
|
|
pipeline = get_safety_pipeline()
|
|
|
|
|
if pipeline:
|
|
|
|
|
pre_result = pipeline.pre_check(effective_prompt)
|
|
|
|
|
if not pre_result.allowed:
|
|
|
|
|
raise HTTPException(status_code=400, detail=pre_result.reason or "Input moderation failed")
|
|
|
|
|
|
|
|
|
|
task_id = orch.submit_task(goal=effective_prompt[:200])
|
|
|
|
|
|
|
|
|
|
# Dynamic head selection
|
|
|
|
|
head_ids = select_heads_for_complexity(effective_prompt)
|
|
|
|
|
if parsed.intent.value == "head_strategy" and parsed.head_id:
|
|
|
|
|
head_ids = [parsed.head_id]
|
|
|
|
|
|
|
|
|
|
force_second = parsed.intent == UserIntent.RERUN_RISK
|
|
|
|
|
return_heads = parsed.intent == UserIntent.SOURCES
|
|
|
|
|
|
|
|
|
|
result = run_dvadasa(
|
|
|
|
|
orchestrator=orch,
|
|
|
|
|
task_id=task_id,
|
|
|
|
|
user_prompt=effective_prompt,
|
|
|
|
|
parsed=parsed,
|
|
|
|
|
head_ids=head_ids if parsed.intent.value != "normal" or body.get("use_all_heads") else None,
|
|
|
|
|
event_bus=bus,
|
|
|
|
|
force_second_pass=force_second,
|
|
|
|
|
return_head_outputs=return_heads,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if return_heads and isinstance(result, tuple):
|
|
|
|
|
final, head_outputs = result
|
|
|
|
|
else:
|
fix: deep GPU integration, fix all ruff/mypy issues, add .dockerignore
- Integrate GPU scoring inline into reasoning/multi_path.py (auto-uses GPU when available)
- Integrate GPU deduplication into multi_agent/consensus_engine.py
- Add semantic_search() method to memory/semantic_graph.py with GPU acceleration
- Integrate GPU training into self_improvement/training.py AutoTrainer
- Fix all 758 ruff lint issues (whitespace, import sorting, unused imports, ambiguous vars, undefined names)
- Fix all 40 mypy type errors across the codebase (no-any-return, union-attr, arg-type, etc.)
- Fix deprecated ruff config keys (select/ignore -> [tool.ruff.lint])
- Add .dockerignore to exclude .venv/, tests/, docs/ from Docker builds
- Add type hints and docstrings to verification/outcome.py
- Fix E402 import ordering in witness_agent.py
- Fix F821 undefined names in vector_pgvector.py and native.py
- Fix E741 ambiguous variable names in reflective.py and recommender.py
All 276 tests pass. 0 ruff errors. 0 mypy errors.
Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
2026-04-28 05:48:37 +00:00
|
|
|
final = result # type: ignore[assignment]
|
2026-02-09 21:51:42 -08:00
|
|
|
head_outputs = []
|
|
|
|
|
|
|
|
|
|
if not final:
|
|
|
|
|
raise HTTPException(status_code=500, detail="Failed to produce response")
|
|
|
|
|
|
|
|
|
|
if pipeline:
|
|
|
|
|
post_result = pipeline.post_check(final.final_answer)
|
|
|
|
|
if not post_result.passed:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=400,
|
|
|
|
|
detail=f"Output scan failed: {', '.join(post_result.flags)}",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
entry = {
|
|
|
|
|
"prompt": effective_prompt,
|
|
|
|
|
"final_answer": final.final_answer,
|
|
|
|
|
"confidence_score": final.confidence_score,
|
|
|
|
|
"head_contributions": final.head_contributions,
|
|
|
|
|
}
|
|
|
|
|
store.append_history(session_id, entry)
|
|
|
|
|
|
|
|
|
|
response: dict[str, Any] = {
|
|
|
|
|
"task_id": task_id,
|
|
|
|
|
"final_answer": final.final_answer,
|
|
|
|
|
"transparency_report": final.transparency_report.model_dump(),
|
|
|
|
|
"head_contributions": final.head_contributions,
|
|
|
|
|
"confidence_score": final.confidence_score,
|
|
|
|
|
}
|
|
|
|
|
if parsed.intent == UserIntent.SHOW_DISSENT:
|
|
|
|
|
response["response_mode"] = "show_dissent"
|
|
|
|
|
response["disputed_claims"] = final.transparency_report.agreement_map.disputed_claims
|
|
|
|
|
elif parsed.intent == UserIntent.EXPLAIN_REASONING:
|
|
|
|
|
response["response_mode"] = "explain"
|
|
|
|
|
elif parsed.intent == UserIntent.SOURCES and head_outputs:
|
|
|
|
|
response["sources"] = extract_sources_from_head_outputs(head_outputs)
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.websocket("/{session_id}/stream")
|
|
|
|
|
async def stream_websocket(websocket: WebSocket, session_id: str) -> None:
|
|
|
|
|
"""WebSocket for streaming Dvādaśa response. Send {\"prompt\": \"...\"} to start."""
|
|
|
|
|
await websocket.accept()
|
|
|
|
|
try:
|
|
|
|
|
data = await websocket.receive_json()
|
|
|
|
|
prompt = data.get("prompt", "")
|
|
|
|
|
async def send_evt(evt: dict) -> None:
|
|
|
|
|
await websocket.send_json(evt)
|
|
|
|
|
await handle_stream(session_id, prompt, send_evt)
|
|
|
|
|
except WebSocketDisconnect:
|
|
|
|
|
pass
|
|
|
|
|
except Exception as e:
|
|
|
|
|
try:
|
|
|
|
|
await websocket.send_json({"type": "error", "message": str(e)})
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|