mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
fix(aibridge): track Charm Crush client and session ID (#24630)
*Disclaimer: implemented by a Coder Agent using Claude Opus 4.6* Porting https://github.com/coder/aibridge/pull/277 to coder/coder after the [aibridge code move](https://github.com/coder/coder/pull/24190). ## Summary Fixes client detection and session ID tracking for the [Charm Crush](https://github.com/charmbracelet/crush) AI coding client. ## Changes ### Bug fix: User-Agent matching The actual Crush user-agent is `Charm-Crush/{version} (https://charm.land/crush)` (hyphenated), but `GuessClient` only checked for `charm crush/` (space-separated). After lowercasing, `Charm-Crush/0.2.0` becomes `charm-crush/0.2.0`, which did not match the `charm crush/` prefix. Now matches both formats for backwards compatibility. ### Session ID tracking Adds an explicit `ClientCrush` case to `GuessSessionID`. Crush does not currently send a session ID header to upstream AI providers, so this returns `nil` (consistent with how `ClientZed`, `ClientRoo`, and `ClientCursor` are handled). ### Tests - Added `charm_crush_hyphen` test case for `GuessClient` using the real user-agent format. - Added `crush_returns_empty` test case for `GuessSessionID`.
This commit is contained in:
+1
-1
@@ -51,7 +51,7 @@ func GuessClient(r *http.Request) Client {
|
||||
return ClientRoo
|
||||
case strings.HasPrefix(userAgent, "coder-agents/"):
|
||||
return ClientCoderAgents
|
||||
case strings.HasPrefix(userAgent, "charm crush/"):
|
||||
case strings.HasPrefix(userAgent, "charm crush/") || strings.HasPrefix(userAgent, "charm-crush/"):
|
||||
return ClientCrush
|
||||
case r.Header.Get("x-cursor-client-version") != "":
|
||||
return ClientCursor
|
||||
|
||||
@@ -79,10 +79,15 @@ func TestGuessClient(t *testing.T) {
|
||||
wantClient: aibridge.ClientCoderAgents,
|
||||
},
|
||||
{
|
||||
name: "charm_crush",
|
||||
name: "charm_crush_space",
|
||||
userAgent: "Charm Crush/0.1.11",
|
||||
wantClient: aibridge.ClientCrush,
|
||||
},
|
||||
{
|
||||
name: "charm_crush_hyphen",
|
||||
userAgent: "Charm-Crush/0.2.0 (https://charm.land/crush)",
|
||||
wantClient: aibridge.ClientCrush,
|
||||
},
|
||||
{
|
||||
name: "cursor_x_cursor_client_version",
|
||||
userAgent: "connect-es/1.6.1",
|
||||
|
||||
@@ -75,6 +75,8 @@ func GuessSessionID(client Client, r *http.Request) *string {
|
||||
return cleanRef(r.Header.Get("X-KILOCODE-TASKID"))
|
||||
case ClientCoderAgents:
|
||||
return cleanRef(r.Header.Get("X-Coder-Chat-Id"))
|
||||
case ClientCrush:
|
||||
return nil // Crush does not send a session ID header.
|
||||
case ClientRoo:
|
||||
return nil // RooCode doesn't send a session ID.
|
||||
case ClientCursor:
|
||||
|
||||
@@ -182,6 +182,11 @@ func TestGuessSessionID(t *testing.T) {
|
||||
name: "coder_agents_without_chat_id",
|
||||
client: aibridge.ClientCoderAgents,
|
||||
},
|
||||
// Crush.
|
||||
{
|
||||
name: "crush_returns_empty",
|
||||
client: aibridge.ClientCrush,
|
||||
},
|
||||
// Roo.
|
||||
{
|
||||
name: "roo_returns_empty",
|
||||
|
||||
Reference in New Issue
Block a user