kernel/capabilities/
mod.rs1pub mod chat;
6pub mod chunk;
7pub mod stop_matcher;
8pub mod think_splitter;
9pub mod tools;
10
11pub use chat::{
12 AttachmentKind, ChatAttachment, ChatMessage, ChatMlPrompt, ChatRole, ChatWireError,
13 decode_tool_specs,
14};
15pub use chunk::{AudioFrame, CapabilityChunk, GenerationStats};
16pub use stop_matcher::{StopMatcher, stop_strings};
17pub use think_splitter::{Piece, TagPair, ThinkSplitter, has_visible_tags};
18pub use tools::{ToolCall, ToolSpec};
19
20pub(crate) fn char_boundary_from_end(text: &str, chars_from_end: usize) -> usize {
24 if chars_from_end == 0 {
25 return text.len();
26 }
27 text.char_indices()
28 .rev()
29 .nth(chars_from_end - 1)
30 .map_or(0, |(index, _)| index)
31}
32
33pub(crate) fn held_suffix_len(text: &str, candidates: &[String]) -> usize {
37 let max_chars = candidates
38 .iter()
39 .map(|candidate| candidate.chars().count())
40 .max()
41 .unwrap_or(1);
42 let cap = max_chars.saturating_sub(1).min(text.chars().count());
43 for length in (1..=cap).rev() {
44 let start = char_boundary_from_end(text, length);
45 let suffix = &text[start..];
46 if candidates
47 .iter()
48 .any(|candidate| candidate.starts_with(suffix))
49 {
50 return text.len() - start;
51 }
52 }
53 0
54}