plainllm 1.2.0

A plain & simple LLM client
Documentation
use super::chat_completion::Tool;
use super::types::{Choice, LLMResponse, Message};
use serde::{Deserialize, Serialize};
use serde_json::Value;

#[derive(Serialize, Debug, Clone)]
pub struct ResponseRequest {
    pub model: String,
    pub input: Value,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub instructions: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub temperature: Option<f32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub top_p: Option<f32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub max_output_tokens: Option<u32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub stream: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tool_choice: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tools: Option<Vec<Tool>>,
}

impl ResponseRequest {
    pub fn new(model: String, input: Value) -> Self {
        Self {
            model,
            input,
            instructions: None,
            temperature: None,
            top_p: None,
            max_output_tokens: None,
            stream: None,
            tool_choice: None,
            tools: None,
        }
    }
}

#[derive(Deserialize, Debug, Clone)]
pub struct ResponseObject {
    pub id: String,
    pub object: String,
    #[serde(rename = "created_at")]
    pub created_at: u64,
    pub model: String,
    pub output: Vec<ResponseOutput>,
}

#[derive(Deserialize, Debug, Clone)]
pub struct ResponseOutput {
    #[serde(rename = "type")]
    pub item_type: String,
    pub role: Option<String>,
    pub content: Option<Vec<ResponseContent>>, // handle text only
}

#[derive(Deserialize, Debug, Clone)]
pub struct ResponseContent {
    #[serde(rename = "type")]
    pub content_type: String,
    pub text: Option<String>,
}

impl From<ResponseObject> for LLMResponse {
    fn from(resp: ResponseObject) -> Self {
        let text = resp
            .output
            .get(0)
            .and_then(|o| o.content.as_ref())
            .and_then(|c| c.get(0))
            .and_then(|c| c.text.clone())
            .unwrap_or_default();
        let msg = Message {
            role: "assistant".to_string(),
            content: Some(text),
            tool_calls: None,
            tool_call_id: None,
        };
        LLMResponse {
            id: resp.id,
            object: resp.object,
            created: resp.created_at,
            model: resp.model,
            choices: vec![Choice {
                index: 0,
                message: Some(msg),
                finish_reason: Some("stop".into()),
            }],
            system_fingerprint: None,
        }
    }
}