Session Persistence
Amadev auto-saves chat history to PostgreSQL. Every request to /v1/chat/completions can optionally (or automatically) save the user message and assistant response.
How It Works
Request Flow
POST /v1/chat/completions
body: { session_id?: "abc123", messages: [...], ... }
│
┌─────┴─────┐
│ │
Has ID? No ID?
│ │
┌─────┘ └─────┐
│ │
Lookup conv Auto-create
verify userId new conv
│ │
└─────┬──────────────────┘
│
conversation.id
│
┌──────────┴──────────┐
│ │
Save user msg Save assistant
(await first) (void after)
│ │
└──────────┬──────────┘
│
Response includes
session_id: "..."
Listing: GET /v1/conversations
Detail: GET /v1/conversations/:id
Database Models
model Conversation {
id String @id @default(cuid())
title String @default("New Chat")
userId String?
user User? @relation(...)
messages ChatMessage[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model ChatMessage {
id String @id @default(cuid())
conversationId String
conversation Conversation @relation(...)
role String // "user" or "assistant"
parts Json // [{ type: "text", text: "..." }]
createdAt DateTime @default(now())
}
API Endpoints
POST /v1/chat/completions
Save chat messages by including session_id:
{
"model": "groq/compound",
"session_id": "existing-session-id",
"messages": [
{ "role": "user", "content": "Hello" }
]
}
Response includes session_id:
{
"session_id": "abc123",
"choices": [{ "message": { "content": "Hi there!" } }]
}
If session_id is omitted (non-streaming), a new conversation is auto-created.
Conversation CRUD
| Method | Endpoint | Description |
|---|---|---|
GET | /v1/conversations?limit=50&offset=0 | List conversations |
POST | /v1/conversations | Create conversation { title } |
GET | /v1/conversations/:id | Get with all messages |
PATCH | /v1/conversations/:id | Update title { title } |
DELETE | /v1/conversations/:id | Delete + cascade messages |
Agent Sessions
Agent-managed conversations:
| Method | Endpoint | Description |
|---|---|---|
GET | /v1/sessions/:id/messages | List agent session messages |
POST | /v1/sessions/:id/messages | Add message to agent session |
Implementation Details
ensureConversation(conversationId?, userId?)
- If
conversationIdprovided → lookup & verify ownership - If not provided →
prisma.conversation.create() - Returns
{ id, isNew }
saveChatMessage(conversationId, role, content)
- Creates
ChatMessagerecord withparts: [{ type: "text", text: content }] - Auto-title: if message count ≤ 2, uses first user message as title (truncated at 80 chars)
- Updates conversation
updatedAttimestamp
Ordering Guarantee
User messages are saved with await before proceeding, assistant messages are saved with void. This ensures:
user → assistant → user → assistant → ...
Streaming Caveat
Streaming (stream: true) only saves sessions if session_id is explicitly provided. Auto-creation is disabled for streaming to avoid saving incomplete conversations.
Viewing Conversations
From Code
const convs = await prisma.conversation.findMany({
where: { userId: "..." },
orderBy: { updatedAt: "desc" },
include: { _count: { select: { messages: true } } },
});
From Admin
Visit /admin/usage to see session activity in the daily usage chart.
From API
curl -H "X-API-Key: amallm_..." /v1/conversations
curl -H "X-API-Key: amallm_..." /v1/conversations/:id
