Agent: one turn path, tools and history in their own modules; SDK: one parser
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
//! History window selection and context-size error detection.
|
||||
|
||||
use crate::llm::Entry;
|
||||
|
||||
pub fn is_too_large(error: &str) -> bool {
|
||||
let Some((status, body)) = error
|
||||
.strip_prefix("HTTP ")
|
||||
.and_then(|error| error.split_once(':'))
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
if !matches!(status.split_whitespace().next(), Some("400" | "413")) {
|
||||
return false;
|
||||
}
|
||||
let body = body.to_ascii_lowercase();
|
||||
body.contains("context_length_exceeded")
|
||||
|| body.contains("maximum context length")
|
||||
|| body.contains("context length exceeded")
|
||||
|| body.contains("too large")
|
||||
|| (body.contains("too long")
|
||||
&& ["context", "input", "prompt"]
|
||||
.iter()
|
||||
.any(|term| body.contains(term)))
|
||||
}
|
||||
|
||||
pub fn next_turn_start(history: &[Entry], from: usize, current: usize) -> Option<usize> {
|
||||
let end = current.min(history.len().checked_sub(1)?);
|
||||
(from..=end).find(|&index| matches!(&history[index], Entry::User { .. }))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn detects_context_size_errors_only_for_http_400_or_413() {
|
||||
assert!(is_too_large("HTTP 400: context_length_exceeded"));
|
||||
assert!(is_too_large("HTTP 413: prompt is too long"));
|
||||
assert!(is_too_large("HTTP 400: maximum context length"));
|
||||
assert!(is_too_large("HTTP 400: request is too large"));
|
||||
assert!(!is_too_large("HTTP 500: prompt is too long"));
|
||||
assert!(!is_too_large("HTTP 400: invalid token"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn history_skip_advances_by_whole_user_turns() {
|
||||
let history = vec![
|
||||
Entry::User {
|
||||
text: "first".into(),
|
||||
},
|
||||
Entry::ToolCall {
|
||||
id: "a".into(),
|
||||
name: "tool".into(),
|
||||
arguments: "{}".into(),
|
||||
},
|
||||
Entry::ToolResult {
|
||||
id: "a".into(),
|
||||
output: "done".into(),
|
||||
},
|
||||
Entry::User {
|
||||
text: "second".into(),
|
||||
},
|
||||
Entry::ToolCall {
|
||||
id: "b".into(),
|
||||
name: "tool".into(),
|
||||
arguments: "{}".into(),
|
||||
},
|
||||
Entry::ToolResult {
|
||||
id: "b".into(),
|
||||
output: "done".into(),
|
||||
},
|
||||
Entry::User {
|
||||
text: "current".into(),
|
||||
},
|
||||
];
|
||||
assert_eq!(next_turn_start(&history, 0, 6), Some(0));
|
||||
assert_eq!(next_turn_start(&history, 1, 6), Some(3));
|
||||
assert_eq!(next_turn_start(&history, 4, 6), Some(6));
|
||||
assert_eq!(next_turn_start(&history, usize::MAX, 6).unwrap_or(6), 6);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user