Streamable HTTP CLI flag (#3394)

This commit is contained in:
Angie Jones
2025-07-13 18:09:04 -05:00
committed by GitHub
parent 192a8077dc
commit 1987956422
7 changed files with 203 additions and 10 deletions
+25
View File
@@ -341,6 +341,16 @@ enum Command {
)]
remote_extensions: Vec<String>,
/// Add streamable HTTP extensions with a URL
#[arg(
long = "with-streamable-http-extension",
value_name = "URL",
help = "Add streamable HTTP extensions (can be specified multiple times)",
long_help = "Add streamable HTTP extensions from a URL. Can be specified multiple times. Format: 'url...'",
action = clap::ArgAction::Append
)]
streamable_http_extensions: Vec<String>,
/// Add builtin extensions by name
#[arg(
long = "with-builtin",
@@ -509,6 +519,16 @@ enum Command {
)]
remote_extensions: Vec<String>,
/// Add streamable HTTP extensions
#[arg(
long = "with-streamable-http-extension",
value_name = "URL",
help = "Add streamable HTTP extensions (can be specified multiple times)",
long_help = "Add streamable HTTP extensions. Can be specified multiple times. Format: 'url...'",
action = clap::ArgAction::Append
)]
streamable_http_extensions: Vec<String>,
/// Add builtin extensions by name
#[arg(
long = "with-builtin",
@@ -674,6 +694,7 @@ pub async fn cli() -> Result<()> {
max_turns,
extensions,
remote_extensions,
streamable_http_extensions,
builtins,
}) => {
return match command {
@@ -714,6 +735,7 @@ pub async fn cli() -> Result<()> {
no_session: false,
extensions,
remote_extensions,
streamable_http_extensions,
builtins,
extensions_override: None,
additional_system_prompt: None,
@@ -774,6 +796,7 @@ pub async fn cli() -> Result<()> {
max_turns,
extensions,
remote_extensions,
streamable_http_extensions,
builtins,
params,
explain,
@@ -863,6 +886,7 @@ pub async fn cli() -> Result<()> {
no_session,
extensions,
remote_extensions,
streamable_http_extensions,
builtins,
extensions_override: input_config.extensions_override,
additional_system_prompt: input_config.additional_system_prompt,
@@ -990,6 +1014,7 @@ pub async fn cli() -> Result<()> {
no_session: false,
extensions: Vec::new(),
remote_extensions: Vec::new(),
streamable_http_extensions: Vec::new(),
builtins: Vec::new(),
extensions_override: None,
additional_system_prompt: None,
+1
View File
@@ -37,6 +37,7 @@ pub async fn agent_generator(
no_session: false,
extensions: requirements.external,
remote_extensions: requirements.remote,
streamable_http_extensions: Vec::new(),
builtins: requirements.builtin,
extensions_override: None,
additional_system_prompt: None,
+42
View File
@@ -29,6 +29,8 @@ pub struct SessionBuilderConfig {
pub extensions: Vec<String>,
/// List of remote extension commands to add
pub remote_extensions: Vec<String>,
/// List of streamable HTTP extension commands to add
pub streamable_http_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
@@ -454,6 +456,43 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> Session {
}
}
// Add streamable HTTP extensions if provided
for extension_str in session_config.streamable_http_extensions {
if let Err(e) = session
.add_streamable_http_extension(extension_str.clone())
.await
{
eprintln!(
"{}",
style(format!(
"Warning: Failed to start streamable HTTP extension '{}': {}",
extension_str, e
))
.yellow()
);
eprintln!(
"{}",
style(format!(
"Continuing without streamable HTTP extension '{}'",
extension_str
))
.yellow()
);
// Offer debugging help
if let Err(debug_err) = offer_extension_debugging_help(
&extension_str,
&e.to_string(),
Arc::clone(&provider_for_display),
session_config.interactive,
)
.await
{
eprintln!("Note: Could not start debugging session: {}", debug_err);
}
}
}
// Add builtin extensions
for builtin in session_config.builtins {
if let Err(e) = session.add_builtin(builtin.clone()).await {
@@ -531,6 +570,7 @@ mod tests {
no_session: false,
extensions: vec!["echo test".to_string()],
remote_extensions: vec!["http://example.com".to_string()],
streamable_http_extensions: vec!["http://example.com/streamable".to_string()],
builtins: vec!["developer".to_string()],
extensions_override: None,
additional_system_prompt: Some("Test prompt".to_string()),
@@ -549,6 +589,7 @@ mod tests {
assert_eq!(config.extensions.len(), 1);
assert_eq!(config.remote_extensions.len(), 1);
assert_eq!(config.streamable_http_extensions.len(), 1);
assert_eq!(config.builtins.len(), 1);
assert!(config.debug);
assert_eq!(config.max_tool_repetitions, Some(5));
@@ -567,6 +608,7 @@ mod tests {
assert!(!config.no_session);
assert!(config.extensions.is_empty());
assert!(config.remote_extensions.is_empty());
assert!(config.streamable_http_extensions.is_empty());
assert!(config.builtins.is_empty());
assert!(config.extensions_override.is_none());
assert!(config.additional_system_prompt.is_none());
+34
View File
@@ -244,6 +244,40 @@ impl Session {
Ok(())
}
/// Add a streamable HTTP extension to the session
///
/// # Arguments
/// * `extension_url` - URL of the server
pub async fn add_streamable_http_extension(&mut self, extension_url: String) -> Result<()> {
let name: String = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(8)
.map(char::from)
.collect();
let config = ExtensionConfig::StreamableHttp {
name,
uri: extension_url,
envs: Envs::new(HashMap::new()),
env_keys: Vec::new(),
headers: HashMap::new(),
description: Some(goose::config::DEFAULT_EXTENSION_DESCRIPTION.to_string()),
// TODO: should set timeout
timeout: Some(goose::config::DEFAULT_EXTENSION_TIMEOUT),
bundled: None,
};
self.agent
.add_extension(config)
.await
.map_err(|e| anyhow::anyhow!("Failed to start extension: {}", e))?;
// Invalidate the completion cache when a new extension is added
self.invalidate_completion_cache().await;
Ok(())
}
/// Add a builtin extension to the session
///
/// # Arguments