fix(harness): improve auto-rename prompt quality - #422
Conversation
Haiku was generating conversational responses ("I apologize..."),
generic titles ("Start a Conversation"), and titles with embedded
quotes/newlines instead of clean session names. Rewrites the system
prompt with few-shot examples and strict constraints, adds a
sanitization layer that strips quotes, truncates at newlines, and
rejects known bad patterns (apologies, filler, generic starters).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update server-level auto-rename test to use partial matching for prompt content (exact separator format is tested in the harness test). Remove duplicate unicode chars from quote-stripping regex. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…cker - Update VERTEX_MODEL from claude-3-5-haiku@20241022 (500 since Jul 11) to claude-haiku-4-5@20251001 - Drop version-pinned Vertex model map entries (all were 404); use unversioned names that auto-resolve to latest - Add claude-sonnet-4-5 and claude-opus-4-5 to model picker (server list and frontend dropdown) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
72d6359 to
55ff47c
Compare
dimakis
left a comment
There was a problem hiding this comment.
Centaur Review
Found 2 issue(s).
packages/harness/src/auto-rename.ts
Clean quality-of-life improvement to auto-rename. Sanitization logic is well-tested and the prompt upgrade is solid. Two minor suggestions: tighten the unanchored would you like rejection pattern, and simplify the now-identity Vertex model map.
- 🔵 unsafe_assumptions (L33): The
/would you like/ipattern is the only REJECTED_PATTERN not anchored to^. This means a legitimate title like "Fix Would You Like Dialog" would be falsely rejected. Anchoring it to end-of-string (/would you like.*$/i) or keeping it unanchored but with more context (/would you like (me |to )/i) would reduce false positives while still catching Haiku run-on.[fixable]
packages/harness/src/providers/anthropic-vertex.ts
Clean quality-of-life improvement to auto-rename. Sanitization logic is well-tested and the prompt upgrade is solid. Two minor suggestions: tighten the unanchored would you like rejection pattern, and simplify the now-identity Vertex model map.
- 🔵 style (L17): VERTEX_MODEL_MAP is now an identity mapping — every key maps to itself. The fallback
VERTEX_MODEL_MAP[this.model] ?? this.modelwould return the same value with or without the map. It documents "supported models" but aSetor inline comment would communicate that intent more clearly and avoid confusion about whether the map is supposed to transform anything.[fixable]
Reviewed at 55ff47c
| /^(hello|hi|hey|greetings)/i, | ||
| /^(sure|certainly|of\s+course)/i, | ||
| /^(here|let\s+me)/i, | ||
| /would you like/i, |
There was a problem hiding this comment.
🔵 unsafe_assumptions: The /would you like/i pattern is the only REJECTED_PATTERN not anchored to ^. This means a legitimate title like "Fix Would You Like Dialog" would be falsely rejected. Anchoring it to end-of-string (/would you like.*$/i) or keeping it unanchored but with more context (/would you like (me |to )/i) would reduce false positives while still catching Haiku run-on. [fixable]
|
|
||
| /** Vertex AI model name mapping (Vertex uses different naming). */ | ||
| /** Vertex AI model name mapping. Unversioned names auto-resolve to latest. */ | ||
| const VERTEX_MODEL_MAP: Record<string, string> = { |
There was a problem hiding this comment.
🔵 style: VERTEX_MODEL_MAP is now an identity mapping — every key maps to itself. The fallback VERTEX_MODEL_MAP[this.model] ?? this.model would return the same value with or without the map. It documents "supported models" but a Set or inline comment would communicate that intent more clearly and avoid confusion about whether the map is supposed to transform anything. [fixable]
- Anchor /would you like/ rejection pattern to ^ to avoid false positives on legitimate titles containing the phrase - Remove identity VERTEX_MODEL_MAP — unversioned model names pass through directly to Vertex without needing a mapping layer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dimakis
left a comment
There was a problem hiding this comment.
Centaur Review
Found 5 issue(s) (2 warning).
packages/harness/src/providers/anthropic-vertex.ts
Solid improvement to auto-rename robustness with good sanitization logic and test coverage. Main concern is whether the Vertex model map removal could break callers that pass standard (non-Vertex) model names to Vertex clients.
- 🟡 regressions (L54): The VERTEX_MODEL_MAP removal means callers must now pass Vertex-format model names (e.g. 'claude-haiku-4-5@20251001') directly. If any caller passes standard API names like 'claude-opus-4-6' to a Vertex client, the API call will fail — previously the map translated these. Verify that all call sites that construct AnthropicVertexModelProvider with Vertex enabled pass Vertex-compatible model names.
server/auto-rename.ts
Solid improvement to auto-rename robustness with good sanitization logic and test coverage. Main concern is whether the Vertex model map removal could break callers that pass standard (non-Vertex) model names to Vertex clients.
- 🟡 missing_tests: sanitizeSessionName is not re-exported from server/auto-rename.ts (nor from packages/harness/src/index.ts). The server test file imports from ../auto-rename.js and cannot test sanitizeSessionName. Either add it to the re-export list in both files, or accept that sanitizeSessionName is only tested via the harness test suite. If it's intentionally internal, the export in auto-rename.ts should be test-only — but then the harness test imports it as a public export.
[fixable]
packages/harness/__tests__/auto-rename.test.ts
Solid improvement to auto-rename robustness with good sanitization logic and test coverage. Main concern is whether the Vertex model map removal could break callers that pass standard (non-Vertex) model names to Vertex clients.
- 🔵 missing_tests: No test for sanitizeSessionName with smart/curly quotes (U+201C, U+201D, U+2018, U+2019) even though the regex explicitly handles them. Adding a test like sanitizeSessionName('\u201CHello\u201D') === 'Hello' would verify the Unicode quote stripping works.
[fixable]
packages/harness/src/auto-rename.ts
Solid improvement to auto-rename robustness with good sanitization logic and test coverage. Main concern is whether the Vertex model map removal could break callers that pass standard (non-Vertex) model names to Vertex clients.
- 🔵 unsafe_assumptions (L243): The quote-stripping regex uses a character class that includes both whitespace (\s) and quote chars with
+quantifier:^[\s"'\u201C\u201D\u2018\u2019]+. This means a title like" Spaced Title "correctly producesSpaced Title, but a title that legitimately starts with an apostrophe (e.g.'Twas) would lose it. Low-risk for session names but worth noting.
server/__tests__/auto-rename.test.ts
Solid improvement to auto-rename robustness with good sanitization logic and test coverage. Main concern is whether the Vertex model map removal could break callers that pass standard (non-Vertex) model names to Vertex clients.
- 🔵 style (L161): The server test relaxed its assertion from exact argument matching (toHaveBeenCalledWith) to individual field checks (call[0].model, call[0].messages[0].content). This is fine for resilience against prompt changes, but the system prompt (NAMING_SYSTEM_PROMPT) is now completely unverified in the server test suite. Consider adding a minimal assertion like
expect(call[0].system).toContain('3-6 word title')so the server tests catch accidental system prompt deletions.[fixable]
Reviewed at 474210d
| const conversationMessages = messages.filter((m) => m.role !== 'system'); | ||
|
|
||
| const apiModel = this.isVertex ? (VERTEX_MODEL_MAP[this.model] ?? this.model) : this.model; | ||
| const apiModel = this.model; |
There was a problem hiding this comment.
🟡 regressions: The VERTEX_MODEL_MAP removal means callers must now pass Vertex-format model names (e.g. 'claude-haiku-4-5@20251001') directly. If any caller passes standard API names like 'claude-opus-4-6' to a Vertex client, the API call will fail — previously the map translated these. Verify that all call sites that construct AnthropicVertexModelProvider with Vertex enabled pass Vertex-compatible model names.
| let name = raw.split('\n')[0].trim(); | ||
|
|
||
| // Strip surrounding quotes (single, double, smart quotes) | ||
| name = name.replace(/^[\s"'\u201C\u201D\u2018\u2019]+|[\s"'\u201C\u201D\u2018\u2019]+$/g, ''); |
There was a problem hiding this comment.
🔵 unsafe_assumptions: The quote-stripping regex uses a character class that includes both whitespace (\s) and quote chars with + quantifier: ^[\s"'\u201C\u201D\u2018\u2019]+. This means a title like " Spaced Title " correctly produces Spaced Title, but a title that legitimately starts with an apostrophe (e.g. 'Twas) would lose it. Low-risk for session names but worth noting.
| ); | ||
| const call = mockCreate.mock.calls[0]; | ||
| expect(call[0].model).toBe(AUTO_RENAME_MODEL); | ||
| expect(call[0].max_tokens).toBe(20); |
There was a problem hiding this comment.
🔵 style: The server test relaxed its assertion from exact argument matching (toHaveBeenCalledWith) to individual field checks (call[0].model, call[0].messages[0].content). This is fine for resilience against prompt changes, but the system prompt (NAMING_SYSTEM_PROMPT) is now completely unverified in the server test suite. Consider adding a minimal assertion like expect(call[0].system).toContain('3-6 word title') so the server tests catch accidental system prompt deletions. [fixable]
Summary
sanitizeSessionName()that strips quotes, truncates at newlines, and rejects known bad patterns (apologies, generic starters, conversational filler)---delimiters instead of bare newlines for clearer multi-prompt inputProblem
Haiku was producing garbage session titles in production:
"I apologize, but I cannot access the specific Jira ticket li"— full conversational response"\"OpenShift OpenCode Agent Integration\"\n\nWould you like me to"— embedded quotes + trailing conversation"Start a Conversation"— generic filler when it couldn't extract intentTest plan
🤖 Generated with Claude Code