@elizaos/app-core 2.0.3-beta.4 → 2.0.3-beta.6

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.
Files changed (97) hide show
  1. package/api/i18n-locale-routes.d.ts +7 -0
  2. package/api/i18n-locale-routes.d.ts.map +1 -0
  3. package/api/i18n-locale-routes.js +58 -0
  4. package/api/ios-local-agent-transport.d.ts +3 -0
  5. package/api/ios-local-agent-transport.d.ts.map +1 -1
  6. package/api/ios-local-agent-transport.js +22 -1
  7. package/api/server.d.ts.map +1 -1
  8. package/api/server.js +5 -0
  9. package/benchmark/cerebras-autowire.d.ts.map +1 -1
  10. package/benchmark/cerebras-autowire.js +9 -2
  11. package/package.json +36 -36
  12. package/packaging/debian/rules +1 -1
  13. package/packaging/flatpak/generate-sources.sh +6 -1
  14. package/packaging/snap/snapcraft.yaml +15 -11
  15. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaAgentService.java +2 -1
  16. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaNativeBridge.java +5 -0
  17. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaStartupTrace.java +28 -0
  18. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoicePlugin.java +1 -1
  19. package/platforms/android/app/src/main/java/ai/elizaos/app/MainActivity.java +1 -0
  20. package/platforms/electrobun/electrobun.config.ts +31 -1
  21. package/platforms/electrobun/package.json +10 -10
  22. package/platforms/electrobun/remotes/local-model/README.md +2 -5
  23. package/platforms/electrobun/remotes/local-model/src/bun/eliza1-catalog.ts +0 -16
  24. package/platforms/electrobun/remotes/local-model/src/dev/phase8-smoke.ts +0 -2
  25. package/platforms/electrobun/scripts/smoke-test.sh +8 -2
  26. package/platforms/electrobun/scripts/stage-macos-release-artifacts.sh +8 -2
  27. package/platforms/electrobun/scripts/sync-web-assets.mjs +31 -2
  28. package/platforms/electrobun/src/bridge/electrobun-boot-config.ts +8 -0
  29. package/platforms/electrobun/src/bridge/electrobun-crypto-ready.ts +5 -1
  30. package/platforms/electrobun/src/bridge/electrobun-direct-rpc.ts +5 -11
  31. package/platforms/electrobun/src/preload.js +1 -1
  32. package/platforms/ios/App/App/Base.lproj/Main.storyboard +1 -1
  33. package/platforms/ios/App/App/ElizaBridgeViewController.swift +22 -0
  34. package/platforms/ios/App/App/ElizaStartupTrace.swift +12 -0
  35. package/platforms/ios/App/App.xcodeproj/project.pbxproj +8 -0
  36. package/runtime/eliza.d.ts.map +1 -1
  37. package/runtime/eliza.js +18 -0
  38. package/runtime/voice-warmup.d.ts +4 -4
  39. package/runtime/voice-warmup.d.ts.map +1 -1
  40. package/runtime/voice-warmup.js +4 -4
  41. package/scripts/aosp/compile-libllama.mjs +25 -5
  42. package/scripts/aosp/compile-libllama.test.mjs +17 -1
  43. package/scripts/assert-required-bundled-packages.test.ts +24 -2
  44. package/scripts/benchmark-preflight.mjs +31 -2
  45. package/scripts/build-bundled-agent-skills-artifact.mjs +32 -8
  46. package/scripts/build-bundled-orchestrator-artifact.mjs +34 -12
  47. package/scripts/build-llama-cpp-mtp.mjs +27 -3
  48. package/scripts/build-patched-electrobun-cli.mjs +30 -2
  49. package/scripts/bun-riscv64/bun-version.json +1 -1
  50. package/scripts/bun-riscv64/validate.sh +21 -8
  51. package/scripts/check-real-local-reset.ts +13 -1
  52. package/scripts/check-sms-gateway-completion-audit.mjs +96 -31
  53. package/scripts/check-sms-gateway-readiness.mjs +54 -17
  54. package/scripts/clean-repo.mjs +21 -3
  55. package/scripts/copy-runtime-node-modules.ts +68 -63
  56. package/scripts/desktop-build.mjs +46 -5
  57. package/scripts/dev-platform-no-install.test.mjs +19 -0
  58. package/scripts/dev-platform.mjs +6 -2
  59. package/scripts/disable-local-eliza-workspace.mjs +23 -1
  60. package/scripts/docker-ci-smoke.sh +6 -5
  61. package/scripts/ensure-avatars.mjs +18 -5
  62. package/scripts/ensure-bundled-workspaces.mjs +4 -15
  63. package/scripts/ensure-type-package-aliases.mjs +47 -3
  64. package/scripts/ffi-stub/Makefile +5 -2
  65. package/scripts/ios-xcframework/build-xcframework.mjs +22 -11
  66. package/scripts/ios-xcframework/run-physical-device-smoke.mjs +99 -6
  67. package/scripts/ios-xcframework/runtime-symbol-shim.c +560 -105
  68. package/scripts/lib/agent-source-watcher.test.mjs +24 -4
  69. package/scripts/lib/apple-entitlement-audit.test.mjs +19 -2
  70. package/scripts/lib/artifact-staleness.test.mts +18 -1
  71. package/scripts/lib/patch-bun-exports.mjs +20 -2
  72. package/scripts/lib/patch-bun-exports.test.mjs +108 -4
  73. package/scripts/lib/renderer-build-manifest.test.mts +18 -1
  74. package/scripts/lib/stage-android-agent.mjs +16 -3
  75. package/scripts/lib/verify-ondevice-artifact.test.mts +18 -1
  76. package/scripts/link-docker-local-app-packages.mjs +26 -1
  77. package/scripts/mas-smoke.test.mjs +25 -9
  78. package/scripts/omnivoice-fuse/prepare.mjs +27 -4
  79. package/scripts/package-electrobun-linux.mjs +22 -7
  80. package/scripts/patch-deps.mjs +18 -5
  81. package/scripts/playwright-ui-live-stack.ts +16 -3
  82. package/scripts/playwright-ui-smoke-api-stub.mjs +167 -2
  83. package/scripts/prepare-ios-cocoapods.sh +5 -1
  84. package/scripts/prune-cdn-local-assets.mjs +52 -5
  85. package/scripts/run-mobile-build-android-app-actions.test.mjs +19 -1
  86. package/scripts/run-mobile-build-mtp-staleness.test.mts +20 -4
  87. package/scripts/run-mobile-build.mjs +74 -16
  88. package/scripts/stage-android-agent.test.mjs +19 -1
  89. package/scripts/stage-desktop-fused-lib.mjs +26 -1
  90. package/scripts/sync-desktop-renderer.mjs +53 -12
  91. package/scripts/test-sms-gateway-software.mjs +20 -4
  92. package/cli/command-format.d.ts +0 -2
  93. package/cli/command-format.d.ts.map +0 -1
  94. package/cli/command-format.js +0 -20
  95. package/register-runtime-hooks.d.ts +0 -2
  96. package/register-runtime-hooks.d.ts.map +0 -1
  97. package/register-runtime-hooks.js +0 -19
