feat(goose-acp): enable parallel sessions with isolated agent state (#6392)

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Adrian Cole
2026-01-15 06:19:17 +08:00
committed by GitHub
parent fb0eca2c36
commit 7d4a6bd8ff
86 changed files with 2594 additions and 1938 deletions
+28 -30
View File
@@ -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)
+32 -8
View File
@@ -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