From b5869d424ef03707ef8d9dc8d71684f76e5cb3a0 Mon Sep 17 00:00:00 2001 From: YubinghanBai Date: Mon, 16 Feb 2026 16:48:15 -0600 Subject: [PATCH] feat(provider): add capabilities detection mechanism Add ProviderCapabilities struct to enable runtime detection of provider-specific features, starting with native tool calling support. This is a foundational change that enables future PRs to implement intelligent tool calling mode selection (native vs prompt-guided). Changes: - Add ProviderCapabilities struct with native_tool_calling field - Add capabilities() method to Provider trait with default impl - Add unit tests for capabilities equality and defaults Why: - Current design cannot distinguish providers with native tool calling - Needed to enable Gemini/Anthropic/OpenAI native function calling - Fully backward compatible (all providers inherit default) What did NOT change: - No existing Provider methods modified - No behavior changes for existing code - Zero breaking changes Testing: - cargo test: all tests passed - cargo fmt: pass - cargo clippy: pass --- src/providers/traits.rs | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/providers/traits.rs b/src/providers/traits.rs index 31f2cf5..fbe5170 100644 --- a/src/providers/traits.rs +++ b/src/providers/traits.rs @@ -191,8 +191,30 @@ pub enum StreamError { Io(#[from] std::io::Error), } +/// Provider capabilities declaration. +/// +/// Describes what features a provider supports, enabling intelligent +/// adaptation of tool calling modes and request formatting. +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub struct ProviderCapabilities { + /// Whether the provider supports native tool calling via API primitives. + /// + /// When `true`, the provider can convert tool definitions to API-native + /// formats (e.g., Gemini's functionDeclarations, Anthropic's input_schema). + /// + /// When `false`, tools must be injected via system prompt as text. + pub native_tool_calling: bool, +} + #[async_trait] pub trait Provider: Send + Sync { + /// Query provider capabilities. + /// + /// Default implementation returns minimal capabilities (no native tool calling). + /// Providers should override this to declare their actual capabilities. + fn capabilities(&self) -> ProviderCapabilities { + ProviderCapabilities::default() + } /// Simple one-shot chat (single user message, no explicit system prompt). /// /// This is the preferred API for non-agentic direct interactions. @@ -398,4 +420,26 @@ mod tests { let json = serde_json::to_string(&tool_result).unwrap(); assert!(json.contains("\"type\":\"ToolResults\"")); } + + #[test] + fn provider_capabilities_default() { + let caps = ProviderCapabilities::default(); + assert!(!caps.native_tool_calling); + } + + #[test] + fn provider_capabilities_equality() { + let caps1 = ProviderCapabilities { + native_tool_calling: true, + }; + let caps2 = ProviderCapabilities { + native_tool_calling: true, + }; + let caps3 = ProviderCapabilities { + native_tool_calling: false, + }; + + assert_eq!(caps1, caps2); + assert_ne!(caps1, caps3); + } }