feat(backend): exclude sub-conversations when searching for conversations (#11733)

This commit is contained in:
Hiep Le
2025-11-15 00:21:27 +07:00
committed by GitHub
parent 2841e35f24
commit 833aae1833
8 changed files with 671 additions and 3 deletions

View File

@@ -26,6 +26,7 @@ class AppConversationInfoService(ABC):
sort_order: AppConversationSortOrder = AppConversationSortOrder.CREATED_AT_DESC,
page_id: str | None = None,
limit: int = 100,
include_sub_conversations: bool = False,
) -> AppConversationInfoPage:
"""Search for sandboxed conversations."""

View File

@@ -99,6 +99,12 @@ async def search_app_conversations(
lte=100,
),
] = 100,
include_sub_conversations: Annotated[
bool,
Query(
title='If True, include sub-conversations in the results. If False (default), exclude all sub-conversations.'
),
] = False,
app_conversation_service: AppConversationService = (
app_conversation_service_dependency
),
@@ -114,6 +120,7 @@ async def search_app_conversations(
updated_at__lt=updated_at__lt,
page_id=page_id,
limit=limit,
include_sub_conversations=include_sub_conversations,
)
@@ -193,7 +200,8 @@ async def stream_app_conversation_start(
user_context: UserContext = user_context_dependency,
) -> list[AppConversationStartTask]:
"""Start an app conversation start task and stream updates from it.
Leaves the connection open until either the conversation starts or there was an error"""
Leaves the connection open until either the conversation starts or there was an error
"""
response = StreamingResponse(
_stream_app_conversation_start(request, user_context),
media_type='application/json',

View File

@@ -30,6 +30,7 @@ class AppConversationService(ABC):
sort_order: AppConversationSortOrder = AppConversationSortOrder.CREATED_AT_DESC,
page_id: str | None = None,
limit: int = 100,
include_sub_conversations: bool = False,
) -> AppConversationPage:
"""Search for sandboxed conversations."""

View File

@@ -105,6 +105,7 @@ class LiveStatusAppConversationService(GitAppConversationService):
sort_order: AppConversationSortOrder = AppConversationSortOrder.CREATED_AT_DESC,
page_id: str | None = None,
limit: int = 20,
include_sub_conversations: bool = False,
) -> AppConversationPage:
"""Search for sandboxed conversations."""
page = await self.app_conversation_info_service.search_app_conversation_info(
@@ -116,6 +117,7 @@ class LiveStatusAppConversationService(GitAppConversationService):
sort_order=sort_order,
page_id=page_id,
limit=limit,
include_sub_conversations=include_sub_conversations,
)
conversations: list[AppConversation] = await self._build_app_conversations(
page.items

View File

@@ -111,10 +111,18 @@ class SQLAppConversationInfoService(AppConversationInfoService):
sort_order: AppConversationSortOrder = AppConversationSortOrder.CREATED_AT_DESC,
page_id: str | None = None,
limit: int = 100,
include_sub_conversations: bool = False,
) -> AppConversationInfoPage:
"""Search for sandboxed conversations without permission checks."""
query = await self._secure_select()
# Conditionally exclude sub-conversations based on the parameter
if not include_sub_conversations:
# Exclude sub-conversations (only include top-level conversations)
query = query.where(
StoredConversationMetadata.parent_conversation_id.is_(None)
)
query = self._apply_filters(
query=query,
title__contains=title__contains,

View File

@@ -6,9 +6,10 @@ import os
import re
import uuid
from datetime import datetime, timedelta, timezone
from typing import Annotated
import base62
from fastapi import APIRouter, Depends, Request, status
from fastapi import APIRouter, Depends, Query, Request, status
from fastapi.responses import JSONResponse
from jinja2 import Environment, FileSystemLoader
from pydantic import BaseModel, ConfigDict, Field
@@ -309,6 +310,12 @@ async def search_conversations(
limit: int = 20,
selected_repository: str | None = None,
conversation_trigger: ConversationTrigger | None = None,
include_sub_conversations: Annotated[
bool,
Query(
title='If True, include sub-conversations in the results. If False (default), exclude all sub-conversations.'
),
] = False,
conversation_store: ConversationStore = Depends(get_conversation_store),
app_conversation_service: AppConversationService = app_conversation_service_dependency,
) -> ConversationInfoResultSet:
@@ -343,6 +350,7 @@ async def search_conversations(
limit=limit,
# Apply age filter at the service level if possible
created_at__gte=age_filter_date,
include_sub_conversations=include_sub_conversations,
)
# Convert V1 conversations to ConversationInfo format
@@ -1187,6 +1195,7 @@ async def _fetch_v1_conversations_safe(
app_conversation_service: App conversation service for V1
v1_page_id: Page ID for V1 pagination
limit: Maximum number of results
include_sub_conversations: If True, include sub-conversations in results
Returns:
Tuple of (v1_conversations, v1_next_page_id)