use std::future::Future;
use super::GenerationIdentity;
use crate::{
transform::{Report, TransformError},
wire::{
DeclaredFields,
claude::generate_content as c,
gemini as g,
openai::{chat as h, responses as r},
},
};
pub(crate) trait RequestMode: DeclaredFields + Clone {
fn set_buffered(&mut self);
fn set_streaming(&mut self);
fn buffered(mut self) -> Self {
self.set_buffered();
self
}
fn streaming(mut self) -> Self {
self.set_streaming();
self
}
fn emit_usage(&self) -> bool {
true
}
}
impl RequestMode for h::GenerateContentRequestBody {
fn set_buffered(&mut self) {
self.stream = Some(Some(false));
}
fn set_streaming(&mut self) {
self.stream = Some(Some(true));
let mut options = self
.stream_options
.take()
.flatten()
.unwrap_or_else(|| h::StreamOptions::builder().build())
.into_declared();
options.include_usage = Some(true);
self.stream_options = Some(Some(options));
}
fn emit_usage(&self) -> bool {
if self.stream.flatten() != Some(true) {
return true;
}
self.stream_options
.as_ref()
.and_then(Option::as_ref)
.and_then(|v| v.include_usage)
== Some(true)
}
}
impl RequestMode for c::GenerateContentRequestBody {
fn set_buffered(&mut self) {
self.stream = Some(false);
}
fn set_streaming(&mut self) {
self.stream = Some(true);
}
}
impl RequestMode for r::GenerateContentRequestBody {
fn set_buffered(&mut self) {
self.stream = Some(Some(false));
}
fn set_streaming(&mut self) {
self.stream = Some(Some(true));
}
}
impl RequestMode for g::GenerateContentRequestBody {
fn set_buffered(&mut self) {}
fn set_streaming(&mut self) {}
}
pub(crate) trait PreparedGeneration: Sized {
type Source: RequestMode;
type Target: RequestMode;
fn target_request(&self) -> &Self::Target;
fn identities(&self) -> &GenerationIdentity;
fn report(&self) -> &Report;
fn requests_mut(&mut self) -> (&mut Self::Source, &mut Self::Target);
}
macro_rules! prepared_generation {
($pair:ty, $source:ty => $target:ty) => {
impl super::prepared::PreparedGeneration for $pair {
type Source = $source;
type Target = $target;
fn target_request(&self) -> &$target {
&self.target_request
}
fn identities(&self) -> &super::GenerationIdentity {
&self.identities
}
fn report(&self) -> &crate::transform::Report {
&self.report
}
fn requests_mut(&mut self) -> (&mut $source, &mut $target) {
(&mut self.original_request, &mut self.target_request)
}
}
};
}
pub(crate) use prepared_generation;
pub(crate) async fn for_stream_synthesis<P, F, Fut>(
input: P::Source,
prepare: F,
) -> Result<P, TransformError>
where
P: PreparedGeneration,
F: FnOnce(P::Source) -> Fut,
Fut: Future<Output = Result<P, TransformError>>,
{
let original = input.into_declared();
let mut prepared = prepare(original.clone().buffered()).await?;
let (source, target) = prepared.requests_mut();
*source = original;
target.set_buffered();
Ok(prepared)
}
macro_rules! stream_synthesis {
($pair:ty, $source:ty $(, $extra:ident: $extra_ty:ty)* $(,)?) => {
impl $pair {
pub async fn prepare_for_stream_synthesis<S: crate::capability::StateStore>(
input: $source,
endpoint: super::Endpoint,
identities: super::GenerationIdentity,
state: &super::GenerationStateAccess<'_, S>,
$($extra: $extra_ty,)*
) -> Result<Self, crate::transform::TransformError> {
super::prepared::for_stream_synthesis(input, |buffered| {
Self::prepare_with_state(buffered, endpoint, identities, state $(, $extra)*)
})
.await
}
pub async fn prepare_for_stream_synthesis_with_capabilities<
S: crate::capability::StateStore,
R: crate::capability::ResourceAccess,
>(
input: $source,
endpoint: super::Endpoint,
identities: super::GenerationIdentity,
state: &super::GenerationStateAccess<'_, S>,
resources: &super::GenerationResources<'_, R>,
$($extra: $extra_ty,)*
) -> Result<Self, crate::transform::TransformError> {
super::prepared::for_stream_synthesis(input, |buffered| {
Self::prepare_with_capabilities(
buffered, endpoint, identities, state, resources $(, $extra)*
)
})
.await
}
}
};
}
pub(crate) use stream_synthesis;