#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, dead_code)]
mod ffi {
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ResponseType {
Call,
Respond,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NeedleResponse {
#[serde(rename = "type")]
pub kind: ResponseType,
pub success: bool,
pub error: Option<String>,
pub error_code: Option<String>,
pub reason: Option<String>,
pub function_calls: Vec<FunctionCall>,
pub reasoning: Option<String>,
pub confidence: f64,
pub validation: Option<Validation>,
pub prefill_tps: f64,
pub decode_tps: f64,
pub peak_ram_mb: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionCall {
pub name: String,
pub arguments: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Validation {
pub negation: bool,
pub ungrounded: Vec<String>,
}
pub struct Needle;
impl Needle {
pub fn init(system: &str, tools_json: &str) -> anyhow::Result<Self> {
let system_c = CString::new(system)?;
let tools_c = CString::new(tools_json)?;
let ret = unsafe {
ffi::needle_init(system_c.as_ptr(), tools_c.as_ptr(), std::ptr::null())
};
if ret < 0 {
anyhow::bail!("needle_init failed with code {ret}");
}
Ok(Needle)
}
pub fn complete(&self, text: &str, max_new_tokens: i32) -> anyhow::Result<NeedleResponse> {
let text_c = CString::new(text)?;
let mut buf = vec![0u8; 65536];
unsafe {
ffi::needle_complete(
text_c.as_ptr(),
max_new_tokens,
buf.as_mut_ptr() as *mut c_char,
buf.len() as i32,
);
}
let cstr = unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) };
let cstr_str = cstr.to_str()?;
Ok(serde_json::from_str(cstr_str)?)
}
pub fn reset(&self) {
unsafe { ffi::needle_reset() };
}
pub fn load_weights(blob: &[u8]) -> anyhow::Result<()> {
let ret = unsafe { ffi::needle_load(blob.as_ptr() as *const c_char, blob.len() as u64) };
if ret != 0 {
anyhow::bail!("needle_load failed with code {ret}");
}
Ok(())
}
}