Skip to content

Commit 64a0ecf

Browse files
committed
fix: return synthetic empty text on Anthropic empty content response
Anthropic returns an empty content array (stop_reason=end_turn) after side-effect-only tool calls like react or skip — the model has nothing further to say but the response is valid. Previously this was treated as an error, exhausting retries and falling through to the next model in the fallback chain, which then failed for unrelated reasons (e.g. deepseek-reasoner expecting reasoning_content). Return a synthetic empty Text response instead so the agentic loop terminates gracefully.
1 parent 931105c commit 64a0ecf

File tree

1 file changed

+12
-6
lines changed

1 file changed

+12
-6
lines changed

src/llm/model.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,15 +1253,21 @@ fn parse_anthropic_response(
12531253
}
12541254
}
12551255

1256-
let choice = OneOrMany::many(assistant_content).map_err(|_| {
1256+
let choice = OneOrMany::many(assistant_content).unwrap_or_else(|_| {
1257+
// Anthropic returns an empty content array when stop_reason is end_turn
1258+
// and the model has nothing further to say (e.g. after a side-effect-only
1259+
// tool call like react/skip). Treat this as a clean empty response rather
1260+
// than an error so the agentic loop terminates gracefully.
1261+
let stop_reason = body["stop_reason"].as_str().unwrap_or("unknown");
12571262
tracing::debug!(
1258-
stop_reason = body["stop_reason"].as_str().unwrap_or("unknown"),
1263+
stop_reason,
12591264
content_blocks = content_blocks.len(),
1260-
raw_content = %body["content"],
1261-
"empty assistant_content after parsing Anthropic response"
1265+
"empty assistant_content from Anthropic — returning synthetic empty text"
12621266
);
1263-
CompletionError::ResponseError("empty response from Anthropic".into())
1264-
})?;
1267+
OneOrMany::one(AssistantContent::Text(Text {
1268+
text: String::new(),
1269+
}))
1270+
});
12651271

12661272
let input_tokens = body["usage"]["input_tokens"].as_u64().unwrap_or(0);
12671273
let output_tokens = body["usage"]["output_tokens"].as_u64().unwrap_or(0);

0 commit comments

Comments
 (0)