diff --git a/api/detection.py b/api/detection.py index 9f3f33f1..18815295 100644 --- a/api/detection.py +++ b/api/detection.py @@ -31,11 +31,24 @@ def is_title_generation_request(request_data: MessagesRequest) -> bool: Title generation requests are detected by a system prompt containing title extraction instructions, no tools, and a single user message. + + Matches both legacy phrasing and Claude Code 2.1+ session title prompts + (JSON \"title\" field, sentence-case title instructions, etc.). """ if not request_data.system or request_data.tools: return False system_text = extract_text_from_content(request_data.system).lower() - return "new conversation topic" in system_text and "title" in system_text + if "title" not in system_text: + return False + return ( + "new conversation topic" in system_text + or "sentence-case title" in system_text + or ( + "return json" in system_text + and "field" in system_text + and ("coding session" in system_text or "this session" in system_text) + ) + ) def is_prefix_detection_request(request_data: MessagesRequest) -> tuple[bool, str]: diff --git a/tests/api/test_request_utils.py b/tests/api/test_request_utils.py index 9c1e07b8..eb86dc75 100644 --- a/tests/api/test_request_utils.py +++ b/tests/api/test_request_utils.py @@ -151,6 +151,20 @@ class TestTitleGenerationRequest: assert is_title_generation_request(req) is False + def test_title_generation_claude_code_session_title_prompt(self): + """Claude Code 2.1+ session title JSON (sentence-case) is detected.""" + block = MagicMock() + block.text = ( + "Generate a concise, sentence-case title (3-7 words) that captures the " + "main topic or goal of this coding session. Return JSON with a single " + '"title" field.' + ) + req = MagicMock(spec=MessagesRequest) + req.system = [block] + req.tools = None + + assert is_title_generation_request(req) is True + class TestExtractCommandPrefix: """Tests for extract_command_prefix function."""