perspt_sdk/model/
capabilities.rs1use serde::{Deserialize, Serialize};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
18pub struct ProviderCapabilities {
19 pub tool_calling: bool,
20 pub strict_schema: bool,
21 pub parallel_tool_calls: bool,
22 pub streaming_tool_calls: bool,
23 pub prompt_caching: bool,
24 pub structured_output: bool,
25 pub max_context_tokens: u32,
26}
27
28impl ProviderCapabilities {
29 pub fn text_only(max_context_tokens: u32) -> Self {
31 Self {
32 tool_calling: false,
33 strict_schema: false,
34 parallel_tool_calls: false,
35 streaming_tool_calls: false,
36 prompt_caching: false,
37 structured_output: false,
38 max_context_tokens,
39 }
40 }
41
42 pub fn satisfies(&self, required: &ProviderCapabilityMask) -> bool {
44 (!required.tool_calling || self.tool_calling)
45 && (!required.strict_schema || self.strict_schema)
46 && (!required.parallel_tool_calls || self.parallel_tool_calls)
47 && (!required.streaming_tool_calls || self.streaming_tool_calls)
48 && (!required.prompt_caching || self.prompt_caching)
49 && (!required.structured_output || self.structured_output)
50 && self.max_context_tokens >= required.min_context_tokens
51 }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
56pub struct ProviderCapabilityMask {
57 pub tool_calling: bool,
58 pub strict_schema: bool,
59 pub parallel_tool_calls: bool,
60 pub streaming_tool_calls: bool,
61 pub prompt_caching: bool,
62 pub structured_output: bool,
63 pub min_context_tokens: u32,
64}
65
66impl ProviderCapabilityMask {
67 pub fn tool_loop() -> Self {
69 Self {
70 tool_calling: true,
71 ..Self::default()
72 }
73 }
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
81#[serde(rename_all = "snake_case", tag = "missing")]
82pub enum CapabilityDegradation {
83 StrictSchema,
86 ParallelToolCalls,
88 StreamingToolCalls,
91 PromptCaching,
94 ToolCalling,
97 ContextWindow { needed: u32, available: u32 },
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 fn full() -> ProviderCapabilities {
107 ProviderCapabilities {
108 tool_calling: true,
109 strict_schema: true,
110 parallel_tool_calls: true,
111 streaming_tool_calls: true,
112 prompt_caching: true,
113 structured_output: true,
114 max_context_tokens: 200_000,
115 }
116 }
117
118 #[test]
119 fn a_full_record_satisfies_the_tool_loop_mask() {
120 assert!(full().satisfies(&ProviderCapabilityMask::tool_loop()));
121 }
122
123 #[test]
124 fn text_only_fails_the_tool_loop_mask() {
125 assert!(
126 !ProviderCapabilities::text_only(8192).satisfies(&ProviderCapabilityMask::tool_loop())
127 );
128 }
129
130 #[test]
131 fn context_window_is_a_hard_requirement() {
132 let mask = ProviderCapabilityMask {
133 min_context_tokens: 1_000_000,
134 ..ProviderCapabilityMask::default()
135 };
136 assert!(!full().satisfies(&mask));
137 }
138}