use std::collections::BTreeMap;
use serde::Serialize;
use serde_json::Value;
use crate::completion::{ExtensionOptions, ProviderExtension, ReplyExtras};
use crate::message::Api;
use crate::providers::openai::extension::{AccessPrograms, Envelope, ItemPhase};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ChatGptExt;
impl ProviderExtension for ChatGptExt {
const PROVIDER: &'static str = crate::providers::chatgpt::PROVIDER_NAME;
type Options = ChatGptOptions;
type Extras = ChatGptExtras;
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct ChatGptOptions {
#[serde(rename = "openai.responses")]
pub responses: ChatGptResponses,
}
impl ChatGptOptions {
#[must_use]
pub fn prompt_cache_key(mut self, key: impl Into<String>) -> Self {
self.responses.prompt_cache_key = Some(key.into());
self
}
#[must_use]
pub fn client_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.responses
.client_metadata
.insert(key.into(), value.into());
self
}
#[must_use]
pub fn access_programs(mut self, programs: AccessPrograms) -> Self {
self.responses.access_programs = Some(programs);
self
}
}
impl ExtensionOptions for ChatGptOptions {
type Ext = ChatGptExt;
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct ChatGptResponses {
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt_cache_key: Option<String>,
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
pub client_metadata: BTreeMap<String, String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub access_programs: Option<AccessPrograms>,
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ChatGptExtras {
pub service_tier: Option<String>,
pub reasoning_effort: Option<String>,
pub reasoning_summary: Option<String>,
pub reasoning_mode: Option<String>,
pub reasoning_context: Option<String>,
pub prompt_cache_retention: Option<String>,
pub incomplete_reason: Option<String>,
pub phases: Option<Vec<ItemPhase>>,
}
impl ReplyExtras for ChatGptExtras {
fn from_reply(_api: &Api, raw: &Value) -> Result<Self, serde_json::Error> {
let envelope = Envelope::from_reply(raw)?;
Ok(Self {
service_tier: envelope.service_tier,
reasoning_effort: envelope.reasoning_effort,
reasoning_summary: envelope.reasoning_summary,
reasoning_mode: envelope.reasoning_mode,
reasoning_context: envelope.reasoning_context,
prompt_cache_retention: envelope.prompt_cache_retention,
incomplete_reason: envelope.incomplete_reason,
phases: envelope.phases,
})
}
}
#[cfg(test)]
mod tests;