mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-30 06:43:27 +00:00
* refactor(rust): extract litellm-host-native as the shared Rust host driver Move service and hook dispatch out of host-http into a Driver that owns the machine and Rust handlers, returning at completion or a stream boundary and holding the demand reply until the consumer advances. Move the in-process runner onto the same driver. host-http now layers encoding, SSE, body polling and lifecycle observation over it. host-python keeps driving litellm-host directly Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(rust): interrupt the machine when the in-process stream consumer fails Restores the pre-refactor interruption path for StreamConsumer errors via Driver::fail and ports the generic run lifecycle tests into host-native. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * refactor(rust): separate the machine contract from coroutine execution * auth update * refactor(rust): use standard flow control for host requests * style(rust): keep host driver imports formatted * chores * mostly relocation * refactor(rust): separate interceptors from queued observers * refactor(rust): centralize legacy callback mappings and lifecycle * docs: define Python host boundaries and migration plan * refactor: enforce Python host and bridge boundaries * refactor(rust): separate operations from callback composition * refactor(rust): compose SDK policy through call hooks --------- Co-authored-by: Yujong Lee <yujong@berri.ai> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
77 lines
2.2 KiB
Rust
77 lines
2.2 KiB
Rust
use crate::observation::ObservationSender;
|
|
use std::future::Future;
|
|
|
|
use futures_util::{TryStreamExt, stream::BoxStream};
|
|
|
|
use crate::{
|
|
machine::{CallMachine, ChannelInterceptors, HostServices, MachineFault},
|
|
protocol::Protocol,
|
|
};
|
|
|
|
pub enum CallOutput<Response, Head, Chunk, Error> {
|
|
Complete(Response),
|
|
Stream {
|
|
head: Head,
|
|
chunks: BoxStream<'static, Result<Chunk, Error>>,
|
|
},
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
pub enum HostedCompletion<Response> {
|
|
Complete(Response),
|
|
StreamEnded,
|
|
Detached,
|
|
}
|
|
|
|
impl<Response> From<Response> for HostedCompletion<Response> {
|
|
fn from(response: Response) -> Self {
|
|
Self::Complete(response)
|
|
}
|
|
}
|
|
|
|
pub type OutputOf<P> = CallOutput<
|
|
<P as Protocol>::Response,
|
|
<P as Protocol>::StreamHead,
|
|
<P as Protocol>::Chunk,
|
|
<P as Protocol>::Error,
|
|
>;
|
|
|
|
pub type HostedMachine<P> = CallMachine<P, HostedCompletion<<P as Protocol>::Response>>;
|
|
|
|
pub fn hosted_call<P, F, Fut>(
|
|
request: P::Request,
|
|
observers: Option<ObservationSender>,
|
|
execute: F,
|
|
) -> HostedMachine<P>
|
|
where
|
|
P: Protocol,
|
|
P::Error: From<MachineFault>,
|
|
F: FnOnce(
|
|
P::Request,
|
|
HostServices<P>,
|
|
ChannelInterceptors<P>,
|
|
Option<ObservationSender>,
|
|
) -> Fut
|
|
+ Send
|
|
+ 'static,
|
|
Fut: Future<Output = Result<OutputOf<P>, P::Error>> + Send + 'static,
|
|
{
|
|
CallMachine::new(observers, move |host| {
|
|
Box::pin(async move {
|
|
match execute(request, host.services, host.interceptors, host.observers).await? {
|
|
CallOutput::Complete(response) => Ok(HostedCompletion::Complete(response)),
|
|
CallOutput::Stream { head, mut chunks } => {
|
|
if host.stream.open_stream(head).await?.is_break() {
|
|
return Ok(HostedCompletion::Detached);
|
|
}
|
|
while let Some(chunk) = chunks.try_next().await? {
|
|
if host.stream.send_chunk(chunk).await?.is_break() {
|
|
return Ok(HostedCompletion::Detached);
|
|
}
|
|
}
|
|
Ok(HostedCompletion::StreamEnded)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|