Compact session automatically for streaming providers on Context Length Exceeded (#4565)
This commit is contained in:
@@ -926,7 +926,7 @@ impl Session {
|
|||||||
.reply(
|
.reply(
|
||||||
self.messages.clone(),
|
self.messages.clone(),
|
||||||
session_config.clone(),
|
session_config.clone(),
|
||||||
Some(cancel_token),
|
Some(cancel_token.clone()),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -1285,6 +1285,55 @@ impl Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Some(Err(e)) => {
|
Some(Err(e)) => {
|
||||||
|
// Check if it's a ProviderError::ContextLengthExceeded
|
||||||
|
if e.downcast_ref::<goose::providers::errors::ProviderError>()
|
||||||
|
.map(|provider_error| matches!(provider_error, goose::providers::errors::ProviderError::ContextLengthExceeded(_)))
|
||||||
|
.unwrap_or(false) {
|
||||||
|
|
||||||
|
output::render_text(
|
||||||
|
"Context limit reached. Performing auto-compaction...",
|
||||||
|
Some(Color::Yellow),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try auto-compaction first - keep the stream alive!
|
||||||
|
if let Ok(compact_result) = goose::context_mgmt::auto_compact::perform_compaction(&self.agent, self.messages.messages()).await {
|
||||||
|
self.messages = compact_result.messages;
|
||||||
|
|
||||||
|
// Persist the compacted messages
|
||||||
|
if let Some(session_file) = &self.session_file {
|
||||||
|
let provider = self.agent.provider().await.ok();
|
||||||
|
let working_dir = std::env::current_dir().ok();
|
||||||
|
if let Err(e) = session::persist_messages_with_schedule_id(
|
||||||
|
session_file,
|
||||||
|
&self.messages,
|
||||||
|
provider,
|
||||||
|
self.scheduled_job_id.clone(),
|
||||||
|
working_dir,
|
||||||
|
).await {
|
||||||
|
eprintln!("Failed to persist compacted messages: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output::render_text(
|
||||||
|
"Compaction complete. Conversation has been automatically compacted to continue.",
|
||||||
|
Some(Color::Yellow),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Restart the stream after successful compaction - keep the stream alive!
|
||||||
|
stream = self
|
||||||
|
.agent
|
||||||
|
.reply(
|
||||||
|
self.messages.clone(),
|
||||||
|
session_config.clone(),
|
||||||
|
Some(cancel_token.clone())
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Auto-compaction failed, fall through to common error handling below
|
||||||
|
}
|
||||||
eprintln!("Error: {}", e);
|
eprintln!("Error: {}", e);
|
||||||
cancel_token_clone.cancel();
|
cancel_token_clone.cancel();
|
||||||
drop(stream);
|
drop(stream);
|
||||||
@@ -1296,47 +1345,46 @@ impl Session {
|
|||||||
if e.downcast_ref::<goose::providers::errors::ProviderError>()
|
if e.downcast_ref::<goose::providers::errors::ProviderError>()
|
||||||
.map(|provider_error| matches!(provider_error, goose::providers::errors::ProviderError::ContextLengthExceeded(_)))
|
.map(|provider_error| matches!(provider_error, goose::providers::errors::ProviderError::ContextLengthExceeded(_)))
|
||||||
.unwrap_or(false) {
|
.unwrap_or(false) {
|
||||||
|
output::render_error(&format!("Error: Context length exceeded: {}", e));
|
||||||
|
|
||||||
output::render_error(&format!("Error: Context length exceeded: {}", e));
|
let prompt = "The tool calling loop was interrupted. How would you like to proceed?";
|
||||||
|
let selected = match cliclack::select(prompt.to_string())
|
||||||
let prompt = "The tool calling loop was interrupted. How would you like to proceed?";
|
.item("clear", "Clear Session", "Removes all messages from Goose's memory")
|
||||||
let selected = match cliclack::select(prompt.to_string())
|
.item("summarize", "Summarize Session", "Summarize the session to reduce context length")
|
||||||
.item("clear", "Clear Session", "Removes all messages from Goose's memory")
|
.interact()
|
||||||
.item("summarize", "Summarize Session", "Summarize the session to reduce context length")
|
{
|
||||||
.interact()
|
Ok(choice) => Some(choice),
|
||||||
{
|
Err(e) => {
|
||||||
Ok(choice) => Some(choice),
|
if e.kind() == std::io::ErrorKind::Interrupted {
|
||||||
Err(e) => {
|
// If interrupted, do nothing and let user handle it manually
|
||||||
if e.kind() == std::io::ErrorKind::Interrupted {
|
output::render_text("Operation cancelled. You can use /clear or /summarize to continue.", Some(Color::Yellow), true);
|
||||||
// If interrupted, do nothing and let user handle it manually
|
None
|
||||||
output::render_text("Operation cancelled. You can use /clear or /summarize to continue.", Some(Color::Yellow), true);
|
} else {
|
||||||
None
|
return Err(e.into());
|
||||||
} else {
|
|
||||||
return Err(e.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(choice) = selected {
|
|
||||||
match choice {
|
|
||||||
"clear" => {
|
|
||||||
self.messages.clear();
|
|
||||||
let msg = format!("Session cleared.\n{}", "-".repeat(50));
|
|
||||||
output::render_text(&msg, Some(Color::Yellow), true);
|
|
||||||
}
|
|
||||||
"summarize" => {
|
|
||||||
// Use the helper function to summarize context
|
|
||||||
let message_suffix = "Goose summarized messages for you.";
|
|
||||||
if let Err(e) = Self::summarize_context_messages(&mut self.messages, &self.agent, message_suffix).await {
|
|
||||||
output::render_error(&format!("Failed to summarize: {}", e));
|
|
||||||
output::render_text("Consider using /clear to start fresh.", Some(Color::Yellow), true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
};
|
||||||
unreachable!()
|
|
||||||
|
if let Some(choice) = selected {
|
||||||
|
match choice {
|
||||||
|
"clear" => {
|
||||||
|
self.messages.clear();
|
||||||
|
let msg = format!("Session cleared.\n{}", "-".repeat(50));
|
||||||
|
output::render_text(&msg, Some(Color::Yellow), true);
|
||||||
|
}
|
||||||
|
"summarize" => {
|
||||||
|
// Use the helper function to summarize context
|
||||||
|
let message_suffix = "Goose summarized messages for you.";
|
||||||
|
if let Err(e) = Self::summarize_context_messages(&mut self.messages, &self.agent, message_suffix).await {
|
||||||
|
output::render_error(&format!("Failed to summarize: {}", e));
|
||||||
|
output::render_text("Consider using /clear to start fresh.", Some(Color::Yellow), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
output::render_error(
|
output::render_error(
|
||||||
"The error above was an exception we were not able to handle.\n\
|
"The error above was an exception we were not able to handle.\n\
|
||||||
|
|||||||
Reference in New Issue
Block a user