chatgpt/functions/
types.rs

1use crate::functions::{CallableAsyncFunction, FunctionArgument};
2use async_trait::async_trait;
3use schemars::schema_for;
4use serde::ser::SerializeStruct;
5use serde::{Deserialize, Serialize, Serializer};
6use serde_json::Value;
7use std::marker::PhantomData;
8
9/// A descriptor containing information about a ChatGPT function
10#[derive(Debug, Clone)]
11pub struct FunctionDescriptor<A: FunctionArgument> {
12    /// Contains the name of the function, by which it will be called, e.g. `my_function`
13    pub name: &'static str,
14    /// Describes what this function does. Description should clearly state what this function does so ChatGPT understands when to call it.
15    pub description: &'static str,
16    /// Phantom data used for referencing the type of parameter object.
17    pub parameters: PhantomData<A>,
18}
19
20impl<A: FunctionArgument> Serialize for FunctionDescriptor<A> {
21    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
22    where
23        S: Serializer,
24    {
25        let mut s = serializer.serialize_struct("FunctionDescriptor", 3)?;
26        s.serialize_field("name", self.name)?;
27        s.serialize_field("description", self.description)?;
28        let mut schema = schema_for!(A);
29        schema.meta_schema = None; // I don't think ChatGPT will need $schema meta information
30        s.serialize_field("parameters", &schema)?;
31
32        s.end()
33    }
34}
35
36/// Trait that indicates a callable GPT Function. Should not be implemented directly, see [GptFunction] instead.
37#[async_trait]
38pub trait GptFunctionHolder: Send + Sync {
39    /// Attempts to invoke this function and returns the result.
40    async fn try_invoke(&self, args: &str) -> crate::Result<serde_json::Value>;
41}
42
43/// This struct represents a ChatGPT function.
44#[derive(Debug, Clone)]
45pub struct GptFunction<A: FunctionArgument, C: CallableAsyncFunction<A>>
46where
47    A: Send + Sync,
48    C: Send + Sync,
49{
50    /// Descriptor for this function. See [FunctionDescriptor] fields for details
51    pub descriptor: FunctionDescriptor<A>,
52    /// Phantom data used for referencing the handler for this function. See [CallableAsyncFunction] for details.
53    pub callable: PhantomData<C>,
54}
55
56#[async_trait]
57impl<A: FunctionArgument + Send + Sync, C: CallableAsyncFunction<A> + Send + Sync> GptFunctionHolder
58    for GptFunction<A, C>
59{
60    async fn try_invoke(&self, args: &str) -> crate::Result<Value> {
61        let args_value: A = serde_json::from_str(args).map_err(crate::err::Error::from)?;
62        C::invoke(args_value).await
63    }
64}
65
66/// Determines how ChatGPT will be calling the functions.
67#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Serialize)]
68pub enum FunctionCallingMode {
69    /// ChatGPT automatically determines if it should call a function
70    Auto,
71    /// ChatGPT does not call any functions
72    None,
73}
74
75/// Determines how this client will validate function calls.
76#[derive(Serialize, Debug, Copy, Clone, Default, PartialOrd, PartialEq)]
77pub enum FunctionValidationStrategy {
78    /// Whenever ChatGPT attempts to call an undefined function, or calls a functions with wrong parameters, sends a `System` message correcting it.
79    Strict,
80    /// Whenever ChatGPT attempts to call an undefined function, or calls a functions with wrong parameters, ignores the function call. This is default behaviour
81    #[default]
82    Loose,
83}
84
85/// Represents a function call attempted by ChatGPT API
86#[derive(Debug, Clone, PartialOrd, PartialEq, Serialize, Deserialize)]
87pub struct FunctionCall {
88    /// Name of the function attempted to call
89    pub name: String,
90    /// Arguments used to call this function, represented by a stringified JSON Object
91    pub arguments: String,
92}