use super::spec::HarmonyVocab;
pub(super) fn message_marker_after_tool_call_header(
vocab: &HarmonyVocab,
src: &str,
start: usize,
cursor: usize,
) -> Option<usize> {
let closes_header = src[cursor..].starts_with(&vocab.message_marker)
&& src[start..cursor].contains(&vocab.tool_call_header_prefix);
closes_header.then(|| cursor + vocab.message_marker.len())
}
pub(super) fn frame_marker(
vocab: &HarmonyVocab,
call_tag_opens: &[String],
src: &str,
cursor: usize,
) -> Option<usize> {
if vocab.frame_prefix.is_empty() || vocab.frame_suffix.is_empty() {
return None;
}
let rest = src.get(cursor..)?;
if !rest.starts_with(&vocab.frame_prefix) {
return None;
}
let marker_end_rel = rest.find(&vocab.frame_suffix)?;
if marker_end_rel < vocab.frame_prefix.len() {
return None;
}
let marker = &rest[vocab.frame_prefix.len()..marker_end_rel];
let after_marker = cursor + marker_end_rel + vocab.frame_suffix.len();
if vocab.header_markers.iter().any(|entry| entry == marker) {
Some(header_tail(vocab, call_tag_opens, src, after_marker))
} else if vocab.standalone_markers.iter().any(|entry| entry == marker) {
Some(after_marker)
} else {
None
}
}
pub(super) fn tool_call_line(vocab: &HarmonyVocab, src: &str, cursor: usize) -> Option<usize> {
let rest = src.get(cursor..)?;
if !rest.starts_with(&vocab.message_marker) {
return None;
}
let after_message = cursor + vocab.message_marker.len();
if !src[after_message..]
.trim_start()
.starts_with(&vocab.tool_call_header_prefix)
{
return None;
}
let rel_end = src[after_message..]
.find('\n')
.unwrap_or(src.len() - after_message);
Some(after_message + rel_end)
}
pub(super) fn corrupted_opener(
vocab: &HarmonyVocab,
call_tag_opens: &[String],
src: &str,
cursor: usize,
) -> Option<usize> {
let rest = src.get(cursor..)?;
let opener = vocab
.corrupted_openers
.iter()
.filter(|opener| opener.ends_with(&vocab.frame_prefix))
.find(|opener| rest.starts_with(opener.as_str()))?;
let frame_at = cursor + opener.len() - vocab.frame_prefix.len();
frame_marker(vocab, call_tag_opens, src, frame_at)
}
fn header_tail(
vocab: &HarmonyVocab,
call_tag_opens: &[String],
src: &str,
after_marker: usize,
) -> usize {
let tail = &src[after_marker..];
let next_frame = tail.find(&vocab.frame_prefix);
let next_call_tag = call_tag_opens
.iter()
.filter_map(|open| tail.find(open.as_str()))
.min();
if let Some(message) = tail.find(&vocab.message_marker) {
let prefix = &tail[..message];
let before_payload = !prefix.contains('\n')
&& !call_tag_opens
.iter()
.any(|open| prefix.contains(open.as_str()));
if before_payload && next_frame == Some(message) {
return after_marker + message + vocab.message_marker.len();
}
}
[next_frame, next_call_tag, tail.find('\n')]
.into_iter()
.flatten()
.min()
.map_or(after_marker, |boundary| after_marker + boundary)
}