Skip to main content

distri_types/configuration/
package.rs

1use crate::ToolDefinition;
2use crate::agent::StandardDefinition;
3use crate::configuration::manifest::DistriServerConfig;
4use serde::{Deserialize, Serialize};
5use std::path::PathBuf;
6
7/// Tool definition ready for DAP registration with runtime info
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct PluginToolDefinition {
10    pub name: String,
11    pub package_name: String,
12    pub description: String,
13    #[serde(default)]
14    pub parameters: serde_json::Value,
15    #[serde(default, skip_serializing_if = "Option::is_none")]
16    pub auth: Option<crate::auth::AuthRequirement>,
17}
18
19/// Cloud-specific metadata for agents (optional, only present in cloud responses)
20#[derive(Debug, Clone, Serialize, Deserialize, Default)]
21pub struct AgentCloudMetadata {
22    #[serde(default, skip_serializing_if = "Option::is_none")]
23    pub id: Option<uuid::Uuid>,
24    #[serde(default, skip_serializing_if = "Option::is_none")]
25    pub published: Option<bool>,
26    #[serde(default, skip_serializing_if = "Option::is_none")]
27    pub published_at: Option<chrono::DateTime<chrono::Utc>>,
28    #[serde(default, skip_serializing_if = "Option::is_none")]
29    pub is_owner: Option<bool>,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct AgentConfigWithTools {
34    #[serde(flatten)]
35    pub agent: AgentConfig,
36    #[serde(default, skip_serializing_if = "Vec::is_empty")]
37    pub resolved_tools: Vec<ToolDefinition>,
38    #[serde(default, skip_serializing_if = "Option::is_none")]
39    pub markdown: Option<String>,
40    /// Cloud-specific metadata (optional, only present in cloud responses)
41    #[serde(flatten, default)]
42    pub cloud: AgentCloudMetadata,
43}
44
45/// Unified agent configuration enum
46#[derive(Debug, Clone, Serialize, Deserialize)]
47#[serde(tag = "agent_type", rename_all = "snake_case")]
48pub enum AgentConfig {
49    /// Standard markdown-based agent
50    StandardAgent(StandardDefinition),
51    /// Workflow-based agent — executes a workflow DAG instead of an LLM loop
52    WorkflowAgent(WorkflowAgentDefinition),
53}
54
55/// Definition for a workflow-based agent.
56/// The workflow definition is stored as JSON to avoid crate dependency on distri-workflow.
57/// Deserialize to `distri_workflow::WorkflowDefinition` at execution time.
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct WorkflowAgentDefinition {
60    pub name: String,
61    pub description: String,
62    #[serde(default = "default_version")]
63    pub version: String,
64    /// The workflow definition as JSON.
65    pub definition: serde_json::Value,
66    /// JSON Schema for required inputs (validated before execution).
67    #[serde(default, skip_serializing_if = "Option::is_none")]
68    pub input_schema: Option<serde_json::Value>,
69}
70
71fn default_version() -> String {
72    "0.1.0".to_string()
73}
74
75impl AgentConfig {
76    /// Get the name of the agent
77    pub fn get_name(&self) -> &str {
78        match self {
79            AgentConfig::StandardAgent(def) => &def.name,
80            AgentConfig::WorkflowAgent(def) => &def.name,
81        }
82    }
83
84    pub fn get_definition(&self) -> &StandardDefinition {
85        match self {
86            AgentConfig::StandardAgent(def) => def,
87            AgentConfig::WorkflowAgent(_) => {
88                panic!("WorkflowAgent does not have a StandardDefinition")
89            }
90        }
91    }
92
93    /// Get the description of the agent
94    pub fn get_description(&self) -> &str {
95        match self {
96            AgentConfig::StandardAgent(def) => &def.description,
97            AgentConfig::WorkflowAgent(def) => &def.description,
98        }
99    }
100
101    /// Get the tools configuration, if this is a standard agent.
102    pub fn get_tools_config(&self) -> Option<&crate::ToolsConfig> {
103        match self {
104            AgentConfig::StandardAgent(def) => def.tools.as_ref(),
105            AgentConfig::WorkflowAgent(_) => None,
106        }
107    }
108
109    /// Validate the configuration
110    pub fn validate(&self) -> anyhow::Result<()> {
111        match self {
112            AgentConfig::StandardAgent(def) => def.validate(),
113            AgentConfig::WorkflowAgent(_def) => Ok(()), // Workflow validation happens at execution
114        }
115    }
116
117    /// Get the working directory with fallback chain: agent config -> package config -> DISTRI_HOME -> current_dir
118    pub fn get_working_directory(
119        &self,
120        package_config: Option<&DistriServerConfig>,
121    ) -> anyhow::Result<std::path::PathBuf> {
122        // Fall back to package configuration
123        if let Some(config) = package_config {
124            return config.get_working_directory();
125        }
126
127        // Try DISTRI_HOME environment variable
128        if let Ok(distri_home) = std::env::var("DISTRI_HOME") {
129            return Ok(std::path::PathBuf::from(distri_home));
130        }
131
132        // Fallback to current directory
133        std::env::current_dir()
134            .map_err(|e| anyhow::anyhow!("Failed to get current directory: {}", e))
135    }
136}
137
138/// Agent definition ready for DAP registration with runtime info
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct PluginAgentDefinition {
141    pub name: String,
142    pub package_name: String,
143    pub description: String,
144    pub file_path: PathBuf,
145    /// The full agent configuration (supports all agent types)
146    pub agent_config: AgentConfig,
147}
148
149/// Built DAP package artifact ready for registration in distri
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct PluginArtifact {
152    pub name: String,
153    pub path: PathBuf,
154    pub configuration: crate::configuration::manifest::DistriServerConfig,
155    pub tools: Vec<PluginToolDefinition>,
156    pub agents: Vec<PluginAgentDefinition>,
157}