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