1use anthropic::ANTHROPIC_API_URL;
2use anyhow::{Context as _, anyhow};
3use client::telemetry::Telemetry;
4use gpui::BackgroundExecutor;
5use http_client::{AsyncBody, HttpClient, Method, Request as HttpRequest};
6use std::env;
7use std::sync::Arc;
8use telemetry_events::{AssistantEventData, AssistantKind, AssistantPhase};
9use util::ResultExt;
10
11pub const ANTHROPIC_PROVIDER_ID: &str = "anthropic";
12
13pub fn report_assistant_event(
14 event: AssistantEventData,
15 telemetry: Option<Arc<Telemetry>>,
16 client: Arc<dyn HttpClient>,
17 model_api_key: Option<String>,
18 executor: &BackgroundExecutor,
19) {
20 if let Some(telemetry) = telemetry.as_ref() {
21 telemetry.report_assistant_event(event.clone());
22 if telemetry.metrics_enabled() && event.model_provider == ANTHROPIC_PROVIDER_ID {
23 if let Some(api_key) = model_api_key {
24 executor
25 .spawn(async move {
26 report_anthropic_event(event, client, api_key)
27 .await
28 .log_err();
29 })
30 .detach();
31 } else {
32 log::error!("Cannot send Anthropic telemetry because API key is missing");
33 }
34 }
35 }
36}
37
38async fn report_anthropic_event(
39 event: AssistantEventData,
40 client: Arc<dyn HttpClient>,
41 api_key: String,
42) -> anyhow::Result<()> {
43 let uri = format!("{ANTHROPIC_API_URL}/v1/log/zed");
44 let request_builder = HttpRequest::builder()
45 .method(Method::POST)
46 .uri(uri)
47 .header("X-Api-Key", api_key)
48 .header("Content-Type", "application/json");
49 let serialized_event: serde_json::Value = serde_json::json!({
50 "completion_type": match event.kind {
51 AssistantKind::Inline => "natural_language_completion_in_editor",
52 AssistantKind::InlineTerminal => "natural_language_completion_in_terminal",
53 AssistantKind::Panel => "conversation_message",
54 },
55 "event": match event.phase {
56 AssistantPhase::Response => "response",
57 AssistantPhase::Invoked => "invoke",
58 AssistantPhase::Accepted => "accept",
59 AssistantPhase::Rejected => "reject",
60 },
61 "metadata": {
62 "language_name": event.language_name,
63 "message_id": event.message_id,
64 "platform": env::consts::OS,
65 }
66 });
67
68 let request = request_builder
69 .body(AsyncBody::from(serialized_event.to_string()))
70 .context("Failed to construct Anthropic telemetry HTTP request body")?;
71
72 let response = client
73 .send(request)
74 .await
75 .context("Failed to send telemetry HTTP request to Anthropic")?;
76
77 if response.status().is_success() {
78 Ok(())
79 } else {
80 Err(anyhow!(
81 "Anthropic telemetry logging failed with HTTP status: {}",
82 response.status()
83 ))
84 }
85}