use super::phantom::looks_truncated_mid_sentence;
use super::types::{ProgressCallback, ProgressEvent};
use crate::brain::agent::context::AgentContext;
use crate::brain::provider::Message;
use uuid::Uuid;
pub(super) fn try_emit_truncation_continue(
iteration_text: &str,
reasoning_text: Option<&String>,
context: &mut AgentContext,
session_id: Uuid,
progress_callback: &Option<ProgressCallback>,
) -> bool {
if !looks_truncated_mid_sentence(iteration_text.trim_end()) {
return false;
}
let preview: String = iteration_text
.chars()
.rev()
.take(60)
.collect::<String>()
.chars()
.rev()
.collect();
tracing::warn!(
"Response ended with finish_reason=stop but last chars look \
mid-sentence (tail={:?}) — asking model to continue once.",
preview,
);
if let Some(cb) = progress_callback {
cb(
session_id,
ProgressEvent::SelfHealingAlert {
message: "Response was cut off mid-sentence — asking model to continue".into(),
},
);
}
if !iteration_text.is_empty()
&& let Some(cb) = progress_callback
{
cb(
session_id,
ProgressEvent::IntermediateText {
text: iteration_text.to_string(),
reasoning: reasoning_text.cloned(),
},
);
}
context.add_message(Message::assistant(iteration_text.to_string()));
context.add_message(Message::user(
"[System: Your previous reply was cut off mid-sentence (no terminal \
punctuation). Continue from exactly where you left off — do NOT repeat \
what you already wrote, do NOT restart the answer, do NOT re-plan. \
Just keep writing.]"
.to_string(),
));
true
}