artificial_core/provider/prompt_execute.rs
1use std::{future::Future, pin::Pin};
2
3use crate::{
4 error::Result,
5 generic::GenericChatCompletionResponse,
6 template::{IntoPrompt, PromptTemplate},
7};
8
9/// A **backend** turns a prompt into a network call to a concrete provider
10/// (OpenAI, Ollama, Anthropic, …) and parses the structured response.
11///
12/// The trait is intentionally minimal:
13///
14/// * **One associated type** – the in-memory `Message` representation this
15/// provider accepts.
16/// * **One async-ish method** – `complete`, which performs a *single*
17/// non-streaming round-trip and returns a value whose type is dictated by
18/// the `PromptTemplate`.
19///
20/// The method returns a [`Pin<Box<dyn Future>>`] so we stay object-safe
21/// without pulling in `async_trait`.
22pub trait PromptExecutionProvider: Send + Sync {
23 /// Chat message type consumed by this backend.
24 ///
25 /// A simple setup can re-use `crate::generic::GenericMessage`.
26 /// Providers with richer wire formats (function calls, images …) can
27 /// supply their own struct.
28 type Message: Send + Sync + 'static;
29
30 /// Execute the prompt and deserialize the provider’s reply into
31 /// `P::Output`.
32 ///
33 /// The blanket constraint `P: PromptTemplate<Message = Self::Message>`
34 /// guarantees at **compile time** that callers only feed the backend
35 /// messages it understands.
36 fn prompt_execute<'a, 'p, P>(&'a self, prompt: P) -> BoxedResponseFut<'p, P::Output>
37 where
38 'a: 'p,
39 P: PromptTemplate + Send + Sync + 'p,
40 <P as IntoPrompt>::Message: Into<Self::Message>;
41}
42
43pub type BoxedResponseFut<'p, Output> =
44 Pin<Box<dyn Future<Output = Result<GenericChatCompletionResponse<Output>>> + Send + 'p>>;