claude-flows 0.2.1

Claude integration for flows.network
Documentation
//! Claude integration for [Flows.network](https://flows.network)
//!
//! # Quick Start
//!
//! To get started, let's write a tiny flow function.
//!
//! ```rust
//! use claude_flows::{
//!     chat,
//!     ClaudeFlows,
//! };
//! use lambda_flows::{request_received, send_response};
//! use serde_json::Value;
//! use std::collections::HashMap;
//!
//! #[no_mangle]
//! #[tokio::main(flavor = "current_thread")]
//! pub async fn run() {
//!     request_received(handler).await;
//! }
//!
//! async fn handler(_qry: HashMap<String, Value>, body: Vec<u8>) {
//!     let cf = ClaudeFlows::new();
//!     let co = chat::ChatOptions::default();
//!
//!     let r = match cf.chat_completion(
//!         "any_conversation_id",
//!         String::from_utf8_lossy(&body).into_owned().as_str(),
//!         &co,
//!     )
//!     .await
//!     {
//!         Ok(c) => c,
//!         Err(e) => e,
//!     };
//!     
//!     send_response(
//!         200,
//!         vec![(
//!             String::from("content-type"),
//!             String::from("text/plain; charset=UTF-8"),
//!         )],
//!         r.as_bytes().to_vec(),
//!     );
//! }
//! ```
//!
//! When the Lambda request is received, chat
//! using [chat_completion] then send the response.

use lazy_static::lazy_static;
use std::thread::sleep;
use std::time::Duration;

pub mod chat;

lazy_static! {
    static ref CLAUDE_API_PREFIX: String = String::from(
        std::option_env!("CLAUDE_API_PREFIX").unwrap_or("https://claude.flows.network/api")
    );
}

extern "C" {
    fn get_flows_user(p: *mut u8) -> i32;
    fn get_flow_id(p: *mut u8) -> i32;
}

unsafe fn _get_flows_user() -> String {
    let mut flows_user = Vec::<u8>::with_capacity(100);
    let c = get_flows_user(flows_user.as_mut_ptr());
    flows_user.set_len(c as usize);
    String::from_utf8(flows_user).unwrap()
}

unsafe fn _get_flow_id() -> String {
    let mut flow_id = Vec::<u8>::with_capacity(100);
    let c = get_flow_id(flow_id.as_mut_ptr());
    if c == 0 {
        panic!("Failed to get flow id");
    }
    flow_id.set_len(c as usize);
    String::from_utf8(flow_id).unwrap()
}

const MAX_RETRY_TIMES: u8 = 10;
const RETRY_INTERVAL: u64 = 10; // Wait 10 seconds before retry

/// The account name you provide to
/// [Flows.network](https://flows.network) platform,
/// which is tied to your Claude API key.
///
/// If set as `Default`, the 'Default' named account will be used.
/// If there is no 'Default' named account,
/// a random one will be selected from all your connected accounts.
///
pub enum FlowsAccount {
    Default,
    Provided(String),
}

/// The main struct for setting the basic configuration
/// for Claude interface.
pub struct ClaudeFlows {
    /// `account` is a [FlowsAccount] used to select your tied Claude API key.
    account: FlowsAccount,

    /// Use retry_times to set the number of retries when requesting
    /// Claude's api encounters a problem. Default is 0 and max number is 10.
    retry_times: u8,
}

impl ClaudeFlows {
    pub fn new() -> ClaudeFlows {
        ClaudeFlows {
            account: FlowsAccount::Default,
            retry_times: 0,
        }
    }

    pub fn set_flows_account(&mut self, account: FlowsAccount) {
        self.account = account;
    }

    pub fn set_retry_times(&mut self, retry_times: u8) {
        self.retry_times = retry_times;
    }

    fn keep_trying<T, F>(&self, f: F) -> Result<T, String>
    where
        F: Fn(&str) -> Retry<T>,
    {
        let account = match &self.account {
            FlowsAccount::Default => "",
            FlowsAccount::Provided(s) => s.as_str(),
        };
        let mut retry_times = match self.retry_times {
            r if r > MAX_RETRY_TIMES => MAX_RETRY_TIMES,
            r => r,
        };

        loop {
            match f(account) {
                Retry::Yes(s) => match retry_times > 0 {
                    true => {
                        sleep(Duration::from_secs(crate::RETRY_INTERVAL));
                        retry_times = retry_times - 1;
                        continue;
                    }
                    false => return Err(s),
                },
                Retry::No(r) => return r,
            }
        }
    }
}

enum Retry<T> {
    Yes(String),
    No(Result<T, String>),
}