Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions src/repositories/conversation_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,26 @@
from src.utils import logger
from src.utils.datetime_utils import utc_now_naive

MAX_CONVERSATION_TITLE_LENGTH = 255


class ConversationRepository:
def __init__(self, db_session: AsyncSession):
self.db = db_session

def _normalize_title(self, title: str | None) -> str | None:
if title is None:
return None
normalized = str(title).strip()
if not normalized:
return ""
if len(normalized) > MAX_CONVERSATION_TITLE_LENGTH:
logger.warning(
f"Conversation title too long ({len(normalized)}), truncate to {MAX_CONVERSATION_TITLE_LENGTH}"
)
return normalized[:MAX_CONVERSATION_TITLE_LENGTH]
return normalized

async def create_conversation(
self,
user_id: str,
Expand All @@ -31,11 +46,13 @@ async def create_conversation(
metadata = (metadata or {}).copy()
metadata.setdefault("attachments", [])

normalized_title = self._normalize_title(title)

conversation = Conversation(
thread_id=thread_id,
user_id=str(user_id),
agent_id=agent_id,
title=title or "New Conversation",
title=normalized_title or "New Conversation",
status="active",
extra_metadata=metadata,
)
Expand Down Expand Up @@ -203,8 +220,9 @@ async def update_conversation(
if not conversation:
return None

if title is not None:
conversation.title = title
normalized_title = self._normalize_title(title)
if normalized_title is not None:
conversation.title = normalized_title
if status is not None:
conversation.status = status

Expand Down
22 changes: 22 additions & 0 deletions test/test_conversation_repository.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from __future__ import annotations

from src.repositories.conversation_repository import ConversationRepository, MAX_CONVERSATION_TITLE_LENGTH


def test_normalize_title_truncates_when_too_long():
repo = ConversationRepository(None) # type: ignore[arg-type]
raw = "a" * (MAX_CONVERSATION_TITLE_LENGTH + 50)

normalized = repo._normalize_title(raw)

assert normalized is not None
assert len(normalized) == MAX_CONVERSATION_TITLE_LENGTH
assert normalized == "a" * MAX_CONVERSATION_TITLE_LENGTH


def test_normalize_title_trims_spaces():
repo = ConversationRepository(None) # type: ignore[arg-type]

normalized = repo._normalize_title(" hello world ")

assert normalized == "hello world"
12 changes: 9 additions & 3 deletions web/src/components/AgentChatComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -626,12 +626,15 @@ const deleteThread = async (threadId) => {
const updateThread = async (threadId, title) => {
if (!threadId || !title) return

const normalizedTitle = String(title).replace(/\s+/g, ' ').trim().slice(0, 255)
if (!normalizedTitle) return

chatState.isRenamingThread = true
try {
await threadApi.updateThread(threadId, title)
await threadApi.updateThread(threadId, normalizedTitle)
const thread = threads.value.find((t) => t.id === threadId)
if (thread) {
thread.title = title
thread.title = normalizedTitle
}
} catch (error) {
console.error('Failed to update thread:', error)
Expand Down Expand Up @@ -750,7 +753,10 @@ const sendMessage = async ({

// 如果是新对话,用消息内容作为标题
if ((threadMessages.value[threadId] || []).length === 0) {
updateThread(threadId, text)
const autoTitle = text.replace(/\s+/g, ' ').trim().slice(0, 255)
if (autoTitle) {
void updateThread(threadId, autoTitle).catch(() => {})
}
}

const requestData = {
Expand Down