Redesign Extensions page. Remove enable toggle in UI. Treat Extension Manager as core MCP enabler per session. (#8940)
Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
This commit is contained in:
+149
-93
@@ -12,7 +12,7 @@ use crate::config::extensions::get_enabled_extensions_with_config;
|
||||
use crate::config::paths::Paths;
|
||||
use crate::config::permission::PermissionManager;
|
||||
use crate::config::{Config, GooseMode};
|
||||
use crate::conversation::message::{ActionRequiredData, Message, MessageContent};
|
||||
use crate::conversation::message::{ActionRequiredData, Message, MessageContent, ToolRequest};
|
||||
use crate::mcp_utils::ToolResult;
|
||||
use crate::permission::permission_confirmation::PrincipalType;
|
||||
use crate::permission::{Permission, PermissionConfirmation};
|
||||
@@ -560,6 +560,77 @@ fn summarize_tool_call(tool_name: &str, arguments: Option<&serde_json::Value>) -
|
||||
}
|
||||
}
|
||||
|
||||
fn tool_call_identity_meta(tool_request: &ToolRequest) -> Option<Meta> {
|
||||
let tool_call = tool_request.tool_call.as_ref().ok()?;
|
||||
let tool_name = tool_call.name.to_string();
|
||||
let extension_name = tool_request
|
||||
.tool_meta
|
||||
.as_ref()
|
||||
.and_then(|meta| meta.get("goose_extension"))
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.map(ToString::to_string)
|
||||
.or_else(|| {
|
||||
tool_name
|
||||
.split_once("__")
|
||||
.map(|(extension_name, _)| extension_name.to_string())
|
||||
});
|
||||
|
||||
let mut tool_call_meta = serde_json::Map::new();
|
||||
tool_call_meta.insert("toolName".to_string(), serde_json::Value::String(tool_name));
|
||||
if let Some(extension_name) = extension_name {
|
||||
tool_call_meta.insert(
|
||||
"extensionName".to_string(),
|
||||
serde_json::Value::String(extension_name),
|
||||
);
|
||||
}
|
||||
|
||||
let mut goose_meta = serde_json::Map::new();
|
||||
goose_meta.insert(
|
||||
"toolCall".to_string(),
|
||||
serde_json::Value::Object(tool_call_meta),
|
||||
);
|
||||
|
||||
let mut meta = serde_json::Map::new();
|
||||
meta.insert("goose".to_string(), serde_json::Value::Object(goose_meta));
|
||||
Some(meta)
|
||||
}
|
||||
|
||||
struct PendingToolCall {
|
||||
tool_call: ToolCall,
|
||||
identity_meta: Option<Meta>,
|
||||
fallback_title: String,
|
||||
}
|
||||
|
||||
fn pending_tool_call_from_request(tool_request: &ToolRequest) -> PendingToolCall {
|
||||
let tool_name = match &tool_request.tool_call {
|
||||
Ok(tool_call) => tool_call.name.to_string(),
|
||||
Err(_) => "error".to_string(),
|
||||
};
|
||||
let args_value = tool_request
|
||||
.tool_call
|
||||
.as_ref()
|
||||
.ok()
|
||||
.and_then(|tc| tc.arguments.as_ref())
|
||||
.map(|a| serde_json::Value::Object(a.clone()));
|
||||
let fallback_title = summarize_tool_call(&tool_name, args_value.as_ref());
|
||||
let identity_meta = tool_call_identity_meta(tool_request);
|
||||
|
||||
let mut tool_call = ToolCall::new(
|
||||
ToolCallId::new(tool_request.id.clone()),
|
||||
fallback_title.clone(),
|
||||
)
|
||||
.status(ToolCallStatus::Pending);
|
||||
if let Some(args) = args_value {
|
||||
tool_call = tool_call.raw_input(args);
|
||||
}
|
||||
|
||||
PendingToolCall {
|
||||
tool_call,
|
||||
identity_meta,
|
||||
fallback_title,
|
||||
}
|
||||
}
|
||||
|
||||
fn builtin_to_extension_config(name: &str) -> ExtensionConfig {
|
||||
if let Some(def) = PLATFORM_EXTENSIONS.get(name) {
|
||||
ExtensionConfig::Platform {
|
||||
@@ -1405,27 +1476,10 @@ impl GooseAcpAgent {
|
||||
.tool_requests
|
||||
.insert(tool_request.id.clone(), tool_request.clone());
|
||||
|
||||
let tool_name = match &tool_request.tool_call {
|
||||
Ok(tool_call) => tool_call.name.to_string(),
|
||||
Err(_) => "error".to_string(),
|
||||
};
|
||||
|
||||
let args_value = tool_request
|
||||
let pending_tool_call = pending_tool_call_from_request(tool_request);
|
||||
let initial_tool_call = pending_tool_call
|
||||
.tool_call
|
||||
.as_ref()
|
||||
.ok()
|
||||
.and_then(|tc| tc.arguments.as_ref())
|
||||
.map(|a| serde_json::Value::Object(a.clone()));
|
||||
let fallback_title = summarize_tool_call(&tool_name, args_value.as_ref());
|
||||
|
||||
let mut initial_tool_call = ToolCall::new(
|
||||
ToolCallId::new(tool_request.id.clone()),
|
||||
fallback_title.clone(),
|
||||
)
|
||||
.status(ToolCallStatus::Pending);
|
||||
if let Some(args) = args_value.clone() {
|
||||
initial_tool_call = initial_tool_call.raw_input(args);
|
||||
}
|
||||
.meta(pending_tool_call.identity_meta.clone());
|
||||
cx.send_notification(SessionNotification::new(
|
||||
session_id.clone(),
|
||||
SessionUpdate::ToolCall(initial_tool_call),
|
||||
@@ -1440,6 +1494,8 @@ impl GooseAcpAgent {
|
||||
let request_id = tool_request.id.clone();
|
||||
let cx = cx.clone();
|
||||
let name = tool_call.name.to_string();
|
||||
let identity_meta = pending_tool_call.identity_meta.clone();
|
||||
let fallback_title = pending_tool_call.fallback_title.clone();
|
||||
let args_json = tool_call
|
||||
.arguments
|
||||
.as_ref()
|
||||
@@ -1454,71 +1510,56 @@ impl GooseAcpAgent {
|
||||
.unwrap_or_default();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let provider: Arc<dyn Provider> = match agent.provider().await {
|
||||
Ok(p) => p,
|
||||
let title = match agent.provider().await {
|
||||
Ok(provider) => {
|
||||
if provider.manages_own_context() {
|
||||
return;
|
||||
}
|
||||
|
||||
let system =
|
||||
"Summarize this tool call in a short lowercase phrase (3-8 words). \
|
||||
No punctuation. No quotes. Examples: reading project configuration, \
|
||||
checking network connectivity, listing files in src directory";
|
||||
let user_text = format!("Tool: {name}\nArguments: {args_json}");
|
||||
let message = Message::user().with_text(&user_text);
|
||||
match provider
|
||||
.complete_fast(&sid.0, system, &[message], &[])
|
||||
.await
|
||||
{
|
||||
Ok((response, _)) => {
|
||||
let summary: String = response
|
||||
.content
|
||||
.iter()
|
||||
.filter_map(|c: &MessageContent| c.as_text())
|
||||
.collect::<String>()
|
||||
.trim()
|
||||
.to_string();
|
||||
if summary.is_empty() {
|
||||
fallback_title.clone()
|
||||
} else {
|
||||
summary
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("tool call summary: fast_complete failed: {e}");
|
||||
fallback_title.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("tool call summary: failed to get provider: {e}");
|
||||
let fields = ToolCallUpdateFields::new().title(fallback_title);
|
||||
let _ = cx.send_notification(SessionNotification::new(
|
||||
sid,
|
||||
SessionUpdate::ToolCallUpdate(ToolCallUpdate::new(
|
||||
ToolCallId::new(request_id),
|
||||
fields,
|
||||
)),
|
||||
));
|
||||
return;
|
||||
fallback_title.clone()
|
||||
}
|
||||
};
|
||||
|
||||
// in these case, the title summarization request would
|
||||
// be added to the conversation which we don't want
|
||||
if provider.manages_own_context() {
|
||||
return;
|
||||
}
|
||||
|
||||
let system = "Summarize this tool call in a short lowercase phrase (3-8 words). \
|
||||
No punctuation. No quotes. Examples: reading project configuration, \
|
||||
checking network connectivity, listing files in src directory";
|
||||
let user_text = format!("Tool: {name}\nArguments: {args_json}");
|
||||
let message = Message::user().with_text(&user_text);
|
||||
match provider
|
||||
.complete_fast(&sid.0, system, &[message], &[])
|
||||
.await
|
||||
{
|
||||
Ok((response, _)) => {
|
||||
let summary: String = response
|
||||
.content
|
||||
.iter()
|
||||
.filter_map(|c: &MessageContent| c.as_text())
|
||||
.collect::<String>()
|
||||
.trim()
|
||||
.to_string();
|
||||
let title = if summary.is_empty() {
|
||||
fallback_title
|
||||
} else {
|
||||
summary
|
||||
};
|
||||
let fields = ToolCallUpdateFields::new().title(title);
|
||||
let _ = cx.send_notification(SessionNotification::new(
|
||||
sid,
|
||||
SessionUpdate::ToolCallUpdate(ToolCallUpdate::new(
|
||||
ToolCallId::new(request_id),
|
||||
fields,
|
||||
)),
|
||||
));
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("tool call summary: fast_complete failed: {e}");
|
||||
let fields = ToolCallUpdateFields::new().title(fallback_title);
|
||||
let _ = cx.send_notification(SessionNotification::new(
|
||||
sid,
|
||||
SessionUpdate::ToolCallUpdate(ToolCallUpdate::new(
|
||||
ToolCallId::new(request_id),
|
||||
fields,
|
||||
)),
|
||||
));
|
||||
}
|
||||
}
|
||||
let fields = ToolCallUpdateFields::new().title(title);
|
||||
let _ = cx.send_notification(SessionNotification::new(
|
||||
sid,
|
||||
SessionUpdate::ToolCallUpdate(
|
||||
ToolCallUpdate::new(ToolCallId::new(request_id), fields)
|
||||
.meta(identity_meta),
|
||||
),
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2172,21 +2213,14 @@ impl GooseAcpAgent {
|
||||
// don't require a full GooseAcpSession.
|
||||
replay_tool_requests.insert(tool_request.id.clone(), tool_request.clone());
|
||||
|
||||
let tool_name = match &tool_request.tool_call {
|
||||
Ok(tool_call) => tool_call.name.to_string(),
|
||||
Err(_) => "error".to_string(),
|
||||
};
|
||||
let pending_tool_call = pending_tool_call_from_request(tool_request);
|
||||
let tool_call = pending_tool_call.tool_call.meta(
|
||||
merge_replay_message_meta(pending_tool_call.identity_meta, message),
|
||||
);
|
||||
|
||||
cx.send_notification(SessionNotification::new(
|
||||
args.session_id.clone(),
|
||||
SessionUpdate::ToolCall(
|
||||
ToolCall::new(
|
||||
ToolCallId::new(tool_request.id.clone()),
|
||||
format_tool_name(&tool_name),
|
||||
)
|
||||
.status(ToolCallStatus::Pending)
|
||||
.meta(replay_message_meta(message)),
|
||||
),
|
||||
SessionUpdate::ToolCall(tool_call),
|
||||
))?;
|
||||
}
|
||||
MessageContent::ToolResponse(tool_response) => {
|
||||
@@ -3020,6 +3054,28 @@ print(\"hello, world\")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tool_call_identity_meta_uses_goose_extension_metadata() {
|
||||
let request = ToolRequest {
|
||||
id: "req_1".to_string(),
|
||||
tool_call: Ok(CallToolRequestParams::new("context7__query-docs")),
|
||||
metadata: None,
|
||||
tool_meta: Some(serde_json::json!({"goose_extension": "context7"})),
|
||||
};
|
||||
|
||||
let meta = tool_call_identity_meta(&request).expect("expected metadata");
|
||||
|
||||
assert_eq!(
|
||||
meta.get("goose"),
|
||||
Some(&serde_json::json!({
|
||||
"toolCall": {
|
||||
"toolName": "context7__query-docs",
|
||||
"extensionName": "context7",
|
||||
},
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_summarize_tool_call_long_value_truncated() {
|
||||
let long_path = "a".repeat(80);
|
||||
|
||||
@@ -783,13 +783,6 @@ 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: true,
|
||||
default_enabled: false,
|
||||
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: true,
|
||||
default_enabled: false,
|
||||
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: true,
|
||||
default_enabled: false,
|
||||
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: true,
|
||||
default_enabled: false,
|
||||
unprefixed_tools: false,
|
||||
hidden: false,
|
||||
client_factory: |ctx| Box::new(tom::TomClient::new(ctx).unwrap()),
|
||||
|
||||
@@ -1986,10 +1986,12 @@ extensions:
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// User config (higher priority / write target) disables developer and adds a new extension
|
||||
// User config (higher priority / write target) has already migrated, then disables
|
||||
// developer and adds a new extension.
|
||||
std::fs::write(
|
||||
local_file.path(),
|
||||
r#"
|
||||
extensions_on_demand_migration: true
|
||||
extensions:
|
||||
developer:
|
||||
enabled: false
|
||||
@@ -2014,7 +2016,7 @@ extensions:
|
||||
let values = config.load()?;
|
||||
let extensions = values.get("extensions").unwrap().as_mapping().unwrap();
|
||||
|
||||
// developer should be disabled (user config overrides system)
|
||||
// developer should be disabled (user config overrides system after migration)
|
||||
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,8 +13,13 @@ 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,
|
||||
@@ -210,4 +215,22 @@ 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,10 +114,18 @@ 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_preserves_enabled_state() {
|
||||
fn test_migrate_platform_extensions_refreshes_metadata_without_changing_enabled() {
|
||||
let mut config = Mapping::new();
|
||||
let mut extensions = Mapping::new();
|
||||
let todo_entry = ExtensionEntry {
|
||||
@@ -149,6 +157,105 @@ 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]
|
||||
|
||||
@@ -144,7 +144,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:\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_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",
|
||||
mcp.url
|
||||
);
|
||||
fs::write(temp_dir.path().join(CONFIG_YAML_NAME), config_yaml).unwrap();
|
||||
@@ -194,7 +194,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:\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_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"
|
||||
);
|
||||
fs::write(temp_dir.path().join(CONFIG_YAML_NAME), config_yaml).unwrap();
|
||||
|
||||
@@ -363,7 +363,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:\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_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",
|
||||
mcp.url
|
||||
);
|
||||
fs::write(temp_dir.path().join(CONFIG_YAML_NAME), config_yaml).unwrap();
|
||||
@@ -601,7 +601,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:\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_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",
|
||||
mcp.url
|
||||
);
|
||||
fs::write(temp_dir.path().join(CONFIG_YAML_NAME), config_yaml).unwrap();
|
||||
@@ -1198,7 +1198,7 @@ pub async fn run_prompt_skill<C: Connection>() {
|
||||
.await;
|
||||
|
||||
let config = TestConnectionConfig {
|
||||
builtins: vec!["summon".to_string()],
|
||||
builtins: vec!["summon".to_string(), "skills".to_string()],
|
||||
cwd: Some(cwd),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -253,6 +253,7 @@ 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(sacp::schema::ReadTextFileResponse::new(
|
||||
|
||||
Reference in New Issue
Block a user