aimux_core/options.rs
1//! `CallOptions` — the provider-facing options passed to `do_generate` / `do_stream`.
2//!
3//! Aligned with V4 `LanguageModelV4CallOptions`.
4
5use std::collections::HashMap;
6
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9use ts_rs::TS;
10
11use crate::language_model_message::LanguageModelPrompt;
12use crate::shared::AbortSignal;
13pub use crate::tool::{FunctionTool, ProviderTool, Tool, ToolChoice};
14use crate::types::ReasoningEffort;
15
16/// How the model should format its response.
17#[derive(Debug, Clone, Serialize, Deserialize, TS)]
18#[ts(export)]
19pub enum ResponseFormat {
20 /// Plain text (default).
21 Text,
22 /// JSON output, optionally constrained to a schema.
23 Json {
24 schema: Option<Value>,
25 name: Option<String>,
26 description: Option<String>,
27 },
28}
29
30/// Per-call timeout configuration.
31///
32/// Aligned with V4 `LanguageModelV4CallOptions.timeout`
33/// (`TimeoutConfiguration`). All values are milliseconds; `None` disables the
34/// corresponding limit. A `total` timeout also covers retry backoff and the
35/// whole streamed response.
36#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, TS)]
37#[ts(export)]
38pub struct TimeoutConfiguration {
39 /// Overall timeout for the entire call (including retries and, for
40 /// streaming, the whole stream), in milliseconds.
41 pub total_ms: Option<u64>,
42 /// Timeout waiting for the first stream chunk (streaming only).
43 pub first_chunk_ms: Option<u64>,
44 /// Maximum idle time between consecutive stream chunks (streaming only).
45 pub chunk_ms: Option<u64>,
46}
47
48/// Options passed to `LanguageModel::do_generate` / `do_stream`.
49///
50/// This is the **provider-facing** options struct. Users interact with
51/// `GenerateTextOptions` (user-facing) which is converted to `CallOptions`
52/// by the `generate_text` / `stream_text` functions.
53#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
54#[ts(export)]
55pub struct CallOptions {
56 /// The standardized prompt (message array). Required.
57 pub prompt: LanguageModelPrompt,
58
59 /// Maximum tokens to generate.
60 pub max_output_tokens: Option<u32>,
61
62 /// Sampling temperature.
63 pub temperature: Option<f64>,
64
65 /// Stop sequences.
66 pub stop_sequences: Option<Vec<String>>,
67
68 /// Nucleus sampling `top_p`.
69 pub top_p: Option<f64>,
70
71 /// Top-k sampling.
72 pub top_k: Option<f64>,
73
74 /// Presence penalty.
75 pub presence_penalty: Option<f64>,
76
77 /// Frequency penalty.
78 pub frequency_penalty: Option<f64>,
79
80 /// Response format (text or JSON).
81 pub response_format: Option<ResponseFormat>,
82
83 /// Seed for reproducibility.
84 pub seed: Option<u64>,
85
86 /// Tools available to the model (function tools and/or provider-defined tools).
87 pub tools: Option<Vec<Tool>>,
88
89 /// How the model should choose tools.
90 pub tool_choice: ToolChoice,
91
92 /// Extra HTTP headers.
93 pub headers: Option<HashMap<String, String>>,
94
95 /// Provider-specific options (keyed by provider name).
96 pub provider_options: Option<HashMap<String, Value>>,
97
98 /// Top-level reasoning effort. Maps to OpenAI `reasoning_effort` and
99 /// Anthropic `thinking` config.
100 pub reasoning: Option<ReasoningEffort>,
101
102 /// Per-call request body overrides. Deep-merged into the provider-built
103 /// request body (after any built-in vendor override) before sending.
104 /// `null` values delete the corresponding key. See RFC-0017.
105 pub body_overrides: Option<Value>,
106
107 /// Per-call retry count override. `None` uses the provider's configured
108 /// `RetryConfig.max_retries`. `Some(0)` disables retries.
109 pub max_retries: Option<u32>,
110
111 /// Per-call timeout configuration (total / first-chunk / chunk idle).
112 /// `None` = no timeouts (provider defaults still apply at the HTTP layer).
113 pub timeout: Option<TimeoutConfiguration>,
114
115 /// Abort signal for cancelling the call.
116 ///
117 /// Runtime handle — never crosses the JSON boundary (bindings that only
118 /// pass JSON cannot set it; Node bridges a JS `AbortSignal` natively).
119 #[serde(skip)]
120 #[ts(skip)]
121 pub abort_signal: Option<AbortSignal>,
122}
123
124impl CallOptions {
125 /// Create a `CallOptions` with the given prompt and all other fields set
126 /// to their defaults (`None` / `ToolChoice::Auto`).
127 ///
128 /// This is the recommended construction baseline in tests — combined with
129 /// struct-update syntax (`CallOptions { tools: Some(..), ..CallOptions::new(prompt) }`)
130 /// it avoids spelling out every `None` field, so adding a new optional
131 /// field to `CallOptions` no longer requires batch-editing every test.
132 pub fn new(prompt: LanguageModelPrompt) -> Self {
133 CallOptions {
134 prompt,
135 max_output_tokens: None,
136 temperature: None,
137 stop_sequences: None,
138 top_p: None,
139 top_k: None,
140 presence_penalty: None,
141 frequency_penalty: None,
142 response_format: None,
143 seed: None,
144 tools: None,
145 tool_choice: ToolChoice::default(),
146 headers: None,
147 provider_options: None,
148 reasoning: None,
149 body_overrides: None,
150 max_retries: None,
151 timeout: None,
152 abort_signal: None,
153 }
154 }
155}