use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use crate::{AuthMetadata, Tool};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OAuthProviderConfig {
pub provider: String,
pub client_id: Option<String>,
pub client_secret: Option<String>,
pub authorization_url: String,
pub token_url: String,
pub refresh_url: Option<String>,
pub scopes: Vec<String>,
pub redirect_uri: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecretProviderConfig {
pub provider: String,
pub key_name: String,
pub location: Option<String>, pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AuthProviderConfig {
#[serde(rename = "oauth")]
OAuth(OAuthProviderConfig),
#[serde(rename = "secret")]
Secret(SecretProviderConfig),
}
#[async_trait]
pub trait Integration: Send + Sync + std::fmt::Debug {
fn get_name(&self) -> String;
fn get_description(&self) -> String;
fn get_version(&self) -> String {
"1.0.0".to_string()
}
fn get_auth_metadata(&self) -> Option<Box<dyn AuthMetadata>> {
None
}
fn get_tools(&self) -> Vec<Arc<dyn Tool>>;
fn get_callbacks(&self) -> HashMap<String, serde_json::Value> {
HashMap::new() }
fn get_notifications(&self) -> Vec<String> {
vec![] }
fn get_metadata(&self) -> HashMap<String, serde_json::Value> {
HashMap::new()
}
async fn initialize(&self) -> Result<(), anyhow::Error> {
Ok(()) }
async fn shutdown(&self) -> Result<(), anyhow::Error> {
Ok(()) }
}
#[derive(Debug)]
pub struct IntegrationTool {
tool: Arc<dyn Tool>,
integration_name: String,
}
impl IntegrationTool {
pub fn new(tool: Arc<dyn Tool>, integration_name: String) -> Self {
Self {
tool,
integration_name,
}
}
pub fn get_integration_name(&self) -> &str {
&self.integration_name
}
pub fn get_tool(&self) -> &Arc<dyn Tool> {
&self.tool
}
}
#[async_trait]
impl Tool for IntegrationTool {
fn get_name(&self) -> String {
self.tool.get_name()
}
fn get_parameters(&self) -> serde_json::Value {
self.tool.get_parameters()
}
fn get_description(&self) -> String {
self.tool.get_description()
}
fn is_external(&self) -> bool {
self.tool.is_external()
}
fn is_mcp(&self) -> bool {
self.tool.is_mcp()
}
fn is_sync(&self) -> bool {
self.tool.is_sync()
}
fn is_final(&self) -> bool {
self.tool.is_final()
}
fn needs_executor_context(&self) -> bool {
self.tool.needs_executor_context()
}
fn get_auth_metadata(&self) -> Option<Box<dyn AuthMetadata>> {
self.tool.get_auth_metadata()
}
fn get_plugin_name(&self) -> Option<String> {
Some(self.integration_name.clone())
}
async fn execute(
&self,
tool_call: crate::ToolCall,
context: Arc<crate::ToolContext>,
) -> Result<Vec<crate::Part>, anyhow::Error> {
self.tool.execute(tool_call, context).await
}
fn execute_sync(
&self,
tool_call: crate::ToolCall,
context: Arc<crate::ToolContext>,
) -> Result<Vec<crate::Part>, anyhow::Error> {
self.tool.execute_sync(tool_call, context)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntegrationInfo {
pub name: String,
pub description: String,
pub version: String,
pub tools: Vec<String>, pub callbacks: HashMap<String, serde_json::Value>,
pub notifications: Vec<String>,
pub requires_auth: bool,
pub auth_entity: Option<String>,
pub metadata: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntegrationToolDefinition {
pub name: String,
pub description: String,
pub version: Option<String>,
#[serde(default)]
pub parameters: serde_json::Value,
#[serde(default, skip_serializing_if = "Option::is_none", rename = "auth")]
pub auth: Option<crate::AuthRequirement>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntegrationData {
#[serde(default)]
pub name: String,
pub description: String,
pub version: String,
#[serde(default)]
pub tools: Vec<IntegrationToolDefinition>,
#[serde(default)]
pub callbacks: HashMap<String, serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none", rename = "auth")]
pub auth: Option<crate::AuthRequirement>,
#[serde(default)]
pub notifications: Vec<String>,
#[serde(default)]
pub metadata: HashMap<String, serde_json::Value>,
}
impl IntegrationInfo {
pub fn from_integration(integration: &dyn Integration) -> Self {
let auth_metadata = integration.get_auth_metadata();
let (requires_auth, auth_entity) = if let Some(auth) = auth_metadata.as_ref() {
(auth.requires_auth(), Some(auth.get_auth_entity()))
} else {
(false, None)
};
Self {
name: integration.get_name(),
description: integration.get_description(),
version: integration.get_version(),
tools: integration
.get_tools()
.iter()
.map(|t| t.get_name())
.collect(),
callbacks: integration.get_callbacks(),
notifications: integration.get_notifications(),
requires_auth,
auth_entity,
metadata: integration.get_metadata(),
}
}
}