use crate::ir::StreamDelta;
use super::super::ctx::StreamCtx;
use super::super::state::StreamState;
use super::DeltaVec;
pub(super) fn close_reasoning(state: &mut StreamState, ctx: &StreamCtx, deltas: &mut DeltaVec) {
state.thinking_done = true;
if ctx.enable_thinking && state.all_toks.len() > 1 {
let full = ctx
.state
.tokenizer
.decode(&state.all_toks[..state.all_toks.len() - 1])
.unwrap_or_default();
let stable = full.trim_end_matches('\u{FFFD}');
if stable.len() > state.emitted {
let residual = &stable[state.emitted..];
if !residual.is_empty() {
deltas.push(StreamDelta::Reasoning {
text: residual.to_string(),
token_ids: state.take_ids_if(ctx.req_return_token_ids),
});
}
}
}
if !state.reasoning_suppressing_leak && !state.reasoning_tag_scan_buf.is_empty() {
let tail = std::mem::take(&mut state.reasoning_tag_scan_buf);
if !tail.is_empty() {
deltas.push(StreamDelta::Reasoning {
text: tail,
token_ids: Vec::new(),
});
}
}
if let Some(ref mut det) = state.detector {
det.reset();
}
state.emitted = 0;
state.all_toks.clear();
state.content_decoded.clear();
state.detok_prefix_offset = 0;
state.detok_read_offset = 0;
}