mirror of
https://github.com/aljazceru/goose.git
synced 2025-12-18 22:54:24 +01:00
feat: add recipes, a custom goose agent configuration (#2115)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use console::style;
|
||||
use goose::agents::extension::ExtensionError;
|
||||
use goose::agents::Agent;
|
||||
use goose::config::{Config, ExtensionConfigManager};
|
||||
use goose::config::{Config, ExtensionConfig, ExtensionConfigManager};
|
||||
use goose::session;
|
||||
use goose::session::Identifier;
|
||||
use mcp_client::transport::Error as McpClientError;
|
||||
@@ -10,14 +10,31 @@ use std::process;
|
||||
use super::output;
|
||||
use super::Session;
|
||||
|
||||
pub async fn build_session(
|
||||
identifier: Option<Identifier>,
|
||||
resume: bool,
|
||||
extensions: Vec<String>,
|
||||
remote_extensions: Vec<String>,
|
||||
builtins: Vec<String>,
|
||||
debug: bool,
|
||||
) -> Session {
|
||||
/// Configuration for building a new Goose session
|
||||
///
|
||||
/// This struct contains all the parameters needed to create a new session,
|
||||
/// including session identification, extension configuration, and debug settings.
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct SessionBuilderConfig {
|
||||
/// Optional identifier for the session (name or path)
|
||||
pub identifier: Option<Identifier>,
|
||||
/// Whether to resume an existing session
|
||||
pub resume: bool,
|
||||
/// List of stdio extension commands to add
|
||||
pub extensions: Vec<String>,
|
||||
/// List of remote extension commands to add
|
||||
pub remote_extensions: Vec<String>,
|
||||
/// List of builtin extension commands to add
|
||||
pub builtins: Vec<String>,
|
||||
/// List of extensions to enable, enable only this set and ignore configured ones
|
||||
pub extensions_override: Option<Vec<ExtensionConfig>>,
|
||||
/// Any additional system prompt to append to the default
|
||||
pub additional_system_prompt: Option<String>,
|
||||
/// Enable debug printing
|
||||
pub debug: bool,
|
||||
}
|
||||
|
||||
pub async fn build_session(session_config: SessionBuilderConfig) -> Session {
|
||||
// Load config and get provider/model
|
||||
let config = Config::global();
|
||||
|
||||
@@ -36,8 +53,8 @@ pub async fn build_session(
|
||||
let mut agent = Agent::new(provider);
|
||||
|
||||
// Handle session file resolution and resuming
|
||||
let session_file = if resume {
|
||||
if let Some(identifier) = identifier {
|
||||
let session_file = if session_config.resume {
|
||||
if let Some(identifier) = session_config.identifier {
|
||||
let session_file = session::get_path(identifier);
|
||||
if !session_file.exists() {
|
||||
output::render_error(&format!(
|
||||
@@ -60,7 +77,7 @@ pub async fn build_session(
|
||||
}
|
||||
} else {
|
||||
// Create new session with provided name/path or generated name
|
||||
let id = match identifier {
|
||||
let id = match session_config.identifier {
|
||||
Some(identifier) => identifier,
|
||||
None => Identifier::Name(session::generate_session_id()),
|
||||
};
|
||||
@@ -69,7 +86,7 @@ pub async fn build_session(
|
||||
session::get_path(id)
|
||||
};
|
||||
|
||||
if resume {
|
||||
if session_config.resume {
|
||||
// Read the session metadata
|
||||
let metadata = session::read_metadata(&session_file).unwrap_or_else(|e| {
|
||||
output::render_error(&format!("Failed to read session metadata: {}", e));
|
||||
@@ -92,34 +109,38 @@ pub async fn build_session(
|
||||
|
||||
// Setup extensions for the agent
|
||||
// Extensions need to be added after the session is created because we change directory when resuming a session
|
||||
for extension in ExtensionConfigManager::get_all().expect("should load extensions") {
|
||||
if extension.enabled {
|
||||
let config = extension.config.clone();
|
||||
agent
|
||||
.add_extension(config.clone())
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
let err = match e {
|
||||
ExtensionError::Transport(McpClientError::StdioProcessError(inner)) => {
|
||||
inner
|
||||
}
|
||||
_ => e.to_string(),
|
||||
};
|
||||
println!("Failed to start extension: {}, {:?}", config.name(), err);
|
||||
println!(
|
||||
"Please check extension configuration for {}.",
|
||||
config.name()
|
||||
);
|
||||
process::exit(1);
|
||||
});
|
||||
// If we get extensions_override, only run those extensions and none other
|
||||
let extensions_to_run: Vec<_> = if let Some(extensions) = session_config.extensions_override {
|
||||
extensions.into_iter().collect()
|
||||
} else {
|
||||
ExtensionConfigManager::get_all()
|
||||
.expect("should load extensions")
|
||||
.into_iter()
|
||||
.filter(|ext| ext.enabled)
|
||||
.map(|ext| ext.config)
|
||||
.collect()
|
||||
};
|
||||
|
||||
for extension in extensions_to_run {
|
||||
if let Err(e) = agent.add_extension(extension.clone()).await {
|
||||
let err = match e {
|
||||
ExtensionError::Transport(McpClientError::StdioProcessError(inner)) => inner,
|
||||
_ => e.to_string(),
|
||||
};
|
||||
eprintln!("Failed to start extension: {}, {:?}", extension.name(), err);
|
||||
eprintln!(
|
||||
"Please check extension configuration for {}.",
|
||||
extension.name()
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Create new session
|
||||
let mut session = Session::new(agent, session_file.clone(), debug);
|
||||
let mut session = Session::new(agent, session_file.clone(), session_config.debug);
|
||||
|
||||
// Add extensions if provided
|
||||
for extension_str in extensions {
|
||||
for extension_str in session_config.extensions {
|
||||
if let Err(e) = session.add_extension(extension_str).await {
|
||||
eprintln!("Failed to start extension: {}", e);
|
||||
process::exit(1);
|
||||
@@ -127,7 +148,7 @@ pub async fn build_session(
|
||||
}
|
||||
|
||||
// Add remote extensions if provided
|
||||
for extension_str in remote_extensions {
|
||||
for extension_str in session_config.remote_extensions {
|
||||
if let Err(e) = session.add_remote_extension(extension_str).await {
|
||||
eprintln!("Failed to start extension: {}", e);
|
||||
process::exit(1);
|
||||
@@ -135,7 +156,7 @@ pub async fn build_session(
|
||||
}
|
||||
|
||||
// Add builtin extensions
|
||||
for builtin in builtins {
|
||||
for builtin in session_config.builtins {
|
||||
if let Err(e) = session.add_builtin(builtin).await {
|
||||
eprintln!("Failed to start builtin extension: {}", e);
|
||||
process::exit(1);
|
||||
@@ -148,6 +169,10 @@ pub async fn build_session(
|
||||
.extend_system_prompt(super::prompt::get_cli_prompt())
|
||||
.await;
|
||||
|
||||
if let Some(additional_prompt) = session_config.additional_system_prompt {
|
||||
session.agent.extend_system_prompt(additional_prompt).await;
|
||||
}
|
||||
|
||||
// Only override system prompt if a system override exists
|
||||
let system_prompt_file: Option<String> = config.get_param("GOOSE_SYSTEM_PROMPT_FILE_PATH").ok();
|
||||
if let Some(ref path) = system_prompt_file {
|
||||
@@ -156,6 +181,6 @@ pub async fn build_session(
|
||||
session.agent.override_system_prompt(override_prompt).await;
|
||||
}
|
||||
|
||||
output::display_session_info(resume, &provider_name, &model, &session_file);
|
||||
output::display_session_info(session_config.resume, &provider_name, &model, &session_file);
|
||||
session
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user