cns/api/
FastAPI endpoints. Thin routing layer — validates input, sets user context, delegates to services.
Files
chat.py—POST /chat. Non-streaming chat. Handles image compression (two tiers: 1200px inference, 512px storage), document processing (PDF/DOCX/XLSX/TXT/CSV/JSON), per-user distributed request lock (60s TTL). Supportsinclude_thinkingflag to include thinking trace in response. Delegates toorchestrator.process_message().websocket_chat.py—WebSocket /ws/chat. Real-time bidirectional chat with custom auth protocol (first message = auth token). Queue-based streaming: orchestrator pushes events via callback, async loop consumes and sends. Thinking events gated behind per-messageinclude_thinkingflag (default false). Thread context propagation viarun_in_threadpool().actions.py—POST /actions. Domain-routed state mutations (~2200 lines). Domains: REMINDER, MEMORY, CONTACTS, USER, DOMAIN_KNOWLEDGE, CONTINUUM, LORA. Schema-based validation per action. AlsoGET /tools/{tool_name}/queryfor direct tool polling.data.py—GET /data?type=.... Unified read endpoint. Types: HISTORY, MEMORIES, DASHBOARD, USER, DOMAINDOCS, WORKING_MEMORY, LORA. Pagination via offset/limit.health.py—GET /health,/health/threads,/health/thread-dump. No auth required.tool_config.py— CRUD for per-user tool configuration. Lists configurable tools, gets/sets config viaUserCredentialService, validates against Pydantic schemas.update.py—GET /check_update. Version comparison against/VERSIONfile. No auth required.demo.py—POST /demo/session,POST /demo/chat. Ephemeral demo sessions in Valkey (15 min TTL, 5 msg/min rate limit). Supports account conversion flow.files.py—GET /files/{file_id}. Serves code execution file artifacts fromdata/users/{user_id}/tmp/. Security: auth gate, file_id regex validation, path traversal guard, forced-download headers (Content-Disposition: attachment,application/octet-stream).federation.py—POST /federation/deliver. Server-to-server webhook for Lattice federation. Receives inbound federated messages and delivers to local users viaPagerTool. No user auth (Lattice handles verification).base.py— Response types (SuccessResponse,ErrorResponsefrozen dataclasses),ErrorDetail/ResponseMetaTypedDicts,APIResponse = SuccessResponse | ErrorResponseunion alias, error hierarchy (APIError,ValidationError,NotFoundError,ServiceUnavailableError),BaseHandlertemplate method pattern.
Patterns to Follow
Endpoint Structure
- Protected routes use
Depends(get_current_user)fromauth.api. - Set user context immediately:
set_current_user_id(user_id)at the top of the handler. - Use
BaseHandlerfor request processing with automatic error handling and request IDs. - Return responses via
create_success_response()/create_error_response().
Response Types
base.py defines two frozen dataclasses for API responses:
SuccessResponse(data: dict[str, Any], meta: ResponseMeta)—.to_dict()hardcodes"success": TrueErrorResponse(error: ErrorDetail, meta: ResponseMeta)—.to_dict()hardcodes"success": FalseAPIResponse = SuccessResponse | ErrorResponse— union alias (cannot be used withisinstance; use the concrete types)ErrorDetail(TypedDict)—{code: str, message: str, details: dict[str, Any]}ResponseMeta(TypedDict, total=False)—{timestamp: str, request_id: str}- Both are frozen; use
dataclasses.replace()for mutation (seeauth/api.pyfor pattern) - Construct via
create_success_response(data, meta)/create_error_response(exception, request_id)
Wire format (unchanged):
{"success": true, "data": {...}, "meta": {"request_id": "..."}}
{"success": false, "error": {"code": "...", "message": "...", "details": {...}}, "meta": {"request_id": "..."}}
Actions Domain Routing
- Each domain has a handler class extending
BaseDomainHandler. - Actions define validation schemas:
required,optional,typesfields. - Domain handlers validate, then delegate to tools or repositories.
- New domains: add handler class, add to domain router in
ActionsEndpoint.
Concurrency
UserRequestLockensures one active request per user (distributed via Valkey, 60s TTL).- WebSocket uses
run_in_threadpool()with context propagation for sync orchestrator code.
Error Handling
- All errors extend
APIError(Exception)withmessage: str,code: str,details: dict[str, Any] create_error_response(exception, request_id)maps anyAPIErrorsubclass toErrorResponsewith the correctErrorDetail- HTTP 400:
ValidationError(bad input, schema violations) - HTTP 402:
InsufficientBalanceError(billing) - HTTP 404:
NotFoundError(resource not found) - HTTP 500: Unhandled exceptions (logged, generic message to client)
- HTTP 503:
ServiceUnavailableError(infrastructure down) - Infrastructure failures propagate (no catch-and-return-None). Only
exceptfor adding context before re-raising.