Skip to main content

aether_project/
agent_config.rs

1use crate::{McpSourceSpec, PromptSource};
2use aether_core::agent_spec::ToolFilter;
3use llm::{ProviderConnectionOverrides, ReasoningEffort};
4
5#[derive(Debug, Clone, Default, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
6#[serde(rename_all = "camelCase", deny_unknown_fields)]
7#[schemars(transform = require_agent_invocation_surface_schema)]
8pub struct AgentConfig {
9    #[schemars(length(min = 1))]
10    pub name: String,
11    #[schemars(length(min = 1))]
12    pub description: String,
13    #[schemars(length(min = 1))]
14    pub model: String,
15    #[serde(default, skip_serializing_if = "Option::is_none")]
16    pub reasoning_effort: Option<ReasoningEffort>,
17    #[serde(default, skip_serializing_if = "Option::is_none")]
18    #[schemars(range(min = 1))]
19    pub context_window: Option<u32>,
20    #[serde(default)]
21    pub user_invocable: bool,
22    #[serde(default)]
23    pub agent_invocable: bool,
24    #[serde(default, skip_serializing_if = "ProviderConnectionOverrides::is_empty")]
25    pub providers: ProviderConnectionOverrides,
26    #[serde(default, skip_serializing_if = "Vec::is_empty")]
27    #[schemars(length(min = 1))]
28    pub prompts: Vec<PromptSource>,
29    #[serde(default, skip_serializing_if = "Vec::is_empty")]
30    pub mcps: Vec<McpSourceSpec>,
31    #[serde(default, skip_serializing_if = "ToolFilter::is_empty")]
32    pub tools: ToolFilter,
33}
34
35fn require_agent_invocation_surface_schema(schema: &mut schemars::Schema) {
36    schema.insert(
37        "anyOf".to_string(),
38        serde_json::json!([
39            { "required": ["userInvocable"], "properties": { "userInvocable": { "const": true } } },
40            { "required": ["agentInvocable"], "properties": { "agentInvocable": { "const": true } } }
41        ]),
42    );
43}