use crate::{
config::{EffectiveConfig, Settings},
providers::{
ChatMessage, ProviderEvent, ProviderRequest, ProviderSelection,
provider_from_selection_with_settings_for_workload,
},
};
use std::{path::Path, thread, time::Duration};
const MAX_OUTPUT_BYTES: usize = 1024 * 1024;
const PROMPT: &str = include_str!("../../prompts/progressive_event_summaries.md");
pub(crate) fn summarize_records(
config: &EffectiveConfig,
settings: &Settings,
cwd: &Path,
records: &[&str],
status: &mut crate::sessions::progressive_summaries::Status,
) -> anyhow::Result<String> {
let raw_records = records.join(",\n");
status.batch(records.len(), raw_records.len() + 2);
let mut selected = match (&settings.psm.provider, &settings.psm.model) {
(Some(provider), Some(model)) => {
crate::auth::load_effective_provider_selection(&config.paths, provider, model)?
}
_ => config.clone(),
};
selected.thinking_level = settings.psm.reasoning.unwrap_or(config.thinking_level);
let selection = ProviderSelection::from_config(&selected)?;
status.selection(&selection);
let provider = provider_from_selection_with_settings_for_workload(
&selected,
&selection,
cwd,
settings,
crate::providers::FastWorkload::ProgressiveSessionMaintenance,
)?;
let request = ProviderRequest::new_without_tools(
selection.model,
vec![
ChatMessage::system(PROMPT),
ChatMessage::user(format!("[{raw_records}]")),
],
)
.with_thinking_level(selected.thinking_level)
.with_text_verbosity(settings.text_verbosity_for(&selection.provider));
status.stage(crate::sessions::progressive_summaries::Stage::RequestingSummary);
let cancellation = crate::cancellation::AgentCancellation::default();
let (token, timeout) = cancellation.child_token();
let (done_sender, done_receiver) = crossbeam_channel::bounded::<()>(1);
let watchdog = thread::Builder::new()
.name("psm-timeout".into())
.spawn(move || {
if done_receiver.recv_timeout(Duration::from_secs(120))
== Err(crossbeam_channel::RecvTimeoutError::Timeout)
{
timeout.cancel();
}
})?;
let mut raw = String::new();
let mut receiving = false;
let result = provider.stream_cancellable(request, &token, &mut |event| {
token.check()?;
if !receiving {
receiving = true;
status.stage(crate::sessions::progressive_summaries::Stage::ReceivingSummary);
}
if let ProviderEvent::TextDelta(delta) = event {
anyhow::ensure!(
raw.len() + delta.len() <= MAX_OUTPUT_BYTES,
"PSM response exceeds limit"
);
raw.push_str(&delta);
}
Ok(())
});
let _ = done_sender.send(());
let _ = watchdog.join();
anyhow::ensure!(
!token.is_canceled(),
"PSM provider request exceeded 120-second deadline"
);
result?;
token.check()?;
Ok(raw)
}