mermaid_cli/models/capabilities.rs
1//! Per-model capability metadata.
2//!
3//! Adapters expose `ModelCapabilities` via `Model::capabilities()` so the
4//! rest of the codebase can ask facts like "does this model support tool
5//! calls?" or "what reasoning levels does it accept?" without per-provider
6//! string matching scattered through the codebase. This is the same
7//! pattern Roo Code uses on its `ModelInfo` struct (`supports_reasoning_*`
8//! flags) and Codex CLI uses on `ModelPreset.supported_reasoning_efforts`.
9//!
10//! For Step 1 the values are hardcoded conservative defaults. A future
11//! step can add per-model lookup (similar to https://models.dev) or
12//! runtime probing (Ollama `/api/show`).
13
14use super::reasoning::ReasoningCapability;
15
16/// Capability flags advertised by a model adapter.
17#[derive(Debug, Clone)]
18pub struct ModelCapabilities {
19 /// Model accepts tool/function-calling requests in the chat API.
20 pub supports_tools: bool,
21 /// Model accepts image inputs in messages (vision-capable).
22 pub supports_vision: bool,
23 /// Reasoning controls the model exposes — see `ReasoningCapability`.
24 pub supports_reasoning: ReasoningCapability,
25 /// Maximum context window in tokens, if known.
26 pub max_context_tokens: Option<usize>,
27 /// The model's per-response output ceiling in tokens, if known (from
28 /// `/models` metadata or a documented per-model table).
29 pub max_output_tokens: Option<usize>,
30}
31
32impl ModelCapabilities {
33 /// Conservative defaults for an Ollama-served model. We assume tool
34 /// calling (every modern Ollama-supported model the project targets
35 /// has it), assume no vision (the safer static default — real vision
36 /// support is probed from the `/api/show` `capabilities` array by
37 /// `OllamaAdapter::vision_supported` and refreshed into the runtime
38 /// snapshot via `Msg::ProviderVisionResolved`), and treat reasoning as
39 /// binary on/off (matches the `think: bool` semantics for everything
40 /// except gpt-oss).
41 pub fn ollama_default() -> Self {
42 Self {
43 supports_tools: true,
44 supports_vision: false,
45 supports_reasoning: ReasoningCapability::Binary,
46 max_context_tokens: None,
47 max_output_tokens: None,
48 }
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
57 fn ollama_default_is_conservative() {
58 let caps = ModelCapabilities::ollama_default();
59 assert!(caps.supports_tools);
60 assert!(!caps.supports_vision);
61 assert_eq!(caps.supports_reasoning, ReasoningCapability::Binary);
62 assert!(caps.max_context_tokens.is_none());
63 }
64
65 #[test]
66 fn capabilities_are_cloneable() {
67 let caps = ModelCapabilities::ollama_default();
68 let cloned = caps.clone();
69 assert_eq!(cloned.supports_tools, caps.supports_tools);
70 }
71}