fix: revert the change for unexpected change from ui/goose2 work (#9098)
This commit is contained in:
@@ -811,6 +811,13 @@ impl Agent {
|
||||
|
||||
let results = futures::future::join_all(extension_futures).await;
|
||||
|
||||
// Persist once after all extensions are loaded
|
||||
if results.iter().any(|r| r.success) {
|
||||
if let Err(e) = self.persist_extension_state(&session_id).await {
|
||||
warn!("Failed to persist extension state after bulk load: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ pub static PLATFORM_EXTENSIONS: Lazy<HashMap<&'static str, PlatformExtensionDef>
|
||||
display_name: "Analyze",
|
||||
description:
|
||||
"Analyze code structure with tree-sitter: directory overviews, file details, symbol call graphs",
|
||||
default_enabled: false,
|
||||
default_enabled: true,
|
||||
unprefixed_tools: true,
|
||||
hidden: false,
|
||||
client_factory: |ctx| Box::new(analyze::AnalyzeClient::new(ctx).unwrap()),
|
||||
@@ -64,7 +64,7 @@ pub static PLATFORM_EXTENSIONS: Lazy<HashMap<&'static str, PlatformExtensionDef>
|
||||
display_name: "Apps",
|
||||
description:
|
||||
"Create and manage custom Goose apps through chat. Apps are HTML/CSS/JavaScript and run in sandboxed windows.",
|
||||
default_enabled: false,
|
||||
default_enabled: true,
|
||||
unprefixed_tools: false,
|
||||
hidden: false,
|
||||
client_factory: |ctx| Box::new(apps::AppsManagerClient::new(ctx).unwrap()),
|
||||
@@ -105,7 +105,7 @@ pub static PLATFORM_EXTENSIONS: Lazy<HashMap<&'static str, PlatformExtensionDef>
|
||||
name: summon::EXTENSION_NAME,
|
||||
display_name: "Summon",
|
||||
description: "Load knowledge and delegate tasks to subagents",
|
||||
default_enabled: false,
|
||||
default_enabled: true,
|
||||
unprefixed_tools: true,
|
||||
hidden: false,
|
||||
client_factory: |ctx| Box::new(summon::SummonClient::new(ctx).unwrap()),
|
||||
@@ -182,7 +182,7 @@ pub static PLATFORM_EXTENSIONS: Lazy<HashMap<&'static str, PlatformExtensionDef>
|
||||
display_name: "Top Of Mind",
|
||||
description:
|
||||
"Inject custom context into every turn via GOOSE_MOIM_MESSAGE_TEXT and GOOSE_MOIM_MESSAGE_FILE environment variables",
|
||||
default_enabled: false,
|
||||
default_enabled: true,
|
||||
unprefixed_tools: false,
|
||||
hidden: false,
|
||||
client_factory: |ctx| Box::new(tom::TomClient::new(ctx).unwrap()),
|
||||
|
||||
@@ -1994,12 +1994,10 @@ extensions:
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// User config (higher priority / write target) has already migrated, then disables
|
||||
// developer and adds a new extension.
|
||||
// User config (higher priority / write target) disables developer and adds a new extension
|
||||
std::fs::write(
|
||||
local_file.path(),
|
||||
r#"
|
||||
extensions_on_demand_migration: true
|
||||
extensions:
|
||||
developer:
|
||||
enabled: false
|
||||
@@ -2024,7 +2022,7 @@ extensions:
|
||||
let values = config.load()?;
|
||||
let extensions = values.get("extensions").unwrap().as_mapping().unwrap();
|
||||
|
||||
// developer should be disabled (user config overrides system after migration)
|
||||
// developer should be disabled (user config overrides system)
|
||||
let dev = extensions.get("developer").unwrap().as_mapping().unwrap();
|
||||
assert!(!dev.get("enabled").unwrap().as_bool().unwrap());
|
||||
// Fields from the system config should be preserved via merge
|
||||
|
||||
@@ -13,13 +13,8 @@ pub const DEFAULT_EXTENSION_DESCRIPTION: &str = "";
|
||||
pub const DEFAULT_DISPLAY_NAME: &str = "Developer";
|
||||
const EXTENSIONS_CONFIG_KEY: &str = "extensions";
|
||||
|
||||
fn default_extension_enabled() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, ToSchema)]
|
||||
pub struct ExtensionEntry {
|
||||
#[serde(default = "default_extension_enabled")]
|
||||
pub enabled: bool,
|
||||
#[serde(flatten)]
|
||||
pub config: ExtensionConfig,
|
||||
@@ -215,22 +210,4 @@ mod tests {
|
||||
assert!(!is_extension_available(&unknown_platform));
|
||||
assert!(is_extension_available(&builtin));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extension_entry_defaults_missing_enabled_to_true() {
|
||||
let value = serde_yaml::from_str(
|
||||
r#"
|
||||
type: stdio
|
||||
name: github
|
||||
description: GitHub tools
|
||||
cmd: npx
|
||||
args: []
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let entry: ExtensionEntry = serde_yaml::from_value(value).unwrap();
|
||||
|
||||
assert!(entry.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,18 +114,10 @@ mod tests {
|
||||
assert!(changed);
|
||||
let extensions_key = serde_yaml::Value::String(EXTENSIONS_CONFIG_KEY.to_string());
|
||||
assert!(config.contains_key(&extensions_key));
|
||||
|
||||
let extensions = config.get(&extensions_key).unwrap().as_mapping().unwrap();
|
||||
for (key, value) in extensions {
|
||||
let key = key.as_str().unwrap();
|
||||
let def = PLATFORM_EXTENSIONS.get(key).unwrap();
|
||||
let entry: ExtensionEntry = serde_yaml::from_value(value.clone()).unwrap();
|
||||
assert_eq!(entry.enabled, def.default_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_migrate_platform_extensions_refreshes_metadata_without_changing_enabled() {
|
||||
fn test_migrate_platform_extensions_preserves_enabled_state() {
|
||||
let mut config = Mapping::new();
|
||||
let mut extensions = Mapping::new();
|
||||
let todo_entry = ExtensionEntry {
|
||||
@@ -157,105 +149,6 @@ mod tests {
|
||||
let todo_entry: ExtensionEntry = serde_yaml::from_value(todo_value.clone()).unwrap();
|
||||
|
||||
assert!(!todo_entry.enabled);
|
||||
match todo_entry.config {
|
||||
ExtensionConfig::Platform {
|
||||
description,
|
||||
display_name,
|
||||
..
|
||||
} => {
|
||||
assert_ne!(description, "old description");
|
||||
assert_ne!(display_name.as_deref(), Some("Old Name"));
|
||||
}
|
||||
other => panic!("expected platform extension, got {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_migrate_platform_extensions_preserves_existing_enabled_values() {
|
||||
let mut config = Mapping::new();
|
||||
let mut extensions = Mapping::new();
|
||||
|
||||
let analyze_entry = ExtensionEntry {
|
||||
config: ExtensionConfig::Platform {
|
||||
name: "analyze".to_string(),
|
||||
description: "Analyze code structure".to_string(),
|
||||
display_name: Some("Analyze".to_string()),
|
||||
bundled: Some(true),
|
||||
available_tools: Vec::new(),
|
||||
},
|
||||
enabled: true,
|
||||
};
|
||||
let developer_entry = ExtensionEntry {
|
||||
config: ExtensionConfig::Platform {
|
||||
name: "developer".to_string(),
|
||||
description: "Write and edit files, and execute shell commands".to_string(),
|
||||
display_name: Some("Developer".to_string()),
|
||||
bundled: Some(true),
|
||||
available_tools: Vec::new(),
|
||||
},
|
||||
enabled: false,
|
||||
};
|
||||
let custom_developer_entry = ExtensionEntry {
|
||||
config: ExtensionConfig::Stdio {
|
||||
name: "developer".to_string(),
|
||||
description: "Custom user developer tools".to_string(),
|
||||
cmd: "custom-developer".to_string(),
|
||||
args: Vec::new(),
|
||||
envs: Default::default(),
|
||||
env_keys: Vec::new(),
|
||||
timeout: Some(300),
|
||||
bundled: None,
|
||||
available_tools: Vec::new(),
|
||||
},
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
extensions.insert(
|
||||
serde_yaml::Value::String("analyze".to_string()),
|
||||
serde_yaml::to_value(&analyze_entry).unwrap(),
|
||||
);
|
||||
extensions.insert(
|
||||
serde_yaml::Value::String("developer".to_string()),
|
||||
serde_yaml::to_value(&developer_entry).unwrap(),
|
||||
);
|
||||
extensions.insert(
|
||||
serde_yaml::Value::String("custom-developer".to_string()),
|
||||
serde_yaml::to_value(&custom_developer_entry).unwrap(),
|
||||
);
|
||||
config.insert(
|
||||
serde_yaml::Value::String(EXTENSIONS_CONFIG_KEY.to_string()),
|
||||
serde_yaml::Value::Mapping(extensions),
|
||||
);
|
||||
|
||||
assert!(run_migrations(&mut config));
|
||||
|
||||
let extensions_key = serde_yaml::Value::String(EXTENSIONS_CONFIG_KEY.to_string());
|
||||
let extensions = config.get(&extensions_key).unwrap().as_mapping().unwrap();
|
||||
let analyze: ExtensionEntry = serde_yaml::from_value(
|
||||
extensions
|
||||
.get(serde_yaml::Value::String("analyze".to_string()))
|
||||
.unwrap()
|
||||
.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
let developer: ExtensionEntry = serde_yaml::from_value(
|
||||
extensions
|
||||
.get(serde_yaml::Value::String("developer".to_string()))
|
||||
.unwrap()
|
||||
.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
let custom_developer: ExtensionEntry = serde_yaml::from_value(
|
||||
extensions
|
||||
.get(serde_yaml::Value::String("custom-developer".to_string()))
|
||||
.unwrap()
|
||||
.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(analyze.enabled);
|
||||
assert!(!developer.enabled);
|
||||
assert!(custom_developer.enabled);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -244,7 +244,7 @@ pub async fn run_config_mcp<C: Connection>() {
|
||||
let mcp = McpFixture::new(expected_session_id.clone()).await;
|
||||
|
||||
let config_yaml = format!(
|
||||
"GOOSE_MODEL: {TEST_MODEL}\nGOOSE_PROVIDER: openai\nextensions_on_demand_migration: true\nextensions:\n mcp-fixture:\n enabled: true\n type: streamable_http\n name: mcp-fixture\n description: MCP fixture\n uri: \"{}\"\n",
|
||||
"GOOSE_MODEL: {TEST_MODEL}\nGOOSE_PROVIDER: openai\nextensions:\n mcp-fixture:\n enabled: true\n type: streamable_http\n name: mcp-fixture\n description: MCP fixture\n uri: \"{}\"\n",
|
||||
mcp.url
|
||||
);
|
||||
fs::write(temp_dir.path().join(CONFIG_YAML_NAME), config_yaml).unwrap();
|
||||
@@ -294,7 +294,7 @@ pub async fn run_config_mcp<C: Connection>() {
|
||||
pub async fn run_fs_read_text_file_true<C: Connection>() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let config_yaml = format!(
|
||||
"GOOSE_MODEL: {TEST_MODEL}\nGOOSE_PROVIDER: openai\nextensions_on_demand_migration: true\nextensions:\n developer:\n enabled: true\n type: platform\n name: developer\n description: Developer\n display_name: Developer\n bundled: true\n available_tools: []\n"
|
||||
"GOOSE_MODEL: {TEST_MODEL}\nGOOSE_PROVIDER: openai\nextensions:\n developer:\n enabled: true\n type: platform\n name: developer\n description: Developer\n display_name: Developer\n bundled: true\n available_tools: []\n"
|
||||
);
|
||||
fs::write(temp_dir.path().join(CONFIG_YAML_NAME), config_yaml).unwrap();
|
||||
|
||||
@@ -463,7 +463,7 @@ pub async fn run_load_mode<C: Connection>() {
|
||||
let mcp = McpFixture::new(expected_session_id.clone()).await;
|
||||
|
||||
let config_yaml = format!(
|
||||
"GOOSE_MODEL: {TEST_MODEL}\nGOOSE_PROVIDER: openai\nextensions_on_demand_migration: true\nextensions:\n mcp-fixture:\n enabled: true\n type: streamable_http\n name: mcp-fixture\n description: MCP fixture\n uri: \"{}\"\n",
|
||||
"GOOSE_MODEL: {TEST_MODEL}\nGOOSE_PROVIDER: openai\nextensions:\n mcp-fixture:\n enabled: true\n type: streamable_http\n name: mcp-fixture\n description: MCP fixture\n uri: \"{}\"\n",
|
||||
mcp.url
|
||||
);
|
||||
fs::write(temp_dir.path().join(CONFIG_YAML_NAME), config_yaml).unwrap();
|
||||
@@ -703,7 +703,7 @@ async fn run_mode_set_impl<C: Connection>(via: SetModeVia) {
|
||||
let mcp = McpFixture::new(expected_session_id.clone()).await;
|
||||
|
||||
let config_yaml = format!(
|
||||
"GOOSE_MODEL: {TEST_MODEL}\nGOOSE_PROVIDER: openai\nextensions_on_demand_migration: true\nextensions:\n mcp-fixture:\n enabled: true\n type: streamable_http\n name: mcp-fixture\n description: MCP fixture\n uri: \"{}\"\n",
|
||||
"GOOSE_MODEL: {TEST_MODEL}\nGOOSE_PROVIDER: openai\nextensions:\n mcp-fixture:\n enabled: true\n type: streamable_http\n name: mcp-fixture\n description: MCP fixture\n uri: \"{}\"\n",
|
||||
mcp.url
|
||||
);
|
||||
fs::write(temp_dir.path().join(CONFIG_YAML_NAME), config_yaml).unwrap();
|
||||
@@ -1305,7 +1305,7 @@ pub async fn run_prompt_skill<C: Connection>() {
|
||||
.await;
|
||||
|
||||
let config = TestConnectionConfig {
|
||||
builtins: vec!["summon".to_string(), "skills".to_string()],
|
||||
builtins: vec!["summon".to_string()],
|
||||
cwd: Some(cwd),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -523,7 +523,6 @@ fn test_developer_fs_requests_use_acp_session_id() {
|
||||
// gpt-5-nano routes to the Responses API; use a Chat Completions
|
||||
// model so the canned SSE fixtures are parsed correctly.
|
||||
current_model: "gpt-4.1".to_string(),
|
||||
builtins: vec!["developer".to_string()],
|
||||
read_text_file: Some(Arc::new(move |req| {
|
||||
*seen_session_id_clone.lock().unwrap() = Some(req.session_id.0.to_string());
|
||||
Ok(agent_client_protocol::schema::ReadTextFileResponse::new(
|
||||
|
||||
Reference in New Issue
Block a user