From 2a985c1cc7d92c148f25c5f37decbe8be54cc740 Mon Sep 17 00:00:00 2001 From: zhaoyanchao Date: Tue, 28 Apr 2026 14:53:57 +0800 Subject: [PATCH] =?UTF-8?q?feat(runtime):=20=E4=B8=BA=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E6=96=87=E8=B6=85=E9=99=90=E9=94=99=E8=AF=AF=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=87=8D=E8=AF=95=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加 RuntimeError::is_retryable_context_error 方法,用于识别可重试的上下文错误(如令牌超限、上下文窗口超限等)。当对话执行遇到此类错误时,自动触发会话压缩并重试,而非直接失败,提高系统的鲁棒性。 --- rust/crates/runtime/src/conversation.rs | 52 +++++++++++++++++-------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/rust/crates/runtime/src/conversation.rs b/rust/crates/runtime/src/conversation.rs index ba92168b..c32a9127 100644 --- a/rust/crates/runtime/src/conversation.rs +++ b/rust/crates/runtime/src/conversation.rs @@ -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) =