awaken-runtime 0.6.0

Phase-based execution engine, plugin system, and agent loop for Awaken
Documentation
use std::sync::Arc;

use async_trait::async_trait;
use awaken_runtime_contract::contract::executor::{
    InferenceExecutionError, InferenceRequest, InferenceStream, LlmExecutor,
};
use awaken_runtime_contract::contract::inference::StreamResult;

use super::PoolExecutor;
use super::pool_observed_stream::PoolObservedStream;

#[async_trait]
impl LlmExecutor for PoolExecutor {
    async fn execute(
        &self,
        request: InferenceRequest,
    ) -> Result<StreamResult, InferenceExecutionError> {
        let inner = &self.inner;
        let session_key = inner.session_key(&request);
        let mut idx = inner.select_active(&session_key);
        let mut tried = vec![false; inner.members.len()];
        loop {
            tried[idx] = true;
            if let Err(err) = inner.check_member(idx) {
                match inner.next_on_unavailable(&session_key, idx, &tried) {
                    Some(next) => {
                        idx = next;
                        continue;
                    }
                    None => return Err(inner.no_member_available_error(err, &tried)),
                }
            }

            let req = inner.request_for(idx, &request);
            match inner.members[idx].executor.execute(req).await {
                Ok(result) => {
                    inner.breaker.record_success(&inner.members[idx].model_id);
                    inner.reset_switch_budget(&session_key);
                    return Ok(result);
                }
                Err(err) => {
                    inner.record_failure(idx, &err);
                    match inner.next_on_error(&session_key, idx, &err, &tried) {
                        Some(next) => idx = next,
                        None if inner.router.should_switch_on_error(&err) => {
                            return Err(inner.error_driven_no_member_available_error(err, &tried));
                        }
                        None => return Err(err),
                    }
                }
            }
        }
    }

    fn execute_stream(
        &self,
        request: InferenceRequest,
    ) -> std::pin::Pin<
        Box<
            dyn std::future::Future<Output = Result<InferenceStream, InferenceExecutionError>>
                + Send
                + '_,
        >,
    > {
        Box::pin(async move {
            let inner = Arc::clone(&self.inner);
            let session_key = inner.session_key(&request);
            let attempt_key = inner.stream_attempt_key(&session_key, &request);
            let mut idx = inner.select_active(&session_key);
            let mut tried = inner.stream_tried_mask(attempt_key.as_deref());
            loop {
                tried[idx] = true;
                if let Err(err) = inner.check_member(idx) {
                    match inner.next_on_unavailable(&session_key, idx, &tried) {
                        Some(next) => {
                            idx = next;
                            continue;
                        }
                        None => return Err(inner.no_member_available_error(err, &tried)),
                    }
                }

                let req = inner.request_for(idx, &request);
                match inner.members[idx].executor.execute_stream(req).await {
                    Ok(stream) => {
                        let attempt_key = inner
                            .mark_stream_active(attempt_key.as_deref(), idx)
                            .then_some(attempt_key)
                            .flatten();
                        let observed = PoolObservedStream::new(
                            stream,
                            Arc::clone(&inner),
                            session_key,
                            attempt_key,
                            idx,
                        );
                        return Ok(Box::pin(observed) as InferenceStream);
                    }
                    Err(err) => {
                        inner.record_failure(idx, &err);
                        inner.mark_stream_open_failure(attempt_key.as_deref(), idx);
                        match inner.next_on_error(&session_key, idx, &err, &tried) {
                            Some(next) => {
                                idx = next;
                                if attempt_key.is_some() {
                                    inner.merge_stream_tried_mask(
                                        &mut tried,
                                        attempt_key.as_deref(),
                                    );
                                }
                            }
                            None if inner.router.should_switch_on_error(&err) => {
                                return Err(
                                    inner.error_driven_no_member_available_error(err, &tried)
                                );
                            }
                            None => return Err(err),
                        }
                    }
                }
            }
        })
    }

    fn name(&self) -> &str {
        &self.inner.pool_id
    }

    fn supports_upstream_model_override(&self) -> bool {
        false
    }

    fn record_stream_success(&self, _request: &InferenceRequest) {
        // Request-scoped success callbacks do not carry the immutable stream
        // identity needed to distinguish an old stream from the current
        // recovery stream for the same logical request. PoolObservedStream
        // records drain success with its captured member index, so ignore this
        // ambiguous duplicate path.
    }

    fn record_stream_failure(&self, request: &InferenceRequest, err: &InferenceExecutionError) {
        self.inner.record_stream_member_failure(request, err);
    }
}