fix: auto-compact on context limit error (#3635)
Signed-off-by: Kyle 🐆 <kyle@privkey.io>
This commit is contained in:
@@ -1235,11 +1235,29 @@ impl Agent {
|
|||||||
messages_to_add.push(final_message_tool_resp);
|
messages_to_add.push(final_message_tool_resp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ProviderError::ContextLengthExceeded(_)) => {
|
Err(ProviderError::ContextLengthExceeded(error_msg)) => {
|
||||||
yield AgentEvent::Message(Message::assistant().with_context_length_exceeded(
|
info!("Context length exceeded, attempting compaction");
|
||||||
"The context length of the model has been exceeded. Please start a new session and try again.",
|
|
||||||
));
|
match auto_compact::perform_compaction(self, messages.messages()).await {
|
||||||
break;
|
Ok(compact_result) => {
|
||||||
|
messages = compact_result.messages;
|
||||||
|
|
||||||
|
yield AgentEvent::Message(
|
||||||
|
Message::assistant().with_summarization_requested(
|
||||||
|
"Context limit reached. Conversation has been automatically compacted to continue."
|
||||||
|
)
|
||||||
|
);
|
||||||
|
yield AgentEvent::HistoryReplaced(messages.messages().to_vec());
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
yield AgentEvent::Message(Message::assistant().with_context_length_exceeded(
|
||||||
|
format!("Context length exceeded and cannot summarize: {}. Unable to continue.", error_msg)
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error: {}", e);
|
error!("Error: {}", e);
|
||||||
|
|||||||
@@ -120,6 +120,50 @@ pub async fn check_compaction_needed(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform compaction on messages without checking thresholds
|
||||||
|
///
|
||||||
|
/// This function directly performs compaction on the provided messages.
|
||||||
|
/// If the most recent message is a user message, it will be preserved by removing it
|
||||||
|
/// before compaction and adding it back afterwards.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `agent` - The agent to use for context management
|
||||||
|
/// * `messages` - The current message history
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * `AutoCompactResult` containing the compacted messages and metadata
|
||||||
|
pub async fn perform_compaction(agent: &Agent, messages: &[Message]) -> Result<AutoCompactResult> {
|
||||||
|
info!("Performing message compaction");
|
||||||
|
|
||||||
|
// Check if the most recent message is a user message
|
||||||
|
let (messages_to_compact, preserved_user_message) = if let Some(last_message) = messages.last()
|
||||||
|
{
|
||||||
|
if matches!(last_message.role, rmcp::model::Role::User) {
|
||||||
|
// Remove the last user message before compaction
|
||||||
|
(&messages[..messages.len() - 1], Some(last_message.clone()))
|
||||||
|
} else {
|
||||||
|
(messages, None)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(messages, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Perform the compaction on messages excluding the preserved user message
|
||||||
|
let (mut compacted_messages, _, summarization_usage) =
|
||||||
|
agent.summarize_context(messages_to_compact).await?;
|
||||||
|
|
||||||
|
// Add back the preserved user message if it exists
|
||||||
|
if let Some(user_message) = preserved_user_message {
|
||||||
|
compacted_messages.push(user_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(AutoCompactResult {
|
||||||
|
compacted: true,
|
||||||
|
messages: compacted_messages,
|
||||||
|
summarization_usage,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if messages need compaction and compact them if necessary
|
/// Check if messages need compaction and compact them if necessary
|
||||||
///
|
///
|
||||||
/// This is a convenience wrapper function that combines checking and compaction.
|
/// This is a convenience wrapper function that combines checking and compaction.
|
||||||
@@ -163,33 +207,8 @@ pub async fn check_and_compact_messages(
|
|||||||
check_result.usage_ratio * 100.0
|
check_result.usage_ratio * 100.0
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check if the most recent message is a user message
|
// Use perform_compaction to do the actual work
|
||||||
let (messages_to_compact, preserved_user_message) = if let Some(last_message) = messages.last()
|
perform_compaction(agent, messages).await
|
||||||
{
|
|
||||||
if matches!(last_message.role, rmcp::model::Role::User) {
|
|
||||||
// Remove the last user message before auto-compaction
|
|
||||||
(&messages[..messages.len() - 1], Some(last_message.clone()))
|
|
||||||
} else {
|
|
||||||
(messages, None)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(messages, None)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Perform the compaction on messages excluding the preserved user message
|
|
||||||
let (mut compacted_messages, _, summarization_usage) =
|
|
||||||
agent.summarize_context(messages_to_compact).await?;
|
|
||||||
|
|
||||||
// Add back the preserved user message if it exists
|
|
||||||
if let Some(user_message) = preserved_user_message {
|
|
||||||
compacted_messages.push(user_message);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(AutoCompactResult {
|
|
||||||
compacted: true,
|
|
||||||
messages: compacted_messages,
|
|
||||||
summarization_usage,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
Reference in New Issue
Block a user