Chat Handlers
Handler Overview
Chat handlers in chat/handlers.rs split into two categories:
- Pure DB operations — conversation CRUD handled entirely in Rust against PostgreSQL
- gRPC-proxied operations — message sending and streaming delegated to the Intelligence service
Conversation CRUD (Pure Rust + DB)
create_conversation
POST /chat/conversations
Body: { title?: string, metadata?: object }- Generates a new
Uuid::new_v4()for the conversation ID (note: theconversationstable hasid UUID PRIMARY KEYwith noDEFAULT gen_random_uuid()— the caller must provide the UUID) - Inserts row into
conversationswithuser_idfromauth_middlewareextension - Returns:
{ id, user_id, title, metadata, created_at, updated_at }
list_conversations
GET /chat/conversations?cursor=<uuid>&limit=<n>- Cursor-based pagination ordered by
updated_at DESC - Filters by
user_idfrom session - Returns:
{ conversations[], next_cursor?, total_count }
get_conversation
GET /chat/conversations/{id}- Fetches from
conversationstable (verifiesuser_idownership) - Fetches messages from
chat_messagestable (written by Python Intelligence) - Ownership check:
WHERE id = $1 AND user_id = $2 - Returns full conversation with messages and source chunks
update_conversation / delete_conversation
- Both verify
user_idownership before mutation - DELETE cascades to
chat_messagesvia foreign key
Message Operations (gRPC-proxied)
send_message (Non-streaming)
stream_chat (SSE Streaming)
SSE Bridge implementation uses async-stream + Axum’s Sse<impl Stream<Item = Event>>:
let stream = async_stream::stream! {
while let Some(chunk) = grpc_stream.message().await? {
let event = Event::default().data(serde_json::to_string(&chunk)?);
yield Ok::<Event, Error>(event);
}
}
Sse::new(stream).keep_alive(KeepAlive::default())generate_conversation_title
POST /chat/conversations/{id}/generate-title
Body: { user_message: string, assistant_message: string }- Calls gRPC
Chat.GenerateTitle(GenerateTitleRequest) - Intelligence service uses the LLM to generate a concise title
- Rust updates
conversations.titlein DB - Returns:
{ title: string }
Error Handling
Chat handler errors are typed in chat/error.rs. gRPC status codes are mapped to HTTP status codes:
| gRPC Status | HTTP Status | Scenario |
|---|---|---|
NOT_FOUND | 404 | Conversation not found in Intelligence |
PERMISSION_DENIED | 403 | User doesn’t own the conversation |
INVALID_ARGUMENT | 400 | Malformed request message |
RESOURCE_EXHAUSTED | 429 | Rate limited by Intelligence |
UNAVAILABLE | 503 | Intelligence service down |
DEADLINE_EXCEEDED | 504 | LLM timeout (> 1200s for chat) |
INTERNAL | 500 | Unhandled Python exception |
Last updated on