99
1010from client import AsyncLlamaStackClientHolder
1111from configuration import configuration
12- from models .responses import ConversationResponse , ConversationDeleteResponse
12+ from models .responses import (
13+ ConversationResponse ,
14+ ConversationDeleteResponse ,
15+ ConversationsListResponse ,
16+ ConversationDetails ,
17+ )
18+ from models .database .conversations import UserConversation
1319from auth import get_auth_dependency
14- from utils .endpoints import check_configuration_loaded
20+ from app .database import get_session
21+ from utils .endpoints import check_configuration_loaded , validate_conversation_ownership
1522from utils .suid import check_suid
1623
1724logger = logging .getLogger ("app.endpoints.handlers" )
6673 },
6774}
6875
76+ conversations_list_responses : dict [int | str , dict [str , Any ]] = {
77+ 200 : {
78+ "conversations" : [
79+ {
80+ "conversation_id" : "123e4567-e89b-12d3-a456-426614174000" ,
81+ "created_at" : "2024-01-01T00:00:00Z" ,
82+ "last_message_at" : "2024-01-01T00:05:00Z" ,
83+ "last_used_model" : "gemini/gemini-1.5-flash" ,
84+ "last_used_provider" : "gemini" ,
85+ "message_count" : 5 ,
86+ },
87+ {
88+ "conversation_id" : "456e7890-e12b-34d5-a678-901234567890" ,
89+ "created_at" : "2024-01-01T01:00:00Z" ,
90+ "last_message_at" : "2024-01-01T01:02:00Z" ,
91+ "last_used_model" : "gemini/gemini-2.0-flash" ,
92+ "last_used_provider" : "gemini" ,
93+ "message_count" : 2 ,
94+ },
95+ ]
96+ },
97+ 503 : {
98+ "detail" : {
99+ "response" : "Unable to connect to Llama Stack" ,
100+ "cause" : "Connection error." ,
101+ }
102+ },
103+ }
104+
69105
70106def simplify_session_data (session_data : dict ) -> list [dict [str , Any ]]:
71107 """Simplify session data to include only essential conversation information.
@@ -109,10 +145,64 @@ def simplify_session_data(session_data: dict) -> list[dict[str, Any]]:
109145 return chat_history
110146
111147
148+ @router .get ("/conversations" , responses = conversations_list_responses )
149+ def get_conversations_list_endpoint_handler (
150+ auth : Any = Depends (auth_dependency ),
151+ ) -> ConversationsListResponse :
152+ """Handle request to retrieve all conversations for the authenticated user."""
153+ check_configuration_loaded (configuration )
154+
155+ user_id , _ , _ = auth
156+
157+ logger .info ("Retrieving conversations for user %s" , user_id )
158+
159+ with get_session () as session :
160+ try :
161+ # Get all conversations for this user
162+ user_conversations = (
163+ session .query (UserConversation ).filter_by (user_id = user_id ).all ()
164+ )
165+
166+ # Return conversation summaries with metadata
167+ conversations = [
168+ ConversationDetails (
169+ conversation_id = conv .id ,
170+ created_at = conv .created_at .isoformat () if conv .created_at else None ,
171+ last_message_at = (
172+ conv .last_message_at .isoformat ()
173+ if conv .last_message_at
174+ else None
175+ ),
176+ message_count = conv .message_count ,
177+ last_used_model = conv .last_used_model ,
178+ last_used_provider = conv .last_used_provider ,
179+ )
180+ for conv in user_conversations
181+ ]
182+
183+ logger .info (
184+ "Found %d conversations for user %s" , len (conversations ), user_id
185+ )
186+
187+ return ConversationsListResponse (conversations = conversations )
188+
189+ except Exception as e :
190+ logger .exception (
191+ "Error retrieving conversations for user %s: %s" , user_id , e
192+ )
193+ raise HTTPException (
194+ status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
195+ detail = {
196+ "response" : "Unknown error" ,
197+ "cause" : f"Unknown error while getting conversations for user { user_id } " ,
198+ },
199+ ) from e
200+
201+
112202@router .get ("/conversations/{conversation_id}" , responses = conversation_responses )
113203async def get_conversation_endpoint_handler (
114204 conversation_id : str ,
115- _auth : Any = Depends (auth_dependency ),
205+ auth : Any = Depends (auth_dependency ),
116206) -> ConversationResponse :
117207 """Handle request to retrieve a conversation by ID."""
118208 check_configuration_loaded (configuration )
@@ -128,6 +218,13 @@ async def get_conversation_endpoint_handler(
128218 },
129219 )
130220
221+ user_id , _ , _ = auth
222+
223+ validate_conversation_ownership (
224+ user_id = user_id ,
225+ conversation_id = conversation_id ,
226+ )
227+
131228 agent_id = conversation_id
132229 logger .info ("Retrieving conversation %s" , conversation_id )
133230
@@ -187,7 +284,7 @@ async def get_conversation_endpoint_handler(
187284)
188285async def delete_conversation_endpoint_handler (
189286 conversation_id : str ,
190- _auth : Any = Depends (auth_dependency ),
287+ auth : Any = Depends (auth_dependency ),
191288) -> ConversationDeleteResponse :
192289 """Handle request to delete a conversation by ID."""
193290 check_configuration_loaded (configuration )
@@ -202,6 +299,14 @@ async def delete_conversation_endpoint_handler(
202299 "cause" : f"Conversation ID { conversation_id } is not a valid UUID" ,
203300 },
204301 )
302+
303+ user_id , _ , _ = auth
304+
305+ validate_conversation_ownership (
306+ user_id = user_id ,
307+ conversation_id = conversation_id ,
308+ )
309+
205310 agent_id = conversation_id
206311 logger .info ("Deleting conversation %s" , conversation_id )
207312
0 commit comments