cactus-react-native 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,11 +3,8 @@ cmake_minimum_required(VERSION 3.10)
3
3
  project(cactus)
4
4
 
5
5
  set(CMAKE_CXX_STANDARD 17)
6
-
7
- # Use cactus as the C++ source directory
8
6
  set(SOURCE_DIR ${CMAKE_SOURCE_DIR}/../../../../cactus)
9
7
 
10
- # Include directories to match cactus core structure
11
8
  include_directories(${SOURCE_DIR})
12
9
  include_directories(${SOURCE_DIR}/ggml-cpu)
13
10
  include_directories(${SOURCE_DIR}/minja)
@@ -127,7 +124,6 @@ function(build_library target_name cpu_flags)
127
124
 
128
125
  endfunction()
129
126
 
130
- # Default target (no specific CPU features)
131
127
  build_library("cactus" "")
132
128
 
133
129
  if (${ANDROID_ABI} STREQUAL "arm64-v8a")
@@ -21,11 +21,14 @@ import java.util.Random;
21
21
  import java.io.File;
22
22
  import java.io.FileInputStream;
23
23
  import java.io.PushbackInputStream;
24
+ import java.util.concurrent.ExecutorService;
25
+ import java.util.concurrent.Executors;
24
26
 
25
27
  public class Cactus implements LifecycleEventListener {
26
28
  public static final String NAME = "Cactus";
27
29
 
28
30
  private ReactApplicationContext reactContext;
31
+ private final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
29
32
 
30
33
  public Cactus(ReactApplicationContext reactContext) {
31
34
  reactContext.addLifecycleEventListener(this);
@@ -95,7 +98,7 @@ public class Cactus implements LifecycleEventListener {
95
98
  }
96
99
  promise.resolve(result);
97
100
  }
98
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
101
+ }.executeOnExecutor(singleThreadExecutor);
99
102
  }
100
103
 
101
104
  public void initContext(double id, final ReadableMap params, final Promise promise) {
@@ -139,7 +142,7 @@ public class Cactus implements LifecycleEventListener {
139
142
  promise.resolve(result);
140
143
  tasks.remove(this);
141
144
  }
142
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
145
+ }.executeOnExecutor(singleThreadExecutor);
143
146
  tasks.put(task, "initContext");
144
147
  }
145
148
 
@@ -178,7 +181,7 @@ public class Cactus implements LifecycleEventListener {
178
181
  promise.resolve(result);
179
182
  tasks.remove(this);
180
183
  }
181
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
184
+ }.executeOnExecutor(singleThreadExecutor);
182
185
  tasks.put(task, "getFormattedChat-" + contextId);
183
186
  }
184
187
 
@@ -211,7 +214,7 @@ public class Cactus implements LifecycleEventListener {
211
214
  promise.resolve(result);
212
215
  tasks.remove(this);
213
216
  }
214
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
217
+ }.executeOnExecutor(singleThreadExecutor);
215
218
  tasks.put(task, "loadSession-" + contextId);
216
219
  }
217
220
 
@@ -244,12 +247,12 @@ public class Cactus implements LifecycleEventListener {
244
247
  promise.resolve(result);
245
248
  tasks.remove(this);
246
249
  }
247
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
250
+ }.executeOnExecutor(singleThreadExecutor);
248
251
  tasks.put(task, "saveSession-" + contextId);
249
252
  }
250
253
 
