use libc::c_char;
use nemo_flow::api::runtime::{ScopeStackHandle, ThreadScopeStackBinding};
use nemo_flow::plugin::PluginRegistrationContext;
use serde_json::Value as Json;
use nemo_flow::api::event::Event;
#[cfg(test)]
use nemo_flow::api::llm::LlmAttributes;
use nemo_flow::api::llm::{LlmHandle, LlmRequest};
#[cfg(test)]
use nemo_flow::api::scope::ScopeAttributes;
use nemo_flow::api::scope::{ScopeHandle, ScopeType};
#[cfg(test)]
use nemo_flow::api::tool::ToolAttributes;
use nemo_flow::api::tool::ToolHandle;
use nemo_flow::codec::traits::{LlmCodec, LlmResponseCodec};
use crate::convert::{json_to_c_string, str_to_c_string};
#[cfg(test)]
use crate::{api, convert};
pub struct FfiScopeHandle(pub ScopeHandle);
pub struct FfiToolHandle(pub ToolHandle);
pub struct FfiLLMHandle(pub LlmHandle);
pub struct FfiLLMRequest(pub LlmRequest);
pub struct FfiEvent(pub Event);
pub struct FfiScopeStack(pub ScopeStackHandle);
pub struct FfiThreadScopeStackBinding(pub ThreadScopeStackBinding);
pub struct FfiAtifExporter(pub nemo_flow::observability::atif::AtifExporter);
pub struct FfiAtofExporter(pub nemo_flow::observability::atof::AtofExporter);
pub struct FfiOpenTelemetrySubscriber(pub nemo_flow::observability::otel::OpenTelemetrySubscriber);
pub struct FfiOpenInferenceSubscriber(
pub nemo_flow::observability::openinference::OpenInferenceSubscriber,
);
pub struct FfiPluginContext(pub *mut PluginRegistrationContext);
pub struct FfiCodecHandle {
#[allow(dead_code)]
pub(crate) codec: std::sync::Arc<dyn LlmCodec>,
pub(crate) response_codec: std::sync::Arc<dyn LlmResponseCodec>,
}
#[repr(i32)]
#[derive(Debug, Clone, Copy)]
pub enum NemoFlowScopeType {
Agent = 0,
Function = 1,
Tool = 2,
Llm = 3,
Retriever = 4,
Embedder = 5,
Reranker = 6,
Guardrail = 7,
Evaluator = 8,
Custom = 9,
Unknown = 10,
}
impl From<NemoFlowScopeType> for ScopeType {
fn from(v: NemoFlowScopeType) -> Self {
match v {
NemoFlowScopeType::Agent => ScopeType::Agent,
NemoFlowScopeType::Function => ScopeType::Function,
NemoFlowScopeType::Tool => ScopeType::Tool,
NemoFlowScopeType::Llm => ScopeType::Llm,
NemoFlowScopeType::Retriever => ScopeType::Retriever,
NemoFlowScopeType::Embedder => ScopeType::Embedder,
NemoFlowScopeType::Reranker => ScopeType::Reranker,
NemoFlowScopeType::Guardrail => ScopeType::Guardrail,
NemoFlowScopeType::Evaluator => ScopeType::Evaluator,
NemoFlowScopeType::Custom => ScopeType::Custom,
NemoFlowScopeType::Unknown => ScopeType::Unknown,
}
}
}
impl From<ScopeType> for NemoFlowScopeType {
fn from(v: ScopeType) -> Self {
match v {
ScopeType::Agent => NemoFlowScopeType::Agent,
ScopeType::Function => NemoFlowScopeType::Function,
ScopeType::Tool => NemoFlowScopeType::Tool,
ScopeType::Llm => NemoFlowScopeType::Llm,
ScopeType::Retriever => NemoFlowScopeType::Retriever,
ScopeType::Embedder => NemoFlowScopeType::Embedder,
ScopeType::Reranker => NemoFlowScopeType::Reranker,
ScopeType::Guardrail => NemoFlowScopeType::Guardrail,
ScopeType::Evaluator => NemoFlowScopeType::Evaluator,
ScopeType::Custom => NemoFlowScopeType::Custom,
ScopeType::Unknown => NemoFlowScopeType::Unknown,
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_scope_handle_free(ptr: *mut FfiScopeHandle) {
if !ptr.is_null() {
drop(unsafe { Box::from_raw(ptr) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_tool_handle_free(ptr: *mut FfiToolHandle) {
if !ptr.is_null() {
drop(unsafe { Box::from_raw(ptr) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_llm_handle_free(ptr: *mut FfiLLMHandle) {
if !ptr.is_null() {
drop(unsafe { Box::from_raw(ptr) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_llm_request_free(ptr: *mut FfiLLMRequest) {
if !ptr.is_null() {
drop(unsafe { Box::from_raw(ptr) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_free(ptr: *mut FfiEvent) {
if !ptr.is_null() {
drop(unsafe { Box::from_raw(ptr) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_scope_stack_free(ptr: *mut FfiScopeStack) {
if !ptr.is_null() {
drop(unsafe { Box::from_raw(ptr) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_atif_exporter_free(ptr: *mut FfiAtifExporter) {
if !ptr.is_null() {
drop(unsafe { Box::from_raw(ptr) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_atof_exporter_free(ptr: *mut FfiAtofExporter) {
if !ptr.is_null() {
drop(unsafe { Box::from_raw(ptr) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_otel_subscriber_free(ptr: *mut FfiOpenTelemetrySubscriber) {
if !ptr.is_null() {
drop(unsafe { Box::from_raw(ptr) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_openinference_subscriber_free(
ptr: *mut FfiOpenInferenceSubscriber,
) {
if !ptr.is_null() {
drop(unsafe { Box::from_raw(ptr) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_codec_free(handle: *mut FfiCodecHandle) {
if !handle.is_null() {
drop(unsafe { Box::from_raw(handle) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_scope_handle_uuid(ptr: *const FfiScopeHandle) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
str_to_c_string(&unsafe { &*ptr }.0.uuid.to_string())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_scope_handle_name(ptr: *const FfiScopeHandle) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
str_to_c_string(&unsafe { &*ptr }.0.name)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_scope_handle_scope_type(
ptr: *const FfiScopeHandle,
) -> NemoFlowScopeType {
if ptr.is_null() {
return NemoFlowScopeType::Unknown;
}
unsafe { &*ptr }.0.scope_type.into()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_scope_handle_attributes(ptr: *const FfiScopeHandle) -> u32 {
if ptr.is_null() {
return 0;
}
unsafe { &*ptr }.0.attributes.bits()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_scope_handle_parent_uuid(
ptr: *const FfiScopeHandle,
) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match &unsafe { &*ptr }.0.parent_uuid {
Some(u) => str_to_c_string(&u.to_string()),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_scope_handle_data(ptr: *const FfiScopeHandle) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match &unsafe { &*ptr }.0.data {
Some(d) => json_to_c_string(d),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_scope_handle_metadata(
ptr: *const FfiScopeHandle,
) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match &unsafe { &*ptr }.0.metadata {
Some(m) => json_to_c_string(m),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_tool_handle_uuid(ptr: *const FfiToolHandle) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
str_to_c_string(&unsafe { &*ptr }.0.uuid.to_string())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_tool_handle_name(ptr: *const FfiToolHandle) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
str_to_c_string(&unsafe { &*ptr }.0.name)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_tool_handle_attributes(ptr: *const FfiToolHandle) -> u32 {
if ptr.is_null() {
return 0;
}
unsafe { &*ptr }.0.attributes.bits()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_tool_handle_parent_uuid(
ptr: *const FfiToolHandle,
) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match &unsafe { &*ptr }.0.parent_uuid {
Some(u) => str_to_c_string(&u.to_string()),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_llm_handle_uuid(ptr: *const FfiLLMHandle) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
str_to_c_string(&unsafe { &*ptr }.0.uuid.to_string())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_llm_handle_name(ptr: *const FfiLLMHandle) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
str_to_c_string(&unsafe { &*ptr }.0.name)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_llm_handle_attributes(ptr: *const FfiLLMHandle) -> u32 {
if ptr.is_null() {
return 0;
}
unsafe { &*ptr }.0.attributes.bits()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_llm_handle_parent_uuid(ptr: *const FfiLLMHandle) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match &unsafe { &*ptr }.0.parent_uuid {
Some(u) => str_to_c_string(&u.to_string()),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_llm_request_new(
headers_json: *const c_char,
content_json: *const c_char,
) -> *mut FfiLLMRequest {
let headers = match crate::convert::c_str_to_json(headers_json) {
Some(Json::Object(m)) => m,
_ => serde_json::Map::new(),
};
let content = crate::convert::c_str_to_json(content_json).unwrap_or(Json::Null);
Box::into_raw(Box::new(FfiLLMRequest(LlmRequest { headers, content })))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_llm_request_headers(ptr: *const FfiLLMRequest) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
json_to_c_string(&Json::Object(unsafe { &*ptr }.0.headers.clone()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_llm_request_content(ptr: *const FfiLLMRequest) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
json_to_c_string(&unsafe { &*ptr }.0.content)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_uuid(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
str_to_c_string(&unsafe { &*ptr }.0.uuid().to_string())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_name(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
str_to_c_string(unsafe { &*ptr }.0.name())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_kind(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
str_to_c_string(unsafe { &*ptr }.0.kind())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_atof_version(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match &unsafe { &*ptr }.0 {
Event::Scope(event) => str_to_c_string(&event.base.atof_version),
Event::Mark(event) => str_to_c_string(&event.base.atof_version),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_scope_category(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.scope_category() {
Some(nemo_flow::api::event::ScopeCategory::Start) => str_to_c_string("start"),
Some(nemo_flow::api::event::ScopeCategory::End) => str_to_c_string("end"),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_category(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.category() {
Some(category) => str_to_c_string(category.as_str()),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_attributes_json(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.attributes() {
Some(attributes) => json_to_c_string(&serde_json::json!(attributes)),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_category_profile(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.category_profile() {
Some(profile) => {
let value = serde_json::to_value(profile).unwrap_or(Json::Null);
json_to_c_string(&value)
}
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_data_schema(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.data_schema() {
Some(schema) => {
let value = serde_json::to_value(schema).unwrap_or(Json::Null);
json_to_c_string(&value)
}
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_attributes(ptr: *const FfiEvent) -> u32 {
if ptr.is_null() {
return 0;
}
0
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_data(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.data() {
Some(d) => json_to_c_string(d),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_metadata(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.metadata() {
Some(m) => json_to_c_string(m),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_timestamp(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
str_to_c_string(&unsafe { &*ptr }.0.timestamp().to_rfc3339())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_input(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.input() {
Some(d) => json_to_c_string(d),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_output(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.output() {
Some(d) => json_to_c_string(d),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_model_name(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.model_name() {
Some(s) => str_to_c_string(s),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_tool_call_id(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.tool_call_id() {
Some(s) => str_to_c_string(s),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_parent_uuid(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.parent_uuid() {
Some(u) => str_to_c_string(&u.to_string()),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_scope_type(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.scope_type() {
Some(st) => str_to_c_string(st.as_str()),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_annotated_request(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.annotated_request() {
Some(a) => {
let value = serde_json::to_value(a.as_ref()).unwrap_or_default();
json_to_c_string(&value)
}
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_event_annotated_response(ptr: *const FfiEvent) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
match unsafe { &*ptr }.0.annotated_response() {
Some(a) => {
let value = serde_json::to_value(a.as_ref()).unwrap_or_default();
json_to_c_string(&value)
}
None => std::ptr::null_mut(),
}
}
#[cfg(test)]
#[path = "../../tests/unit/types_tests.rs"]
mod tests;