@@ -8,110 +8,36 @@
8
8
  * expects the libelizainference ABI v1 exports.
9
9
  *
10
10
  * This file provides those ABI entry points for link/device-smoke validation.
11
- * It does not fake inference. Text entry points return "not loaded" until the
12
- * mobile bridge is wired to a real llama context, and voice entry points return
13
- * explicit unsupported / missing-model errors until real OmniVoice assets are
14
- * present in the bundle. Missing optimized kernels remain handled by the
15
- * generated CAPABILITIES.json gate.
11
+ * Text entry points run a real llama context for the mobile benchmark harness,
12
+ * and voice entry points return explicit unsupported / missing-model errors
13
+ * until real OmniVoice assets are present in the bundle. Missing optimized
14
+ * kernels remain handled by the generated CAPABILITIES.json gate.
16
15
  */
17
16
 
18
17
  #include <stdbool.h>
18
+ #include <stdio.h>
19
19
  #include <stdint.h>
20
20
  #include <stdlib.h>
21
21
  #include <string.h>
22
+ #include <pthread.h>
22
23
 
23
24
  #include "../ffi-stub/ffi.h"
25
+ #include "llama.h"
24
26
 
25
27
  #define ELIZA_INFERENCE_ABI_VERSION_STRING "1"
26
-
27
- typedef int32_t llama_token;
28
- typedef int32_t llama_pos;
29
- typedef int32_t llama_seq_id;
30
-
31
- struct llama_model_tensor_buft_override {
32
- const char * pattern;
33
- void * buft;
34
- };
35
-
36
- struct llama_model_kv_override;
37
-
38
- struct llama_model_params {
39
- void ** devices;
40
- const struct llama_model_tensor_buft_override * tensor_buft_overrides;
41
- int32_t n_gpu_layers;
42
- int split_mode;
43
- int32_t main_gpu;
44
- const float * tensor_split;
45
- void * progress_callback;
46
- void * progress_callback_user_data;
47
- const struct llama_model_kv_override * kv_overrides;
48
- bool vocab_only;
49
- bool use_mmap;
50
- bool use_direct_io;
51
- bool use_mlock;
52
- bool check_tensors;
53
- bool use_extra_bufts;
54
- bool no_host;
55
- bool no_alloc;
56
- };
57
-
58
- struct llama_sampler_seq_config {
59
- llama_seq_id seq_id;
60
- void * sampler;
61
- };
62
-
63
- struct llama_context_params {
64
- uint32_t n_ctx;
65
- uint32_t n_batch;
66
- uint32_t n_ubatch;
67
- uint32_t n_seq_max;
68
- int32_t n_threads;
69
- int32_t n_threads_batch;
70
- int rope_scaling_type;
71
- int pooling_type;
72
- int attention_type;
73
- int flash_attn_type;
74
- float rope_freq_base;
75
- float rope_freq_scale;
76
- float yarn_ext_factor;
77
- float yarn_attn_factor;
78
- float yarn_beta_fast;
79
- float yarn_beta_slow;
80
- uint32_t yarn_orig_ctx;
81
- float defrag_thold;
82
- void * cb_eval;
83
- void * cb_eval_user_data;
84
- int type_k;
85
- int type_v;
86
- void * abort_callback;
87
- void * abort_callback_data;
88
- bool embeddings;
89
- bool offload_kqv;
90
- bool no_perf;
91
- bool op_offload;
92
- bool swa_full;
93
- bool kv_unified;
94
- struct llama_sampler_seq_config * samplers;
95
- size_t n_samplers;
96
- };
97
-
98
- struct llama_batch {
99
- int32_t n_tokens;
100
- llama_token * token;
101
- float * embd;
102
- llama_pos * pos;
103
- int32_t * n_seq_id;
104
- llama_seq_id ** seq_id;
105
- int8_t * logits;
106
- };
107
-
108
- extern void llama_log_set(void * log_callback, void * user_data);
109
- extern bool llama_supports_gpu_offload(void);
28
+ #define ELIZA_IOS_MAX_TEXT_CONTEXTS 8
110
29
 
