main¶
main ¶
FastAPI application — Alkiviades streaming SSE chat endpoint with authentication.
get_sql_session_mgr ¶
get_sql_session_mgr() -> SQLSessionManager
Get or create the module-level SQLSessionManager (lazy init).
Returns the singleton SQLSessionManager instance. Initializes on first call if not already set — this covers both the lifespan path and the test fixture path where lifespan may not be triggered.
lifespan
async
¶
Application lifespan — init DB, bootstrap admin, migrate legacy sessions on startup.
login
async
¶
login(
body: LoginRequest, response: Response, request: Request
) -> dict
Authenticate user with email/password, return JWT access token and set refresh cookie.
Validates credentials against the SQLite users table, creates a JWT access token (15-minute expiry) and an httpOnly refresh cookie (7 days). Returns a 401 "Invalid credentials" for wrong email, wrong password, or nonexistent user. Rate-limited at 5 requests per 60 seconds per IP.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body
|
LoginRequest
|
LoginRequest with email and password fields. |
required |
response
|
Response
|
FastAPI Response object used to set the refresh cookie. |
required |
request
|
Request
|
FastAPI Request object for rate limiting by client IP. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Dict with access_token, token_type, is_admin flag, and role. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
401 if credentials are invalid. |
refresh
async
¶
Issue a new access token using a valid refresh token from the httpOnly cookie.
Validates the refresh token from the request cookie: checks it exists, hasn't been revoked, and hasn't expired. Rotates the token — revokes the old one and issues a new refresh cookie. Rate-limited at 5 requests per 60 seconds per IP.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
Request
|
FastAPI Request with the httpOnly refresh_token cookie. |
required |
response
|
Response
|
FastAPI Response for setting the new refresh cookie. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Dict with a fresh access_token and token_type. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
401 if cookie is missing, token is invalid, revoked, or expired. |
logout
async
¶
Revoke refresh token and clear cookie.
Idempotent — returns 200 even without a valid auth token. If a refresh_token cookie is present, marks it as revoked in the database and clears the cookie from the response.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
Request
|
FastAPI Request with the optional refresh_token cookie. |
required |
response
|
Response
|
FastAPI Response for clearing the refresh cookie. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Dict with status 'ok'. |
auth_me
async
¶
auth_me(user: dict = Depends(get_current_user)) -> dict
Return current user profile including role.
Requires a valid JWT access token in the Authorization header.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user
|
dict
|
Decoded JWT payload injected by get_current_user dependency. |
Depends(get_current_user)
|
Returns:
| Type | Description |
|---|---|
dict
|
Dict with id, email, role, and is_admin fields. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
404 if the user no longer exists in the database. |
health
async
¶
Public health check endpoint.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Dict with status 'ok'. |
health_debug
async
¶
health_debug(user: dict = Depends(require_admin)) -> dict
System diagnostics endpoint — admin only.
Returns Python version, API key status, knowledge base size, embedding configuration, and environment variables (with secrets redacted).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user
|
dict
|
Decoded JWT payload — must have admin role. |
Depends(require_admin)
|
Returns:
| Type | Description |
|---|---|
dict
|
Dict with system diagnostic information. |
admin_logs
async
¶
admin_logs(
limit: int = 100, user: dict = Depends(require_admin)
) -> dict
Return the last N lines of the application log file.
Admin only. Reads from the rotating file log.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
limit
|
int
|
Maximum number of log lines to return (default 100). |
100
|
user
|
dict
|
Decoded JWT payload — must have admin role. |
Depends(require_admin)
|
Returns:
| Type | Description |
|---|---|
dict
|
Dict with a 'lines' key containing the log lines as a list of strings. |
admin_logs_stream
async
¶
admin_logs_stream(
request: Request, user: dict = Depends(require_admin)
) -> EventSourceResponse
SSE stream of new log entries.
Admin only. Polls the log file every 2 seconds for new content and pushes each new line as an SSE event. Automatically stops when the client disconnects.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
Request
|
FastAPI Request for disconnect detection. |
required |
user
|
dict
|
Decoded JWT payload — must have admin role. |
Depends(require_admin)
|
Returns:
| Type | Description |
|---|---|
EventSourceResponse
|
EventSourceResponse yielding 'log' events with new log lines. |
admin_list_users
async
¶
admin_list_users(
user: dict = Depends(require_admin),
) -> list[dict]
List all users with API key status.
Admin only. Returns all registered users ordered by creation date descending, with per-user key configuration status.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user
|
dict
|
Decoded JWT payload — must have admin role. |
Depends(require_admin)
|
Returns:
| Type | Description |
|---|---|
list[dict]
|
List of dicts with id, email, role, queries_remaining, |
list[dict]
|
created_at, and keys status. |
admin_create_user
async
¶
admin_create_user(
body: dict, user: dict = Depends(require_admin)
) -> dict
Create a new user account.
Admin only. Creates a standard user with the given email and password. Password must be at least 8 characters. The email must be unique.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body
|
dict
|
Dict with 'email' and 'password' keys. |
required |
user
|
dict
|
Decoded JWT payload — must have admin role. |
Depends(require_admin)
|
Returns:
| Type | Description |
|---|---|
dict
|
Dict with id, email, role, and created flag. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
422 if email or password missing/invalid, 409 if email already exists. |
admin_delete_user
async
¶
admin_delete_user(
user_id: str, user: dict = Depends(require_admin)
) -> dict
Delete a user and all their associated data.
Admin only. Removes the user's sessions, messages, refresh tokens, and the user record. Cannot delete admin accounts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
str
|
UUID of the user to delete. |
required |
user
|
dict
|
Decoded JWT payload — must have admin role. |
Depends(require_admin)
|
Returns:
| Type | Description |
|---|---|
dict
|
Dict with deleted flag and user_id. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
404 if user not found, 403 if target is admin. |
admin_reset_user_keys
async
¶
admin_reset_user_keys(
user_id: str, user: dict = Depends(require_admin)
) -> dict
Clear a user's personal API keys.
Admin only. Removes any user-configured API keys, causing the user to fall back to system keys on their next request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
str
|
UUID of the target user. |
required |
user
|
dict
|
Decoded JWT payload — must have admin role. |
Depends(require_admin)
|
Returns:
| Type | Description |
|---|---|
dict
|
Dict with status and the user's new key status. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
404 if user not found. |
get_axes
async
¶
Get the current global axis values.
Returns the three political axes (ethical, alignment, social) that modulate all agent responses.
Returns:
| Type | Description |
|---|---|
dict
|
Dict with ethical, alignment, and social float values. |
set_axes
async
¶
set_axes(
body: dict, user: dict = Depends(get_current_user)
) -> dict
Update the global axis values.
Accepts partial updates — only provided keys are modified. Values are clamped to the range [-1.0, 1.0].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body
|
dict
|
Dict with any of 'ethical', 'alignment', 'social' keys. |
required |
user
|
dict
|
Decoded JWT payload (any authenticated user). |
Depends(get_current_user)
|
Returns:
| Type | Description |
|---|---|
dict
|
The updated axes dict with all three current values. |
get_user_keys
async
¶
get_user_keys(
user: dict = Depends(get_current_user),
) -> dict
Return the current user's API key status.
Values are redacted — only indicates whether each key is configured (user-provided or system fallback).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user
|
dict
|
Decoded JWT payload. |
Depends(get_current_user)
|
Returns:
| Type | Description |
|---|---|
dict
|
Dict with deepseek, tavily, and scrapingant key status entries. |
set_user_keys
async
¶
set_user_keys(
body: dict, user: dict = Depends(get_current_user)
) -> dict
Save personal API keys for the current user.
Partial update — only provided keys are stored. Supported keys: deepseek, tavily, scrapingant. Values are Fernet-encrypted at rest.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body
|
dict
|
Dict with optional 'deepseek', 'tavily', 'scrapingant' string values. |
required |
user
|
dict
|
Decoded JWT payload. |
Depends(get_current_user)
|
Returns:
| Type | Description |
|---|---|
dict
|
Dict with updated key status for all three providers. |
clear_user_keys
async
¶
clear_user_keys(
user: dict = Depends(get_current_user),
) -> dict
Remove all personal API keys, reverting to system keys.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user
|
dict
|
Decoded JWT payload. |
Depends(get_current_user)
|
Returns:
| Type | Description |
|---|---|
dict
|
Dict with updated key status showing system fallback for all providers. |
list_sessions
async
¶
list_sessions(
user: dict = Depends(get_current_user),
) -> list[dict]
List sessions for the authenticated user.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user
|
dict
|
Decoded JWT payload. |
Depends(get_current_user)
|
Returns:
| Type | Description |
|---|---|
list[dict]
|
List of session dicts with id, title, created_at, updated_at, |
list[dict]
|
and turn_count for each session. |
get_session
async
¶
get_session(
session_id: str,
user: dict = Depends(get_current_user),
preview: bool = False,
) -> dict
Get session details with full conversation history.
Returns all turns by default. With ?preview=true, returns only the first 3 turns (for sidebar hover previews).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
UUID of the session to load. |
required |
user
|
dict
|
Decoded JWT payload. |
Depends(get_current_user)
|
preview
|
bool
|
If true, return only the first 3 turns. |
False
|
Returns:
| Type | Description |
|---|---|
dict
|
Session dict with id, title, axes, turns list, and timestamps. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
404 if session not found or not owned by user. |
delete_session_endpoint
async
¶
delete_session_endpoint(
session_id: str, user: dict = Depends(get_current_user)
) -> dict
Delete a session and all its messages.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
UUID of the session to delete. |
required |
user
|
dict
|
Decoded JWT payload. |
Depends(get_current_user)
|
Returns:
| Type | Description |
|---|---|
dict
|
Dict with status 'deleted'. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
404 if session not found or not owned by user. |
rebuild_kb
async
¶
rebuild_kb(user: dict = Depends(require_admin)) -> dict
Rebuild the knowledge base from source files.
Admin only. Re-processes all files in processed/ and stratcom/, rebuilding chunk vectors and saving to the vector pickle file. Returns a diff of files added, removed, and changed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user
|
dict
|
Decoded JWT payload — must have admin role. |
Depends(require_admin)
|
Returns:
| Type | Description |
|---|---|
dict
|
Dict with chunk count and diff dict (added, removed, changed lists). |
chat
async
¶
chat(
body: ChatRequest,
user: dict = Depends(get_current_user),
) -> dict
Non-streaming chat endpoint — runs agent and returns complete response.
Fallback for clients that don't support SSE. Resolves all tool calls and streaming internally, then returns the full reply.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body
|
ChatRequest
|
ChatRequest with message, session_id, and optional axes override. |
required |
user
|
dict
|
Decoded JWT payload. |
Depends(get_current_user)
|
Returns:
| Type | Description |
|---|---|
dict
|
Dict with reply, session_id, and sources list. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
400 if no DeepSeek API key is configured. |
chat_stream
async
¶
chat_stream(
body: ChatRequest,
request: Request,
user: dict = Depends(get_current_user),
) -> EventSourceResponse
SSE streaming chat endpoint.
Streams the agent's response token by token alongside RAG source citations, tool call events, and tool results. Sends heartbeat events every 15 seconds to keep the connection alive. On completion, persists the conversation turn to SQLite.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body
|
ChatRequest
|
ChatRequest with message, session_id, and optional axes override. |
required |
request
|
Request
|
FastAPI Request for disconnect detection. |
required |
user
|
dict
|
Decoded JWT payload. |
Depends(get_current_user)
|
Returns:
| Type | Description |
|---|---|
EventSourceResponse
|
EventSourceResponse yielding token, source, tool_call, |
EventSourceResponse
|
tool_result, done, error, and heartbeat events. |
Raises:
| Type | Description |
|---|---|
HTTPException
|
400 if no DeepSeek API key is configured. |