codetether_agent/provider/
anthropic.rs1use super::{
4 CompletionRequest, CompletionResponse, ModelInfo, Provider, StreamChunk,
5};
6use anyhow::Result;
7use async_trait::async_trait;
8
9pub struct AnthropicProvider {
10 api_key: String,
11}
12
13impl std::fmt::Debug for AnthropicProvider {
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 f.debug_struct("AnthropicProvider")
16 .field("api_key", &"<REDACTED>")
17 .field("api_key_len", &self.api_key.len())
18 .finish()
19 }
20}
21
22impl AnthropicProvider {
23 pub fn new(api_key: String) -> Result<Self> {
24 tracing::debug!(
25 provider = "anthropic",
26 api_key_len = api_key.len(),
27 "Creating Anthropic provider"
28 );
29 Ok(Self { api_key })
30 }
31
32 fn validate_api_key(&self) -> Result<()> {
34 if self.api_key.is_empty() {
35 anyhow::bail!("Anthropic API key is empty");
36 }
37 if self.api_key.len() < 10 {
38 tracing::warn!(provider = "anthropic", "API key seems unusually short");
39 }
40 Ok(())
41 }
42}
43
44#[async_trait]
45impl Provider for AnthropicProvider {
46 fn name(&self) -> &str {
47 "anthropic"
48 }
49
50 async fn list_models(&self) -> Result<Vec<ModelInfo>> {
51 tracing::debug!(provider = "anthropic", "Listing available models");
52 self.validate_api_key()?;
53
54 Ok(vec![
55 ModelInfo {
56 id: "claude-sonnet-4-20250514".to_string(),
57 name: "Claude Sonnet 4".to_string(),
58 provider: "anthropic".to_string(),
59 context_window: 200_000,
60 max_output_tokens: Some(64_000),
61 supports_vision: true,
62 supports_tools: true,
63 supports_streaming: true,
64 input_cost_per_million: Some(3.0),
65 output_cost_per_million: Some(15.0),
66 },
67 ModelInfo {
68 id: "claude-opus-4-20250514".to_string(),
69 name: "Claude Opus 4".to_string(),
70 provider: "anthropic".to_string(),
71 context_window: 200_000,
72 max_output_tokens: Some(32_000),
73 supports_vision: true,
74 supports_tools: true,
75 supports_streaming: true,
76 input_cost_per_million: Some(15.0),
77 output_cost_per_million: Some(75.0),
78 },
79 ])
80 }
81
82 async fn complete(&self, request: CompletionRequest) -> Result<CompletionResponse> {
83 tracing::debug!(
84 provider = "anthropic",
85 model = %request.model,
86 message_count = request.messages.len(),
87 tool_count = request.tools.len(),
88 "Starting completion request"
89 );
90
91 self.validate_api_key()?;
93
94 anyhow::bail!("Anthropic provider not yet implemented")
96 }
97
98 async fn complete_stream(
99 &self,
100 request: CompletionRequest,
101 ) -> Result<futures::stream::BoxStream<'static, StreamChunk>> {
102 tracing::debug!(
103 provider = "anthropic",
104 model = %request.model,
105 message_count = request.messages.len(),
106 "Starting streaming completion request"
107 );
108
109 self.validate_api_key()?;
110 anyhow::bail!("Anthropic provider not yet implemented")
111 }
112}