111
30
  struct EliInferenceContext {
112
31
  char * bundle_dir;
113
32
  };
114
33
 
34
+ struct ElizaTextContext {
35
+ int64_t id;
36
+ struct llama_model * model;
37
+ struct llama_context * ctx;
38
+ const struct llama_vocab * vocab;
39
+ };
40
+
115
41
  static char * eliza_dup_cstr(const char * s) {
116
42
  const char * value = s != NULL ? s : "";
117
43
  const size_t len = strlen(value);
@@ -134,6 +60,223 @@ static void set_out_error(char ** out_error, const char * msg) {
134
60
  }
135
61
  }
136
62
 
63
+ static pthread_mutex_t g_text_context_lock = PTHREAD_MUTEX_INITIALIZER;
64
+ static bool g_llama_backend_initialized = false;
65
+ static bool g_llama_device_backends_loaded = false;
66
+ static ggml_backend_dev_t g_cpu_only_devices[2] = {NULL, NULL};
67
+ static int64_t g_next_text_context_id = 1;
68
+ static struct ElizaTextContext * g_text_contexts[ELIZA_IOS_MAX_TEXT_CONTEXTS];
69
+
70
+ static const char * find_json_key(const char * json, const char * key) {
71
+ if (json == NULL || key == NULL) return NULL;
72
+ char pattern[96];
73
+ const int written = snprintf(pattern, sizeof(pattern), "\"%s\"", key);
74
+ if (written <= 0 || (size_t) written >= sizeof(pattern)) return NULL;
75
+ const char * p = strstr(json, pattern);
76
+ if (p == NULL) return NULL;
77
+ p = strchr(p + written, ':');
78
+ return p != NULL ? p + 1 : NULL;
79
+ }
80
+
81
+ static int json_int_param(const char * json, const char * key, int fallback) {
82
+ const char * value = find_json_key(json, key);
83
+ if (value == NULL) return fallback;
84
+ char * end = NULL;
85
+ const long parsed = strtol(value, &end, 10);
86
+ return end != value ? (int) parsed : fallback;
87
+ }
88
+
89
+ static double json_double_param(
90
+ const char * json,
91
+ const char * key,
92
+ double fallback) {
93
+ const char * value = find_json_key(json, key);
94
+ if (value == NULL) return fallback;
95
+ char * end = NULL;
96
+ const double parsed = strtod(value, &end);
97
+ return end != value ? parsed : fallback;
98
+ }
99
+
100
+ static bool json_bool_param(
101
+ const char * json,
102
+ const char * key,
103
+ bool fallback) {
104
+ const char * value = find_json_key(json, key);
105
+ if (value == NULL) return fallback;
106
+ while (*value == ' ' || *value == '\t' || *value == '\n' || *value == '\r') {
107
+ value++;
108
+ }
109
+ if (strncmp(value, "true", 4) == 0) return true;
110
+ if (strncmp(value, "false", 5) == 0) return false;
111
+ return fallback;
112
+ }
113
+
114
+ static char * json_error(const char * stage, const char * message) {
115
+ const char * safe_stage = stage != NULL ? stage : "unknown";
116
+ const char * safe_message = message != NULL ? message : "unknown error";
117
+ const size_t len = strlen(safe_stage) + strlen(safe_message) + 48;
118
+ char * out = (char *) malloc(len);
119
+ if (out == NULL) return NULL;
120
+ snprintf(
121
+ out,
122
+ len,
123
+ "{\"error\":\"%s\",\"stage\":\"%s\"}",
124
+ safe_message,
125
+ safe_stage);
126
+ return out;
127
+ }
128
+
129
+ static bool append_bytes(
130
+ char ** buffer,
131
+ size_t * length,
132
+ size_t * capacity,
133
+ const char * bytes,
134
+ size_t n) {
135
+ if (n == 0) return true;
136
+ if (*length + n + 1 > *capacity) {
137
+ size_t next = *capacity > 0 ? *capacity : 128;
138
+ while (*length + n + 1 > next) next *= 2;
139
+ char * grown = (char *) realloc(*buffer, next);
140
+ if (grown == NULL) return false;
141
+ *buffer = grown;
142
+ *capacity = next;
143
+ }
144
+ memcpy(*buffer + *length, bytes, n);
145
+ *length += n;
146
+ (*buffer)[*length] = '\0';
147
+ return true;
148
+ }
149
+
150
+ static char * json_escape(const char * value) {
151
+ const char * text = value != NULL ? value : "";
152
+ size_t capacity = strlen(text) * 2 + 1;
153
+ char * out = (char *) malloc(capacity);
154
+ if (out == NULL) return NULL;
155
+ size_t length = 0;
156
+ out[0] = '\0';
157
+
158
+ for (const unsigned char * p = (const unsigned char *) text; *p != '\0'; p++) {
159
+ char escaped[7];
160
+ const char * chunk = NULL;
161
+ size_t chunk_len = 0;
162
+ switch (*p) {
163
+ case '\\':
164
+ chunk = "\\\\";
165
+ chunk_len = 2;
166
+ break;
167
+ case '"':
168
+ chunk = "\\\"";
169
+ chunk_len = 2;
170
+ break;
171
+ case '\n':
172
+ chunk = "\\n";
173
+ chunk_len = 2;
174
+ break;
175
+ case '\r':
176
+ chunk = "\\r";
177
+ chunk_len = 2;
178
+ break;
179
+ case '\t':
180
+ chunk = "\\t";
181
+ chunk_len = 2;
182
+ break;
183
+ default:
184
+ if (*p < 0x20) {
185
+ snprintf(escaped, sizeof(escaped), "\\u%04x", *p);
186
+ chunk = escaped;
187
+ chunk_len = 6;
188
+ } else {
189
+ escaped[0] = (char) *p;
190
+ chunk = escaped;
191
+ chunk_len = 1;
192
+ }
193
+ break;
194
+ }
195
+ if (!append_bytes(&out, &length, &capacity, chunk, chunk_len)) {
196
+ free(out);
197
+ return NULL;
198
+ }
199
+ }
200
+ return out;
201
+ }
202
+
203
+ static void ensure_llama_backend_initialized(bool load_device_backends) {
204
+ pthread_mutex_lock(&g_text_context_lock);
205
+ if (!g_llama_backend_initialized) {
206
+ llama_backend_init();
207
+ g_llama_backend_initialized = true;
208
+ }
209
+ if (load_device_backends && !g_llama_device_backends_loaded) {
210
+ ggml_backend_load_all();
211
+ g_llama_device_backends_loaded = true;
212
+ }
213
+ pthread_mutex_unlock(&g_text_context_lock);
214
+ }
215
+
216
+ static bool configure_cpu_only_devices(struct llama_model_params * model_params) {
217
+ pthread_mutex_lock(&g_text_context_lock);
218
+ ggml_backend_dev_t cpu_dev =
219
+ ggml_backend_dev_by_type(GGML_BACKEND_DEVICE_TYPE_CPU);
220
+ if (cpu_dev != NULL) {
221
+ g_cpu_only_devices[0] = cpu_dev;
222
+ g_cpu_only_devices[1] = NULL;
223
+ model_params->devices = g_cpu_only_devices;
224
+ }
225
+ pthread_mutex_unlock(&g_text_context_lock);
226
+ return cpu_dev != NULL;
227
+ }
228
+
229
+ static int store_text_context(struct ElizaTextContext * text_context) {
230
+ int slot = -1;
231
+ pthread_mutex_lock(&g_text_context_lock);
232
+ for (int i = 0; i < ELIZA_IOS_MAX_TEXT_CONTEXTS; i++) {
233
+ if (g_text_contexts[i] == NULL) {
234
+ slot = i;
235
+ break;
236
+ }
237
+ }
238
+ if (slot >= 0) {
239
+ text_context->id = g_next_text_context_id++;
240
+ g_text_contexts[slot] = text_context;
241
+ }
242
+ pthread_mutex_unlock(&g_text_context_lock);
243
+ return slot;
244
+ }
245
+
246
+ static struct ElizaTextContext * get_text_context(int64_t context_id) {
247
+ struct ElizaTextContext * found = NULL;
248
+ pthread_mutex_lock(&g_text_context_lock);
249
+ for (int i = 0; i < ELIZA_IOS_MAX_TEXT_CONTEXTS; i++) {
250
+ if (g_text_contexts[i] != NULL && g_text_contexts[i]->id == context_id) {
251
+ found = g_text_contexts[i];
252
+ break;
253
+ }
254
+ }
255
+ pthread_mutex_unlock(&g_text_context_lock);
256
+ return found;
257
+ }
258
+
259
+ static struct ElizaTextContext * take_text_context(int64_t context_id) {
260
+ struct ElizaTextContext * found = NULL;
261
+ pthread_mutex_lock(&g_text_context_lock);
262
+ for (int i = 0; i < ELIZA_IOS_MAX_TEXT_CONTEXTS; i++) {
263
+ if (g_text_contexts[i] != NULL && g_text_contexts[i]->id == context_id) {
264
+ found = g_text_contexts[i];
265
+ g_text_contexts[i] = NULL;
266
+ break;
267
+ }
268
+ }
269
+ pthread_mutex_unlock(&g_text_context_lock);
270
+ return found;
271
+ }
272
+
273
+ static void free_text_context(struct ElizaTextContext * text_context) {
274
+ if (text_context == NULL) return;
275
+ if (text_context->ctx != NULL) llama_free(text_context->ctx);
276
+ if (text_context->model != NULL) llama_model_free(text_context->model);
277
+ free(text_context);
278
+ }
279
+
137
280
  /* ---- llama-cpp-capacitor bridge exports --------------------------- */
