1use libc::c_char;
14use nemo_flow::api::runtime::{ScopeStackHandle, ThreadScopeStackBinding};
15use nemo_flow::plugin::PluginRegistrationContext;
16use serde_json::Value as Json;
17
18use nemo_flow::api::event::Event;
19#[cfg(test)]
20use nemo_flow::api::llm::LlmAttributes;
21use nemo_flow::api::llm::{LlmHandle, LlmRequest};
22#[cfg(test)]
23use nemo_flow::api::scope::ScopeAttributes;
24use nemo_flow::api::scope::{ScopeHandle, ScopeType};
25#[cfg(test)]
26use nemo_flow::api::tool::ToolAttributes;
27use nemo_flow::api::tool::ToolHandle;
28use nemo_flow::codec::traits::{LlmCodec, LlmResponseCodec};
29
30use crate::convert::{json_to_c_string, str_to_c_string};
31#[cfg(test)]
32use crate::{api, convert};
33
34pub struct FfiScopeHandle(pub ScopeHandle);
41pub struct FfiToolHandle(pub ToolHandle);
43pub struct FfiLLMHandle(pub LlmHandle);
45pub struct FfiLLMRequest(pub LlmRequest);
47pub struct FfiEvent(pub Event);
49pub struct FfiScopeStack(pub ScopeStackHandle);
51pub struct FfiThreadScopeStackBinding(pub ThreadScopeStackBinding);
53pub struct FfiAtifExporter(pub nemo_flow::observability::atif::AtifExporter);
55pub struct FfiAtofExporter(pub nemo_flow::observability::atof::AtofExporter);
57pub struct FfiOpenTelemetrySubscriber(pub nemo_flow::observability::otel::OpenTelemetrySubscriber);
59pub struct FfiOpenInferenceSubscriber(
61 pub nemo_flow::observability::openinference::OpenInferenceSubscriber,
62);
63pub struct FfiPluginContext(pub *mut PluginRegistrationContext);
74
75pub struct FfiCodecHandle {
82 #[allow(dead_code)]
83 pub(crate) codec: std::sync::Arc<dyn LlmCodec>,
84 pub(crate) response_codec: std::sync::Arc<dyn LlmResponseCodec>,
85}
86
87#[repr(i32)]
93#[derive(Debug, Clone, Copy)]
94pub enum NemoFlowScopeType {
95 Agent = 0,
97 Function = 1,
99 Tool = 2,
101 Llm = 3,
103 Retriever = 4,
105 Embedder = 5,
107 Reranker = 6,
109 Guardrail = 7,
111 Evaluator = 8,
113 Custom = 9,
115 Unknown = 10,
117}
118
119impl From<NemoFlowScopeType> for ScopeType {
120 fn from(v: NemoFlowScopeType) -> Self {
121 match v {
122 NemoFlowScopeType::Agent => ScopeType::Agent,
123 NemoFlowScopeType::Function => ScopeType::Function,
124 NemoFlowScopeType::Tool => ScopeType::Tool,
125 NemoFlowScopeType::Llm => ScopeType::Llm,
126 NemoFlowScopeType::Retriever => ScopeType::Retriever,
127 NemoFlowScopeType::Embedder => ScopeType::Embedder,
128 NemoFlowScopeType::Reranker => ScopeType::Reranker,
129 NemoFlowScopeType::Guardrail => ScopeType::Guardrail,
130 NemoFlowScopeType::Evaluator => ScopeType::Evaluator,
131 NemoFlowScopeType::Custom => ScopeType::Custom,
132 NemoFlowScopeType::Unknown => ScopeType::Unknown,
133 }
134 }
135}
136
137impl From<ScopeType> for NemoFlowScopeType {
138 fn from(v: ScopeType) -> Self {
139 match v {
140 ScopeType::Agent => NemoFlowScopeType::Agent,
141 ScopeType::Function => NemoFlowScopeType::Function,
142 ScopeType::Tool => NemoFlowScopeType::Tool,
143 ScopeType::Llm => NemoFlowScopeType::Llm,
144 ScopeType::Retriever => NemoFlowScopeType::Retriever,
145 ScopeType::Embedder => NemoFlowScopeType::Embedder,
146 ScopeType::Reranker => NemoFlowScopeType::Reranker,
147 ScopeType::Guardrail => NemoFlowScopeType::Guardrail,
148 ScopeType::Evaluator => NemoFlowScopeType::Evaluator,
149 ScopeType::Custom => NemoFlowScopeType::Custom,
150 ScopeType::Unknown => NemoFlowScopeType::Unknown,
151 }
152 }
153}
154
155#[unsafe(no_mangle)]
164pub unsafe extern "C" fn nemo_flow_scope_handle_free(ptr: *mut FfiScopeHandle) {
165 if !ptr.is_null() {
166 drop(unsafe { Box::from_raw(ptr) });
167 }
168}
169
170#[unsafe(no_mangle)]
175pub unsafe extern "C" fn nemo_flow_tool_handle_free(ptr: *mut FfiToolHandle) {
176 if !ptr.is_null() {
177 drop(unsafe { Box::from_raw(ptr) });
178 }
179}
180
181#[unsafe(no_mangle)]
186pub unsafe extern "C" fn nemo_flow_llm_handle_free(ptr: *mut FfiLLMHandle) {
187 if !ptr.is_null() {
188 drop(unsafe { Box::from_raw(ptr) });
189 }
190}
191
192#[unsafe(no_mangle)]
197pub unsafe extern "C" fn nemo_flow_llm_request_free(ptr: *mut FfiLLMRequest) {
198 if !ptr.is_null() {
199 drop(unsafe { Box::from_raw(ptr) });
200 }
201}
202
203#[unsafe(no_mangle)]
208pub unsafe extern "C" fn nemo_flow_event_free(ptr: *mut FfiEvent) {
209 if !ptr.is_null() {
210 drop(unsafe { Box::from_raw(ptr) });
211 }
212}
213
214#[unsafe(no_mangle)]
219pub unsafe extern "C" fn nemo_flow_scope_stack_free(ptr: *mut FfiScopeStack) {
220 if !ptr.is_null() {
221 drop(unsafe { Box::from_raw(ptr) });
222 }
223}
224
225#[unsafe(no_mangle)]
230pub unsafe extern "C" fn nemo_flow_atif_exporter_free(ptr: *mut FfiAtifExporter) {
231 if !ptr.is_null() {
232 drop(unsafe { Box::from_raw(ptr) });
233 }
234}
235
236#[unsafe(no_mangle)]
241pub unsafe extern "C" fn nemo_flow_atof_exporter_free(ptr: *mut FfiAtofExporter) {
242 if !ptr.is_null() {
243 drop(unsafe { Box::from_raw(ptr) });
244 }
245}
246
247#[unsafe(no_mangle)]
253pub unsafe extern "C" fn nemo_flow_otel_subscriber_free(ptr: *mut FfiOpenTelemetrySubscriber) {
254 if !ptr.is_null() {
255 drop(unsafe { Box::from_raw(ptr) });
256 }
257}
258
259#[unsafe(no_mangle)]
266pub unsafe extern "C" fn nemo_flow_openinference_subscriber_free(
267 ptr: *mut FfiOpenInferenceSubscriber,
268) {
269 if !ptr.is_null() {
270 drop(unsafe { Box::from_raw(ptr) });
271 }
272}
273
274#[unsafe(no_mangle)]
281pub unsafe extern "C" fn nemo_flow_codec_free(handle: *mut FfiCodecHandle) {
282 if !handle.is_null() {
283 drop(unsafe { Box::from_raw(handle) });
284 }
285}
286
287#[unsafe(no_mangle)]
297pub unsafe extern "C" fn nemo_flow_scope_handle_uuid(ptr: *const FfiScopeHandle) -> *mut c_char {
298 if ptr.is_null() {
299 return std::ptr::null_mut();
300 }
301 str_to_c_string(&unsafe { &*ptr }.0.uuid.to_string())
302}
303
304#[unsafe(no_mangle)]
310pub unsafe extern "C" fn nemo_flow_scope_handle_name(ptr: *const FfiScopeHandle) -> *mut c_char {
311 if ptr.is_null() {
312 return std::ptr::null_mut();
313 }
314 str_to_c_string(&unsafe { &*ptr }.0.name)
315}
316
317#[unsafe(no_mangle)]
322pub unsafe extern "C" fn nemo_flow_scope_handle_scope_type(
323 ptr: *const FfiScopeHandle,
324) -> NemoFlowScopeType {
325 if ptr.is_null() {
326 return NemoFlowScopeType::Unknown;
327 }
328 unsafe { &*ptr }.0.scope_type.into()
329}
330
331#[unsafe(no_mangle)]
336pub unsafe extern "C" fn nemo_flow_scope_handle_attributes(ptr: *const FfiScopeHandle) -> u32 {
337 if ptr.is_null() {
338 return 0;
339 }
340 unsafe { &*ptr }.0.attributes.bits()
341}
342
343#[unsafe(no_mangle)]
349pub unsafe extern "C" fn nemo_flow_scope_handle_parent_uuid(
350 ptr: *const FfiScopeHandle,
351) -> *mut c_char {
352 if ptr.is_null() {
353 return std::ptr::null_mut();
354 }
355 match &unsafe { &*ptr }.0.parent_uuid {
356 Some(u) => str_to_c_string(&u.to_string()),
357 None => std::ptr::null_mut(),
358 }
359}
360
361#[unsafe(no_mangle)]
367pub unsafe extern "C" fn nemo_flow_scope_handle_data(ptr: *const FfiScopeHandle) -> *mut c_char {
368 if ptr.is_null() {
369 return std::ptr::null_mut();
370 }
371 match &unsafe { &*ptr }.0.data {
372 Some(d) => json_to_c_string(d),
373 None => std::ptr::null_mut(),
374 }
375}
376
377#[unsafe(no_mangle)]
383pub unsafe extern "C" fn nemo_flow_scope_handle_metadata(
384 ptr: *const FfiScopeHandle,
385) -> *mut c_char {
386 if ptr.is_null() {
387 return std::ptr::null_mut();
388 }
389 match &unsafe { &*ptr }.0.metadata {
390 Some(m) => json_to_c_string(m),
391 None => std::ptr::null_mut(),
392 }
393}
394
395#[unsafe(no_mangle)]
404pub unsafe extern "C" fn nemo_flow_tool_handle_uuid(ptr: *const FfiToolHandle) -> *mut c_char {
405 if ptr.is_null() {
406 return std::ptr::null_mut();
407 }
408 str_to_c_string(&unsafe { &*ptr }.0.uuid.to_string())
409}
410
411#[unsafe(no_mangle)]
416pub unsafe extern "C" fn nemo_flow_tool_handle_name(ptr: *const FfiToolHandle) -> *mut c_char {
417 if ptr.is_null() {
418 return std::ptr::null_mut();
419 }
420 str_to_c_string(&unsafe { &*ptr }.0.name)
421}
422
423#[unsafe(no_mangle)]
428pub unsafe extern "C" fn nemo_flow_tool_handle_attributes(ptr: *const FfiToolHandle) -> u32 {
429 if ptr.is_null() {
430 return 0;
431 }
432 unsafe { &*ptr }.0.attributes.bits()
433}
434
435#[unsafe(no_mangle)]
441pub unsafe extern "C" fn nemo_flow_tool_handle_parent_uuid(
442 ptr: *const FfiToolHandle,
443) -> *mut c_char {
444 if ptr.is_null() {
445 return std::ptr::null_mut();
446 }
447 match &unsafe { &*ptr }.0.parent_uuid {
448 Some(u) => str_to_c_string(&u.to_string()),
449 None => std::ptr::null_mut(),
450 }
451}
452
453#[unsafe(no_mangle)]
462pub unsafe extern "C" fn nemo_flow_llm_handle_uuid(ptr: *const FfiLLMHandle) -> *mut c_char {
463 if ptr.is_null() {
464 return std::ptr::null_mut();
465 }
466 str_to_c_string(&unsafe { &*ptr }.0.uuid.to_string())
467}
468
469#[unsafe(no_mangle)]
474pub unsafe extern "C" fn nemo_flow_llm_handle_name(ptr: *const FfiLLMHandle) -> *mut c_char {
475 if ptr.is_null() {
476 return std::ptr::null_mut();
477 }
478 str_to_c_string(&unsafe { &*ptr }.0.name)
479}
480
481#[unsafe(no_mangle)]
486pub unsafe extern "C" fn nemo_flow_llm_handle_attributes(ptr: *const FfiLLMHandle) -> u32 {
487 if ptr.is_null() {
488 return 0;
489 }
490 unsafe { &*ptr }.0.attributes.bits()
491}
492
493#[unsafe(no_mangle)]
499pub unsafe extern "C" fn nemo_flow_llm_handle_parent_uuid(ptr: *const FfiLLMHandle) -> *mut c_char {
500 if ptr.is_null() {
501 return std::ptr::null_mut();
502 }
503 match &unsafe { &*ptr }.0.parent_uuid {
504 Some(u) => str_to_c_string(&u.to_string()),
505 None => std::ptr::null_mut(),
506 }
507}
508
509#[unsafe(no_mangle)]
524pub unsafe extern "C" fn nemo_flow_llm_request_new(
525 headers_json: *const c_char,
526 content_json: *const c_char,
527) -> *mut FfiLLMRequest {
528 let headers = match crate::convert::c_str_to_json(headers_json) {
529 Some(Json::Object(m)) => m,
530 _ => serde_json::Map::new(),
531 };
532 let content = crate::convert::c_str_to_json(content_json).unwrap_or(Json::Null);
533
534 Box::into_raw(Box::new(FfiLLMRequest(LlmRequest { headers, content })))
535}
536
537#[unsafe(no_mangle)]
542pub unsafe extern "C" fn nemo_flow_llm_request_headers(ptr: *const FfiLLMRequest) -> *mut c_char {
543 if ptr.is_null() {
544 return std::ptr::null_mut();
545 }
546 json_to_c_string(&Json::Object(unsafe { &*ptr }.0.headers.clone()))
547}
548
549#[unsafe(no_mangle)]
554pub unsafe extern "C" fn nemo_flow_llm_request_content(ptr: *const FfiLLMRequest) -> *mut c_char {
555 if ptr.is_null() {
556 return std::ptr::null_mut();
557 }
558 json_to_c_string(&unsafe { &*ptr }.0.content)
559}
560
561#[unsafe(no_mangle)]
570pub unsafe extern "C" fn nemo_flow_event_uuid(ptr: *const FfiEvent) -> *mut c_char {
571 if ptr.is_null() {
572 return std::ptr::null_mut();
573 }
574 str_to_c_string(&unsafe { &*ptr }.0.uuid().to_string())
575}
576
577#[unsafe(no_mangle)]
583pub unsafe extern "C" fn nemo_flow_event_name(ptr: *const FfiEvent) -> *mut c_char {
584 if ptr.is_null() {
585 return std::ptr::null_mut();
586 }
587 str_to_c_string(unsafe { &*ptr }.0.name())
588}
589
590#[unsafe(no_mangle)]
596pub unsafe extern "C" fn nemo_flow_event_kind(ptr: *const FfiEvent) -> *mut c_char {
597 if ptr.is_null() {
598 return std::ptr::null_mut();
599 }
600 str_to_c_string(unsafe { &*ptr }.0.kind())
601}
602
603#[unsafe(no_mangle)]
608pub unsafe extern "C" fn nemo_flow_event_atof_version(ptr: *const FfiEvent) -> *mut c_char {
609 if ptr.is_null() {
610 return std::ptr::null_mut();
611 }
612 match &unsafe { &*ptr }.0 {
613 Event::Scope(event) => str_to_c_string(&event.base.atof_version),
614 Event::Mark(event) => str_to_c_string(&event.base.atof_version),
615 }
616}
617
618#[unsafe(no_mangle)]
623pub unsafe extern "C" fn nemo_flow_event_scope_category(ptr: *const FfiEvent) -> *mut c_char {
624 if ptr.is_null() {
625 return std::ptr::null_mut();
626 }
627 match unsafe { &*ptr }.0.scope_category() {
628 Some(nemo_flow::api::event::ScopeCategory::Start) => str_to_c_string("start"),
629 Some(nemo_flow::api::event::ScopeCategory::End) => str_to_c_string("end"),
630 None => std::ptr::null_mut(),
631 }
632}
633
634#[unsafe(no_mangle)]
639pub unsafe extern "C" fn nemo_flow_event_category(ptr: *const FfiEvent) -> *mut c_char {
640 if ptr.is_null() {
641 return std::ptr::null_mut();
642 }
643 match unsafe { &*ptr }.0.category() {
644 Some(category) => str_to_c_string(category.as_str()),
645 None => std::ptr::null_mut(),
646 }
647}
648
649#[unsafe(no_mangle)]
654pub unsafe extern "C" fn nemo_flow_event_attributes_json(ptr: *const FfiEvent) -> *mut c_char {
655 if ptr.is_null() {
656 return std::ptr::null_mut();
657 }
658 match unsafe { &*ptr }.0.attributes() {
659 Some(attributes) => json_to_c_string(&serde_json::json!(attributes)),
660 None => std::ptr::null_mut(),
661 }
662}
663
664#[unsafe(no_mangle)]
669pub unsafe extern "C" fn nemo_flow_event_category_profile(ptr: *const FfiEvent) -> *mut c_char {
670 if ptr.is_null() {
671 return std::ptr::null_mut();
672 }
673 match unsafe { &*ptr }.0.category_profile() {
674 Some(profile) => {
675 let value = serde_json::to_value(profile).unwrap_or(Json::Null);
676 json_to_c_string(&value)
677 }
678 None => std::ptr::null_mut(),
679 }
680}
681
682#[unsafe(no_mangle)]
688pub unsafe extern "C" fn nemo_flow_event_data_schema(ptr: *const FfiEvent) -> *mut c_char {
689 if ptr.is_null() {
690 return std::ptr::null_mut();
691 }
692 match unsafe { &*ptr }.0.data_schema() {
693 Some(schema) => {
694 let value = serde_json::to_value(schema).unwrap_or(Json::Null);
695 json_to_c_string(&value)
696 }
697 None => std::ptr::null_mut(),
698 }
699}
700
701#[unsafe(no_mangle)]
706pub unsafe extern "C" fn nemo_flow_event_attributes(ptr: *const FfiEvent) -> u32 {
707 if ptr.is_null() {
708 return 0;
709 }
710 0
711}
712
713#[unsafe(no_mangle)]
719pub unsafe extern "C" fn nemo_flow_event_data(ptr: *const FfiEvent) -> *mut c_char {
720 if ptr.is_null() {
721 return std::ptr::null_mut();
722 }
723 match unsafe { &*ptr }.0.data() {
724 Some(d) => json_to_c_string(d),
725 None => std::ptr::null_mut(),
726 }
727}
728
729#[unsafe(no_mangle)]
735pub unsafe extern "C" fn nemo_flow_event_metadata(ptr: *const FfiEvent) -> *mut c_char {
736 if ptr.is_null() {
737 return std::ptr::null_mut();
738 }
739 match unsafe { &*ptr }.0.metadata() {
740 Some(m) => json_to_c_string(m),
741 None => std::ptr::null_mut(),
742 }
743}
744
745#[unsafe(no_mangle)]
750pub unsafe extern "C" fn nemo_flow_event_timestamp(ptr: *const FfiEvent) -> *mut c_char {
751 if ptr.is_null() {
752 return std::ptr::null_mut();
753 }
754 str_to_c_string(&unsafe { &*ptr }.0.timestamp().to_rfc3339())
755}
756
757#[unsafe(no_mangle)]
763pub unsafe extern "C" fn nemo_flow_event_input(ptr: *const FfiEvent) -> *mut c_char {
764 if ptr.is_null() {
765 return std::ptr::null_mut();
766 }
767 match unsafe { &*ptr }.0.input() {
768 Some(d) => json_to_c_string(d),
769 None => std::ptr::null_mut(),
770 }
771}
772
773#[unsafe(no_mangle)]
779pub unsafe extern "C" fn nemo_flow_event_output(ptr: *const FfiEvent) -> *mut c_char {
780 if ptr.is_null() {
781 return std::ptr::null_mut();
782 }
783 match unsafe { &*ptr }.0.output() {
784 Some(d) => json_to_c_string(d),
785 None => std::ptr::null_mut(),
786 }
787}
788
789#[unsafe(no_mangle)]
795pub unsafe extern "C" fn nemo_flow_event_model_name(ptr: *const FfiEvent) -> *mut c_char {
796 if ptr.is_null() {
797 return std::ptr::null_mut();
798 }
799 match unsafe { &*ptr }.0.model_name() {
800 Some(s) => str_to_c_string(s),
801 None => std::ptr::null_mut(),
802 }
803}
804
805#[unsafe(no_mangle)]
811pub unsafe extern "C" fn nemo_flow_event_tool_call_id(ptr: *const FfiEvent) -> *mut c_char {
812 if ptr.is_null() {
813 return std::ptr::null_mut();
814 }
815 match unsafe { &*ptr }.0.tool_call_id() {
816 Some(s) => str_to_c_string(s),
817 None => std::ptr::null_mut(),
818 }
819}
820
821#[unsafe(no_mangle)]
827pub unsafe extern "C" fn nemo_flow_event_parent_uuid(ptr: *const FfiEvent) -> *mut c_char {
828 if ptr.is_null() {
829 return std::ptr::null_mut();
830 }
831 match unsafe { &*ptr }.0.parent_uuid() {
832 Some(u) => str_to_c_string(&u.to_string()),
833 None => std::ptr::null_mut(),
834 }
835}
836
837#[unsafe(no_mangle)]
843pub unsafe extern "C" fn nemo_flow_event_scope_type(ptr: *const FfiEvent) -> *mut c_char {
844 if ptr.is_null() {
845 return std::ptr::null_mut();
846 }
847 match unsafe { &*ptr }.0.scope_type() {
848 Some(st) => str_to_c_string(st.as_str()),
849 None => std::ptr::null_mut(),
850 }
851}
852
853#[unsafe(no_mangle)]
860pub unsafe extern "C" fn nemo_flow_event_annotated_request(ptr: *const FfiEvent) -> *mut c_char {
861 if ptr.is_null() {
862 return std::ptr::null_mut();
863 }
864 match unsafe { &*ptr }.0.annotated_request() {
865 Some(a) => {
866 let value = serde_json::to_value(a.as_ref()).unwrap_or_default();
867 json_to_c_string(&value)
868 }
869 None => std::ptr::null_mut(),
870 }
871}
872
873#[unsafe(no_mangle)]
880pub unsafe extern "C" fn nemo_flow_event_annotated_response(ptr: *const FfiEvent) -> *mut c_char {
881 if ptr.is_null() {
882 return std::ptr::null_mut();
883 }
884 match unsafe { &*ptr }.0.annotated_response() {
885 Some(a) => {
886 let value = serde_json::to_value(a.as_ref()).unwrap_or_default();
887 json_to_c_string(&value)
888 }
889 None => std::ptr::null_mut(),
890 }
891}
892
893#[cfg(test)]
894#[path = "../../tests/unit/types_tests.rs"]
895mod tests;