feat: extensions read config (#1637)

This commit is contained in:
Lily Delalande
2025-03-12 18:41:31 -07:00
committed by GitHub
parent 68b3b3f9cc
commit 4537264387
15 changed files with 756 additions and 190 deletions
+1 -1
View File
@@ -171,7 +171,7 @@ impl Capabilities {
.await
.map_err(|e| ExtensionError::Initialization(config.clone(), e))?;
let sanitized_name = normalize(config.name().to_string());
let sanitized_name = normalize(config.key().to_string());
// Store instructions if provided
if let Some(instructions) = init_result.instructions {
+11 -3
View File
@@ -3,8 +3,10 @@ use std::collections::HashMap;
use mcp_client::client::Error as ClientError;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use utoipa::ToSchema;
use crate::config;
use crate::config::extensions::name_to_key;
/// Errors from Extension operation
#[derive(Error, Debug)]
@@ -21,7 +23,7 @@ pub enum ExtensionError {
pub type ExtensionResult<T> = Result<T, ExtensionError>;
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[derive(Debug, Clone, Deserialize, Serialize, Default, ToSchema)]
pub struct Envs {
/// A map of environment variables to set, e.g. API_KEY -> some_secret, HOST -> host
#[serde(default)]
@@ -43,7 +45,7 @@ impl Envs {
}
/// Represents the different types of MCP extensions that can be added to the manager
#[derive(Debug, Clone, Deserialize, Serialize)]
#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
#[serde(tag = "type")]
pub enum ExtensionConfig {
/// Server-sent events client with a URI endpoint
@@ -130,13 +132,19 @@ impl ExtensionConfig {
}
}
pub fn key(&self) -> String {
let name = self.name();
name_to_key(&name)
}
/// Get the extension name regardless of variant
pub fn name(&self) -> &str {
pub fn name(&self) -> String {
match self {
Self::Sse { name, .. } => name,
Self::Stdio { name, .. } => name,
Self::Builtin { name, .. } => name,
}
.to_string()
}
}
+23 -15
View File
@@ -3,23 +3,28 @@ use crate::agents::ExtensionConfig;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use utoipa::ToSchema;
pub const DEFAULT_EXTENSION: &str = "developer";
pub const DEFAULT_EXTENSION_TIMEOUT: u64 = 300;
#[derive(Debug, Deserialize, Serialize, Clone)]
#[derive(Debug, Deserialize, Serialize, Clone, ToSchema)]
pub struct ExtensionEntry {
pub enabled: bool,
#[serde(flatten)]
pub config: ExtensionConfig,
}
pub fn name_to_key(name: &str) -> String {
name.to_string()
}
/// Extension configuration management
pub struct ExtensionManager;
impl ExtensionManager {
/// Get the extension configuration if enabled
pub fn get_config(name: &str) -> Result<Option<ExtensionConfig>> {
/// Get the extension configuration if enabled -- uses key
pub fn get_config(key: &str) -> Result<Option<ExtensionConfig>> {
let config = Config::global();
// Try to get the extension entry
@@ -28,7 +33,7 @@ impl ExtensionManager {
Err(super::ConfigError::NotFound(_)) => {
// Initialize with default developer extension
let defaults = HashMap::from([(
DEFAULT_EXTENSION.to_string(),
name_to_key(DEFAULT_EXTENSION), // Use key format for top-level key in config
ExtensionEntry {
enabled: true,
config: ExtensionConfig::Builtin {
@@ -43,7 +48,7 @@ impl ExtensionManager {
Err(e) => return Err(e.into()),
};
Ok(extensions.get(name).and_then(|entry| {
Ok(extensions.get(key).and_then(|entry| {
if entry.enabled {
Some(entry.config.clone())
} else {
@@ -60,33 +65,35 @@ impl ExtensionManager {
.get_param("extensions")
.unwrap_or_else(|_| HashMap::new());
extensions.insert(entry.config.name().parse()?, entry);
let key = entry.config.key();
extensions.insert(key, entry);
config.set_param("extensions", serde_json::to_value(extensions)?)?;
Ok(())
}
/// Remove an extension configuration
pub fn remove(name: &str) -> Result<()> {
/// Remove an extension configuration -- uses the key
pub fn remove(key: &str) -> Result<()> {
let config = Config::global();
let mut extensions: HashMap<String, ExtensionEntry> = config
.get_param("extensions")
.unwrap_or_else(|_| HashMap::new());
extensions.remove(name);
extensions.remove(key);
config.set_param("extensions", serde_json::to_value(extensions)?)?;
Ok(())
}
/// Enable or disable an extension
pub fn set_enabled(name: &str, enabled: bool) -> Result<()> {
/// Enable or disable an extension -- uses key
pub fn set_enabled(key: &str, enabled: bool) -> Result<()> {
let config = Config::global();
let mut extensions: HashMap<String, ExtensionEntry> = config
.get_param("extensions")
.unwrap_or_else(|_| HashMap::new());
if let Some(entry) = extensions.get_mut(name) {
if let Some(entry) = extensions.get_mut(key) {
entry.enabled = enabled;
config.set_param("extensions", serde_json::to_value(extensions)?)?;
}
@@ -109,16 +116,17 @@ impl ExtensionManager {
.unwrap_or_else(|_| get_keys(Default::default())))
}
/// Check if an extension is enabled
pub fn is_enabled(name: &str) -> Result<bool> {
/// Check if an extension is enabled - FIXED to use key
pub fn is_enabled(key: &str) -> Result<bool> {
let config = Config::global();
let extensions: HashMap<String, ExtensionEntry> = config
.get_param("extensions")
.unwrap_or_else(|_| HashMap::new());
Ok(extensions.get(name).map(|e| e.enabled).unwrap_or(false))
Ok(extensions.get(key).map(|e| e.enabled).unwrap_or(false))
}
}
fn get_keys(entries: HashMap<String, ExtensionEntry>) -> Vec<String> {
entries.into_keys().collect()
}
+1 -1
View File
@@ -1,6 +1,6 @@
mod base;
mod experiments;
mod extensions;
pub mod extensions;
pub use crate::agents::ExtensionConfig;
pub use base::{Config, ConfigError, APP_STRATEGY};