Skip to main content

openai_api_dispatch/executor/
mod.rs

1use alloc::{string::String, sync::Arc};
2
3use crate::task::{Response, Task};
4
5// TODO add a reqwless no_std client implementation
6
7#[cfg(feature = "std")]
8/// Non-streaming Chat Completions execution through `async-openai`.
9pub mod openai;
10
11/// Executes tasks independently of their transport.
12///
13/// An unsuccessful [`Response`] is distinct from an execution error. Returned
14/// futures do not promise `Send`, and the trait is not dyn-compatible.
15pub trait Executor {
16    /// Returns the fallback model used when a task does not specify one.
17    fn default_model(&self) -> &Arc<Option<String>>;
18
19    /// Executes one task; `Err` indicates execution failed before a response.
20    fn execute(&self, task: Task) -> impl Future<Output = anyhow::Result<Response>>;
21}
22
23#[derive(Debug, Clone)]
24/// A network-free executor for tests.
25///
26/// Returns the task ID as text and reports 100 tokens. Defaults to success and
27/// model `dummy`; a task's explicit model takes precedence. Failure mode returns
28/// `Ok(Response { success: false, .. })`, not an execution error.
29pub struct DummyExecutor {
30    success: bool,
31    default_model: String,
32    arc_default_model: Arc<Option<String>>,
33}
34
35impl Default for DummyExecutor {
36    fn default() -> Self {
37        let success = true;
38        let default_model = String::from("dummy");
39        let arc_default_model = Arc::new(Some(default_model.clone()));
40
41        Self {
42            success,
43            default_model,
44            arc_default_model,
45        }
46    }
47}
48
49impl DummyExecutor {
50    /// Makes subsequent responses successful (the default).
51    pub fn set_success(&mut self) {
52        self.success = true;
53    }
54
55    /// Makes subsequent responses unsuccessful without returning `Err`.
56    pub fn set_fail(&mut self) {
57        self.success = false;
58    }
59}
60
61impl Executor for DummyExecutor {
62    fn default_model(&self) -> &Arc<Option<String>> {
63        &self.arc_default_model
64    }
65
66    async fn execute(&self, task: Task) -> anyhow::Result<Response> {
67        let tokens = 100;
68        let contents = alloc::format!("{}", task.id);
69        let model = task
70            .model
71            .as_ref()
72            .cloned()
73            .unwrap_or_else(|| self.default_model.clone());
74
75        let response = if self.success {
76            Response::success(task, tokens, model, contents)
77        } else {
78            Response::error(task, tokens, model, contents)
79        };
80
81        Ok(response)
82    }
83}