ferrin_core/agent/
prepare_call.rs1use std::fmt;
4use std::future::Future;
5use std::sync::Arc;
6
7use ferrin_spec::BoxFuture;
8use ferrin_spec::JsonValue;
9use ferrin_spec::LanguageModelRef;
10use ferrin_spec::ToolChoice;
11use ferrin_spec::ToolName;
12use ferrin_tool::ToolCallers;
13use ferrin_tool::ToolSet;
14use secrecy::SecretBox;
15
16use super::AgentInput;
17use crate::error::Error;
18use crate::generate_text::ApprovalPolicy;
19use crate::generate_text::Include;
20use crate::generate_text::PrepareStep;
21use crate::generate_text::RefineToolInputs;
22use crate::generate_text::StopCondition;
23use crate::generate_text::ToolCallRepair;
24use crate::prompt::CallSettings;
25use crate::prompt::DownloadFn;
26use crate::prompt::Instructions;
27use crate::retry::RetryPolicy;
28use crate::telemetry::TelemetryOptions;
29use crate::timeout::Timeout;
30
31#[derive(Clone)]
37pub struct PreparedCall {
38 pub input: AgentInput,
40 pub instructions: Option<Instructions>,
42 pub allow_system_in_messages: bool,
44 pub model: LanguageModelRef,
46 pub tools: ToolSet,
48 pub tool_choice: Option<ToolChoice>,
50 pub active_tools: Option<Vec<ToolName>>,
52 pub tool_order: Vec<ToolName>,
54 pub tools_context: Option<JsonValue>,
56 pub runtime_context: Option<JsonValue>,
58 pub tool_approval: Option<Arc<dyn ApprovalPolicy>>,
60 pub tool_approval_secret: Option<Arc<SecretBox<[u8]>>>,
62 pub tool_callers: ToolCallers,
64 pub prepare_step: Option<Arc<dyn PrepareStep>>,
66 pub repair_tool_call: Option<Arc<dyn ToolCallRepair>>,
68 pub refine_tool_inputs: RefineToolInputs,
70 pub download: Option<Arc<dyn DownloadFn>>,
72 pub settings: CallSettings,
74 pub stop_conditions: Vec<Arc<dyn StopCondition>>,
76 pub timeout: Timeout,
78 pub retry_policy: RetryPolicy,
80 pub include: Include,
82 pub max_tool_concurrency: Option<usize>,
84 pub telemetry: TelemetryOptions,
86}
87
88impl fmt::Debug for PreparedCall {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 f.debug_struct("PreparedCall")
91 .field("input", &self.input)
92 .field("instructions", &self.instructions)
93 .field("allow_system_in_messages", &self.allow_system_in_messages)
94 .field("model", &self.model)
95 .field("tools", &self.tools.names().collect::<Vec<_>>())
96 .field("tool_choice", &self.tool_choice)
97 .field("active_tools", &self.active_tools)
98 .field("tool_order", &self.tool_order)
99 .field("tools_context", &self.tools_context)
100 .field("runtime_context", &self.runtime_context.is_some())
101 .field("tool_approval", &self.tool_approval.is_some())
102 .field("tool_approval_secret", &self.tool_approval_secret.is_some())
103 .field("tool_callers", &self.tool_callers)
104 .field("prepare_step", &self.prepare_step.is_some())
105 .field("repair_tool_call", &self.repair_tool_call.is_some())
106 .field("refine_tool_inputs", &self.refine_tool_inputs)
107 .field("download", &self.download.is_some())
108 .field("settings", &self.settings)
109 .field("stop_conditions", &self.stop_conditions.len())
110 .field("timeout", &self.timeout)
111 .field("retry_policy", &self.retry_policy)
112 .field("include", &self.include)
113 .field("max_tool_concurrency", &self.max_tool_concurrency)
114 .finish_non_exhaustive()
115 }
116}
117
118pub struct PrepareCallInput<Opt> {
120 pub options: Opt,
122 pub defaults: PreparedCall,
125 #[cfg(feature = "sandbox")]
127 pub sandbox: Option<Arc<dyn ferrin_tool::Sandbox>>,
128}
129
130impl<Opt: fmt::Debug> fmt::Debug for PrepareCallInput<Opt> {
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 let mut debug = f.debug_struct("PrepareCallInput");
133 debug
134 .field("options", &self.options)
135 .field("defaults", &self.defaults);
136 #[cfg(feature = "sandbox")]
137 debug.field("has_sandbox", &self.sandbox.is_some());
138 debug.finish()
139 }
140}
141
142pub trait PrepareCall<Opt>: Send + Sync {
145 fn prepare_call(
147 &self,
148 input: PrepareCallInput<Opt>,
149 ) -> BoxFuture<'_, Result<PreparedCall, Error>>;
150}
151
152impl<Opt, F, Fut> PrepareCall<Opt> for F
153where
154 F: Fn(PrepareCallInput<Opt>) -> Fut + Send + Sync,
155 Fut: Future<Output = Result<PreparedCall, Error>> + Send + 'static,
156{
157 fn prepare_call(
158 &self,
159 input: PrepareCallInput<Opt>,
160 ) -> BoxFuture<'_, Result<PreparedCall, Error>> {
161 Box::pin(self(input))
162 }
163}