feat(runtime): 为上下文超限错误添加自动重试机制

添加 RuntimeError::is_retryable_context_error 方法,用于识别可重试的上下文错误(如令牌超限、上下文窗口超限等)。当对话执行遇到此类错误时,自动触发会话压缩并重试,而非直接失败,提高系统的鲁棒性。
This commit is contained in:
zhaoyanchao 2026-04-28 14:53:57 +08:00
parent 8fc9296fed
commit 2a985c1cc7
1 changed files with 36 additions and 16 deletions

View File

@ -95,6 +95,22 @@ impl RuntimeError {
message: message.into(),
}
}
/// Checks if this error is eligible for automatic retry and self-healing (e.g., via session compaction).
/// This list can be expanded in the future as new retryable error types are identified.
#[must_use]
pub fn is_retryable_context_error(&self) -> bool {
let msg = self.message.to_lowercase();
let retryable_markers = [
// Context window limits that can be fixed by compaction
"maximum context length",
"too many tokens",
"context_length_exceeded",
"prompt is too long",
"context window",
];
retryable_markers.iter().any(|marker| msg.contains(marker))
}
}
impl Display for RuntimeError {
@ -358,24 +374,28 @@ where
Err(error) => {
self.record_turn_failed(iterations, &error);
let result = compact_session(
&self.session,
CompactionConfig {
max_estimated_tokens: 0,
..Default::default()
},
);
if result.removed_message_count > 0 {
self.session = result.compacted_session;
if error.is_retryable_context_error() {
let result = compact_session(
&self.session,
CompactionConfig {
max_estimated_tokens: 0,
..Default::default()
},
);
if result.removed_message_count > 0 {
self.session = result.compacted_session;
}
let error_msg = format!("API request failed with error: {error}\nI have automatically truncated the earlier conversation history to reduce context length. Please analyze the error, review your task, and continue.");
if let Err(e) = self.session.push_user_text(error_msg) {
return Err(RuntimeError::new(format!(
"Failed to push error message: {e}"
)));
}
continue;
}
let error_msg = format!("API request failed with error: {error}\nI have automatically truncated the earlier conversation history to reduce context length. Please analyze the error, review your task, and continue.");
if let Err(e) = self.session.push_user_text(error_msg) {
return Err(RuntimeError::new(format!(
"Failed to push error message: {e}"
)));
}
continue;
return Err(error);
}
};
let (assistant_message, usage, turn_prompt_cache_events) =