zeph_config/providers/thinking.rs
1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Thinking, reasoning-effort, and prompt-cache config enums shared across providers.
5//!
6//! These types model provider-specific reasoning controls (Claude extended/adaptive
7//! thinking, Gemini thinking levels) and the Anthropic prompt-cache TTL. They are
8//! embedded in [`super::ProviderEntry`] and serialized into `[[llm.providers]]` entries.
9
10use serde::{Deserialize, Serialize};
11
12#[non_exhaustive]
13/// Extended or adaptive thinking mode for Claude.
14///
15/// Serializes with `mode` as tag:
16/// `{ "mode": "extended", "budget_tokens": 10000 }` or `{ "mode": "adaptive" }`.
17#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
18#[serde(tag = "mode", rename_all = "snake_case")]
19pub enum ThinkingConfig {
20 /// Extended thinking with an explicit token budget.
21 Extended {
22 /// Maximum thinking tokens to allocate.
23 budget_tokens: u32,
24 },
25 /// Adaptive thinking that selects effort automatically.
26 Adaptive {
27 /// Explicit effort hint when provided; model-chosen when `None`.
28 #[serde(default, skip_serializing_if = "Option::is_none")]
29 effort: Option<ThinkingEffort>,
30 },
31}
32
33/// Effort level for adaptive thinking.
34#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
35#[serde(rename_all = "lowercase")]
36#[non_exhaustive]
37pub enum ThinkingEffort {
38 /// Minimal thinking; fastest responses.
39 Low,
40 /// Balanced thinking depth. This is the default.
41 #[default]
42 Medium,
43 /// Maximum thinking depth; slowest responses.
44 High,
45}
46
47#[non_exhaustive]
48/// Prompt-cache TTL variant for the Anthropic API.
49///
50/// When used as a TOML config value the accepted strings are `"ephemeral"` and `"1h"`.
51/// On the wire (Anthropic API), `OneHour` serializes as `"1h"` inside the `cache_control.ttl`
52/// field.
53#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Default)]
54#[serde(rename_all = "snake_case")]
55pub enum CacheTtl {
56 /// Default ephemeral TTL (~5 minutes). No beta header required.
57 #[default]
58 Ephemeral,
59 /// Extended 1-hour TTL. Requires the `extended-cache-ttl-2025-04-25` beta header.
60 /// Cache writes cost approximately 2× more than `Ephemeral`.
61 #[serde(rename = "1h")]
62 OneHour,
63}
64
65impl CacheTtl {
66 /// Returns `true` when this TTL variant requires the `extended-cache-ttl-2025-04-25` beta
67 /// header to be sent with each request.
68 #[must_use]
69 pub fn requires_beta(self) -> bool {
70 match self {
71 Self::OneHour => true,
72 Self::Ephemeral => false,
73 }
74 }
75}
76
77/// Thinking level for Gemini models that support extended reasoning.
78///
79/// Maps to `generationConfig.thinkingConfig.thinkingLevel` in the Gemini API.
80/// Valid for Gemini 3+ models. For Gemini 2.5, use `thinking_budget` instead.
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
82#[serde(rename_all = "lowercase")]
83#[non_exhaustive]
84pub enum GeminiThinkingLevel {
85 /// Minimal reasoning pass.
86 Minimal,
87 /// Low reasoning depth.
88 Low,
89 /// Medium reasoning depth.
90 Medium,
91 /// Full reasoning depth.
92 High,
93}