fix: 修复新增对话时内容直接作为标题长度超出表字段长度限制问题, titile 字段长度限制为255

- 新增 MAX_CONVERSATION_TITLE_LENGTH 常量 (255 字符)
- 新增 _normalize_title() 方法用于截断和校验标题
- 防止创建和更新对话时数据库字段溢出
- 前端 AgentChatComponent 同步添加标题标准化处理
- 添加标题标准化的单元测试
This commit is contained in:
肖泽涛 2026-02-20 23:41:44 +08:00 committed by Wenjie Zhang
parent 1f5636520e
commit 80cf6937ed
3 changed files with 52 additions and 6 deletions

View File

@ -12,11 +12,26 @@ from src.storage.postgres.models_business import Conversation, ConversationStats
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,
@ -31,11 +46,13 @@ class ConversationRepository:
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,
)
@ -203,8 +220,9 @@ class ConversationRepository:
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

View File

@ -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"

View File

@ -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)
@ -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 = {