6767)
6868from utils .workspace_path import get_cli_chats_path
6969from services .workspace_resolver import (
70- determine_project_for_conversation ,
7170 infer_invalid_workspace_aliases ,
7271 lookup_workspace_display_name ,
7372 matching_workspace_ids_for_folder ,
@@ -576,38 +575,18 @@ def assemble_single_tab(
576575 return {"error" : "Conversation not found" }, 404
577576
578577 row = rows [0 ]
579- try :
580- parsed = json .loads (row ["value" ])
581- except (json .JSONDecodeError , TypeError , ValueError ) as e :
582- payload_len , payload_fp = _kv_payload_log_meta (row ["value" ])
583- _logger .warning (
584- "Failed to decode Composer from composerData:%s: %s (payload_len=%d, payload_sha256=%s)" ,
585- composer_id ,
586- e ,
587- payload_len ,
588- payload_fp ,
589- )
590- return {"error" : "Failed to parse conversation" }, 500
591- try :
592- composer = Composer .from_dict (parsed , composer_id = composer_id )
593- except SchemaError as e :
594- _logger .warning (
595- "Failed to parse Composer from composerData:%s: %s" ,
596- composer_id ,
597- e ,
598- )
599- return {"error" : "Failed to parse conversation" }, 500
578+ composer = parse_composer_data_row (
579+ row ["key" ], row ["value" ], parse_warnings = parse_warnings ,
580+ )
581+ if composer is None :
582+ return {"error" : "Conversation not found" }, 404
600583
601- # Verify the conversation belongs to the requested workspace.
602- # Always scoped: only load messageRequestContext rows for this composer.
603584 project_layouts_map : dict [str , list [str ]] = {}
604585 invalid_workspace_aliases : dict [str , str ] = {}
605586 project_layouts_map [composer_id ] = load_project_layouts_for_composer (
606587 global_db , composer_id ,
607588 )
608589 if invalid_workspace_ids :
609- # Alias resolution still needs the composer roster, but project layouts
610- # are intentionally limited to this composer (single-tab scope).
611590 composer_rows_for_aliases = safe_fetchall (global_db , COMPOSER_ROWS_WITH_HEADERS_SQL )
612591 invalid_workspace_aliases = infer_invalid_workspace_aliases (
613592 composer_rows = composer_rows_for_aliases ,
@@ -620,23 +599,24 @@ def assemble_single_tab(
620599 invalid_workspace_ids = invalid_workspace_ids ,
621600 )
622601
623- pid = determine_project_for_conversation (
624- composer , composer_id , project_layouts_map ,
625- project_name_map , workspace_path_map ,
626- workspace_entries , {}, composer_id_to_ws , invalid_workspace_ids ,
602+ bubble_map = load_bubbles_for_composer (
603+ global_db , composer_id , parse_warnings = parse_warnings ,
604+ )
605+ assigned = assign_composer_workspace (
606+ composer ,
607+ project_layouts_map = project_layouts_map ,
608+ project_name_map = project_name_map ,
609+ workspace_path_map = workspace_path_map ,
610+ workspace_entries = workspace_entries ,
611+ bubble_map = bubble_map ,
612+ composer_id_to_ws = composer_id_to_ws ,
613+ invalid_workspace_ids = invalid_workspace_ids ,
614+ invalid_workspace_aliases = invalid_workspace_aliases ,
627615 )
628- mapped_ws = composer_id_to_ws .get (composer_id )
629- if not pid and mapped_ws in invalid_workspace_ids :
630- pid = invalid_workspace_aliases .get (mapped_ws )
631- assigned = pid if pid else "global"
632616
633617 if assigned not in matching_ws_ids :
634618 return {"error" : "Conversation not found" }, 404
635619
636- # Scoped loads — only rows for this composer_id.
637- bubble_map = load_bubbles_for_composer (
638- global_db , composer_id , parse_warnings = parse_warnings
639- )
640620 contexts = load_message_request_context_for_composer (global_db , composer_id )
641621 code_block_diffs = load_code_block_diffs_for_composer (global_db , composer_id )
642622
@@ -743,16 +723,18 @@ def assemble_workspace_tabs(
743723 # Get composer data entries with conversations
744724 composer_rows = safe_fetchall (global_db , COMPOSER_ROWS_WITH_HEADERS_SQL )
745725
746- invalid_workspace_aliases = infer_invalid_workspace_aliases (
747- composer_rows = composer_rows ,
748- project_layouts_map = project_layouts_map ,
749- project_name_map = project_name_map ,
750- workspace_path_map = workspace_path_map ,
751- workspace_entries = workspace_entries ,
752- bubble_map = bubble_map ,
753- composer_id_to_ws = composer_id_to_ws ,
754- invalid_workspace_ids = invalid_workspace_ids ,
755- )
726+ invalid_workspace_aliases : dict [str , str ] = {}
727+ if invalid_workspace_ids :
728+ invalid_workspace_aliases = infer_invalid_workspace_aliases (
729+ composer_rows = composer_rows ,
730+ project_layouts_map = project_layouts_map ,
731+ project_name_map = project_name_map ,
732+ workspace_path_map = workspace_path_map ,
733+ workspace_entries = workspace_entries ,
734+ bubble_map = bubble_map ,
735+ composer_id_to_ws = composer_id_to_ws ,
736+ invalid_workspace_ids = invalid_workspace_ids ,
737+ )
756738
757739 for row in composer_rows :
758740 composer = parse_composer_data_row (
@@ -762,16 +744,18 @@ def assemble_workspace_tabs(
762744 continue
763745 composer_id = composer .composer_id
764746 try :
765- # Determine project
766- pid = determine_project_for_conversation (
767- composer , composer_id , project_layouts_map ,
768- project_name_map , workspace_path_map ,
769- workspace_entries , bubble_map , composer_id_to_ws , invalid_workspace_ids ,
747+ assigned = assign_composer_workspace (
748+ composer ,
749+ project_layouts_map = project_layouts_map ,
750+ project_name_map = project_name_map ,
751+ workspace_path_map = workspace_path_map ,
752+ workspace_entries = workspace_entries ,
753+ # Assignment matches summary path; bubble_map used only for tab body.
754+ bubble_map = {},
755+ composer_id_to_ws = composer_id_to_ws ,
756+ invalid_workspace_ids = invalid_workspace_ids ,
757+ invalid_workspace_aliases = invalid_workspace_aliases ,
770758 )
771- mapped_ws = composer_id_to_ws .get (composer_id )
772- if not pid and mapped_ws in invalid_workspace_ids :
773- pid = invalid_workspace_aliases .get (mapped_ws )
774- assigned = pid if pid else "global"
775759
776760 if assigned not in matching_ws_ids :
777761 continue
0 commit comments