From 7263657937063ff9ac905e4f51d4a73cccd96fc9 Mon Sep 17 00:00:00 2001 From: Hiep Le <69354317+hieptl@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:34:30 +0700 Subject: [PATCH] feat(backend): include sub-conversation ids when fetching conversation details (#11734) --- .../app_conversation_models.py | 1 + .../sql_app_conversation_info_service.py | 38 +++++++++++++++++-- .../server/data_models/conversation_info.py | 1 + .../server/routes/manage_conversations.py | 3 ++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/openhands/app_server/app_conversation/app_conversation_models.py b/openhands/app_server/app_conversation/app_conversation_models.py index 4ed04cf91c..d918a2d9b1 100644 --- a/openhands/app_server/app_conversation/app_conversation_models.py +++ b/openhands/app_server/app_conversation/app_conversation_models.py @@ -42,6 +42,7 @@ class AppConversationInfo(BaseModel): metrics: MetricsSnapshot | None = None parent_conversation_id: OpenHandsUUID | None = None + sub_conversation_ids: list[OpenHandsUUID] = Field(default_factory=list) created_at: datetime = Field(default_factory=utc_now) updated_at: datetime = Field(default_factory=utc_now) diff --git a/openhands/app_server/app_conversation/sql_app_conversation_info_service.py b/openhands/app_server/app_conversation/sql_app_conversation_info_service.py index 30fb2b753b..90da5f5d4b 100644 --- a/openhands/app_server/app_conversation/sql_app_conversation_info_service.py +++ b/openhands/app_server/app_conversation/sql_app_conversation_info_service.py @@ -232,6 +232,26 @@ class SQLAppConversationInfoService(AppConversationInfoService): query = query.where(*conditions) return query + async def _get_sub_conversation_ids( + self, parent_conversation_id: UUID + ) -> list[UUID]: + """Get all sub-conversation IDs for a given parent conversation. + + Args: + parent_conversation_id: The ID of the parent conversation + + Returns: + List of sub-conversation IDs + """ + query = await self._secure_select() + query = query.where( + StoredConversationMetadata.parent_conversation_id + == str(parent_conversation_id) + ) + result_set = await self.db_session.execute(query) + rows = result_set.scalars().all() + return [UUID(row.conversation_id) for row in rows] + async def get_app_conversation_info( self, conversation_id: UUID ) -> AppConversationInfo | None: @@ -242,7 +262,9 @@ class SQLAppConversationInfoService(AppConversationInfoService): result_set = await self.db_session.execute(query) result = result_set.scalar_one_or_none() if result: - return self._to_info(result) + # Fetch sub-conversation IDs + sub_conversation_ids = await self._get_sub_conversation_ids(conversation_id) + return self._to_info(result, sub_conversation_ids=sub_conversation_ids) return None async def batch_get_app_conversation_info( @@ -261,8 +283,13 @@ class SQLAppConversationInfoService(AppConversationInfoService): results: list[AppConversationInfo | None] = [] for conversation_id in conversation_id_strs: info = info_by_id.get(conversation_id) + sub_conversation_ids = await self._get_sub_conversation_ids( + UUID(conversation_id) + ) if info: - results.append(self._to_info(info)) + results.append( + self._to_info(info, sub_conversation_ids=sub_conversation_ids) + ) else: results.append(None) @@ -330,7 +357,11 @@ class SQLAppConversationInfoService(AppConversationInfoService): ) return query - def _to_info(self, stored: StoredConversationMetadata) -> AppConversationInfo: + def _to_info( + self, + stored: StoredConversationMetadata, + sub_conversation_ids: list[UUID] | None = None, + ) -> AppConversationInfo: # V1 conversations should always have a sandbox_id sandbox_id = stored.sandbox_id assert sandbox_id is not None @@ -375,6 +406,7 @@ class SQLAppConversationInfoService(AppConversationInfoService): if stored.parent_conversation_id else None ), + sub_conversation_ids=sub_conversation_ids or [], created_at=created_at, updated_at=updated_at, ) diff --git a/openhands/server/data_models/conversation_info.py b/openhands/server/data_models/conversation_info.py index f4c4a77809..78af0e3dc1 100644 --- a/openhands/server/data_models/conversation_info.py +++ b/openhands/server/data_models/conversation_info.py @@ -28,3 +28,4 @@ class ConversationInfo: created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc)) pr_number: list[int] = field(default_factory=list) conversation_version: str = 'V0' + sub_conversation_ids: list[str] = field(default_factory=list) diff --git a/openhands/server/routes/manage_conversations.py b/openhands/server/routes/manage_conversations.py index 8984f79e8c..0b828c76c0 100644 --- a/openhands/server/routes/manage_conversations.py +++ b/openhands/server/routes/manage_conversations.py @@ -1432,4 +1432,7 @@ def _to_conversation_info(app_conversation: AppConversation) -> ConversationInfo created_at=app_conversation.created_at, pr_number=app_conversation.pr_number, conversation_version='V1', + sub_conversation_ids=[ + sub_id.hex for sub_id in app_conversation.sub_conversation_ids + ], )