nemo_flow_ffi/api/
tool_lifecycle.rs1use super::{
5 Arc, FfiScopeHandle, FfiToolHandle, NemoFlowFreeFn, NemoFlowStatus, NemoFlowToolExecCb,
6 TASK_SCOPE_STACK, ToolAttributes, ToolExecutionNextFn, c_char, c_str_to_json,
7 c_str_to_opt_json, c_str_to_string, clear_last_error, core_tool_api, current_scope_stack,
8 json_to_c_string, set_last_error, status_from_error, tokio_runtime,
9 unix_micros_to_opt_timestamp, wrap_tool_exec_fn,
10};
11
12#[unsafe(no_mangle)]
49pub unsafe extern "C" fn nemo_flow_tool_call(
50 name: *const c_char,
51 args_json: *const c_char,
52 parent: *const FfiScopeHandle,
53 attributes: u32,
54 data_json: *const c_char,
55 metadata_json: *const c_char,
56 tool_call_id: *const c_char,
57 timestamp_unix_micros: *const i64,
58 out: *mut *mut FfiToolHandle,
59) -> NemoFlowStatus {
60 clear_last_error();
61 if out.is_null() {
62 set_last_error("out pointer is null");
63 return NemoFlowStatus::NullPointer;
64 }
65 let name = match c_str_to_string(name) {
66 Ok(s) => s,
67 Err(status) => return status,
68 };
69 let args = match c_str_to_json(args_json) {
70 Some(a) => a,
71 None => return NemoFlowStatus::InvalidJson,
72 };
73 let parent_ref = if parent.is_null() {
74 None
75 } else {
76 Some(&unsafe { &*parent }.0)
77 };
78 let attrs = ToolAttributes::from_bits_truncate(attributes);
79 let data = match c_str_to_opt_json(data_json) {
80 Some(d) => d,
81 None => return NemoFlowStatus::InvalidJson,
82 };
83 let metadata = match c_str_to_opt_json(metadata_json) {
84 Some(m) => m,
85 None => return NemoFlowStatus::InvalidJson,
86 };
87 let tool_call_id_opt = if tool_call_id.is_null() {
88 None
89 } else {
90 match c_str_to_string(tool_call_id) {
91 Ok(s) => Some(s),
92 Err(status) => return status,
93 }
94 };
95 let timestamp = match unix_micros_to_opt_timestamp(timestamp_unix_micros) {
96 Some(v) => v,
97 None => return NemoFlowStatus::InvalidArg,
98 };
99
100 match core_tool_api::tool_call(
101 core_tool_api::ToolCallParams::builder()
102 .name(name.as_str())
103 .args(args)
104 .parent_opt(parent_ref)
105 .attributes(attrs)
106 .data_opt(data)
107 .metadata_opt(metadata)
108 .tool_call_id_opt(tool_call_id_opt)
109 .timestamp_opt(timestamp)
110 .build(),
111 ) {
112 Ok(h) => {
113 unsafe { *out = Box::into_raw(Box::new(FfiToolHandle(h))) };
114 NemoFlowStatus::Ok
115 }
116 Err(e) => status_from_error(&e),
117 }
118}
119
120#[unsafe(no_mangle)]
147pub unsafe extern "C" fn nemo_flow_tool_call_end(
148 handle: *const FfiToolHandle,
149 result_json: *const c_char,
150 data_json: *const c_char,
151 metadata_json: *const c_char,
152 timestamp_unix_micros: *const i64,
153) -> NemoFlowStatus {
154 clear_last_error();
155 if handle.is_null() {
156 set_last_error("handle is null");
157 return NemoFlowStatus::NullPointer;
158 }
159 let result = match c_str_to_json(result_json) {
160 Some(r) => r,
161 None => return NemoFlowStatus::InvalidJson,
162 };
163 let data = match c_str_to_opt_json(data_json) {
164 Some(d) => d,
165 None => return NemoFlowStatus::InvalidJson,
166 };
167 let metadata = match c_str_to_opt_json(metadata_json) {
168 Some(m) => m,
169 None => return NemoFlowStatus::InvalidJson,
170 };
171 let timestamp = match unix_micros_to_opt_timestamp(timestamp_unix_micros) {
172 Some(v) => v,
173 None => return NemoFlowStatus::InvalidArg,
174 };
175
176 match core_tool_api::tool_call_end(
177 core_tool_api::ToolCallEndParams::builder()
178 .handle(&unsafe { &*handle }.0)
179 .result(result)
180 .data_opt(data)
181 .metadata_opt(metadata)
182 .timestamp_opt(timestamp)
183 .build(),
184 ) {
185 Ok(()) => NemoFlowStatus::Ok,
186 Err(e) => status_from_error(&e),
187 }
188}
189
190#[unsafe(no_mangle)]
213pub unsafe extern "C" fn nemo_flow_tool_call_execute(
214 name: *const c_char,
215 args_json: *const c_char,
216 func: NemoFlowToolExecCb,
217 func_user_data: *mut libc::c_void,
218 func_free: NemoFlowFreeFn,
219 parent: *const FfiScopeHandle,
220 attributes: u32,
221 data_json: *const c_char,
222 metadata_json: *const c_char,
223 out: *mut *mut c_char,
224) -> NemoFlowStatus {
225 clear_last_error();
226 if out.is_null() {
227 set_last_error("out pointer is null");
228 return NemoFlowStatus::NullPointer;
229 }
230 let name = match c_str_to_string(name) {
231 Ok(s) => s,
232 Err(status) => return status,
233 };
234 let args = match c_str_to_json(args_json) {
235 Some(a) => a,
236 None => return NemoFlowStatus::InvalidJson,
237 };
238 let parent_handle = if parent.is_null() {
239 None
240 } else {
241 Some(unsafe { &*parent }.0.clone())
242 };
243 let attrs = ToolAttributes::from_bits_truncate(attributes);
244 let data = match c_str_to_opt_json(data_json) {
245 Some(d) => d,
246 None => return NemoFlowStatus::InvalidJson,
247 };
248 let metadata = match c_str_to_opt_json(metadata_json) {
249 Some(m) => m,
250 None => return NemoFlowStatus::InvalidJson,
251 };
252
253 let exec_fn = wrap_tool_exec_fn(func, func_user_data, func_free);
254 let default_fn: ToolExecutionNextFn = Arc::new(move |args| exec_fn(args));
255
256 let scope_stack = current_scope_stack();
257 let result = tokio_runtime().block_on(TASK_SCOPE_STACK.scope(scope_stack, async {
258 core_tool_api::tool_call_execute(
259 core_tool_api::ToolCallExecuteParams::builder()
260 .name(name)
261 .args(args)
262 .func(default_fn)
263 .parent_opt(parent_handle)
264 .attributes(attrs)
265 .data_opt(data)
266 .metadata_opt(metadata)
267 .build(),
268 )
269 .await
270 }));
271
272 match result {
273 Ok(json) => {
274 unsafe { *out = json_to_c_string(&json) };
275 NemoFlowStatus::Ok
276 }
277 Err(e) => status_from_error(&e),
278 }
279}