Skip to main content

openrouter_rs/api/
generation.rs

1use std::collections::HashMap;
2
3use reqwest::Client as HttpClient;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7use crate::{
8    error::OpenRouterError,
9    transport::{request as transport_request, response as transport_response},
10    types::ApiResponse,
11};
12
13#[derive(Serialize, Deserialize, Debug)]
14#[non_exhaustive]
15pub struct GenerationData {
16    pub id: String,
17    pub total_cost: f64,
18    pub created_at: String,
19    #[serde(default, skip_serializing_if = "Option::is_none")]
20    pub data_region: Option<String>,
21    pub model: String,
22    pub origin: String,
23    pub usage: f64,
24    pub is_byok: bool,
25    pub upstream_id: Option<String>,
26    pub cache_discount: Option<f64>,
27    pub app_id: Option<u32>,
28    pub streamed: Option<bool>,
29    pub cancelled: Option<bool>,
30    pub provider_name: Option<String>,
31    pub latency: Option<f64>,
32    pub moderation_latency: Option<u32>,
33    pub generation_time: Option<u32>,
34    pub finish_reason: Option<String>,
35    pub native_finish_reason: Option<String>,
36    pub tokens_prompt: Option<u32>,
37    pub tokens_completion: Option<u32>,
38    pub native_tokens_prompt: Option<u32>,
39    pub native_tokens_completion: Option<u32>,
40    pub native_tokens_reasoning: Option<u32>,
41    pub num_fetches: Option<u32>,
42    pub num_media_prompt: Option<u32>,
43    pub num_media_completion: Option<u32>,
44    pub num_search_results: Option<u32>,
45    pub preset_id: Option<String>,
46    pub response_cache_source_id: Option<String>,
47    pub service_tier: Option<String>,
48    #[serde(default, skip_serializing_if = "Option::is_none")]
49    pub status: Option<i32>,
50}
51
52/// Stored prompt/input and completion/output content returned by `GET /generation/content`.
53#[derive(Serialize, Deserialize, Debug, Clone)]
54#[non_exhaustive]
55pub struct GenerationContentData {
56    #[serde(default)]
57    pub input: HashMap<String, Value>,
58    #[serde(default)]
59    pub output: HashMap<String, Value>,
60}
61
62/// Returns metadata about a specific generation request
63///
64/// # Arguments
65///
66/// * `base_url` - The base URL of the OpenRouter API.
67/// * `api_key` - The API key for authentication
68/// * `id` - The ID of the generation request
69///
70/// # Returns
71///
72/// * `Result<GenerationData, OpenRouterError>` - The metadata of the generation request or an error
73pub async fn get_generation(
74    base_url: &str,
75    api_key: &str,
76    id: impl Into<String>,
77) -> Result<GenerationData, OpenRouterError> {
78    let http_client = crate::transport::new_client()?;
79    get_generation_with_client(&http_client, base_url, api_key, id).await
80}
81
82pub(crate) async fn get_generation_with_client(
83    http_client: &HttpClient,
84    base_url: &str,
85    api_key: &str,
86    id: impl Into<String>,
87) -> Result<GenerationData, OpenRouterError> {
88    let id = id.into();
89    let url = format!("{base_url}/generation?id={id}");
90
91    let response =
92        transport_request::with_bearer_auth(transport_request::get(http_client, &url), api_key)
93            .send()
94            .await?;
95
96    if response.status().is_success() {
97        let generation_response: ApiResponse<_> =
98            transport_response::parse_json_response(response, "generation").await?;
99        Ok(generation_response.data)
100    } else {
101        transport_response::handle_error(response).await?;
102        unreachable!()
103    }
104}
105
106/// Returns the stored prompt/input and completion/output content for a specific generation.
107pub async fn get_generation_content(
108    base_url: &str,
109    api_key: &str,
110    id: impl Into<String>,
111) -> Result<GenerationContentData, OpenRouterError> {
112    let http_client = crate::transport::new_client()?;
113    get_generation_content_with_client(&http_client, base_url, api_key, id).await
114}
115
116pub(crate) async fn get_generation_content_with_client(
117    http_client: &HttpClient,
118    base_url: &str,
119    api_key: &str,
120    id: impl Into<String>,
121) -> Result<GenerationContentData, OpenRouterError> {
122    let id = id.into();
123    let url = format!("{base_url}/generation/content?id={id}");
124
125    let response =
126        transport_request::with_bearer_auth(transport_request::get(http_client, &url), api_key)
127            .send()
128            .await?;
129
130    if response.status().is_success() {
131        let generation_response: ApiResponse<_> =
132            transport_response::parse_json_response(response, "generation content").await?;
133        Ok(generation_response.data)
134    } else {
135        transport_response::handle_error(response).await?;
136        unreachable!()
137    }
138}