Skip to content

Commit dc50b7b

Browse files
fix(claude-code): defensive coding improvements for model switching (#7131)
Signed-off-by: Adrian Cole <adrian@tetrate.io>
1 parent 01d425b commit dc50b7b

2 files changed

Lines changed: 16 additions & 6 deletions

File tree

crates/goose/src/providers/claude_code.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ impl CliProcess {
6363
"request_id": request_id,
6464
"request": {"subtype": "set_model", "model": model}
6565
});
66-
let mut req_str = serde_json::to_string(&req).unwrap();
66+
let mut req_str = serde_json::to_string(&req).map_err(|e| {
67+
ProviderError::RequestFailed(format!("Failed to serialize set_model request: {e}"))
68+
})?;
6769
req_str.push('\n');
6870
self.stdin
6971
.write_all(req_str.as_bytes())
@@ -89,6 +91,14 @@ impl CliProcess {
8991
}
9092
if let Ok(parsed) = serde_json::from_str::<Value>(trimmed) {
9193
if parsed.get("type").and_then(|t| t.as_str()) == Some("control_response") {
94+
// Skip responses that don't match our request_id
95+
if parsed
96+
.pointer("/response/request_id")
97+
.and_then(|id| id.as_str())
98+
!= Some(request_id.as_str())
99+
{
100+
continue;
101+
}
92102
let success =
93103
parsed.pointer("/response/subtype").and_then(|s| s.as_str())
94104
== Some("success");
@@ -639,7 +649,9 @@ impl Provider for ClaudeCodeProvider {
639649
"request_id": "model_list",
640650
"request": {"subtype": "initialize"}
641651
});
642-
let mut request_str = serde_json::to_string(&request).unwrap();
652+
let mut request_str = serde_json::to_string(&request).map_err(|e| {
653+
ProviderError::RequestFailed(format!("Failed to serialize initialize request: {e}"))
654+
})?;
643655
request_str.push('\n');
644656
stdin.write_all(request_str.as_bytes()).await.map_err(|e| {
645657
ProviderError::RequestFailed(format!("Failed to write initialize request: {e}"))
@@ -670,7 +682,7 @@ impl Provider for ClaudeCodeProvider {
670682
}
671683
}
672684

673-
let _ = child.start_kill();
685+
let _ = child.kill().await;
674686
Ok(parse_models_from_lines(&lines))
675687
}
676688

crates/goose/tests/providers.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,6 @@ impl ProviderTester {
275275
}
276276

277277
async fn test_model_switch(&self, session_id: &str) -> Result<()> {
278-
// The process is already running with the default model from test_basic_response.
279-
// Switch to model_switch_name and call complete_with_model to exercise send_set_model.
280278
let default = &self.provider.get_model_config().model_name;
281279
let alt = self
282280
.model_switch_name
@@ -297,7 +295,7 @@ impl ProviderTester {
297295
.await?;
298296

299297
assert!(
300-
matches!(response.content[0], MessageContent::Text(_)),
298+
matches!(response.content.first(), Some(MessageContent::Text(_))),
301299
"Expected text response after model switch"
302300
);
303301
println!(

0 commit comments

Comments
 (0)