Skip to Content
API Service (Rust)Chat Handlers

Chat Handlers

Handler Overview

Chat handlers in chat/handlers.rs split into two categories:

  1. Pure DB operations — conversation CRUD handled entirely in Rust against PostgreSQL
  2. 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: the conversations table has id UUID PRIMARY KEY with no DEFAULT gen_random_uuid() — the caller must provide the UUID)
  • Inserts row into conversations with user_id from auth_middleware extension
  • 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_id from session
  • Returns: { conversations[], next_cursor?, total_count }

get_conversation

GET /chat/conversations/{id}
  • Fetches from conversations table (verifies user_id ownership)
  • Fetches messages from chat_messages table (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_id ownership before mutation
  • DELETE cascades to chat_messages via 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.title in 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 StatusHTTP StatusScenario
NOT_FOUND404Conversation not found in Intelligence
PERMISSION_DENIED403User doesn’t own the conversation
INVALID_ARGUMENT400Malformed request message
RESOURCE_EXHAUSTED429Rate limited by Intelligence
UNAVAILABLE503Intelligence service down
DEADLINE_EXCEEDED504LLM timeout (> 1200s for chat)
INTERNAL500Unhandled Python exception
Last updated on