138
281
 
139
282
  char * llama_get_last_error(void) {
@@ -146,26 +289,314 @@ void llama_free_string(char * value) {
146
289
  }
147
290
 
148
291
  int64_t llama_init_context(const char * model_path, const char * params_json) {
149
- (void) params_json;
150
292
  if (model_path == NULL || model_path[0] == '\0') {
151
293
  set_last_error("llama_init_context requires a model path");
152
- } else {
153
- set_last_error(
154
- "iOS static bridge is link-ready but real llama context wiring is not enabled in this slice");
294
+ return -1;
295
+ }
296
+
297
+ struct llama_model_params model_params = llama_model_default_params();
298
+ const bool no_gpu_devices =
299
+ json_bool_param(params_json, "no_gpu_devices", false);
300
+ ensure_llama_backend_initialized(!no_gpu_devices);
301
+
302
+ model_params.n_gpu_layers = no_gpu_devices
303
+ ? 0
304
+ : json_int_param(params_json, "n_gpu_layers", model_params.n_gpu_layers);
305
+ if (no_gpu_devices) {
306
+ if (!configure_cpu_only_devices(&model_params)) {
307
+ set_last_error("CPU backend device is unavailable");
308
+ return -1;
309
+ }
310
+ model_params.main_gpu = -1;
311
+ model_params.use_extra_bufts = false;
312
+ }
313
+ model_params.use_mmap = json_bool_param(
314
+ params_json,
315
+ "use_mmap",
316
+ model_params.use_mmap);
317
+
318
+ struct llama_model * model = llama_model_load_from_file(
319
+ model_path,
320
+ model_params);
321
+ if (model == NULL) {
322
+ set_last_error("llama_model_load_from_file failed");
323
+ return -1;
155
324
  }
156
- return -1;
325
+
326
+ struct llama_context_params context_params = llama_context_default_params();
327
+ context_params.n_ctx = (uint32_t) json_int_param(
328
+ params_json,
329
+ "n_ctx",
330
+ (int) context_params.n_ctx);
331
+ context_params.n_batch = (uint32_t) json_int_param(
332
+ params_json,
333
+ "n_batch",
334
+ (int) context_params.n_batch);
335
+ context_params.n_ubatch = (uint32_t) json_int_param(
336
+ params_json,
337
+ "n_ubatch",
338
+ (int) context_params.n_ubatch);
339
+ context_params.n_seq_max = 1;
340
+ context_params.n_threads = json_int_param(
341
+ params_json,
342
+ "n_threads",
343
+ context_params.n_threads);
344
+ context_params.n_threads_batch = context_params.n_threads;
345
+ context_params.flash_attn_type = json_bool_param(
346
+ params_json,
347
+ "flash_attn",
348
+ false)
349
+ ? LLAMA_FLASH_ATTN_TYPE_ENABLED
350
+ : LLAMA_FLASH_ATTN_TYPE_DISABLED;
351
+ if (no_gpu_devices) {
352
+ context_params.offload_kqv = false;
353
+ context_params.op_offload = false;
354
+ }
355
+
356
+ struct llama_context * ctx = llama_init_from_model(model, context_params);
357
+ if (ctx == NULL) {
358
+ llama_model_free(model);
359
+ set_last_error("llama_init_from_model failed");
360
+ return -1;
361
+ }
362
+
363
+ struct ElizaTextContext * text_context =
364
+ (struct ElizaTextContext *) calloc(1, sizeof(*text_context));
365
+ if (text_context == NULL) {
366
+ llama_free(ctx);
367
+ llama_model_free(model);
368
+ set_last_error("out of memory creating iOS text context");
369
+ return -1;
370
+ }
371
+ text_context->model = model;
372
+ text_context->ctx = ctx;
373
+ text_context->vocab = llama_model_get_vocab(model);
374
+ if (text_context->vocab == NULL) {
375
+ free_text_context(text_context);
376
+ set_last_error("llama_model_get_vocab returned null");
377
+ return -1;
378
+ }
379
+
380
+ if (store_text_context(text_context) < 0) {
381
+ free_text_context(text_context);
382
+ set_last_error("too many active iOS text contexts");
383
+ return -1;
384
+ }
385
+
386
+ set_last_error("No detailed native error captured");
387
+ return text_context->id;
157
388
  }
158
389
 
159
390
  void llama_release_context(int64_t context_id) {
160
- (void) context_id;
391
+ free_text_context(take_text_context(context_id));
161
392
  }
162
393
 
163
394
  char * llama_completion(int64_t context_id, const char * prompt, const char * params_json) {
164
- (void) context_id;
165
- (void) prompt;
166
- (void) params_json;
167
- set_last_error("Native context is not loaded");
168
- return eliza_dup_cstr("{\"error\":\"Native context is not loaded\"}");
395
+ struct ElizaTextContext * text_context = get_text_context(context_id);
396
+ if (text_context == NULL) {
397
+ set_last_error("Native context is not loaded");
398
+ return json_error("llama_completion", "Native context is not loaded");
399
+ }
400
+ if (prompt == NULL) {
401
+ set_last_error("llama_completion requires a prompt");
402
+ return json_error("llama_completion", "llama_completion requires a prompt");
403
+ }
404
+
405
+ int32_t token_capacity = (int32_t) strlen(prompt) + 64;
406
+ if (token_capacity < 64) token_capacity = 64;
407
+ llama_token * prompt_tokens =
408
+ (llama_token *) calloc((size_t) token_capacity, sizeof(*prompt_tokens));
409
+ if (prompt_tokens == NULL) {
410
+ set_last_error("out of memory tokenizing prompt");
411
+ return json_error("llama_tokenize", "out of memory tokenizing prompt");
412
+ }
413
+
414
+ int32_t n_prompt = llama_tokenize(
415
+ text_context->vocab,
416
+ prompt,
417
+ (int32_t) strlen(prompt),
418
+ prompt_tokens,
419
+ token_capacity,
420
+ true,
421
+ true);
422
+ if (n_prompt < 0) {
423
+ token_capacity = -n_prompt;
424
+ llama_token * grown = (llama_token *) realloc(
425
+ prompt_tokens,
426
+ (size_t) token_capacity * sizeof(*prompt_tokens));
427
+ if (grown == NULL) {
428
+ free(prompt_tokens);
429
+ set_last_error("out of memory expanding prompt tokens");
430
+ return json_error(
431
+ "llama_tokenize",
432
+ "out of memory expanding prompt tokens");
433
+ }
434
+ prompt_tokens = grown;
435
+ n_prompt = llama_tokenize(
436
+ text_context->vocab,
437
+ prompt,
438
+ (int32_t) strlen(prompt),
439
+ prompt_tokens,
440
+ token_capacity,
441
+ true,
442
+ true);
443
+ }
444
+ if (n_prompt <= 0) {
445
+ free(prompt_tokens);
446
+ set_last_error("llama_tokenize failed");
447
+ return json_error("llama_tokenize", "llama_tokenize failed");
448
+ }
449
+
450
+ const int64_t prompt_started_us = llama_time_us();
451
+ struct llama_batch prompt_batch = llama_batch_get_one(
452
+ prompt_tokens,
453
+ n_prompt);
454
+ const int decode_prompt_status = llama_decode(
455
+ text_context->ctx,
456
+ prompt_batch);
457
+ const int64_t prompt_elapsed_us = llama_time_us() - prompt_started_us;
458
+ free(prompt_tokens);
459
+ if (decode_prompt_status != 0) {
460
+ set_last_error("llama_decode failed on prompt");
461
+ return json_error("llama_decode", "llama_decode failed on prompt");
462
+ }
463
+
464
+ struct llama_sampler * sampler = llama_sampler_chain_init(
465
+ llama_sampler_chain_default_params());
466
+ if (sampler == NULL) {
467
+ set_last_error("llama_sampler_chain_init failed");
468
+ return json_error(
469
+ "llama_sampler_chain_init",
470
+ "llama_sampler_chain_init failed");
471
+ }
472
+
473
+ const int top_k = json_int_param(params_json, "top_k", 1);
474
+ const double temperature = json_double_param(params_json, "temperature", 0);
475
+ const int seed = json_int_param(params_json, "seed", 42);
476
+ if (top_k > 0) {
477
+ llama_sampler_chain_add(sampler, llama_sampler_init_top_k(top_k));
478
+ }
479
+ if (temperature > 0) {
480
+ llama_sampler_chain_add(
481
+ sampler,
482
+ llama_sampler_init_temp((float) temperature));
483
+ llama_sampler_chain_add(sampler, llama_sampler_init_dist((uint32_t) seed));
484
+ } else {
485
+ llama_sampler_chain_add(sampler, llama_sampler_init_greedy());
486
+ }
487
+
488
+ char * generated = NULL;
489
+ size_t generated_len = 0;
490
+ size_t generated_cap = 0;
491
+ const int n_predict = json_int_param(params_json, "n_predict", 32);
492
+ int n_predicted = 0;
493
+ int decode_status = 0;
494
+ const int64_t generation_started_us = llama_time_us();
495
+ for (int i = 0; i < n_predict; i++) {
496
+ const llama_token token = llama_sampler_sample(
497
+ sampler,
498
+ text_context->ctx,
499
+ -1);
500
+ if (llama_vocab_is_eog(text_context->vocab, token)) {
501
+ break;
502
+ }
503
+ llama_sampler_accept(sampler, token);
504
+
505
+ char piece[512];
506
+ int32_t piece_len = llama_token_to_piece(
507
+ text_context->vocab,
508
+ token,
509
+ piece,
510
+ (int32_t) sizeof(piece),
511
+ 0,
512
+ false);
513
+ if (piece_len < 0) {
514
+ piece_len = 0;
515
+ }
516
+ if (!append_bytes(
517
+ &generated,
518
+ &generated_len,
519
+ &generated_cap,
520
+ piece,
521
+ (size_t) piece_len)) {
522
+ llama_sampler_free(sampler);
523
+ free(generated);
524
+ set_last_error("out of memory collecting generated text");
525
+ return json_error(
526
+ "llama_completion",
527
+ "out of memory collecting generated text");
528
+ }
529
+
530
+ struct llama_batch next_batch = llama_batch_get_one(
531
+ (llama_token *) &token,
532
+ 1);
533
+ decode_status = llama_decode(text_context->ctx, next_batch);
534
+ if (decode_status != 0) {
535
+ break;
536
+ }
537
+ n_predicted++;
538
+ }
539
+ const int64_t generation_elapsed_us =
540
+ llama_time_us() - generation_started_us;
541
+ llama_sampler_free(sampler);
542
+
543
+ if (decode_status != 0) {
544
+ free(generated);
545
+ set_last_error("llama_decode failed during generation");
546
+ return json_error(
547
+ "llama_decode",
548
+ "llama_decode failed during generation");
549
+ }
550
+ if (n_predicted <= 0) {
551
+ free(generated);
552
+ set_last_error("llama_completion produced no tokens");
553
+ return json_error(
554
+ "llama_completion",
555
+ "llama_completion produced no tokens");
556
+ }
557
+
558
+ char * escaped = json_escape(generated != NULL ? generated : "");
559
+ free(generated);
560
+ if (escaped == NULL) {
561
+ set_last_error("out of memory escaping generated text");
562
+ return json_error(
563
+ "llama_completion",
564
+ "out of memory escaping generated text");
565
+ }
566
+
567
+ const double prompt_seconds =
568
+ prompt_elapsed_us > 0 ? (double) prompt_elapsed_us / 1000000.0 : 0.0;
569
+ const double generation_seconds = generation_elapsed_us > 0
570
+ ? (double) generation_elapsed_us / 1000000.0
571
+ : 0.0;
572
+ const double prompt_per_second =
573
+ prompt_seconds > 0 ? (double) n_prompt / prompt_seconds : 0.0;
574
+ const double predicted_per_second = generation_seconds > 0
575
+ ? (double) n_predicted / generation_seconds
576
+ : 0.0;
577
+ const size_t out_len = strlen(escaped) + 384;
578
+ char * out = (char *) malloc(out_len);
579
+ if (out == NULL) {
580
+ free(escaped);
581
+ set_last_error("out of memory formatting benchmark result");
582
+ return json_error(
583
+ "llama_completion",
584
+ "out of memory formatting benchmark result");
585
+ }
586
+ snprintf(
587
+ out,
588
+ out_len,
589
+ "{\"content\":\"%s\",\"tokens_evaluated\":%d,\"tokens_predicted\":%d,"
590
+ "\"timings\":{\"prompt_per_second\":%.6f,"
591
+ "\"predicted_per_second\":%.6f}}",
592
+ escaped,
593
+ n_prompt,
594
+ n_predicted,
595
+ prompt_per_second,
596
+ predicted_per_second);
597
+ free(escaped);
598
+ set_last_error("No detailed native error captured");
599
+ return out;
169
600
  }
170
601
 
171
602
  void llama_stop_completion(int64_t context_id) {
@@ -204,14 +635,38 @@ void llama_embedding_unregister_context(int64_t context_id) {
204
635
  }
205
636
 
206
637
  char * llama_get_model_info(int64_t context_id) {
207
- (void) context_id;
208
- return eliza_dup_cstr(
209
- "{\"error\":\"Native context is not loaded\",\"isChatTemplateSupported\":false}");
638
+ struct ElizaTextContext * text_context = get_text_context(context_id);
639
+ if (text_context == NULL) {
640
+ return eliza_dup_cstr(
641
+ "{\"error\":\"Native context is not loaded\",\"isChatTemplateSupported\":false}");
642
+ }
643
+ char desc[256] = { 0 };
644
+ llama_model_desc(text_context->model, desc, sizeof(desc));
645
+ char * escaped = json_escape(desc);
646
+ if (escaped == NULL) {
647
+ return eliza_dup_cstr("{\"isChatTemplateSupported\":false}");
648
+ }
649
+ const size_t len = strlen(escaped) + 96;
650
+ char * out = (char *) malloc(len);
651
+ if (out == NULL) {
652
+ free(escaped);
653
+ return NULL;
654
+ }
655
+ snprintf(
656
+ out,
657
+ len,
658
+ "{\"description\":\"%s\",\"isChatTemplateSupported\":%s}",
659
+ escaped,
660
+ llama_model_chat_template(text_context->model, NULL) != NULL
661
+ ? "true"
662
+ : "false");
663
+ free(escaped);
664
+ return out;
210
665
  }
211
666
 
212
667
  void * llama_get_context_ptr(int64_t context_id) {
213
- (void) context_id;
214
- return NULL;
668
+ struct ElizaTextContext * text_context = get_text_context(context_id);
669
+ return text_context != NULL ? text_context->ctx : NULL;
215
670
  }
216
671
 
217
672
  /* ---- fail-closed libelizainference exports ------------------------- */