Skip to main content

ferrin_core/generate_text/
config.rs

1//! Configuration shared by `generate_text` and `stream_text`.
2
3use std::fmt;
4use std::sync::Arc;
5
6use ferrin_message::Message;
7use ferrin_provider_util::IdGenerator;
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;
15use tokio_util::sync::CancellationToken;
16
17use super::ApprovalPolicy;
18use super::PrepareStep;
19use super::RefineToolInputs;
20use super::StopCondition;
21use super::ToolCallRepair;
22use crate::clock::Clock;
23use crate::clock::default_clock;
24use crate::hooks::Hooks;
25use crate::ids::default_id_generator;
26use crate::prompt::CallSettings;
27use crate::prompt::DownloadFn;
28use crate::prompt::Instructions;
29use crate::retry::RetryPolicy;
30use crate::telemetry::TelemetryOptions;
31use crate::timeout::Timeout;
32
33/// Which large payloads are copied into step results.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub struct Include {
36    /// Keep the raw request body.
37    pub request_body: bool,
38    /// Keep the messages sent to the model.
39    pub request_messages: bool,
40    /// Keep the raw response body.
41    pub response_body: bool,
42}
43
44impl Default for Include {
45    fn default() -> Self {
46        Self::none()
47    }
48}
49
50impl Include {
51    /// Keeps nothing.
52    #[must_use]
53    pub fn none() -> Self {
54        Self {
55            request_body: false,
56            request_messages: false,
57            response_body: false,
58        }
59    }
60
61    /// Keeps everything.
62    #[must_use]
63    pub fn all() -> Self {
64        Self {
65            request_body: true,
66            request_messages: true,
67            response_body: true,
68        }
69    }
70}
71
72/// Everything a text generation call needs, independent of streaming.
73#[derive(Clone)]
74pub(crate) struct CallConfig {
75    pub(crate) model: LanguageModelRef,
76    pub(crate) system: Option<Instructions>,
77    pub(crate) prompt: Option<String>,
78    pub(crate) messages: Option<Vec<Message>>,
79    pub(crate) allow_system_in_messages: bool,
80    pub(crate) settings: CallSettings,
81    pub(crate) tools: ToolSet,
82    pub(crate) tool_choice: Option<ToolChoice>,
83    pub(crate) active_tools: Option<Vec<ToolName>>,
84    pub(crate) tool_order: Vec<ToolName>,
85    pub(crate) tools_context: Option<JsonValue>,
86    pub(crate) runtime_context: Option<JsonValue>,
87    pub(crate) tool_approval: Option<Arc<dyn ApprovalPolicy>>,
88    pub(crate) tool_approval_secret: Option<Arc<SecretBox<[u8]>>>,
89    pub(crate) tool_callers: ToolCallers,
90    pub(crate) repair_tool_call: Option<Arc<dyn ToolCallRepair>>,
91    pub(crate) refine_tool_inputs: RefineToolInputs,
92    #[cfg(feature = "sandbox")]
93    pub(crate) sandbox: Option<Arc<dyn ferrin_tool::Sandbox>>,
94    pub(crate) stop_conditions: Vec<Arc<dyn StopCondition>>,
95    pub(crate) prepare_step: Option<Arc<dyn PrepareStep>>,
96    pub(crate) retry_policy: RetryPolicy,
97    pub(crate) timeout: Timeout,
98    pub(crate) cancellation: CancellationToken,
99    pub(crate) download: Option<Arc<dyn DownloadFn>>,
100    pub(crate) include: Include,
101    pub(crate) max_tool_concurrency: Option<usize>,
102    pub(crate) telemetry: TelemetryOptions,
103    pub(crate) hooks: Hooks,
104    pub(crate) id_generator: Arc<dyn IdGenerator>,
105    pub(crate) clock: Arc<dyn Clock>,
106}
107
108impl CallConfig {
109    pub(crate) fn new(model: LanguageModelRef) -> Self {
110        Self {
111            model,
112            system: None,
113            prompt: None,
114            messages: None,
115            allow_system_in_messages: false,
116            settings: CallSettings::default(),
117            tools: ToolSet::new(),
118            tool_choice: None,
119            active_tools: None,
120            tool_order: Vec::new(),
121            tools_context: None,
122            runtime_context: None,
123            tool_approval: None,
124            tool_approval_secret: None,
125            tool_callers: ToolCallers::new(),
126            repair_tool_call: None,
127            refine_tool_inputs: RefineToolInputs::default(),
128            #[cfg(feature = "sandbox")]
129            sandbox: None,
130            stop_conditions: Vec::new(),
131            prepare_step: None,
132            retry_policy: RetryPolicy::default(),
133            timeout: Timeout::none(),
134            cancellation: CancellationToken::new(),
135            download: None,
136            include: Include::default(),
137            max_tool_concurrency: None,
138            telemetry: TelemetryOptions::default(),
139            hooks: Hooks::default(),
140            id_generator: default_id_generator(),
141            clock: default_clock(),
142        }
143    }
144}
145
146impl fmt::Debug for CallConfig {
147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        f.debug_struct("CallConfig")
149            .field("model", &self.model)
150            .field("system", &self.system)
151            .field("prompt", &self.prompt)
152            .field("messages", &self.messages.as_ref().map(Vec::len))
153            .field("allow_system_in_messages", &self.allow_system_in_messages)
154            .field("settings", &self.settings)
155            .field("tools", &self.tools.names().collect::<Vec<_>>())
156            .field("tool_choice", &self.tool_choice)
157            .field("active_tools", &self.active_tools)
158            .field("tool_order", &self.tool_order)
159            .field("tools_context", &self.tools_context)
160            .field("runtime_context", &self.runtime_context.is_some())
161            .field("tool_approval", &self.tool_approval.is_some())
162            .field("tool_approval_secret", &self.tool_approval_secret.is_some())
163            .field("tool_callers", &self.tool_callers)
164            .field("repair_tool_call", &self.repair_tool_call.is_some())
165            .field("refine_tool_inputs", &self.refine_tool_inputs)
166            .field("stop_conditions", &self.stop_conditions.len())
167            .field("prepare_step", &self.prepare_step.is_some())
168            .field("retry_policy", &self.retry_policy)
169            .field("timeout", &self.timeout)
170            .field("download", &self.download.is_some())
171            .field("include", &self.include)
172            .field("max_tool_concurrency", &self.max_tool_concurrency)
173            .field("telemetry", &self.telemetry)
174            .field("hooks", &self.hooks)
175            .finish_non_exhaustive()
176    }
177}