feat(goose-acp): enable parallel sessions with isolated agent state (#6392)
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
@@ -10,9 +10,7 @@ use goose::config::{
|
||||
use goose::providers::create;
|
||||
use goose::recipe::{Response, SubRecipe};
|
||||
|
||||
use goose::agents::extension::PlatformExtensionContext;
|
||||
use goose::session::session_manager::SessionType;
|
||||
use goose::session::SessionManager;
|
||||
use goose::session::{EnabledExtensionsState, ExtensionState};
|
||||
use rustyline::EditMode;
|
||||
use std::collections::HashSet;
|
||||
@@ -147,12 +145,15 @@ async fn offer_extension_debugging_help(
|
||||
// Create a minimal agent for debugging
|
||||
let debug_agent = Agent::new();
|
||||
|
||||
let session = SessionManager::create_session(
|
||||
std::env::current_dir()?,
|
||||
"CLI Session".to_string(),
|
||||
SessionType::Hidden,
|
||||
)
|
||||
.await?;
|
||||
let session = debug_agent
|
||||
.config
|
||||
.session_manager
|
||||
.create_session(
|
||||
std::env::current_dir()?,
|
||||
"CLI Session".to_string(),
|
||||
SessionType::Hidden,
|
||||
)
|
||||
.await?;
|
||||
|
||||
debug_agent.update_provider(provider, &session.id).await?;
|
||||
|
||||
@@ -252,10 +253,12 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
|
||||
goose::posthog::set_session_context("cli", session_config.resume);
|
||||
|
||||
let config = Config::global();
|
||||
let agent: Agent = Agent::new();
|
||||
let session_manager = agent.config.session_manager.clone();
|
||||
|
||||
let (saved_provider, saved_model_config) = if session_config.resume {
|
||||
if let Some(ref session_id) = session_config.session_id {
|
||||
match SessionManager::get_session(session_id, false).await {
|
||||
match session_manager.get_session(session_id, false).await {
|
||||
Ok(session_data) => (session_data.provider_name, session_data.model_config),
|
||||
Err(_) => (None, None),
|
||||
}
|
||||
@@ -310,8 +313,6 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
|
||||
.with_temperature(temperature)
|
||||
};
|
||||
|
||||
let agent: Agent = Agent::new();
|
||||
|
||||
agent
|
||||
.apply_recipe_components(
|
||||
session_config.sub_recipes,
|
||||
@@ -348,17 +349,14 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
|
||||
|
||||
let session_id: String = if session_config.no_session {
|
||||
let working_dir = std::env::current_dir().expect("Could not get working directory");
|
||||
let session = SessionManager::create_session(
|
||||
working_dir,
|
||||
"CLI Session".to_string(),
|
||||
SessionType::Hidden,
|
||||
)
|
||||
.await
|
||||
.expect("Could not create session");
|
||||
let session = session_manager
|
||||
.create_session(working_dir, "CLI Session".to_string(), SessionType::Hidden)
|
||||
.await
|
||||
.expect("Could not create session");
|
||||
session.id
|
||||
} else if session_config.resume {
|
||||
if let Some(session_id) = session_config.session_id {
|
||||
match SessionManager::get_session(&session_id, false).await {
|
||||
match session_manager.get_session(&session_id, false).await {
|
||||
Ok(_) => session_id,
|
||||
Err(_) => {
|
||||
output::render_error(&format!(
|
||||
@@ -369,7 +367,7 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match SessionManager::list_sessions().await {
|
||||
match session_manager.list_sessions().await {
|
||||
Ok(sessions) if !sessions.is_empty() => sessions[0].id.clone(),
|
||||
_ => {
|
||||
output::render_error("Cannot resume - no previous sessions found");
|
||||
@@ -389,16 +387,11 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
agent
|
||||
.extension_manager
|
||||
.set_context(PlatformExtensionContext {
|
||||
session_id: Some(session_id.clone()),
|
||||
extension_manager: Some(Arc::downgrade(&agent.extension_manager)),
|
||||
})
|
||||
.await;
|
||||
|
||||
if session_config.resume {
|
||||
let session = SessionManager::get_session(&session_id, false)
|
||||
let session = agent
|
||||
.config
|
||||
.session_manager
|
||||
.get_session(&session_id, false)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
output::render_error(&format!("Failed to read session metadata: {}", e));
|
||||
@@ -451,7 +444,12 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
|
||||
let extensions_to_run: Vec<_> = if let Some(extensions) = session_config.extensions_override {
|
||||
extensions.into_iter().collect()
|
||||
} else if session_config.resume {
|
||||
match SessionManager::get_session(&session_id, false).await {
|
||||
match agent
|
||||
.config
|
||||
.session_manager
|
||||
.get_session(&session_id, false)
|
||||
.await
|
||||
{
|
||||
Ok(session_data) => {
|
||||
if let Some(saved_state) =
|
||||
EnabledExtensionsState::from_extension_data(&session_data.extension_data)
|
||||
|
||||
@@ -33,7 +33,6 @@ use goose::agents::extension::{Envs, ExtensionConfig, PLATFORM_EXTENSIONS};
|
||||
use goose::agents::types::RetryConfig;
|
||||
use goose::agents::{Agent, SessionConfig, COMPACT_TRIGGERS};
|
||||
use goose::config::{Config, GooseMode};
|
||||
use goose::session::SessionManager;
|
||||
use input::InputResult;
|
||||
use rmcp::model::PromptMessage;
|
||||
use rmcp::model::ServerNotification;
|
||||
@@ -229,7 +228,10 @@ impl CliSession {
|
||||
retry_config: Option<RetryConfig>,
|
||||
output_format: String,
|
||||
) -> Self {
|
||||
let messages = SessionManager::get_session(&session_id, true)
|
||||
let messages = agent
|
||||
.config
|
||||
.session_manager
|
||||
.get_session(&session_id, true)
|
||||
.await
|
||||
.map(|session| session.conversation.unwrap_or_default())
|
||||
.unwrap();
|
||||
@@ -693,14 +695,22 @@ impl CliSession {
|
||||
}
|
||||
|
||||
async fn handle_clear(&mut self) -> Result<()> {
|
||||
if let Err(e) =
|
||||
SessionManager::replace_conversation(&self.session_id, &Conversation::default()).await
|
||||
if let Err(e) = self
|
||||
.agent
|
||||
.config
|
||||
.session_manager
|
||||
.replace_conversation(&self.session_id, &Conversation::default())
|
||||
.await
|
||||
{
|
||||
output::render_error(&format!("Failed to clear session: {}", e));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Err(e) = SessionManager::update_session(&self.session_id)
|
||||
if let Err(e) = self
|
||||
.agent
|
||||
.config
|
||||
.session_manager
|
||||
.update(&self.session_id)
|
||||
.total_tokens(Some(0))
|
||||
.input_tokens(Some(0))
|
||||
.output_tokens(Some(0))
|
||||
@@ -1021,7 +1031,13 @@ impl CliSession {
|
||||
}
|
||||
|
||||
if is_json_mode {
|
||||
let metadata = match SessionManager::get_session(&self.session_id, false).await {
|
||||
let metadata = match self
|
||||
.agent
|
||||
.config
|
||||
.session_manager
|
||||
.get_session(&self.session_id, false)
|
||||
.await
|
||||
{
|
||||
Ok(session) => JsonMetadata {
|
||||
total_tokens: session.total_tokens,
|
||||
status: "completed".to_string(),
|
||||
@@ -1037,7 +1053,11 @@ impl CliSession {
|
||||
};
|
||||
println!("{}", serde_json::to_string_pretty(&json_output)?);
|
||||
} else if is_stream_json_mode {
|
||||
let total_tokens = SessionManager::get_session(&self.session_id, false)
|
||||
let total_tokens = self
|
||||
.agent
|
||||
.config
|
||||
.session_manager
|
||||
.get_session(&self.session_id, false)
|
||||
.await
|
||||
.ok()
|
||||
.and_then(|s| s.total_tokens);
|
||||
@@ -1207,7 +1227,11 @@ impl CliSession {
|
||||
}
|
||||
|
||||
pub async fn get_session(&self) -> Result<goose::session::Session> {
|
||||
SessionManager::get_session(&self.session_id, false).await
|
||||
self.agent
|
||||
.config
|
||||
.session_manager
|
||||
.get_session(&self.session_id, false)
|
||||
.await
|
||||
}
|
||||
|
||||
// Get the session's total token usage
|
||||
|
||||
Reference in New Issue
Block a user