pub use super::retry_error::is_retryable_upstream_error;
use super::text::role_label;
use crate::provider::{ContentPart, Message};
pub fn messages_to_rlm_context(messages: &[Message]) -> String {
let mut out = String::new();
for (idx, m) in messages.iter().enumerate() {
out.push_str(&format!("[{} {}]\n", idx, role_label(m.role)));
for part in &m.content {
match part {
ContentPart::Text { text } => {
out.push_str(text);
out.push('\n');
}
ContentPart::Thinking { text } => {
if !text.trim().is_empty() {
out.push_str("[Thinking]\n");
out.push_str(text);
out.push('\n');
}
}
ContentPart::ToolCall {
id,
name,
arguments,
..
} => {
out.push_str(&format!(
"[ToolCall id={id} name={name}]\nargs: {arguments}\n"
));
}
ContentPart::ToolResult {
tool_call_id,
content,
} => {
out.push_str(&format!("[ToolResult id={tool_call_id}]\n"));
out.push_str(content);
out.push('\n');
}
ContentPart::Image { mime_type, url } => {
out.push_str(&format!(
"[Image mime_type={} url_len={}]\n",
mime_type.clone().unwrap_or_else(|| "unknown".to_string()),
url.len()
));
}
ContentPart::File { path, mime_type } => {
out.push_str(&format!(
"[File path={} mime_type={}]\n",
path,
mime_type.clone().unwrap_or_else(|| "unknown".to_string())
));
}
}
}
out.push_str("\n---\n\n");
}
out
}
pub fn is_prompt_too_long_error(err: &anyhow::Error) -> bool {
let msg = err.to_string().to_ascii_lowercase();
msg.contains("prompt is too long")
|| msg.contains("context length")
|| (msg.contains("maximum context") || msg.contains("context window"))
|| (msg.contains("tokens") && msg.contains("maximum") && msg.contains("prompt"))
}