diff --git a/crates/goose-sdk/src/custom_requests.rs b/crates/goose-sdk/src/custom_requests.rs index 17ce9458..ec68de95 100644 --- a/crates/goose-sdk/src/custom_requests.rs +++ b/crates/goose-sdk/src/custom_requests.rs @@ -99,11 +99,43 @@ pub struct GetExtensionsRequest {} /// List configured extensions and any warnings. #[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcResponse)] pub struct GetExtensionsResponse { - /// Array of ExtensionEntry objects with `enabled` flag and config details. + /// Array of ExtensionEntry objects with `enabled` flag, `configKey`, and flattened config details. pub extensions: Vec, pub warnings: Vec, } +/// Persist a new extension to the user's global goose config. +#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcRequest)] +#[request(method = "_goose/config/extensions/add", response = EmptyResponse)] +#[serde(rename_all = "camelCase")] +pub struct AddConfigExtensionRequest { + pub name: String, + /// Extension configuration. Must be a JSON object matching one of the + /// `ExtensionConfig` variants (e.g. `stdio`, `streamable_http`, `builtin`). + /// `name` and `enabled` are injected server-side. + #[serde(default)] + pub extension_config: serde_json::Value, + #[serde(default)] + pub enabled: bool, +} + +/// Remove a persisted extension from the user's global goose config. +#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcRequest)] +#[request(method = "_goose/config/extensions/remove", response = EmptyResponse)] +#[serde(rename_all = "camelCase")] +pub struct RemoveConfigExtensionRequest { + pub config_key: String, +} + +/// Toggle the `enabled` flag for a persisted extension in the user's global goose config. +#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcRequest)] +#[request(method = "_goose/config/extensions/toggle", response = EmptyResponse)] +#[serde(rename_all = "camelCase")] +pub struct ToggleConfigExtensionRequest { + pub config_key: String, + pub enabled: bool, +} + #[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcRequest)] #[request(method = "_goose/session/extensions", response = GetSessionExtensionsResponse)] #[serde(rename_all = "camelCase")] diff --git a/crates/goose/acp-meta.json b/crates/goose/acp-meta.json index 99e048c1..81dfd429 100644 --- a/crates/goose/acp-meta.json +++ b/crates/goose/acp-meta.json @@ -35,6 +35,21 @@ "requestType": "GetExtensionsRequest", "responseType": "GetExtensionsResponse" }, + { + "method": "_goose/config/extensions/add", + "requestType": "AddConfigExtensionRequest", + "responseType": "EmptyResponse" + }, + { + "method": "_goose/config/extensions/remove", + "requestType": "RemoveConfigExtensionRequest", + "responseType": "EmptyResponse" + }, + { + "method": "_goose/config/extensions/toggle", + "requestType": "ToggleConfigExtensionRequest", + "responseType": "EmptyResponse" + }, { "method": "_goose/session/extensions", "requestType": "GetSessionExtensionsRequest", diff --git a/crates/goose/acp-schema.json b/crates/goose/acp-schema.json index cb6d1219..15906dfe 100644 --- a/crates/goose/acp-schema.json +++ b/crates/goose/acp-schema.json @@ -151,7 +151,7 @@ "extensions": { "type": "array", "items": {}, - "description": "Array of ExtensionEntry objects with `enabled` flag and config details." + "description": "Array of ExtensionEntry objects with `enabled` flag, `configKey`, and flattened config details." }, "warnings": { "type": "array", @@ -168,6 +168,60 @@ "x-side": "agent", "x-method": "_goose/config/extensions" }, + "AddConfigExtensionRequest": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "extensionConfig": { + "description": "Extension configuration. Must be a JSON object matching one of the\n`ExtensionConfig` variants (e.g. `stdio`, `streamable_http`, `builtin`).\n`name` and `enabled` are injected server-side.", + "default": null + }, + "enabled": { + "type": "boolean", + "default": false + } + }, + "required": [ + "name" + ], + "description": "Persist a new extension to the user's global goose config.", + "x-side": "agent", + "x-method": "_goose/config/extensions/add" + }, + "RemoveConfigExtensionRequest": { + "type": "object", + "properties": { + "configKey": { + "type": "string" + } + }, + "required": [ + "configKey" + ], + "description": "Remove a persisted extension from the user's global goose config.", + "x-side": "agent", + "x-method": "_goose/config/extensions/remove" + }, + "ToggleConfigExtensionRequest": { + "type": "object", + "properties": { + "configKey": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "configKey", + "enabled" + ], + "description": "Toggle the `enabled` flag for a persisted extension in the user's global goose config.", + "x-side": "agent", + "x-method": "_goose/config/extensions/toggle" + }, "GetSessionExtensionsRequest": { "type": "object", "properties": { @@ -1408,6 +1462,33 @@ "description": "Params for _goose/config/extensions", "title": "GetExtensionsRequest" }, + { + "allOf": [ + { + "$ref": "#/$defs/AddConfigExtensionRequest" + } + ], + "description": "Params for _goose/config/extensions/add", + "title": "AddConfigExtensionRequest" + }, + { + "allOf": [ + { + "$ref": "#/$defs/RemoveConfigExtensionRequest" + } + ], + "description": "Params for _goose/config/extensions/remove", + "title": "RemoveConfigExtensionRequest" + }, + { + "allOf": [ + { + "$ref": "#/$defs/ToggleConfigExtensionRequest" + } + ], + "description": "Params for _goose/config/extensions/toggle", + "title": "ToggleConfigExtensionRequest" + }, { "allOf": [ { diff --git a/crates/goose/src/acp/server.rs b/crates/goose/src/acp/server.rs index cb171431..04332e3e 100644 --- a/crates/goose/src/acp/server.rs +++ b/crates/goose/src/acp/server.rs @@ -2870,7 +2870,17 @@ impl GooseAcpAgent { let warnings = crate::config::extensions::get_warnings(); let extensions_json = extensions .into_iter() - .map(|e| serde_json::to_value(&e)) + .map(|e| { + let config_key = e.config.key(); + let mut value = serde_json::to_value(&e)?; + if let Some(obj) = value.as_object_mut() { + obj.insert( + "config_key".to_string(), + serde_json::Value::String(config_key), + ); + } + Ok::<_, serde_json::Error>(value) + }) .collect::, _>>() .map_err(|e| sacp::Error::internal_error().data(e.to_string()))?; Ok(GetExtensionsResponse { @@ -2879,6 +2889,63 @@ impl GooseAcpAgent { }) } + #[custom_method(AddConfigExtensionRequest)] + async fn on_add_config_extension( + &self, + req: AddConfigExtensionRequest, + ) -> Result { + let mut obj = match req.extension_config { + serde_json::Value::Object(obj) => obj, + _ => { + return Err( + sacp::Error::invalid_params().data("extensionConfig must be a JSON object") + ); + } + }; + obj.insert( + "name".to_string(), + serde_json::Value::String(req.name.clone()), + ); + + let config: crate::agents::ExtensionConfig = + serde_json::from_value(serde_json::Value::Object(obj)) + .map_err(|e| sacp::Error::invalid_params().data(format!("bad config: {e}")))?; + + crate::config::extensions::set_extension(crate::config::extensions::ExtensionEntry { + enabled: req.enabled, + config, + }); + Ok(EmptyResponse {}) + } + + #[custom_method(RemoveConfigExtensionRequest)] + async fn on_remove_config_extension( + &self, + req: RemoveConfigExtensionRequest, + ) -> Result { + let keys = crate::config::extensions::get_all_extension_names(); + if !keys.iter().any(|k| k == &req.config_key) { + return Err(sacp::Error::invalid_params() + .data(format!("Extension '{}' not found", req.config_key))); + } + crate::config::extensions::remove_extension(&req.config_key); + Ok(EmptyResponse {}) + } + + #[custom_method(ToggleConfigExtensionRequest)] + async fn on_toggle_config_extension( + &self, + req: ToggleConfigExtensionRequest, + ) -> Result { + let keys = crate::config::extensions::get_all_extension_names(); + if !keys.iter().any(|k| k == &req.config_key) { + return Err(sacp::Error::invalid_params() + .data(format!("Extension '{}' not found", req.config_key))); + } + crate::config::extensions::set_extension_enabled(&req.config_key, req.enabled); + Ok(EmptyResponse {}) + } + #[custom_method(GetSessionExtensionsRequest)] async fn on_get_session_extensions( &self, diff --git a/ui/goose2/src-tauri/src/commands/extensions.rs b/ui/goose2/src-tauri/src/commands/extensions.rs deleted file mode 100644 index 5b4040f8..00000000 --- a/ui/goose2/src-tauri/src/commands/extensions.rs +++ /dev/null @@ -1,168 +0,0 @@ -use serde_json::Value; -use tauri::State; - -use crate::services::goose_config::GooseConfig; - -fn yaml_to_json(yaml: serde_yaml::Value) -> Value { - match yaml { - serde_yaml::Value::Null => Value::Null, - serde_yaml::Value::Bool(b) => Value::Bool(b), - serde_yaml::Value::Number(n) => { - if let Some(i) = n.as_i64() { - Value::Number(i.into()) - } else if let Some(u) = n.as_u64() { - Value::Number(u.into()) - } else if let Some(f) = n.as_f64() { - serde_json::Number::from_f64(f) - .map(Value::Number) - .unwrap_or(Value::Null) - } else { - Value::Null - } - } - serde_yaml::Value::String(s) => Value::String(s), - serde_yaml::Value::Sequence(seq) => { - Value::Array(seq.into_iter().map(yaml_to_json).collect()) - } - serde_yaml::Value::Mapping(map) => { - let obj = map - .into_iter() - .filter_map(|(k, v)| { - let key = match k { - serde_yaml::Value::String(s) => s, - other => serde_yaml::to_string(&other).ok()?.trim().to_string(), - }; - Some((key, yaml_to_json(v))) - }) - .collect(); - Value::Object(obj) - } - serde_yaml::Value::Tagged(tagged) => yaml_to_json(tagged.value), - } -} - -fn json_to_yaml(json: Value) -> serde_yaml::Value { - match json { - Value::Null => serde_yaml::Value::Null, - Value::Bool(b) => serde_yaml::Value::Bool(b), - Value::Number(n) => { - if let Some(i) = n.as_i64() { - serde_yaml::Value::Number(i.into()) - } else if let Some(u) = n.as_u64() { - serde_yaml::Value::Number(u.into()) - } else if let Some(f) = n.as_f64() { - serde_yaml::Value::Number(f.into()) - } else { - serde_yaml::Value::Null - } - } - Value::String(s) => serde_yaml::Value::String(s), - Value::Array(arr) => { - serde_yaml::Value::Sequence(arr.into_iter().map(json_to_yaml).collect()) - } - Value::Object(obj) => { - let mut map = serde_yaml::Mapping::new(); - for (k, v) in obj { - map.insert(serde_yaml::Value::String(k), json_to_yaml(v)); - } - serde_yaml::Value::Mapping(map) - } - } -} - -fn name_to_key(name: &str) -> String { - let mut result = String::with_capacity(name.len()); - for c in name.chars() { - match c { - c if c.is_ascii_alphanumeric() || c == '_' || c == '-' => result.push(c), - c if c.is_whitespace() => continue, - _ => result.push('_'), - } - } - result.to_lowercase() -} - -#[tauri::command] -pub fn list_extensions(config: State<'_, GooseConfig>) -> Result, String> { - let raw = config.get_extensions_raw(); - let mut entries = Vec::with_capacity(raw.len()); - - for (k, v) in raw { - let key = match k { - serde_yaml::Value::String(s) => s, - _ => continue, - }; - - let mut json = yaml_to_json(v); - - if let Value::Object(ref mut obj) = json { - if !obj.contains_key("type") { - continue; - } - obj.insert("config_key".to_string(), Value::String(key.clone())); - obj.entry("name".to_string()) - .or_insert_with(|| Value::String(key)); - obj.entry("enabled".to_string()) - .or_insert(Value::Bool(false)); - entries.push(json); - } - } - - Ok(entries) -} - -#[tauri::command] -pub fn add_extension( - name: String, - extension_config: Value, - enabled: bool, - config: State<'_, GooseConfig>, -) -> Result<(), String> { - let key = name_to_key(&name); - let mut raw = config.get_extensions_raw(); - - let mut entry = match extension_config { - Value::Object(obj) => obj, - _ => return Err("extension_config must be a JSON object".to_string()), - }; - - entry.insert("enabled".to_string(), Value::Bool(enabled)); - entry.insert("name".to_string(), Value::String(name)); - - let yaml_value = json_to_yaml(Value::Object(entry)); - raw.insert(serde_yaml::Value::String(key), yaml_value); - - config.set_extensions_raw(raw) -} - -#[tauri::command] -pub fn remove_extension(config_key: String, config: State<'_, GooseConfig>) -> Result<(), String> { - let mut raw = config.get_extensions_raw(); - let yaml_key = serde_yaml::Value::String(config_key.clone()); - if raw.remove(&yaml_key).is_none() { - return Err(format!("Extension '{}' not found", config_key)); - } - config.set_extensions_raw(raw) -} - -#[tauri::command] -pub fn toggle_extension( - config_key: String, - enabled: bool, - config: State<'_, GooseConfig>, -) -> Result<(), String> { - let mut raw = config.get_extensions_raw(); - - let yaml_key = serde_yaml::Value::String(config_key.clone()); - if let Some(entry) = raw.get_mut(&yaml_key) { - if let serde_yaml::Value::Mapping(ref mut map) = entry { - map.insert( - serde_yaml::Value::String("enabled".to_string()), - serde_yaml::Value::Bool(enabled), - ); - } - config.set_extensions_raw(raw) - } else { - Err(format!("Extension '{}' not found", config_key)) - } -} diff --git a/ui/goose2/src-tauri/src/commands/mod.rs b/ui/goose2/src-tauri/src/commands/mod.rs index 8acd3c56..51e933f6 100644 --- a/ui/goose2/src-tauri/src/commands/mod.rs +++ b/ui/goose2/src-tauri/src/commands/mod.rs @@ -3,7 +3,6 @@ pub mod agent_setup; pub mod agents; pub mod credentials; pub mod doctor; -pub mod extensions; pub mod git; pub mod git_changes; pub mod model_setup; diff --git a/ui/goose2/src-tauri/src/lib.rs b/ui/goose2/src-tauri/src/lib.rs index f473c45d..e82d11fa 100644 --- a/ui/goose2/src-tauri/src/lib.rs +++ b/ui/goose2/src-tauri/src/lib.rs @@ -56,10 +56,6 @@ pub fn run() { commands::projects::restore_project, commands::doctor::run_doctor, commands::doctor::run_doctor_fix, - commands::extensions::list_extensions, - commands::extensions::add_extension, - commands::extensions::remove_extension, - commands::extensions::toggle_extension, commands::git::get_git_state, commands::git_changes::get_changed_files, commands::git::git_switch_branch, diff --git a/ui/goose2/src-tauri/src/services/goose_config.rs b/ui/goose2/src-tauri/src/services/goose_config.rs index b29319b8..b77b154d 100644 --- a/ui/goose2/src-tauri/src/services/goose_config.rs +++ b/ui/goose2/src-tauri/src/services/goose_config.rs @@ -321,26 +321,6 @@ impl GooseConfig { .collect()) } - pub fn get_extensions_raw(&self) -> serde_yaml::Mapping { - let config = self.read_config_map(); - let key = serde_yaml::Value::String("extensions".to_string()); - config - .get(&key) - .and_then(|v| v.as_mapping()) - .cloned() - .unwrap_or_default() - } - - pub fn set_extensions_raw(&self, extensions: serde_yaml::Mapping) -> Result<(), String> { - let _guard = self.guard.lock().unwrap(); - let mut config = self.read_config_map(); - config.insert( - serde_yaml::Value::String("extensions".to_string()), - serde_yaml::Value::Mapping(extensions), - ); - self.write_config_map(&config) - } - pub fn delete_all_provider_fields(&self, provider_id: &str) -> Result<(), String> { let def = find_provider_def(provider_id) .ok_or_else(|| format!("Unknown provider '{provider_id}'"))?; diff --git a/ui/goose2/src/features/extensions/api/extensions.ts b/ui/goose2/src/features/extensions/api/extensions.ts index 1d28f213..dad02470 100644 --- a/ui/goose2/src/features/extensions/api/extensions.ts +++ b/ui/goose2/src/features/extensions/api/extensions.ts @@ -1,4 +1,4 @@ -import { invoke } from "@tauri-apps/api/core"; +import { getClient } from "@/shared/api/acpConnection"; import type { ExtensionConfig, ExtensionEntry } from "../types"; export function nameToKey(name: string): string { @@ -9,7 +9,9 @@ export function nameToKey(name: string): string { } export async function listExtensions(): Promise { - return invoke("list_extensions"); + const client = await getClient(); + const response = await client.goose.GooseConfigExtensions({}); + return response.extensions as ExtensionEntry[]; } export async function addExtension( @@ -17,7 +19,8 @@ export async function addExtension( extensionConfig: ExtensionConfig, enabled: boolean, ): Promise { - return invoke("add_extension", { + const client = await getClient(); + await client.goose.GooseConfigExtensionsAdd({ name, extensionConfig, enabled, @@ -25,12 +28,14 @@ export async function addExtension( } export async function removeExtension(configKey: string): Promise { - return invoke("remove_extension", { configKey }); + const client = await getClient(); + await client.goose.GooseConfigExtensionsRemove({ configKey }); } export async function toggleExtension( configKey: string, enabled: boolean, ): Promise { - return invoke("toggle_extension", { configKey, enabled }); + const client = await getClient(); + await client.goose.GooseConfigExtensionsToggle({ configKey, enabled }); } diff --git a/ui/sdk/src/generated/client.gen.ts b/ui/sdk/src/generated/client.gen.ts index 4d24696d..13c76ffd 100644 --- a/ui/sdk/src/generated/client.gen.ts +++ b/ui/sdk/src/generated/client.gen.ts @@ -8,6 +8,7 @@ export interface ExtMethodProvider { } import type { + AddConfigExtensionRequest, AddExtensionRequest, ArchiveSessionRequest, CheckSecretRequest, @@ -52,9 +53,11 @@ import type { ReadResourceResponse, RefreshProviderInventoryRequest, RefreshProviderInventoryResponse, + RemoveConfigExtensionRequest, RemoveConfigRequest, RemoveExtensionRequest, RemoveSecretRequest, + ToggleConfigExtensionRequest, UnarchiveSessionRequest, UpdateSessionProjectRequest, UpdateSourceRequest, @@ -123,6 +126,24 @@ export class GooseExtClient { return zGetExtensionsResponse.parse(raw) as GetExtensionsResponse; } + async GooseConfigExtensionsAdd( + params: AddConfigExtensionRequest, + ): Promise { + await this.conn.extMethod("_goose/config/extensions/add", params); + } + + async GooseConfigExtensionsRemove( + params: RemoveConfigExtensionRequest, + ): Promise { + await this.conn.extMethod("_goose/config/extensions/remove", params); + } + + async GooseConfigExtensionsToggle( + params: ToggleConfigExtensionRequest, + ): Promise { + await this.conn.extMethod("_goose/config/extensions/toggle", params); + } + async GooseSessionExtensions( params: GetSessionExtensionsRequest, ): Promise { diff --git a/ui/sdk/src/generated/index.ts b/ui/sdk/src/generated/index.ts index 801e58a1..df0cd080 100644 --- a/ui/sdk/src/generated/index.ts +++ b/ui/sdk/src/generated/index.ts @@ -1,6 +1,6 @@ // This file is auto-generated by @hey-api/openapi-ts -export type { AddExtensionRequest, ArchiveSessionRequest, CheckSecretRequest, CheckSecretResponse, CreateSourceRequest, CreateSourceResponse, DeleteSessionRequest, DeleteSourceRequest, DictationConfigRequest, DictationConfigResponse, DictationDownloadProgress, DictationLocalModelStatus, DictationModelCancelRequest, DictationModelDeleteRequest, DictationModelDownloadProgressRequest, DictationModelDownloadProgressResponse, DictationModelDownloadRequest, DictationModelOption, DictationModelSelectRequest, DictationModelsListRequest, DictationModelsListResponse, DictationProviderStatusEntry, DictationTranscribeRequest, DictationTranscribeResponse, EmptyResponse, ExportSessionRequest, ExportSessionResponse, ExportSourceRequest, ExportSourceResponse, ExtRequest, ExtResponse, GetExtensionsRequest, GetExtensionsResponse, GetSessionExtensionsRequest, GetSessionExtensionsResponse, GetToolsRequest, GetToolsResponse, ImportSessionRequest, ImportSessionResponse, ImportSourcesRequest, ImportSourcesResponse, ListProvidersRequest, ListProvidersResponse, ListSourcesRequest, ListSourcesResponse, ProviderConfigKey, ProviderInventoryEntryDto, ProviderInventoryModelDto, ReadConfigRequest, ReadConfigResponse, ReadResourceRequest, ReadResourceResponse, RefreshProviderInventoryRequest, RefreshProviderInventoryResponse, RefreshProviderInventorySkipDto, RefreshProviderInventorySkipReasonDto, RemoveConfigRequest, RemoveExtensionRequest, RemoveSecretRequest, SourceEntry, SourceType, UnarchiveSessionRequest, UpdateSessionProjectRequest, UpdateSourceRequest, UpdateSourceResponse, UpdateWorkingDirRequest, UpsertConfigRequest, UpsertSecretRequest } from './types.gen.js'; +export type { AddConfigExtensionRequest, AddExtensionRequest, ArchiveSessionRequest, CheckSecretRequest, CheckSecretResponse, CreateSourceRequest, CreateSourceResponse, DeleteSessionRequest, DeleteSourceRequest, DictationConfigRequest, DictationConfigResponse, DictationDownloadProgress, DictationLocalModelStatus, DictationModelCancelRequest, DictationModelDeleteRequest, DictationModelDownloadProgressRequest, DictationModelDownloadProgressResponse, DictationModelDownloadRequest, DictationModelOption, DictationModelSelectRequest, DictationModelsListRequest, DictationModelsListResponse, DictationProviderStatusEntry, DictationTranscribeRequest, DictationTranscribeResponse, EmptyResponse, ExportSessionRequest, ExportSessionResponse, ExportSourceRequest, ExportSourceResponse, ExtRequest, ExtResponse, GetExtensionsRequest, GetExtensionsResponse, GetSessionExtensionsRequest, GetSessionExtensionsResponse, GetToolsRequest, GetToolsResponse, ImportSessionRequest, ImportSessionResponse, ImportSourcesRequest, ImportSourcesResponse, ListProvidersRequest, ListProvidersResponse, ListSourcesRequest, ListSourcesResponse, ProviderConfigKey, ProviderInventoryEntryDto, ProviderInventoryModelDto, ReadConfigRequest, ReadConfigResponse, ReadResourceRequest, ReadResourceResponse, RefreshProviderInventoryRequest, RefreshProviderInventoryResponse, RefreshProviderInventorySkipDto, RefreshProviderInventorySkipReasonDto, RemoveConfigExtensionRequest, RemoveConfigRequest, RemoveExtensionRequest, RemoveSecretRequest, SourceEntry, SourceType, ToggleConfigExtensionRequest, UnarchiveSessionRequest, UpdateSessionProjectRequest, UpdateSourceRequest, UpdateSourceResponse, UpdateWorkingDirRequest, UpsertConfigRequest, UpsertSecretRequest } from './types.gen.js'; export const GOOSE_EXT_METHODS = [ { @@ -38,6 +38,21 @@ export const GOOSE_EXT_METHODS = [ requestType: "GetExtensionsRequest", responseType: "GetExtensionsResponse", }, + { + method: "_goose/config/extensions/add", + requestType: "AddConfigExtensionRequest", + responseType: "EmptyResponse", + }, + { + method: "_goose/config/extensions/remove", + requestType: "RemoveConfigExtensionRequest", + responseType: "EmptyResponse", + }, + { + method: "_goose/config/extensions/toggle", + requestType: "ToggleConfigExtensionRequest", + responseType: "EmptyResponse", + }, { method: "_goose/session/extensions", requestType: "GetSessionExtensionsRequest", diff --git a/ui/sdk/src/generated/types.gen.ts b/ui/sdk/src/generated/types.gen.ts index 14800f98..07a4d8f0 100644 --- a/ui/sdk/src/generated/types.gen.ts +++ b/ui/sdk/src/generated/types.gen.ts @@ -90,12 +90,41 @@ export type GetExtensionsRequest = { */ export type GetExtensionsResponse = { /** - * Array of ExtensionEntry objects with `enabled` flag and config details. + * Array of ExtensionEntry objects with `enabled` flag, `configKey`, and flattened config details. */ extensions: Array; warnings: Array; }; +/** + * Persist a new extension to the user's global goose config. + */ +export type AddConfigExtensionRequest = { + name: string; + /** + * Extension configuration. Must be a JSON object matching one of the + * `ExtensionConfig` variants (e.g. `stdio`, `streamable_http`, `builtin`). + * `name` and `enabled` are injected server-side. + */ + extensionConfig?: unknown; + enabled?: boolean; +}; + +/** + * Remove a persisted extension from the user's global goose config. + */ +export type RemoveConfigExtensionRequest = { + configKey: string; +}; + +/** + * Toggle the `enabled` flag for a persisted extension in the user's global goose config. + */ +export type ToggleConfigExtensionRequest = { + configKey: string; + enabled: boolean; +}; + export type GetSessionExtensionsRequest = { sessionId: string; }; @@ -626,7 +655,7 @@ export type DictationModelSelectRequest = { export type ExtRequest = { id: string; method: string; - params?: AddExtensionRequest | RemoveExtensionRequest | GetToolsRequest | ReadResourceRequest | UpdateWorkingDirRequest | DeleteSessionRequest | GetExtensionsRequest | GetSessionExtensionsRequest | ListProvidersRequest | RefreshProviderInventoryRequest | ReadConfigRequest | UpsertConfigRequest | RemoveConfigRequest | CheckSecretRequest | UpsertSecretRequest | RemoveSecretRequest | ExportSessionRequest | ImportSessionRequest | UpdateSessionProjectRequest | ArchiveSessionRequest | UnarchiveSessionRequest | CreateSourceRequest | ListSourcesRequest | UpdateSourceRequest | DeleteSourceRequest | ExportSourceRequest | ImportSourcesRequest | DictationTranscribeRequest | DictationConfigRequest | DictationModelsListRequest | DictationModelDownloadRequest | DictationModelDownloadProgressRequest | DictationModelCancelRequest | DictationModelDeleteRequest | DictationModelSelectRequest | { + params?: AddExtensionRequest | RemoveExtensionRequest | GetToolsRequest | ReadResourceRequest | UpdateWorkingDirRequest | DeleteSessionRequest | GetExtensionsRequest | AddConfigExtensionRequest | RemoveConfigExtensionRequest | ToggleConfigExtensionRequest | GetSessionExtensionsRequest | ListProvidersRequest | RefreshProviderInventoryRequest | ReadConfigRequest | UpsertConfigRequest | RemoveConfigRequest | CheckSecretRequest | UpsertSecretRequest | RemoveSecretRequest | ExportSessionRequest | ImportSessionRequest | UpdateSessionProjectRequest | ArchiveSessionRequest | UnarchiveSessionRequest | CreateSourceRequest | ListSourcesRequest | UpdateSourceRequest | DeleteSourceRequest | ExportSourceRequest | ImportSourcesRequest | DictationTranscribeRequest | DictationConfigRequest | DictationModelsListRequest | DictationModelDownloadRequest | DictationModelDownloadProgressRequest | DictationModelCancelRequest | DictationModelDeleteRequest | DictationModelSelectRequest | { [key: string]: unknown; } | null; }; diff --git a/ui/sdk/src/generated/zod.gen.ts b/ui/sdk/src/generated/zod.gen.ts index 3a6be88b..015f6c68 100644 --- a/ui/sdk/src/generated/zod.gen.ts +++ b/ui/sdk/src/generated/zod.gen.ts @@ -81,6 +81,30 @@ export const zGetExtensionsResponse = z.object({ warnings: z.array(z.string()) }); +/** + * Persist a new extension to the user's global goose config. + */ +export const zAddConfigExtensionRequest = z.object({ + name: z.string(), + extensionConfig: z.unknown().optional().default(null), + enabled: z.boolean().optional().default(false) +}); + +/** + * Remove a persisted extension from the user's global goose config. + */ +export const zRemoveConfigExtensionRequest = z.object({ + configKey: z.string() +}); + +/** + * Toggle the `enabled` flag for a persisted extension in the user's global goose config. + */ +export const zToggleConfigExtensionRequest = z.object({ + configKey: z.string(), + enabled: z.boolean() +}); + export const zGetSessionExtensionsRequest = z.object({ sessionId: z.string() }); @@ -594,6 +618,9 @@ export const zExtRequest = z.object({ zUpdateWorkingDirRequest, zDeleteSessionRequest, zGetExtensionsRequest, + zAddConfigExtensionRequest, + zRemoveConfigExtensionRequest, + zToggleConfigExtensionRequest, zGetSessionExtensionsRequest, zListProvidersRequest, zRefreshProviderInventoryRequest,