feat: long-running session improvements

- Hang fix: 120s timeout on compression LLM call + raw_stream
  channel-close handling (None => break instead of spinning)
- Supervisor effective active count: stop counting finished
  JoinHandles as occupying capacity slots
- Universal tool result size cap: truncate_if_needed() on
  ToolResult, applied in eval_tool_calls() after escalation block;
  configurable via max_tool_result_chars in AppConfig/AgentConfig
- Windowed compression: compression_keep_last config param keeps
  the N most recent messages visible after compression
- Fix pre-existing flaky test: add #[serial] to
  handle_list_available_unrestricted_when_no_whitelist so it does
  not race with TestConfigDirGuard-based tests that temporarily
  populate the agents data dir
This commit is contained in:
2026-07-23 12:25:54 -06:00
parent d51bdd3086
commit 54c5079cb7
9 changed files with 118 additions and 19 deletions
+25
View File
@@ -184,6 +184,20 @@ pub async fn eval_tool_calls(
}
}
{
let max_chars = ctx
.agent
.as_ref()
.and_then(|a| a.max_tool_result_chars())
.or_else(|| ctx.app.config.max_tool_result_chars);
if let Some(max_chars) = max_chars.filter(|&n| n > 0) {
output = output
.into_iter()
.map(|r| r.truncate_if_needed(max_chars))
.collect();
}
}
Ok(output)
}
@@ -219,6 +233,17 @@ impl ToolResult {
thinking: vec![],
}
}
pub fn truncate_if_needed(mut self, max_chars: usize) -> Self {
let s = self.output.to_string();
if s.len() > max_chars {
let prefix = s.get(..max_chars).unwrap_or(s.as_str());
self.output = json!(format!(
"[truncated: tool output exceeded {max_chars} chars]\n{prefix}"
));
}
self
}
}
#[derive(Debug, Clone, Default)]