From dc92976ffe5da17f4eb7ccbc2758a50a3e3aed12 Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Sun, 31 May 2026 09:50:08 +0800 Subject: [PATCH] =?UTF-8?q?fix(session-title):=20=E5=89=A5=E7=A6=BB=20=20=E6=A0=87=E7=AD=BE=E5=89=8D=E7=BC=80=E5=B9=B6=E6=94=BE?= =?UTF-8?q?=E5=A4=A7=E6=A0=87=E9=A2=98=E5=AD=98=E5=82=A8=E9=95=BF=E5=BA=A6?= =?UTF-8?q?=E8=87=B3=20600=20=E5=AD=97=E7=AC=A6;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 后端: _NOISE_TAG_PATTERN 新增 session 标签, 避免标题以 ... 开头; - 后端: _SESSION_TITLE_MAX_LEN 从 30 放大至 600 (20x), 提升标题信息量; - 前端: 展开详情行中 Title 独立为 .detail-title-row, 独占全宽行显示; - 前端: 新增 -webkit-line-clamp: 3 多行截断样式, 超出部分以 ... 省略; - 测试: 补充 标签剥离用例, 修复截断长度测试适配新上限; 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- src/coding/proxy/routing/executor.py | 4 ++-- src/coding/proxy/server/dashboard.py | 19 ++++++++++++++++++- tests/test_router_executor.py | 11 ++++++++++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/coding/proxy/routing/executor.py b/src/coding/proxy/routing/executor.py index df63e74..328f10e 100644 --- a/src/coding/proxy/routing/executor.py +++ b/src/coding/proxy/routing/executor.py @@ -54,7 +54,7 @@ logger = logging.getLogger(__name__) -_SESSION_TITLE_MAX_LEN = 30 +_SESSION_TITLE_MAX_LEN = 600 # Claude Code 注入的"噪声"标签 — 系统级上下文,不应进入 Session 标题。 # 这些标签由 CC harness 在首个 user 消息 content 中拼接,高度同质, @@ -63,7 +63,7 @@ r"<(?Psystem-reminder|user-preferences|" r"local-command-stdout|local-command-stderr|" r"bash-input|bash-stdout|bash-stderr|" - r"ide_selection|stdin|system_instruction)\b[^>]*>" + r"ide_selection|stdin|system_instruction|session)\b[^>]*>" r".*?", flags=re.DOTALL | re.IGNORECASE, ) diff --git a/src/coding/proxy/server/dashboard.py b/src/coding/proxy/server/dashboard.py index 4c96ef0..cda7991 100644 --- a/src/coding/proxy/server/dashboard.py +++ b/src/coding/proxy/server/dashboard.py @@ -444,6 +444,21 @@ def _build_favicon() -> bytes: .detail-card .detail-item { display: flex; flex-direction: column; gap: 2px; min-width: 0; } .detail-card .detail-label { font-size: 11px; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: .3px; } .detail-card .detail-value { color: var(--text-primary); line-height: 1.4; word-break: break-all; overflow-wrap: break-word; } + .detail-title-row { + padding-bottom: 10px; margin-bottom: 10px; + border-bottom: 1px solid var(--border); + } + .detail-title-row .detail-value { + white-space: normal; + word-break: break-word; + overflow-wrap: break-word; + line-height: 1.5; + max-height: 4.5em; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + } .detail-identity-row { display: flex; gap: 16px; padding-bottom: 10px; margin-bottom: 10px; @@ -1903,9 +1918,11 @@ def _build_favicon() -> bytes: '' + formatCategories(s.client_categories) + '' + '' + '
' + + '
' + + '
Title
' + (sessionTitle ? escapeHtml(sessionTitle) : '–') + '
' + + '
' + '
' + '
Session ID
' + escapeHtml(parsed.session_id || s.session_key) + '
' + - '
Title
' + (sessionTitle ? escapeHtml(sessionTitle) : '–') + '
' + '
Device
' + (parsed.device_id ? escapeHtml(parsed.device_id) : '–') + '
' + '
Account
' + (parsed.account_uuid ? escapeHtml(parsed.account_uuid) : '–') + '
' + '
' + diff --git a/tests/test_router_executor.py b/tests/test_router_executor.py index 070ca95..e10bac6 100644 --- a/tests/test_router_executor.py +++ b/tests/test_router_executor.py @@ -2249,6 +2249,15 @@ def test_strips_local_command_output(self): raw = "build ok构建后的下一步问题" assert _sanitize_user_text(raw) == "构建后的下一步问题" + def test_strips_session_tag(self): + """```` 标签应被完整剥离,不残留在标题中.""" + raw = "session metadata用户真实输入文本" + assert _sanitize_user_text(raw) == "用户真实输入文本" + + def test_strips_session_tag_multiline(self): + raw = "\nline1\nline2\n真实标题" + assert _sanitize_user_text(raw) == "真实标题" + class TestExtractSessionTitle: """``_extract_session_title`` — 端到端从 CanonicalRequest 抽取标题.""" @@ -2258,7 +2267,7 @@ def _build_request(messages: list[dict]): return build_canonical_request({"model": "test", "messages": messages}, {}) def test_truncates_to_max_len(self): - long_text = "用户输入文本" * 20 + long_text = "用户输入文本" * 200 req = self._build_request([{"role": "user", "content": long_text}]) title = _extract_session_title(req) assert len(title) == _SESSION_TITLE_MAX_LEN