Skip to main content

swink_agent/loop_/
config.rs

1//! Configuration for the agent loop.
2
3use std::sync::Arc;
4
5use crate::agent_options::{ApproveToolFn, GetApiKeyFn};
6use crate::async_context_transformer::AsyncContextTransformer;
7use crate::fallback::ModelFallback;
8use crate::message_provider::MessageProvider;
9use crate::retry::RetryStrategy;
10use crate::stream::{StreamFn, StreamOptions};
11use crate::tool::{AgentTool, ApprovalMode};
12use crate::tool_execution_policy::ToolExecutionPolicy;
13use crate::types::ModelSpec;
14
15use super::ConvertToLlmFn;
16
17// ─── AgentLoopConfig ─────────────────────────────────────────────────────────
18
19/// Configuration for the agent loop.
20///
21/// Carries the model spec, stream options, retry strategy, stream function,
22/// tools, and all the hooks that the loop calls at various points.
23pub struct AgentLoopConfig {
24    /// Optional agent name used for transfer chain safety enforcement.
25    ///
26    /// When set, the loop pushes this name onto the [`TransferChain`](crate::transfer::TransferChain)
27    /// at startup so circular transfers back to this agent are detected.
28    pub agent_name: Option<String>,
29    /// Optional transfer chain carried from a previous handoff.
30    ///
31    /// When set, the loop resumes transfer safety checks from this chain.
32    pub transfer_chain: Option<crate::transfer::TransferChain>,
33
34    /// Model specification passed through to `StreamFn`.
35    pub model: ModelSpec,
36
37    /// Stream options passed through to `StreamFn`.
38    pub stream_options: StreamOptions,
39
40    /// Retry strategy applied to model calls.
41    pub retry_strategy: Box<dyn RetryStrategy>,
42
43    /// The pluggable streaming function that calls the LLM provider.
44    pub stream_fn: Arc<dyn StreamFn>,
45
46    /// Available tools for the agent to call.
47    pub tools: Vec<Arc<dyn AgentTool>>,
48
49    /// Converts an `AgentMessage` to an `LlmMessage` for the provider.
50    /// Returns `None` to filter out custom or UI-only messages.
51    pub convert_to_llm: Box<ConvertToLlmFn>,
52
53    /// Optional hook called before `convert_to_llm`; used for context pruning,
54    /// token budget enforcement, or external context injection.
55    /// When the overflow signal is set, the transformer should prune more
56    /// aggressively.
57    pub transform_context: Option<Arc<dyn crate::context_transformer::ContextTransformer>>,
58
59    /// Optional async callback for dynamic API key resolution.
60    pub get_api_key: Option<Box<GetApiKeyFn>>,
61
62    /// Optional provider polled for steering and follow-up messages.
63    ///
64    /// [`MessageProvider::poll_steering`] is called after each tool execution batch.
65    /// [`MessageProvider::poll_follow_up`] is called when the agent would otherwise stop.
66    pub message_provider: Option<Arc<dyn MessageProvider>>,
67
68    /// Shared snapshot of loop-local pending messages for pause checkpoints.
69    #[allow(private_interfaces)]
70    pub pending_message_snapshot: Arc<crate::pause_state::PendingMessageSnapshot>,
71
72    /// Shared snapshot of the loop's full `context_messages` for pause checkpoints.
73    ///
74    /// Updated after each turn's pending-message drain so that `Agent::pause()`
75    /// can reconstruct the complete message history even for messages that have
76    /// been moved out of the shared pending queue and into loop-local context.
77    #[allow(private_interfaces)]
78    pub loop_context_snapshot: Arc<crate::pause_state::LoopContextSnapshot>,
79
80    /// Optional async callback for approving/rejecting tool calls before execution.
81    /// When `Some` and `approval_mode` is `Enabled`, each tool call is sent through
82    /// this callback before dispatch. Rejected tools return an error result to the LLM.
83    pub approve_tool: Option<Box<ApproveToolFn>>,
84
85    /// Controls whether the approval gate is active. Defaults to `Enabled`.
86    pub approval_mode: ApprovalMode,
87
88    /// Pre-turn policies evaluated before each LLM call.
89    pub pre_turn_policies: Vec<Arc<dyn crate::policy::PreTurnPolicy>>,
90
91    /// Pre-dispatch policies evaluated per tool call, before approval.
92    pub pre_dispatch_policies: Vec<Arc<dyn crate::policy::PreDispatchPolicy>>,
93
94    /// Post-turn policies evaluated after each completed turn.
95    pub post_turn_policies: Vec<Arc<dyn crate::policy::PostTurnPolicy>>,
96
97    /// Post-loop policies evaluated after the inner loop exits.
98    pub post_loop_policies: Vec<Arc<dyn crate::policy::PostLoopPolicy>>,
99
100    /// Optional async context transformer (runs before the sync transformer).
101    ///
102    /// Enables async operations like fetching summaries or RAG retrieval
103    /// before context compaction.
104    pub async_transform_context: Option<Arc<dyn AsyncContextTransformer>>,
105
106    /// Optional metrics collector invoked at the end of each turn with
107    /// per-turn timing, token usage, and cost data.
108    pub metrics_collector: Option<Arc<dyn crate::metrics::MetricsCollector>>,
109
110    /// Optional model fallback chain tried when the primary model exhausts
111    /// its retry budget on a retryable error.
112    pub fallback: Option<ModelFallback>,
113
114    /// Controls how tool calls within a turn are dispatched.
115    ///
116    /// Defaults to [`ToolExecutionPolicy::Concurrent`] for backward
117    /// compatibility.
118    pub tool_execution_policy: ToolExecutionPolicy,
119
120    /// Session key-value state store shared with tools and policies.
121    pub session_state: Arc<std::sync::RwLock<crate::SessionState>>,
122
123    /// Optional credential resolver for tool authentication.
124    pub credential_resolver: Option<Arc<dyn crate::credential::CredentialResolver>>,
125
126    /// Optional context caching configuration.
127    pub cache_config: Option<crate::context_cache::CacheConfig>,
128
129    /// Mutable cache state tracking turns since last write.
130    pub cache_state: std::sync::Mutex<crate::context_cache::CacheState>,
131
132    /// Optional dynamic system prompt closure (called fresh each turn).
133    ///
134    /// Its output is injected as a user-role message after the system prompt
135    /// to avoid invalidating provider-side caches.
136    pub dynamic_system_prompt: Option<Arc<dyn Fn() -> String + Send + Sync>>,
137}
138
139impl std::fmt::Debug for AgentLoopConfig {
140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141        f.debug_struct("AgentLoopConfig")
142            .field("model", &self.model)
143            .field("stream_options", &self.stream_options)
144            .field("tools", &format_args!("[{} tool(s)]", self.tools.len()))
145            .field(
146                "pre_turn_policies",
147                &format_args!("[{} policy(ies)]", self.pre_turn_policies.len()),
148            )
149            .field(
150                "pre_dispatch_policies",
151                &format_args!("[{} policy(ies)]", self.pre_dispatch_policies.len()),
152            )
153            .field(
154                "post_turn_policies",
155                &format_args!("[{} policy(ies)]", self.post_turn_policies.len()),
156            )
157            .field(
158                "post_loop_policies",
159                &format_args!("[{} policy(ies)]", self.post_loop_policies.len()),
160            )
161            .field("tool_execution_policy", &self.tool_execution_policy)
162            .finish_non_exhaustive()
163    }
164}