251
254
  public void completion(double id, final ReadableMap params, final Promise promise) {
252
- Log.d(NAME, "🟢 BRIDGE: completion() method called with contextId=" + (int)id);
255
+ Log.d(NAME, "BRIDGE: completion() method called with contextId=" + (int)id);
253
256
  final int contextId = (int) id;
254
257
  AsyncTask task = new AsyncTask<Void, Void, WritableMap>() {
255
258
  private Exception exception;
@@ -260,20 +263,20 @@ public class Cactus implements LifecycleEventListener {
260
263
  try {
261
264
  LlamaContext context = contexts.get(contextId);
262
265
  if (context == null) {
263
- Log.e(NAME, "BRIDGE: Context not found for id=" + contextId);
266
+ Log.e(NAME, "BRIDGE: Context not found for id=" + contextId);
264
267
  throw new Exception("Context not found");
265
268
  }
266
- Log.d(NAME, "BRIDGE: Context found, checking if predicting...");
269
+ Log.d(NAME, "BRIDGE: Context found, checking if predicting...");
267
270
  if (context.isPredicting()) {
268
- Log.e(NAME, "BRIDGE: Context is busy (predicting)");
271
+ Log.e(NAME, "BRIDGE: Context is busy (predicting)");
269
272
  throw new Exception("Context is busy");
270
273
  }
271
- Log.d(NAME, "🚀 BRIDGE: About to call context.completion()...");
274
+ Log.d(NAME, "BRIDGE: About to call context.completion()...");
272
275
  WritableMap result = context.completion(params);
273
- Log.d(NAME, "BRIDGE: context.completion() returned successfully");
276
+ Log.d(NAME, "BRIDGE: context.completion() returned successfully");
274
277
  return result;
275
278
  } catch (Exception e) {
276
- Log.e(NAME, "BRIDGE: Exception in doInBackground: " + e.getMessage());
279
+ Log.e(NAME, "BRIDGE: Exception in doInBackground: " + e.getMessage());
277
280
  exception = e;
278
281
  }
279
282
  return null;
@@ -281,19 +284,19 @@ public class Cactus implements LifecycleEventListener {
281
284
 
282
285
  @Override
283
286
  protected void onPostExecute(WritableMap result) {
284
- Log.d(NAME, "📤 BRIDGE: onPostExecute called");
287
+ Log.d(NAME, "BRIDGE: onPostExecute called");
285
288
  if (exception != null) {
286
- Log.e(NAME, "BRIDGE: Rejecting promise with exception: " + exception.getMessage());
289
+ Log.e(NAME, "BRIDGE: Rejecting promise with exception: " + exception.getMessage());
287
290
  promise.reject(exception);
288
291
  return;
289
292
  }
290
- Log.d(NAME, "BRIDGE: Resolving promise with result");
293
+ Log.d(NAME, "BRIDGE: Resolving promise with result");
291
294
  promise.resolve(result);
292
295
  tasks.remove(this);
293
- Log.d(NAME, "🏁 BRIDGE: completion() finished successfully");
296
+ Log.d(NAME, "BRIDGE: completion() finished successfully");
294
297
  }
295
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
296
- Log.d(NAME, "📋 BRIDGE: AsyncTask queued for execution");
298
+ }.executeOnExecutor(singleThreadExecutor);
299
+ Log.d(NAME, "BRIDGE: AsyncTask queued for execution");
297
300
  tasks.put(task, "completion-" + contextId);
298
301
  }
299
302
 
@@ -332,7 +335,7 @@ public class Cactus implements LifecycleEventListener {
332
335
  promise.resolve(result);
333
336
  tasks.remove(this);
334
337
  }
335
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
338
+ }.executeOnExecutor(singleThreadExecutor);
336
339
  tasks.put(task, "stopCompletion-" + contextId);
337
340
  }
338
341
 
@@ -364,7 +367,7 @@ public class Cactus implements LifecycleEventListener {
364
367
  promise.resolve(result);
365
368
  tasks.remove(this);
366
369
  }
367
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
370
+ }.executeOnExecutor(singleThreadExecutor);
368
371
  tasks.put(task, "tokenize-" + contextId);
369
372
  }
370
373
 
@@ -396,7 +399,7 @@ public class Cactus implements LifecycleEventListener {
396
399
  promise.resolve(result);
397
400
  tasks.remove(this);
398
401
  }
399
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
402
+ }.executeOnExecutor(singleThreadExecutor);
400
403
  tasks.put(task, "tokenize-" + contextId);
401
404
  }
402
405
 
@@ -428,7 +431,7 @@ public class Cactus implements LifecycleEventListener {
428
431
  promise.resolve(result);
429
432
  tasks.remove(this);
430
433
  }
431
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
434
+ }.executeOnExecutor(singleThreadExecutor);
432
435
  tasks.put(task, "detokenize-" + contextId);
433
436
  }
434
437
 
@@ -460,7 +463,7 @@ public class Cactus implements LifecycleEventListener {
460
463
  promise.resolve(result);
461
464
  tasks.remove(this);
462
465
  }
