3232 delete_conversation ,
3333 retrieve_conversation ,
3434)
35- from utils .suid import check_suid
35+ from utils .suid import (
36+ check_suid ,
37+ normalize_conversation_id ,
38+ to_llama_stack_conversation_id ,
39+ )
3640
3741logger = logging .getLogger ("app.endpoints.handlers" )
3842router = APIRouter (tags = ["conversations_v3" ])
@@ -282,9 +286,17 @@ async def get_conversation_endpoint_handler(
282286 ).dump_detail (),
283287 )
284288
289+ # Normalize the conversation ID for database operations (strip conv_ prefix if present)
290+ normalized_conv_id = normalize_conversation_id (conversation_id )
291+ logger .debug (
292+ "GET conversation - original ID: %s, normalized ID: %s" ,
293+ conversation_id ,
294+ normalized_conv_id ,
295+ )
296+
285297 user_id = auth [0 ]
286298 if not can_access_conversation (
287- conversation_id ,
299+ normalized_conv_id ,
288300 user_id ,
289301 others_allowed = (
290302 Action .READ_OTHERS_CONVERSATIONS in request .state .authorized_actions
@@ -293,36 +305,50 @@ async def get_conversation_endpoint_handler(
293305 logger .warning (
294306 "User %s attempted to read conversation %s they don't have access to" ,
295307 user_id ,
296- conversation_id ,
308+ normalized_conv_id ,
297309 )
298310 raise HTTPException (
299311 status_code = status .HTTP_403_FORBIDDEN ,
300312 detail = AccessDeniedResponse (
301313 user_id = user_id ,
302314 resource = "conversation" ,
303- resource_id = conversation_id ,
315+ resource_id = normalized_conv_id ,
304316 action = "read" ,
305317 ).dump_detail (),
306318 )
307319
308320 # If reached this, user is authorized to retrieve this conversation
309- conversation = retrieve_conversation (conversation_id )
321+ # Note: We check if conversation exists in DB but don't fail if it doesn't,
322+ # as it might exist in llama-stack but not be persisted yet
323+ conversation = retrieve_conversation (normalized_conv_id )
310324 if conversation is None :
311- raise HTTPException (
312- status_code = status .HTTP_404_NOT_FOUND ,
313- detail = NotFoundResponse (
314- resource = "conversation" , resource_id = conversation_id
315- ).dump_detail (),
325+ logger .warning (
326+ "Conversation %s not found in database, will try llama-stack" ,
327+ normalized_conv_id ,
316328 )
317329
318- logger .info ("Retrieving conversation %s using Conversations API" , conversation_id )
330+ logger .info (
331+ "Retrieving conversation %s using Conversations API" , normalized_conv_id
332+ )
319333
320334 try :
321335 client = AsyncLlamaStackClientHolder ().get_client ()
322336
337+ # Convert to llama-stack format (add 'conv_' prefix if needed)
338+ llama_stack_conv_id = to_llama_stack_conversation_id (normalized_conv_id )
339+ logger .debug (
340+ "Calling llama-stack list_items with conversation_id: %s" ,
341+ llama_stack_conv_id ,
342+ )
343+
323344 # Use Conversations API to retrieve conversation items
324- conversation_items_response = await client .conversations .list_items (
325- conversation_id = conversation_id ,
345+ from llama_stack_client import NOT_GIVEN
346+
347+ conversation_items_response = await client .conversations .items .list (
348+ conversation_id = llama_stack_conv_id ,
349+ after = NOT_GIVEN , # No pagination cursor
350+ include = NOT_GIVEN , # Include all available data
351+ limit = 1000 , # Max items to retrieve
326352 order = "asc" , # Get items in chronological order
327353 )
328354
@@ -348,7 +374,7 @@ async def get_conversation_endpoint_handler(
348374 chat_history = simplify_conversation_items (items_dicts )
349375
350376 return ConversationResponse (
351- conversation_id = conversation_id ,
377+ conversation_id = normalized_conv_id ,
352378 chat_history = chat_history ,
353379 )
354380
@@ -366,7 +392,7 @@ async def get_conversation_endpoint_handler(
366392 raise HTTPException (
367393 status_code = status .HTTP_404_NOT_FOUND ,
368394 detail = NotFoundResponse (
369- resource = "conversation" , resource_id = conversation_id
395+ resource = "conversation" , resource_id = normalized_conv_id
370396 ).dump_detail (),
371397 ) from e
372398
@@ -375,12 +401,12 @@ async def get_conversation_endpoint_handler(
375401
376402 except Exception as e :
377403 # Handle case where conversation doesn't exist or other errors
378- logger .exception ("Error retrieving conversation %s: %s" , conversation_id , e )
404+ logger .exception ("Error retrieving conversation %s: %s" , normalized_conv_id , e )
379405 raise HTTPException (
380406 status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
381407 detail = {
382408 "response" : "Unknown error" ,
383- "cause" : f"Unknown error while getting conversation { conversation_id } : { str (e )} " ,
409+ "cause" : f"Unknown error while getting conversation { normalized_conv_id } : { str (e )} " ,
384410 },
385411 ) from e
386412
@@ -421,9 +447,12 @@ async def delete_conversation_endpoint_handler(
421447 ).dump_detail (),
422448 )
423449
450+ # Normalize the conversation ID for database operations (strip conv_ prefix if present)
451+ normalized_conv_id = normalize_conversation_id (conversation_id )
452+
424453 user_id = auth [0 ]
425454 if not can_access_conversation (
426- conversation_id ,
455+ normalized_conv_id ,
427456 user_id ,
428457 others_allowed = (
429458 Action .DELETE_OTHERS_CONVERSATIONS in request .state .authorized_actions
@@ -432,46 +461,47 @@ async def delete_conversation_endpoint_handler(
432461 logger .warning (
433462 "User %s attempted to delete conversation %s they don't have access to" ,
434463 user_id ,
435- conversation_id ,
464+ normalized_conv_id ,
436465 )
437466 raise HTTPException (
438467 status_code = status .HTTP_403_FORBIDDEN ,
439468 detail = AccessDeniedResponse (
440469 user_id = user_id ,
441470 resource = "conversation" ,
442- resource_id = conversation_id ,
471+ resource_id = normalized_conv_id ,
443472 action = "delete" ,
444473 ).dump_detail (),
445474 )
446475
447476 # If reached this, user is authorized to delete this conversation
448- conversation = retrieve_conversation (conversation_id )
477+ conversation = retrieve_conversation (normalized_conv_id )
449478 if conversation is None :
450479 raise HTTPException (
451480 status_code = status .HTTP_404_NOT_FOUND ,
452481 detail = NotFoundResponse (
453- resource = "conversation" , resource_id = conversation_id
482+ resource = "conversation" , resource_id = normalized_conv_id
454483 ).dump_detail (),
455484 )
456485
457- logger .info ("Deleting conversation %s using Conversations API" , conversation_id )
486+ logger .info ("Deleting conversation %s using Conversations API" , normalized_conv_id )
458487
459488 try :
460489 # Get Llama Stack client
461490 client = AsyncLlamaStackClientHolder ().get_client ()
462491
492+ # Convert to llama-stack format (add 'conv_' prefix if needed)
493+ llama_stack_conv_id = to_llama_stack_conversation_id (normalized_conv_id )
494+
463495 # Use Conversations API to delete the conversation
464- await client .conversations .openai_delete_conversation (
465- conversation_id = conversation_id
466- )
496+ await client .conversations .delete (conversation_id = llama_stack_conv_id )
467497
468- logger .info ("Successfully deleted conversation %s" , conversation_id )
498+ logger .info ("Successfully deleted conversation %s" , normalized_conv_id )
469499
470500 # Also delete from local database
471- delete_conversation (conversation_id = conversation_id )
501+ delete_conversation (conversation_id = normalized_conv_id )
472502
473503 return ConversationDeleteResponse (
474- conversation_id = conversation_id ,
504+ conversation_id = normalized_conv_id ,
475505 success = True ,
476506 response = "Conversation deleted successfully" ,
477507 )
@@ -488,12 +518,12 @@ async def delete_conversation_endpoint_handler(
488518 # If not found in LlamaStack, still try to delete from local DB
489519 logger .warning (
490520 "Conversation %s not found in LlamaStack, cleaning up local DB" ,
491- conversation_id ,
521+ normalized_conv_id ,
492522 )
493- delete_conversation (conversation_id = conversation_id )
523+ delete_conversation (conversation_id = normalized_conv_id )
494524
495525 return ConversationDeleteResponse (
496- conversation_id = conversation_id ,
526+ conversation_id = normalized_conv_id ,
497527 success = True ,
498528 response = "Conversation deleted successfully" ,
499529 )
@@ -503,12 +533,12 @@ async def delete_conversation_endpoint_handler(
503533
504534 except Exception as e :
505535 # Handle case where conversation doesn't exist or other errors
506- logger .exception ("Error deleting conversation %s: %s" , conversation_id , e )
536+ logger .exception ("Error deleting conversation %s: %s" , normalized_conv_id , e )
507537 raise HTTPException (
508538 status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
509539 detail = {
510540 "response" : "Unknown error" ,
511- "cause" : f"Unknown error while deleting conversation { conversation_id } : { str (e )} " ,
541+ "cause" : f"Unknown error while deleting conversation { normalized_conv_id } : { str (e )} " ,
512542 },
513543 ) from e
514544
@@ -547,9 +577,12 @@ async def update_conversation_endpoint_handler(
547577 ).dump_detail (),
548578 )
549579
580+ # Normalize the conversation ID for database operations (strip conv_ prefix if present)
581+ normalized_conv_id = normalize_conversation_id (conversation_id )
582+
550583 user_id = auth [0 ]
551584 if not can_access_conversation (
552- conversation_id ,
585+ normalized_conv_id ,
553586 user_id ,
554587 others_allowed = (
555588 Action .QUERY_OTHERS_CONVERSATIONS in request .state .authorized_actions
@@ -558,66 +591,69 @@ async def update_conversation_endpoint_handler(
558591 logger .warning (
559592 "User %s attempted to update conversation %s they don't have access to" ,
560593 user_id ,
561- conversation_id ,
594+ normalized_conv_id ,
562595 )
563596 raise HTTPException (
564597 status_code = status .HTTP_403_FORBIDDEN ,
565598 detail = AccessDeniedResponse (
566599 user_id = user_id ,
567600 resource = "conversation" ,
568- resource_id = conversation_id ,
601+ resource_id = normalized_conv_id ,
569602 action = "update" ,
570603 ).dump_detail (),
571604 )
572605
573606 # If reached this, user is authorized to update this conversation
574- conversation = retrieve_conversation (conversation_id )
607+ conversation = retrieve_conversation (normalized_conv_id )
575608 if conversation is None :
576609 raise HTTPException (
577610 status_code = status .HTTP_404_NOT_FOUND ,
578611 detail = NotFoundResponse (
579- resource = "conversation" , resource_id = conversation_id
612+ resource = "conversation" , resource_id = normalized_conv_id
580613 ).dump_detail (),
581614 )
582615
583616 logger .info (
584617 "Updating metadata for conversation %s using Conversations API" ,
585- conversation_id ,
618+ normalized_conv_id ,
586619 )
587620
588621 try :
589622 # Get Llama Stack client
590623 client = AsyncLlamaStackClientHolder ().get_client ()
591624
625+ # Convert to llama-stack format (add 'conv_' prefix if needed)
626+ llama_stack_conv_id = to_llama_stack_conversation_id (normalized_conv_id )
627+
592628 # Prepare metadata with topic summary
593629 metadata = {"topic_summary" : update_request .topic_summary }
594630
595631 # Use Conversations API to update the conversation metadata
596632 await client .conversations .update_conversation (
597- conversation_id = conversation_id ,
633+ conversation_id = llama_stack_conv_id ,
598634 metadata = metadata ,
599635 )
600636
601637 logger .info (
602638 "Successfully updated metadata for conversation %s in LlamaStack" ,
603- conversation_id ,
639+ normalized_conv_id ,
604640 )
605641
606642 # Also update in local database
607643 with get_session () as session :
608644 db_conversation = (
609- session .query (UserConversation ).filter_by (id = conversation_id ).first ()
645+ session .query (UserConversation ).filter_by (id = normalized_conv_id ).first ()
610646 )
611647 if db_conversation :
612648 db_conversation .topic_summary = update_request .topic_summary
613649 session .commit ()
614650 logger .info (
615651 "Successfully updated topic summary in local database for conversation %s" ,
616- conversation_id ,
652+ normalized_conv_id ,
617653 )
618654
619655 return ConversationUpdateResponse (
620- conversation_id = conversation_id ,
656+ conversation_id = normalized_conv_id ,
621657 success = True ,
622658 message = "Topic summary updated successfully" ,
623659 )
@@ -634,7 +670,7 @@ async def update_conversation_endpoint_handler(
634670 raise HTTPException (
635671 status_code = status .HTTP_404_NOT_FOUND ,
636672 detail = NotFoundResponse (
637- resource = "conversation" , resource_id = conversation_id
673+ resource = "conversation" , resource_id = normalized_conv_id
638674 ).dump_detail (),
639675 ) from e
640676
@@ -643,11 +679,11 @@ async def update_conversation_endpoint_handler(
643679
644680 except Exception as e :
645681 # Handle case where conversation doesn't exist or other errors
646- logger .exception ("Error updating conversation %s: %s" , conversation_id , e )
682+ logger .exception ("Error updating conversation %s: %s" , normalized_conv_id , e )
647683 raise HTTPException (
648684 status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
649685 detail = {
650686 "response" : "Unknown error" ,
651- "cause" : f"Unknown error while updating conversation { conversation_id } : { str (e )} " ,
687+ "cause" : f"Unknown error while updating conversation { normalized_conv_id } : { str (e )} " ,
652688 },
653689 ) from e
0 commit comments