Skip to main content

crabtalk_core/agent/
config.rs

1//! Agent configuration.
2//!
3//! [`AgentConfig`] is a serializable struct holding all agent parameters.
4//! Used by [`super::AgentBuilder`] to construct an [`super::Agent`].
5
6use crate::model::ToolChoice;
7use serde::{Deserialize, Serialize};
8
9/// Default maximum iterations for agent execution.
10const DEFAULT_MAX_ITERATIONS: usize = 16;
11
12/// Default compact threshold in estimated tokens (~100k).
13const DEFAULT_COMPACT_THRESHOLD: usize = 100_000;
14
15/// Default max byte length for tool results during compaction.
16const DEFAULT_COMPACT_TOOL_MAX_LEN: usize = 1024;
17
18/// Serializable agent configuration.
19///
20/// Contains all parameters for an agent: identity, system prompt, model,
21/// iteration limits, and delegation scope. Used both as the
22/// TOML deserialization target and the runtime agent definition.
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct AgentConfig {
25    /// Agent identifier. Derived from TOML key, not stored in TOML.
26    #[serde(skip)]
27    pub name: String,
28    /// Human-readable description.
29    #[serde(default)]
30    pub description: String,
31    /// System prompt sent before each LLM request. Loaded from .md file.
32    #[serde(skip)]
33    pub system_prompt: String,
34    /// Model to use from the registry. None = registry's active/default.
35    #[serde(default)]
36    pub model: Option<String>,
37    /// Maximum iterations before stopping.
38    #[serde(default = "default_max_iterations")]
39    pub max_iterations: usize,
40    /// Controls which tool the model calls.
41    #[serde(skip)]
42    pub tool_choice: ToolChoice,
43    /// Whether to enable thinking/reasoning mode.
44    #[serde(default)]
45    pub thinking: bool,
46    /// Agents this agent can delegate to via spawn_task. Empty = no delegation.
47    #[serde(default)]
48    pub members: Vec<String>,
49    /// Skill names this agent can access. Empty = all skills (crabtalk default).
50    #[serde(default)]
51    pub skills: Vec<String>,
52    /// MCP server names this agent can access. Empty = all MCPs (crabtalk default).
53    #[serde(default)]
54    pub mcps: Vec<String>,
55    /// Computed tool whitelist. Empty = all tools. Not serialized.
56    #[serde(skip)]
57    pub tools: Vec<String>,
58    /// Token count threshold for automatic context compaction.
59    /// When history exceeds this, the agent compacts automatically.
60    /// None = disabled. Defaults to 100_000.
61    #[serde(default = "default_compact_threshold")]
62    pub compact_threshold: Option<usize>,
63    /// Max byte length to keep from tool-role messages when compacting.
64    /// Longer results are truncated before sending to the compaction LLM.
65    #[serde(default = "default_compact_tool_max_len")]
66    pub compact_tool_max_len: usize,
67}
68
69fn default_max_iterations() -> usize {
70    DEFAULT_MAX_ITERATIONS
71}
72
73fn default_compact_threshold() -> Option<usize> {
74    Some(DEFAULT_COMPACT_THRESHOLD)
75}
76
77fn default_compact_tool_max_len() -> usize {
78    DEFAULT_COMPACT_TOOL_MAX_LEN
79}
80
81impl Default for AgentConfig {
82    fn default() -> Self {
83        Self {
84            name: String::new(),
85            description: String::new(),
86            system_prompt: String::new(),
87            model: None,
88            max_iterations: DEFAULT_MAX_ITERATIONS,
89            tool_choice: ToolChoice::Auto,
90            thinking: false,
91            members: Vec::new(),
92            skills: Vec::new(),
93            mcps: Vec::new(),
94            tools: Vec::new(),
95            compact_threshold: default_compact_threshold(),
96            compact_tool_max_len: DEFAULT_COMPACT_TOOL_MAX_LEN,
97        }
98    }
99}
100
101impl AgentConfig {
102    /// Create a new config with the given name and defaults for everything else.
103    pub fn new(name: impl Into<String>) -> Self {
104        Self {
105            name: name.into(),
106            ..Default::default()
107        }
108    }
109
110    /// Set the system prompt.
111    pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
112        self.system_prompt = prompt.into();
113        self
114    }
115
116    /// Set the description.
117    pub fn description(mut self, desc: impl Into<String>) -> Self {
118        self.description = desc.into();
119        self
120    }
121
122    /// Set the model to use from the registry.
123    pub fn model(mut self, name: impl Into<String>) -> Self {
124        self.model = Some(name.into());
125        self
126    }
127
128    /// Enable or disable thinking/reasoning mode.
129    pub fn thinking(mut self, enabled: bool) -> Self {
130        self.thinking = enabled;
131        self
132    }
133}