fix(rlm_query): Phase 1+2 - Add diagnostic logs and fallback for empty responses

This commit is contained in:
Hunter Bown
2026-04-26 16:48:00 -05:00
parent c1259eff68
commit 96c979f160
+60 -6
View File
@@ -240,12 +240,31 @@ impl ToolSpec for RlmQueryTool {
let response = timeout(DEFAULT_CHILD_TIMEOUT, client.complete(request)).await;
let elapsed_ms = started.elapsed().as_millis() as u64;
in_flight.fetch_sub(1, Ordering::Relaxed);
let mut text_len = 0;
let mut thinking_len = 0;
let mut finish_reason = None;
if let Ok(Ok(ref res)) = response {
finish_reason = res.stop_reason.clone();
for block in &res.content {
match block {
ContentBlock::Text { text, .. } => text_len += text.len(),
ContentBlock::Thinking { thinking, .. } => thinking_len += thinking.len(),
_ => {}
}
}
}
debug!(
target: "deepseek_cli::tools",
tool = "rlm_query",
idx,
elapsed_ms,
ok = response.is_ok(),
text_len,
thinking_len,
finish_reason = ?finish_reason,
"child request done"
);
(idx, response)
@@ -267,7 +286,7 @@ impl ToolSpec for RlmQueryTool {
.into_iter()
.map(|(idx, res)| {
let text = match res {
Ok(Ok(response)) => extract_text(&response.content),
Ok(Ok(response)) => extract_text(&response.content, idx, response.stop_reason.as_deref()),
Ok(Err(e)) => format!("[error: {e}]"),
Err(_) => format!(
"[error: timed out after {}s]",
@@ -297,15 +316,38 @@ impl ToolSpec for RlmQueryTool {
}
}
fn extract_text(blocks: &[ContentBlock]) -> String {
blocks
fn extract_text(blocks: &[ContentBlock], idx: usize, finish_reason: Option<&str>) -> String {
let text = blocks
.iter()
.filter_map(|b| match b {
ContentBlock::Text { text, .. } => Some(text.as_str()),
_ => None,
})
.collect::<Vec<_>>()
.join("\n")
.join("\n");
if !text.trim().is_empty() {
return text;
}
let thinking = blocks
.iter()
.filter_map(|b| match b {
ContentBlock::Thinking { thinking, .. } => Some(thinking.as_str()),
_ => None,
})
.collect::<Vec<_>>()
.join("\n");
if !thinking.trim().is_empty() {
return format!("[Child {} thinking fallback]\n{}", idx, thinking);
}
format!(
"[empty response from child idx {} — finish_reason={}, raise max_tokens]",
idx,
finish_reason.unwrap_or("unknown")
)
}
#[cfg(test)]
@@ -548,7 +590,7 @@ mod tests {
cache_control: None,
},
];
assert_eq!(extract_text(&blocks), "first\nsecond");
assert_eq!(extract_text(&blocks, 0, None), "first\nsecond");
}
#[test]
@@ -556,7 +598,19 @@ mod tests {
let blocks = vec![ContentBlock::Thinking {
thinking: "no visible text".to_string(),
}];
assert_eq!(extract_text(&blocks), "");
assert_eq!(
extract_text(&blocks, 0, None),
"[Child 0 thinking fallback]\nno visible text"
);
}
#[test]
fn extract_text_returns_sentinel_when_all_empty() {
let blocks = vec![];
assert_eq!(
extract_text(&blocks, 1, Some("length")),
"[empty response from child idx 1 — finish_reason=length, raise max_tokens]"
);
}
#[test]