463
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
466
+ }.executeOnExecutor(singleThreadExecutor);
464
467
  tasks.put(task, "embedding-" + contextId);
465
468
  }
466
469
 
@@ -492,7 +495,7 @@ public class Cactus implements LifecycleEventListener {
492
495
  promise.resolve(result);
493
496
  tasks.remove(this);
494
497
  }
495
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
498
+ }.executeOnExecutor(singleThreadExecutor);
496
499
  tasks.put(task, "bench-" + contextId);
497
500
  }
498
501
 
@@ -525,7 +528,7 @@ public class Cactus implements LifecycleEventListener {
525
528
  return;
526
529
  }
527
530
  }
528
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
531
+ }.executeOnExecutor(singleThreadExecutor);
529
532
  tasks.put(task, "applyLoraAdapters-" + contextId);
530
533
  }
531
534
 
@@ -559,7 +562,7 @@ public class Cactus implements LifecycleEventListener {
559
562
  }
560
563
  promise.resolve(null);
561
564
  }
562
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
565
+ }.executeOnExecutor(singleThreadExecutor);
563
566
  tasks.put(task, "removeLoraAdapters-" + contextId);
564
567
  }
565
568
 
@@ -590,7 +593,7 @@ public class Cactus implements LifecycleEventListener {
590
593
  }
591
594
  promise.resolve(result);
592
595
  }
593
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
596
+ }.executeOnExecutor(singleThreadExecutor);
594
597
  tasks.put(task, "getLoadedLoraAdapters-" + contextId);
595
598
  }
596
599
 
@@ -632,7 +635,7 @@ public class Cactus implements LifecycleEventListener {
632
635
  promise.resolve(null);
633
636
  tasks.remove(this);
634
637
  }
635
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
638
+ }.executeOnExecutor(singleThreadExecutor);
636
639
  tasks.put(task, "releaseContext-" + contextId);
637
640
  }
638
641
 
@@ -659,7 +662,7 @@ public class Cactus implements LifecycleEventListener {
659
662
  promise.resolve(null);
660
663
  tasks.remove(this);
661
664
  }
662
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
665
+ }.executeOnExecutor(singleThreadExecutor);
663
666
  tasks.put(task, "releaseAllContexts");
664
667
  }
665
668
 
@@ -718,7 +721,7 @@ public class Cactus implements LifecycleEventListener {
718
721
  promise.resolve(result);
719
722
  tasks.remove(this);
720
723
  }
721
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
724
+ }.executeOnExecutor(singleThreadExecutor);
722
725
  tasks.put(task, "initMultimodal-" + contextId);
723
726
  }
724
727
 
@@ -750,7 +753,7 @@ public class Cactus implements LifecycleEventListener {
750
753
  promise.resolve(result);
751
754
  tasks.remove(this);
752
755
  }
753
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
756
+ }.executeOnExecutor(singleThreadExecutor);
754
757
  tasks.put(task, "isMultimodalEnabled-" + contextId);
755
758
  }
756
759
 
@@ -782,7 +785,7 @@ public class Cactus implements LifecycleEventListener {
782
785
  promise.resolve(result);
783
786
  tasks.remove(this);
784
787
  }
785
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
788
+ }.executeOnExecutor(singleThreadExecutor);
786
789
  tasks.put(task, "isMultimodalSupportVision-" + contextId);
787
790
  }
788
791
 
@@ -814,7 +817,7 @@ public class Cactus implements LifecycleEventListener {
814
817
  promise.resolve(result);
815
818
  tasks.remove(this);
816
819
  }
817
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
820
+ }.executeOnExecutor(singleThreadExecutor);
818
821
  tasks.put(task, "isMultimodalSupportAudio-" + contextId);
819
822
  }
820
823
 
@@ -846,7 +849,7 @@ public class Cactus implements LifecycleEventListener {
846
849
  promise.resolve(null);
847
850
  tasks.remove(this);
848
851
  }
849
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
852
+ }.executeOnExecutor(singleThreadExecutor);
850
853
  tasks.put(task, "releaseMultimodal-" + contextId);
851
854
  }
852
855
 
@@ -881,7 +884,7 @@ public class Cactus implements LifecycleEventListener {
881
884
  promise.resolve(result);
882
885
  tasks.remove(this);
883
886
  }
