Skip to main content

typesafe/
blocking.rs

1//! Synchronous client (feature `blocking`). Each client owns a private current-thread Tokio
2//! runtime; do not call it from inside an async context.
3
4use std::time::Duration;
5
6use http::header::{HeaderName, HeaderValue};
7use serde::Serialize;
8use serde_json::Value;
9
10use crate::error::{Error, Result};
11use crate::question::Questions;
12use crate::response::{ListModelsResponse, SystemOneResponse};
13use crate::retry::RetryPolicy;
14use crate::rubric::Rubric;
15
16/// Blocking TypeSafe client.
17#[derive(Debug)]
18pub struct Client {
19    inner: crate::Client,
20    rt: tokio::runtime::Runtime,
21}
22
23impl Client {
24    /// Wrap an async client configured via [`crate::Client::builder`].
25    pub fn new(inner: crate::Client) -> Result<Self> {
26        let rt = tokio::runtime::Builder::new_current_thread()
27            .enable_all()
28            .build()
29            .map_err(|e| Error::Config(format!("could not start runtime: {e}")))?;
30        Ok(Self { inner, rt })
31    }
32
33    /// A client configured entirely from the environment.
34    pub fn from_env() -> Result<Self> {
35        Self::new(crate::Client::from_env()?)
36    }
37
38    /// See [`crate::Client::system_one`].
39    pub fn system_one<S: Serialize>(
40        &self,
41        state: S,
42        questions: impl Into<Questions>,
43    ) -> SystemOneRequest<'_> {
44        SystemOneRequest {
45            rt: &self.rt,
46            req: self.inner.system_one(state, questions),
47        }
48    }
49
50    /// See [`crate::Client::ask`].
51    pub fn ask<R: Rubric>(&self, state: impl Serialize) -> AskRequest<'_, R> {
52        AskRequest {
53            rt: &self.rt,
54            req: self.inner.ask(state),
55        }
56    }
57
58    /// `GET /v1/models`.
59    pub fn list_models(&self) -> ListModelsRequest<'_> {
60        ListModelsRequest {
61            rt: &self.rt,
62            req: self.inner.models().list(),
63        }
64    }
65}
66
67macro_rules! forward {
68    ($($name:ident($($arg:ident: $ty:ty),*)),* $(,)?) => {$(
69        #[doc = concat!("See the async request's `", stringify!($name), "`.")]
70        pub fn $name(mut self, $($arg: $ty),*) -> Self {
71            self.req = self.req.$name($($arg),*);
72            self
73        }
74    )*};
75}
76
77/// Blocking `POST /v1/systemone`.
78#[must_use = "call .send()"]
79#[derive(Debug)]
80pub struct SystemOneRequest<'a> {
81    rt: &'a tokio::runtime::Runtime,
82    req: crate::SystemOneRequest,
83}
84
85impl SystemOneRequest<'_> {
86    forward!(
87        retry(policy: RetryPolicy),
88        timeout(timeout: Duration),
89        header(name: HeaderName, value: HeaderValue),
90    );
91
92    /// Override the model for this call.
93    pub fn model(mut self, model: impl Into<String>) -> Self {
94        self.req = self.req.model(model);
95        self
96    }
97
98    /// Add a top-level body field.
99    pub fn extra_body(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
100        self.req = self.req.extra_body(key, value);
101        self
102    }
103
104    /// Send and wait.
105    pub fn send(self) -> Result<SystemOneResponse> {
106        self.rt.block_on(self.req.send())
107    }
108}
109
110/// Blocking [`crate::Client::ask`].
111#[must_use = "call .send()"]
112#[derive(Debug)]
113pub struct AskRequest<'a, R> {
114    rt: &'a tokio::runtime::Runtime,
115    req: crate::AskRequest<R>,
116}
117
118impl<R: Rubric> AskRequest<'_, R> {
119    forward!(
120        retry(policy: RetryPolicy),
121        timeout(timeout: Duration),
122        header(name: HeaderName, value: HeaderValue),
123    );
124
125    /// Override the model for this call.
126    pub fn model(mut self, model: impl Into<String>) -> Self {
127        self.req = self.req.model(model);
128        self
129    }
130
131    /// Add a top-level body field.
132    pub fn extra_body(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
133        self.req = self.req.extra_body(key, value);
134        self
135    }
136
137    /// Send, wait, and decode the answers.
138    pub fn send(self) -> Result<R> {
139        self.rt.block_on(self.req.send())
140    }
141}
142
143/// Blocking `GET /v1/models`.
144#[must_use = "call .send()"]
145#[derive(Debug)]
146pub struct ListModelsRequest<'a> {
147    rt: &'a tokio::runtime::Runtime,
148    req: crate::ListModelsRequest,
149}
150
151impl ListModelsRequest<'_> {
152    forward!(
153        retry(policy: RetryPolicy),
154        timeout(timeout: Duration),
155        header(name: HeaderName, value: HeaderValue),
156    );
157
158    /// Send and wait.
159    pub fn send(self) -> Result<ListModelsResponse> {
160        self.rt.block_on(self.req.send())
161    }
162}