use super::{
Arc, FfiScopeHandle, FfiToolHandle, NemoFlowFreeFn, NemoFlowStatus, NemoFlowToolExecCb,
TASK_SCOPE_STACK, ToolAttributes, ToolExecutionNextFn, c_char, c_str_to_json,
c_str_to_opt_json, c_str_to_string, clear_last_error, core_tool_api, current_scope_stack,
json_to_c_string, set_last_error, status_from_error, tokio_runtime,
unix_micros_to_opt_timestamp, wrap_tool_exec_fn,
};
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_tool_call(
name: *const c_char,
args_json: *const c_char,
parent: *const FfiScopeHandle,
attributes: u32,
data_json: *const c_char,
metadata_json: *const c_char,
tool_call_id: *const c_char,
timestamp_unix_micros: *const i64,
out: *mut *mut FfiToolHandle,
) -> NemoFlowStatus {
clear_last_error();
if out.is_null() {
set_last_error("out pointer is null");
return NemoFlowStatus::NullPointer;
}
let name = match c_str_to_string(name) {
Ok(s) => s,
Err(status) => return status,
};
let args = match c_str_to_json(args_json) {
Some(a) => a,
None => return NemoFlowStatus::InvalidJson,
};
let parent_ref = if parent.is_null() {
None
} else {
Some(&unsafe { &*parent }.0)
};
let attrs = ToolAttributes::from_bits_truncate(attributes);
let data = match c_str_to_opt_json(data_json) {
Some(d) => d,
None => return NemoFlowStatus::InvalidJson,
};
let metadata = match c_str_to_opt_json(metadata_json) {
Some(m) => m,
None => return NemoFlowStatus::InvalidJson,
};
let tool_call_id_opt = if tool_call_id.is_null() {
None
} else {
match c_str_to_string(tool_call_id) {
Ok(s) => Some(s),
Err(status) => return status,
}
};
let timestamp = match unix_micros_to_opt_timestamp(timestamp_unix_micros) {
Some(v) => v,
None => return NemoFlowStatus::InvalidArg,
};
match core_tool_api::tool_call(
core_tool_api::ToolCallParams::builder()
.name(name.as_str())
.args(args)
.parent_opt(parent_ref)
.attributes(attrs)
.data_opt(data)
.metadata_opt(metadata)
.tool_call_id_opt(tool_call_id_opt)
.timestamp_opt(timestamp)
.build(),
) {
Ok(h) => {
unsafe { *out = Box::into_raw(Box::new(FfiToolHandle(h))) };
NemoFlowStatus::Ok
}
Err(e) => status_from_error(&e),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_tool_call_end(
handle: *const FfiToolHandle,
result_json: *const c_char,
data_json: *const c_char,
metadata_json: *const c_char,
timestamp_unix_micros: *const i64,
) -> NemoFlowStatus {
clear_last_error();
if handle.is_null() {
set_last_error("handle is null");
return NemoFlowStatus::NullPointer;
}
let result = match c_str_to_json(result_json) {
Some(r) => r,
None => return NemoFlowStatus::InvalidJson,
};
let data = match c_str_to_opt_json(data_json) {
Some(d) => d,
None => return NemoFlowStatus::InvalidJson,
};
let metadata = match c_str_to_opt_json(metadata_json) {
Some(m) => m,
None => return NemoFlowStatus::InvalidJson,
};
let timestamp = match unix_micros_to_opt_timestamp(timestamp_unix_micros) {
Some(v) => v,
None => return NemoFlowStatus::InvalidArg,
};
match core_tool_api::tool_call_end(
core_tool_api::ToolCallEndParams::builder()
.handle(&unsafe { &*handle }.0)
.result(result)
.data_opt(data)
.metadata_opt(metadata)
.timestamp_opt(timestamp)
.build(),
) {
Ok(()) => NemoFlowStatus::Ok,
Err(e) => status_from_error(&e),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_tool_call_execute(
name: *const c_char,
args_json: *const c_char,
func: NemoFlowToolExecCb,
func_user_data: *mut libc::c_void,
func_free: NemoFlowFreeFn,
parent: *const FfiScopeHandle,
attributes: u32,
data_json: *const c_char,
metadata_json: *const c_char,
out: *mut *mut c_char,
) -> NemoFlowStatus {
clear_last_error();
if out.is_null() {
set_last_error("out pointer is null");
return NemoFlowStatus::NullPointer;
}
let name = match c_str_to_string(name) {
Ok(s) => s,
Err(status) => return status,
};
let args = match c_str_to_json(args_json) {
Some(a) => a,
None => return NemoFlowStatus::InvalidJson,
};
let parent_handle = if parent.is_null() {
None
} else {
Some(unsafe { &*parent }.0.clone())
};
let attrs = ToolAttributes::from_bits_truncate(attributes);
let data = match c_str_to_opt_json(data_json) {
Some(d) => d,
None => return NemoFlowStatus::InvalidJson,
};
let metadata = match c_str_to_opt_json(metadata_json) {
Some(m) => m,
None => return NemoFlowStatus::InvalidJson,
};
let exec_fn = wrap_tool_exec_fn(func, func_user_data, func_free);
let default_fn: ToolExecutionNextFn = Arc::new(move |args| exec_fn(args));
let scope_stack = current_scope_stack();
let result = tokio_runtime().block_on(TASK_SCOPE_STACK.scope(scope_stack, async {
core_tool_api::tool_call_execute(
core_tool_api::ToolCallExecuteParams::builder()
.name(name)
.args(args)
.func(default_fn)
.parent_opt(parent_handle)
.attributes(attrs)
.data_opt(data)
.metadata_opt(metadata)
.build(),
)
.await
}));
match result {
Ok(json) => {
unsafe { *out = json_to_c_string(&json) };
NemoFlowStatus::Ok
}
Err(e) => status_from_error(&e),
}
}