884
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
887
+ }.executeOnExecutor(singleThreadExecutor);
885
888
  tasks.put(task, "multimodalCompletion-" + contextId);
886
889
  }
887
890
 
@@ -913,7 +916,7 @@ public class Cactus implements LifecycleEventListener {
913
916
  promise.resolve(result);
914
917
  tasks.remove(this);
915
918
  }
916
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
919
+ }.executeOnExecutor(singleThreadExecutor);
917
920
  tasks.put(task, "initVocoder-" + contextId);
918
921
  }
919
922
 
@@ -945,7 +948,7 @@ public class Cactus implements LifecycleEventListener {
945
948
  promise.resolve(result);
946
949
  tasks.remove(this);
947
950
  }
948
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
951
+ }.executeOnExecutor(singleThreadExecutor);
949
952
  tasks.put(task, "isVocoderEnabled-" + contextId);
950
953
  }
951
954
 
@@ -977,7 +980,7 @@ public class Cactus implements LifecycleEventListener {
977
980
  promise.resolve(result);
978
981
  tasks.remove(this);
979
982
  }
980
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
983
+ }.executeOnExecutor(singleThreadExecutor);
981
984
  tasks.put(task, "getTTSType-" + contextId);
982
985
  }
983
986
 
@@ -1009,7 +1012,7 @@ public class Cactus implements LifecycleEventListener {
1009
1012
  promise.resolve(result);
1010
1013
  tasks.remove(this);
1011
1014
  }
1012
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
1015
+ }.executeOnExecutor(singleThreadExecutor);
1013
1016
  tasks.put(task, "getFormattedAudioCompletion-" + contextId);
1014
1017
  }
1015
1018
 
@@ -1041,7 +1044,7 @@ public class Cactus implements LifecycleEventListener {
1041
1044
  promise.resolve(result);
1042
1045
  tasks.remove(this);
1043
1046
  }
1044
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
1047
+ }.executeOnExecutor(singleThreadExecutor);
1045
1048
  tasks.put(task, "getAudioCompletionGuideTokens-" + contextId);
1046
1049
  }
1047
1050
 
@@ -1073,7 +1076,7 @@ public class Cactus implements LifecycleEventListener {
1073
1076
  promise.resolve(result);
1074
1077
  tasks.remove(this);
1075
1078
  }
1076
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
1079
+ }.executeOnExecutor(singleThreadExecutor);
1077
1080
  tasks.put(task, "decodeAudioTokens-" + contextId);
1078
1081
  }
1079
1082
 
@@ -1105,7 +1108,7 @@ public class Cactus implements LifecycleEventListener {
1105
1108
  promise.resolve(null);
1106
1109
  tasks.remove(this);
1107
1110
  }
1108
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
1111
+ }.executeOnExecutor(singleThreadExecutor);
1109
1112
  tasks.put(task, "releaseVocoder-" + contextId);
1110
1113
  }
1111
1114
  }
@@ -24,6 +24,7 @@ set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../cactus)
24
24
  # Define public headers
25
25
  set(PUBLIC_HEADERS
26
26
  ${SOURCE_DIR}/cactus.h
27
+ ${SOURCE_DIR}/cactus_ffi.h
27
28
  ${SOURCE_DIR}/llama.h
28
29
  ${SOURCE_DIR}/llama-impl.h
29
30
  ${SOURCE_DIR}/ggml.h
@@ -42,6 +43,7 @@ add_library(cactus SHARED
42
43
  ${SOURCE_DIR}/cactus_tts.cpp
43
44
  ${SOURCE_DIR}/cactus_bench.cpp
44
45
  ${SOURCE_DIR}/cactus_chat.cpp
46
+ ${SOURCE_DIR}/cactus_ffi.cpp
45
47
  ${SOURCE_DIR}/tools/mtmd/mtmd.cpp
46
48
  ${SOURCE_DIR}/tools/mtmd/mtmd-audio.cpp
47
49
  ${SOURCE_DIR}/tools/mtmd/clip.cpp
@@ -127,6 +127,15 @@ CACTUS_FFI_EXPORT int cactus_completion_c(
127
127
  cactus_completion_result_c_t* result
128
128
  );
129
129
 
130
+ // **MULTIMODAL COMPLETION**
131
+ CACTUS_FFI_EXPORT int cactus_multimodal_completion_c(
132
+ cactus_context_handle_t handle,
133
+ const cactus_completion_params_c_t* params,
134
+ const char** media_paths,
135
+ int media_count,
136
+ cactus_completion_result_c_t* result
137
+ );
138
+
130
139
  CACTUS_FFI_EXPORT void cactus_stop_completion_c(cactus_context_handle_t handle);
131
140
 
132
141
  CACTUS_FFI_EXPORT cactus_token_array_c_t cactus_tokenize_c(cactus_context_handle_t handle, const char* text);
@@ -207,10 +216,39 @@ CACTUS_FFI_EXPORT cactus_lora_adapters_c_t cactus_get_loaded_lora_adapters_c(cac
207
216
  CACTUS_FFI_EXPORT bool cactus_validate_chat_template_c(cactus_context_handle_t handle, bool use_jinja, const char* name);
208
217
  CACTUS_FFI_EXPORT char* cactus_get_formatted_chat_c(cactus_context_handle_t handle, const char* messages, const char* chat_template);
209
218
 
219
+ // **ADVANCED: Chat with Jinja and Tools Support**
220
+ typedef struct {
221
+ char* prompt;
222
+ char* json_schema;
223
+ char* tools;
224
+ char* tool_choice;
225
+ bool parallel_tool_calls;
226
+ } cactus_chat_result_c_t;
227
+
228
+ CACTUS_FFI_EXPORT cactus_chat_result_c_t cactus_get_formatted_chat_with_jinja_c(
229
+ cactus_context_handle_t handle,
230
+ const char* messages,
231
+ const char* chat_template,
232
+ const char* json_schema,
233
+ const char* tools,
234
+ bool parallel_tool_calls,
235
+ const char* tool_choice
236
+ );
237
+
210
238
  // **HIGH PRIORITY: Context Management**
211
239
  CACTUS_FFI_EXPORT void cactus_rewind_c(cactus_context_handle_t handle);
212
240
  CACTUS_FFI_EXPORT bool cactus_init_sampling_c(cactus_context_handle_t handle);
213
241
 
242
+ // **COMPLETION CONTROL**
243
+ CACTUS_FFI_EXPORT void cactus_begin_completion_c(cactus_context_handle_t handle);
244
+ CACTUS_FFI_EXPORT void cactus_end_completion_c(cactus_context_handle_t handle);
245
+ CACTUS_FFI_EXPORT void cactus_load_prompt_c(cactus_context_handle_t handle);
246
+ CACTUS_FFI_EXPORT void cactus_load_prompt_with_media_c(cactus_context_handle_t handle, const char** media_paths, int media_count);
247
+
248
+ // **TOKEN PROCESSING**
249
+ CACTUS_FFI_EXPORT int cactus_do_completion_step_c(cactus_context_handle_t handle, char** token_text);
250
+ CACTUS_FFI_EXPORT size_t cactus_find_stopping_strings_c(cactus_context_handle_t handle, const char* text, size_t last_token_size, int stop_type);
251
+
214
252
  // **HIGH PRIORITY: Model Information**
215
253
  CACTUS_FFI_EXPORT int32_t cactus_get_n_ctx_c(cactus_context_handle_t handle);
216
254
  CACTUS_FFI_EXPORT int32_t cactus_get_n_embd_c(cactus_context_handle_t handle);
@@ -221,6 +259,7 @@ CACTUS_FFI_EXPORT int64_t cactus_get_model_params_c(cactus_context_handle_t hand
221
259
  // Memory management functions
222
260
  CACTUS_FFI_EXPORT void cactus_free_bench_result_members_c(cactus_bench_result_c_t* result);
223
261
  CACTUS_FFI_EXPORT void cactus_free_lora_adapters_c(cactus_lora_adapters_c_t* adapters);
262
+ CACTUS_FFI_EXPORT void cactus_free_chat_result_members_c(cactus_chat_result_c_t* result);
224
263
 
225
264
  #ifdef __cplusplus
226
265
  }
@@ -127,6 +127,15 @@ CACTUS_FFI_EXPORT int cactus_completion_c(
127
127
  cactus_completion_result_c_t* result
128
128
  );
129
129
 
130
+ // **MULTIMODAL COMPLETION**
131
+ CACTUS_FFI_EXPORT int cactus_multimodal_completion_c(
132
+ cactus_context_handle_t handle,
133
+ const cactus_completion_params_c_t* params,
134
+ const char** media_paths,
135
+ int media_count,
136
+ cactus_completion_result_c_t* result
137
+ );
138
+
130
139
  CACTUS_FFI_EXPORT void cactus_stop_completion_c(cactus_context_handle_t handle);
131
140
 
132
141
  CACTUS_FFI_EXPORT cactus_token_array_c_t cactus_tokenize_c(cactus_context_handle_t handle, const char* text);
@@ -207,10 +216,39 @@ CACTUS_FFI_EXPORT cactus_lora_adapters_c_t cactus_get_loaded_lora_adapters_c(cac
207
216
  CACTUS_FFI_EXPORT bool cactus_validate_chat_template_c(cactus_context_handle_t handle, bool use_jinja, const char* name);
208
217
  CACTUS_FFI_EXPORT char* cactus_get_formatted_chat_c(cactus_context_handle_t handle, const char* messages, const char* chat_template);
209
218
 
219
+ // **ADVANCED: Chat with Jinja and Tools Support**
220
+ typedef struct {
221
+ char* prompt;
222
+ char* json_schema;
223
+ char* tools;
224
+ char* tool_choice;
225
+ bool parallel_tool_calls;
226
+ } cactus_chat_result_c_t;
227
+
228
+ CACTUS_FFI_EXPORT cactus_chat_result_c_t cactus_get_formatted_chat_with_jinja_c(
229
+ cactus_context_handle_t handle,
230
+ const char* messages,
231
+ const char* chat_template,
232
+ const char* json_schema,
233
+ const char* tools,
234
+ bool parallel_tool_calls,
235
+ const char* tool_choice
236
+ );
237
+
210
238
  // **HIGH PRIORITY: Context Management**
211
239
  CACTUS_FFI_EXPORT void cactus_rewind_c(cactus_context_handle_t handle);
212
240
  CACTUS_FFI_EXPORT bool cactus_init_sampling_c(cactus_context_handle_t handle);
213
241
 
242
+ // **COMPLETION CONTROL**
243
+ CACTUS_FFI_EXPORT void cactus_begin_completion_c(cactus_context_handle_t handle);
244
+ CACTUS_FFI_EXPORT void cactus_end_completion_c(cactus_context_handle_t handle);
245
+ CACTUS_FFI_EXPORT void cactus_load_prompt_c(cactus_context_handle_t handle);
246
+ CACTUS_FFI_EXPORT void cactus_load_prompt_with_media_c(cactus_context_handle_t handle, const char** media_paths, int media_count);
247
+
248
+ // **TOKEN PROCESSING**
249
+ CACTUS_FFI_EXPORT int cactus_do_completion_step_c(cactus_context_handle_t handle, char** token_text);
250
+ CACTUS_FFI_EXPORT size_t cactus_find_stopping_strings_c(cactus_context_handle_t handle, const char* text, size_t last_token_size, int stop_type);
251
+
214
252
  // **HIGH PRIORITY: Model Information**
215
253
  CACTUS_FFI_EXPORT int32_t cactus_get_n_ctx_c(cactus_context_handle_t handle);
216
254
  CACTUS_FFI_EXPORT int32_t cactus_get_n_embd_c(cactus_context_handle_t handle);
@@ -221,6 +259,7 @@ CACTUS_FFI_EXPORT int64_t cactus_get_model_params_c(cactus_context_handle_t hand
221
259
  // Memory management functions
222
260
  CACTUS_FFI_EXPORT void cactus_free_bench_result_members_c(cactus_bench_result_c_t* result);
223
261
  CACTUS_FFI_EXPORT void cactus_free_lora_adapters_c(cactus_lora_adapters_c_t* adapters);
262
+ CACTUS_FFI_EXPORT void cactus_free_chat_result_members_c(cactus_chat_result_c_t* result);
224
263
 
225
264
  #ifdef __cplusplus
226
265
  }
@@ -127,6 +127,15 @@ CACTUS_FFI_EXPORT int cactus_completion_c(
127
127
  cactus_completion_result_c_t* result
128
128
  );
129
129
 
130
+ // **MULTIMODAL COMPLETION**
131
+ CACTUS_FFI_EXPORT int cactus_multimodal_completion_c(
132
+ cactus_context_handle_t handle,
133
+ const cactus_completion_params_c_t* params,
134
+ const char** media_paths,
135
+ int media_count,
136
+ cactus_completion_result_c_t* result
137
+ );
138
+
130
139
  CACTUS_FFI_EXPORT void cactus_stop_completion_c(cactus_context_handle_t handle);
131
140
 
132
141
  CACTUS_FFI_EXPORT cactus_token_array_c_t cactus_tokenize_c(cactus_context_handle_t handle, const char* text);
@@ -207,10 +216,39 @@ CACTUS_FFI_EXPORT cactus_lora_adapters_c_t cactus_get_loaded_lora_adapters_c(cac
207
216
  CACTUS_FFI_EXPORT bool cactus_validate_chat_template_c(cactus_context_handle_t handle, bool use_jinja, const char* name);
208
217
  CACTUS_FFI_EXPORT char* cactus_get_formatted_chat_c(cactus_context_handle_t handle, const char* messages, const char* chat_template);
209
218
 
219
+ // **ADVANCED: Chat with Jinja and Tools Support**
220
+ typedef struct {
221
+ char* prompt;
222
+ char* json_schema;
223
+ char* tools;
224
+ char* tool_choice;
225
+ bool parallel_tool_calls;
226
+ } cactus_chat_result_c_t;
227
+
228
+ CACTUS_FFI_EXPORT cactus_chat_result_c_t cactus_get_formatted_chat_with_jinja_c(
229
+ cactus_context_handle_t handle,
230
+ const char* messages,
231
+ const char* chat_template,
232
+ const char* json_schema,
233
+ const char* tools,
234
+ bool parallel_tool_calls,
235
+ const char* tool_choice
236
+ );
237
+
210
238
  // **HIGH PRIORITY: Context Management**
211
239
  CACTUS_FFI_EXPORT void cactus_rewind_c(cactus_context_handle_t handle);
212
240
  CACTUS_FFI_EXPORT bool cactus_init_sampling_c(cactus_context_handle_t handle);
213
241
 
242
+ // **COMPLETION CONTROL**
243
+ CACTUS_FFI_EXPORT void cactus_begin_completion_c(cactus_context_handle_t handle);
244
+ CACTUS_FFI_EXPORT void cactus_end_completion_c(cactus_context_handle_t handle);
245
+ CACTUS_FFI_EXPORT void cactus_load_prompt_c(cactus_context_handle_t handle);
246
+ CACTUS_FFI_EXPORT void cactus_load_prompt_with_media_c(cactus_context_handle_t handle, const char** media_paths, int media_count);
247
+
248
+ // **TOKEN PROCESSING**
249
+ CACTUS_FFI_EXPORT int cactus_do_completion_step_c(cactus_context_handle_t handle, char** token_text);
250
+ CACTUS_FFI_EXPORT size_t cactus_find_stopping_strings_c(cactus_context_handle_t handle, const char* text, size_t last_token_size, int stop_type);
251
+
214
252
  // **HIGH PRIORITY: Model Information**
215
253
  CACTUS_FFI_EXPORT int32_t cactus_get_n_ctx_c(cactus_context_handle_t handle);
216
254
  CACTUS_FFI_EXPORT int32_t cactus_get_n_embd_c(cactus_context_handle_t handle);
@@ -221,6 +259,7 @@ CACTUS_FFI_EXPORT int64_t cactus_get_model_params_c(cactus_context_handle_t hand
221
259
  // Memory management functions
222
260
  CACTUS_FFI_EXPORT void cactus_free_bench_result_members_c(cactus_bench_result_c_t* result);
223
261
  CACTUS_FFI_EXPORT void cactus_free_lora_adapters_c(cactus_lora_adapters_c_t* adapters);
262
+ CACTUS_FFI_EXPORT void cactus_free_chat_result_members_c(cactus_chat_result_c_t* result);
224
263
 
225
264
  #ifdef __cplusplus
226
265
  }
@@ -127,6 +127,15 @@ CACTUS_FFI_EXPORT int cactus_completion_c(
127
127
  cactus_completion_result_c_t* result
128
128
  );
129
129
 
130
+ // **MULTIMODAL COMPLETION**
131
+ CACTUS_FFI_EXPORT int cactus_multimodal_completion_c(
132
+ cactus_context_handle_t handle,
133
+ const cactus_completion_params_c_t* params,
134
+ const char** media_paths,
135
+ int media_count,
136
+ cactus_completion_result_c_t* result
137
+ );
138
+
130
139
  CACTUS_FFI_EXPORT void cactus_stop_completion_c(cactus_context_handle_t handle);
131
140
 
132
141
  CACTUS_FFI_EXPORT cactus_token_array_c_t cactus_tokenize_c(cactus_context_handle_t handle, const char* text);
@@ -207,10 +216,39 @@ CACTUS_FFI_EXPORT cactus_lora_adapters_c_t cactus_get_loaded_lora_adapters_c(cac
207
216
  CACTUS_FFI_EXPORT bool cactus_validate_chat_template_c(cactus_context_handle_t handle, bool use_jinja, const char* name);
208
217
  CACTUS_FFI_EXPORT char* cactus_get_formatted_chat_c(cactus_context_handle_t handle, const char* messages, const char* chat_template);
209
218
 
219
+ // **ADVANCED: Chat with Jinja and Tools Support**
220
+ typedef struct {
221
+ char* prompt;
222
+ char* json_schema;
223
+ char* tools;
224
+ char* tool_choice;
225
+ bool parallel_tool_calls;
226
+ } cactus_chat_result_c_t;
227
+
228
+ CACTUS_FFI_EXPORT cactus_chat_result_c_t cactus_get_formatted_chat_with_jinja_c(
229
+ cactus_context_handle_t handle,
230
+ const char* messages,
231
+ const char* chat_template,
232
+ const char* json_schema,
233
+ const char* tools,
234
+ bool parallel_tool_calls,
235
+ const char* tool_choice
236
+ );
237
+
210
238
  // **HIGH PRIORITY: Context Management**
211
239
  CACTUS_FFI_EXPORT void cactus_rewind_c(cactus_context_handle_t handle);
212
240
  CACTUS_FFI_EXPORT bool cactus_init_sampling_c(cactus_context_handle_t handle);
213
241
 
242
+ // **COMPLETION CONTROL**
243
+ CACTUS_FFI_EXPORT void cactus_begin_completion_c(cactus_context_handle_t handle);
244
+ CACTUS_FFI_EXPORT void cactus_end_completion_c(cactus_context_handle_t handle);
245
+ CACTUS_FFI_EXPORT void cactus_load_prompt_c(cactus_context_handle_t handle);
246
+ CACTUS_FFI_EXPORT void cactus_load_prompt_with_media_c(cactus_context_handle_t handle, const char** media_paths, int media_count);
247
+
248
+ // **TOKEN PROCESSING**
249
+ CACTUS_FFI_EXPORT int cactus_do_completion_step_c(cactus_context_handle_t handle, char** token_text);
250
+ CACTUS_FFI_EXPORT size_t cactus_find_stopping_strings_c(cactus_context_handle_t handle, const char* text, size_t last_token_size, int stop_type);
251
+
214
252
  // **HIGH PRIORITY: Model Information**
215
253
  CACTUS_FFI_EXPORT int32_t cactus_get_n_ctx_c(cactus_context_handle_t handle);
216
254
  CACTUS_FFI_EXPORT int32_t cactus_get_n_embd_c(cactus_context_handle_t handle);
@@ -221,6 +259,7 @@ CACTUS_FFI_EXPORT int64_t cactus_get_model_params_c(cactus_context_handle_t hand
221
259
  // Memory management functions
222
260
  CACTUS_FFI_EXPORT void cactus_free_bench_result_members_c(cactus_bench_result_c_t* result);
223
261
  CACTUS_FFI_EXPORT void cactus_free_lora_adapters_c(cactus_lora_adapters_c_t* adapters);
262
+ CACTUS_FFI_EXPORT void cactus_free_chat_result_members_c(cactus_chat_result_c_t* result);
224
263
 
225
264
  #ifdef __cplusplus
226
265
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cactus-react-native",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Run AI models locally on mobile devices",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",