llama-cpp-pro 0.2.2
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.
- package/CHANGELOG.md +295 -0
- package/LICENSE +21 -0
- package/LlamaCpp.podspec +33 -0
- package/LlamaCppCapacitor.podspec +33 -0
- package/Package.swift +29 -0
- package/README.md +93 -0
- package/android/build.gradle +88 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/CMakeLists-arm64.txt +138 -0
- package/android/src/main/CMakeLists-x86_64.txt +141 -0
- package/android/src/main/CMakeLists.txt +138 -0
- package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCpp.java +1340 -0
- package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCppPlugin.java +814 -0
- package/android/src/main/java/ai/annadata/plugin/capacitor/ModelAdmissionController.java +214 -0
- package/android/src/main/jni-chat-session.cpp +261 -0
- package/android/src/main/jni-lora.cpp +197 -0
- package/android/src/main/jni-multimodal.cpp +167 -0
- package/android/src/main/jni-tts.cpp +290 -0
- package/android/src/main/jni-utils.h +148 -0
- package/android/src/main/jni.cpp +1808 -0
- package/android/src/main/jniLibs/arm64-v8a/libllama-cpp-arm64.so +0 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/build-native.sh +280 -0
- package/cmake/desktop-metal-embed.cmake +30 -0
- package/cmake/desktop-sources.cmake +100 -0
- package/cmake/ggml-backends.cmake +44 -0
- package/cpp/LICENSE +21 -0
- package/cpp/README.md +15 -0
- package/cpp/anyascii.c +22223 -0
- package/cpp/anyascii.h +42 -0
- package/cpp/cap-completion.cpp +942 -0
- package/cpp/cap-completion.h +127 -0
- package/cpp/cap-embedding.cpp +193 -0
- package/cpp/cap-embedding.h +35 -0
- package/cpp/cap-ios-bridge.cpp +1810 -0
- package/cpp/cap-ios-bridge.h +61 -0
- package/cpp/cap-llama.cpp +412 -0
- package/cpp/cap-llama.h +161 -0
- package/cpp/cap-mtmd.hpp +602 -0
- package/cpp/cap-native-server.cpp +1095 -0
- package/cpp/cap-native-server.h +40 -0
- package/cpp/cap-tts.cpp +591 -0
- package/cpp/cap-tts.h +59 -0
- package/cpp/cap-wasm-fs.cpp +156 -0
- package/cpp/cap-wasm-jspi.cpp +19 -0
- package/cpp/cap-wasm-jspi.h +30 -0
- package/cpp/cap-wasm-vfs.cpp +22 -0
- package/cpp/chat-parser.cpp +393 -0
- package/cpp/chat-parser.h +120 -0
- package/cpp/chat.cpp +2315 -0
- package/cpp/chat.h +221 -0
- package/cpp/common.cpp +1664 -0
- package/cpp/common.h +744 -0
- package/cpp/ggml-alloc.c +1028 -0
- package/cpp/ggml-alloc.h +76 -0
- package/cpp/ggml-backend-impl.h +255 -0
- package/cpp/ggml-backend-reg.cpp +600 -0
- package/cpp/ggml-backend.cpp +2121 -0
- package/cpp/ggml-backend.h +354 -0
- package/cpp/ggml-common.h +1878 -0
- package/cpp/ggml-cpp.h +39 -0
- package/cpp/ggml-cpu/amx/amx.cpp +221 -0
- package/cpp/ggml-cpu/amx/amx.h +8 -0
- package/cpp/ggml-cpu/amx/common.h +91 -0
- package/cpp/ggml-cpu/amx/mmq.cpp +2512 -0
- package/cpp/ggml-cpu/amx/mmq.h +10 -0
- package/cpp/ggml-cpu/arch/arm/cpu-feats.cpp +94 -0
- package/cpp/ggml-cpu/arch/arm/quants.c +3650 -0
- package/cpp/ggml-cpu/arch/arm/repack.cpp +1891 -0
- package/cpp/ggml-cpu/arch/x86/cpu-feats.cpp +327 -0
- package/cpp/ggml-cpu/arch/x86/quants.c +3820 -0
- package/cpp/ggml-cpu/arch/x86/repack.cpp +6307 -0
- package/cpp/ggml-cpu/arch-fallback.h +215 -0
- package/cpp/ggml-cpu/binary-ops.cpp +158 -0
- package/cpp/ggml-cpu/binary-ops.h +16 -0
- package/cpp/ggml-cpu/common.h +73 -0
- package/cpp/ggml-cpu/ggml-cpu-impl.h +559 -0
- package/cpp/ggml-cpu/ggml-cpu.c +3578 -0
- package/cpp/ggml-cpu/ggml-cpu.cpp +672 -0
- package/cpp/ggml-cpu/ops.cpp +10587 -0
- package/cpp/ggml-cpu/ops.h +114 -0
- package/cpp/ggml-cpu/quants.c +1193 -0
- package/cpp/ggml-cpu/quants.h +97 -0
- package/cpp/ggml-cpu/repack.cpp +1982 -0
- package/cpp/ggml-cpu/repack.h +120 -0
- package/cpp/ggml-cpu/simd-mappings.h +1184 -0
- package/cpp/ggml-cpu/traits.cpp +36 -0
- package/cpp/ggml-cpu/traits.h +38 -0
- package/cpp/ggml-cpu/unary-ops.cpp +186 -0
- package/cpp/ggml-cpu/unary-ops.h +28 -0
- package/cpp/ggml-cpu/vec.cpp +348 -0
- package/cpp/ggml-cpu/vec.h +1121 -0
- package/cpp/ggml-cpu.h +145 -0
- package/cpp/ggml-impl.h +622 -0
- package/cpp/ggml-metal-impl.h +688 -0
- package/cpp/ggml-metal.h +66 -0
- package/cpp/ggml-metal.m +6833 -0
- package/cpp/ggml-metal.metal +10754 -0
- package/cpp/ggml-opt.cpp +1093 -0
- package/cpp/ggml-opt.h +256 -0
- package/cpp/ggml-quants.c +5324 -0
- package/cpp/ggml-quants.h +106 -0
- package/cpp/ggml-threading.cpp +12 -0
- package/cpp/ggml-threading.h +14 -0
- package/cpp/ggml.c +7108 -0
- package/cpp/ggml.h +2492 -0
- package/cpp/gguf.cpp +1358 -0
- package/cpp/gguf.h +202 -0
- package/cpp/json-partial.cpp +256 -0
- package/cpp/json-partial.h +38 -0
- package/cpp/json-schema-to-grammar.cpp +985 -0
- package/cpp/json-schema-to-grammar.h +21 -0
- package/cpp/llama-adapter.cpp +388 -0
- package/cpp/llama-adapter.h +76 -0
- package/cpp/llama-arch.cpp +2355 -0
- package/cpp/llama-arch.h +499 -0
- package/cpp/llama-batch.cpp +875 -0
- package/cpp/llama-batch.h +160 -0
- package/cpp/llama-chat.cpp +783 -0
- package/cpp/llama-chat.h +65 -0
- package/cpp/llama-context.cpp +2788 -0
- package/cpp/llama-context.h +306 -0
- package/cpp/llama-cparams.cpp +5 -0
- package/cpp/llama-cparams.h +41 -0
- package/cpp/llama-cpp.h +30 -0
- package/cpp/llama-grammar.cpp +1229 -0
- package/cpp/llama-grammar.h +173 -0
- package/cpp/llama-graph.cpp +1891 -0
- package/cpp/llama-graph.h +810 -0
- package/cpp/llama-hparams.cpp +180 -0
- package/cpp/llama-hparams.h +233 -0
- package/cpp/llama-impl.cpp +167 -0
- package/cpp/llama-impl.h +61 -0
- package/cpp/llama-io.cpp +15 -0
- package/cpp/llama-io.h +35 -0
- package/cpp/llama-kv-cache-iswa.cpp +318 -0
- package/cpp/llama-kv-cache-iswa.h +135 -0
- package/cpp/llama-kv-cache.cpp +2059 -0
- package/cpp/llama-kv-cache.h +374 -0
- package/cpp/llama-kv-cells.h +491 -0
- package/cpp/llama-memory-hybrid.cpp +258 -0
- package/cpp/llama-memory-hybrid.h +137 -0
- package/cpp/llama-memory-recurrent.cpp +1146 -0
- package/cpp/llama-memory-recurrent.h +179 -0
- package/cpp/llama-memory.cpp +59 -0
- package/cpp/llama-memory.h +119 -0
- package/cpp/llama-mmap.cpp +609 -0
- package/cpp/llama-mmap.h +68 -0
- package/cpp/llama-model-loader.cpp +1166 -0
- package/cpp/llama-model-loader.h +170 -0
- package/cpp/llama-model-saver.cpp +282 -0
- package/cpp/llama-model-saver.h +37 -0
- package/cpp/llama-model.cpp +19061 -0
- package/cpp/llama-model.h +491 -0
- package/cpp/llama-sampling.cpp +2575 -0
- package/cpp/llama-sampling.h +32 -0
- package/cpp/llama-vocab.cpp +3792 -0
- package/cpp/llama-vocab.h +176 -0
- package/cpp/llama.cpp +358 -0
- package/cpp/llama.h +1373 -0
- package/cpp/log.cpp +428 -0
- package/cpp/log.h +103 -0
- package/cpp/minja/chat-template.hpp +550 -0
- package/cpp/minja/minja.hpp +3009 -0
- package/cpp/nlohmann/json.hpp +25526 -0
- package/cpp/nlohmann/json_fwd.hpp +187 -0
- package/cpp/regex-partial.cpp +204 -0
- package/cpp/regex-partial.h +56 -0
- package/cpp/sampling.cpp +579 -0
- package/cpp/sampling.h +107 -0
- package/cpp/tools/mtmd/clip-impl.h +473 -0
- package/cpp/tools/mtmd/clip.cpp +4322 -0
- package/cpp/tools/mtmd/clip.h +106 -0
- package/cpp/tools/mtmd/miniaudio/miniaudio.h +93468 -0
- package/cpp/tools/mtmd/mtmd-audio.cpp +769 -0
- package/cpp/tools/mtmd/mtmd-audio.h +47 -0
- package/cpp/tools/mtmd/mtmd-helper.cpp +460 -0
- package/cpp/tools/mtmd/mtmd-helper.h +95 -0
- package/cpp/tools/mtmd/mtmd.cpp +1066 -0
- package/cpp/tools/mtmd/mtmd.h +302 -0
- package/cpp/tools/mtmd/stb/stb_image.h +7988 -0
- package/cpp/unicode-data.cpp +7034 -0
- package/cpp/unicode-data.h +20 -0
- package/cpp/unicode.cpp +1061 -0
- package/cpp/unicode.h +68 -0
- package/cpp/vendor/cpp-httplib/httplib.cpp +16509 -0
- package/cpp/vendor/cpp-httplib/httplib.h +3883 -0
- package/desktop/electron-builder.config.cjs +157 -0
- package/desktop/entitlements.mac.plist +12 -0
- package/desktop/package.json +11 -0
- package/desktop/resolve-package-root.cjs +88 -0
- package/desktop/src/main/backend-selector.cjs +148 -0
- package/desktop/src/main/gpu-probe.cjs +142 -0
- package/desktop/src/main/index.cjs +58 -0
- package/desktop/src/main/ipc-handlers.cjs +212 -0
- package/desktop/src/main/model-store.cjs +50 -0
- package/desktop/src/main/preload.cjs +39 -0
- package/desktop/src/main/sidecar-client.cjs +76 -0
- package/desktop/src/main/sidecar-manager.cjs +364 -0
- package/dist/docs.json +14357 -0
- package/dist/esm/definitions.d.ts +731 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/desktop.d.ts +37 -0
- package/dist/esm/desktop.js +133 -0
- package/dist/esm/desktop.js.map +1 -0
- package/dist/esm/index.d.ts +200 -0
- package/dist/esm/index.js +612 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/isomorphic/desktop.runtime.d.ts +37 -0
- package/dist/esm/isomorphic/desktop.runtime.js +36 -0
- package/dist/esm/isomorphic/desktop.runtime.js.map +1 -0
- package/dist/esm/isomorphic/errors.d.ts +6 -0
- package/dist/esm/isomorphic/errors.js +9 -0
- package/dist/esm/isomorphic/errors.js.map +1 -0
- package/dist/esm/isomorphic/model.admission.d.ts +17 -0
- package/dist/esm/isomorphic/model.admission.js +27 -0
- package/dist/esm/isomorphic/model.admission.js.map +1 -0
- package/dist/esm/isomorphic/model.scheduler.d.ts +31 -0
- package/dist/esm/isomorphic/model.scheduler.js +95 -0
- package/dist/esm/isomorphic/model.scheduler.js.map +1 -0
- package/dist/esm/isomorphic/provider.desktop.d.ts +40 -0
- package/dist/esm/isomorphic/provider.desktop.js +411 -0
- package/dist/esm/isomorphic/provider.desktop.js.map +1 -0
- package/dist/esm/isomorphic/provider.factory.d.ts +2 -0
- package/dist/esm/isomorphic/provider.factory.js +16 -0
- package/dist/esm/isomorphic/provider.factory.js.map +1 -0
- package/dist/esm/isomorphic/provider.interface.d.ts +76 -0
- package/dist/esm/isomorphic/provider.interface.js +2 -0
- package/dist/esm/isomorphic/provider.interface.js.map +1 -0
- package/dist/esm/isomorphic/provider.native.d.ts +18 -0
- package/dist/esm/isomorphic/provider.native.js +173 -0
- package/dist/esm/isomorphic/provider.native.js.map +1 -0
- package/dist/esm/isomorphic/provider.web.d.ts +88 -0
- package/dist/esm/isomorphic/provider.web.js +573 -0
- package/dist/esm/isomorphic/provider.web.js.map +1 -0
- package/dist/esm/isomorphic/sidecar-sse.d.ts +14 -0
- package/dist/esm/isomorphic/sidecar-sse.js +76 -0
- package/dist/esm/isomorphic/sidecar-sse.js.map +1 -0
- package/dist/esm/isomorphic/wasmMemoryCalibration.d.ts +26 -0
- package/dist/esm/isomorphic/wasmMemoryCalibration.js +60 -0
- package/dist/esm/isomorphic/wasmMemoryCalibration.js.map +1 -0
- package/dist/esm/isomorphic/wasmMemoryPolicy.d.ts +55 -0
- package/dist/esm/isomorphic/wasmMemoryPolicy.js +93 -0
- package/dist/esm/isomorphic/wasmMemoryPolicy.js.map +1 -0
- package/dist/esm/storage/manifest.d.ts +13 -0
- package/dist/esm/storage/manifest.js +87 -0
- package/dist/esm/storage/manifest.js.map +1 -0
- package/dist/esm/storage/opfs.store.d.ts +31 -0
- package/dist/esm/storage/opfs.store.js +241 -0
- package/dist/esm/storage/opfs.store.js.map +1 -0
- package/dist/esm/web.d.ts +206 -0
- package/dist/esm/web.js +521 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/esm/workers/async-file.d.ts +13 -0
- package/dist/esm/workers/async-file.js +12 -0
- package/dist/esm/workers/async-file.js.map +1 -0
- package/dist/esm/workers/heapfs.d.ts +55 -0
- package/dist/esm/workers/heapfs.js +115 -0
- package/dist/esm/workers/heapfs.js.map +1 -0
- package/dist/esm/workers/wasm.engine.d.ts +86 -0
- package/dist/esm/workers/wasm.engine.js +504 -0
- package/dist/esm/workers/wasm.engine.js.map +1 -0
- package/dist/esm/workers/worker.protocol.d.ts +160 -0
- package/dist/esm/workers/worker.protocol.js +2 -0
- package/dist/esm/workers/worker.protocol.js.map +1 -0
- package/dist/plugin.cjs +3179 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.js +3181 -0
- package/dist/plugin.js.map +1 -0
- package/dist/wasm/llama_engine.d.ts +74 -0
- package/dist/wasm/llama_engine.js +1829 -0
- package/dist/wasm/llama_engine.wasm +0 -0
- package/dist/wasm/llama_engine_emscripten.mjs +2 -0
- package/dist/wasm/package.json +16 -0
- package/dist/workers/llm.worker.js +1226 -0
- package/dist/workers/llm.worker.js.map +7 -0
- package/extraResources/llama-wasm/llama_engine.d.ts +74 -0
- package/extraResources/llama-wasm/llama_engine.js +1829 -0
- package/extraResources/llama-wasm/llama_engine.wasm +0 -0
- package/extraResources/llama-wasm/llama_engine_emscripten.mjs +2 -0
- package/extraResources/llama-wasm/package.json +16 -0
- package/extraResources/sidecar/README.md +11 -0
- package/extraResources/sidecar/darwin-arm64 +0 -0
- package/extraResources/sidecar/darwin-x64 +0 -0
- package/ios/CMakeLists-arm64.txt +161 -0
- package/ios/CMakeLists-x86_64.txt +188 -0
- package/ios/CMakeLists.txt +161 -0
- package/ios/Frameworks/llama-cpp.framework/Info.plist +28 -0
- package/ios/Frameworks/llama-cpp.framework/llama-cpp +0 -0
- package/ios/Sources/LlamaCppCapacitor/LlamaCpp.swift +1365 -0
- package/ios/Sources/LlamaCppCapacitor/LlamaCppPlugin.swift +694 -0
- package/ios/Sources/LlamaCppCapacitor/LlamaNativeBridge.swift +349 -0
- package/ios/Sources/LlamaCppCapacitor/ModelAdmissionController.swift +177 -0
- package/ios/embed-metal-shaders.sh +24 -0
- package/ios/metal-embed.cmake +29 -0
- package/package.json +281 -0
- package/scripts/build-js-preserve-wasm.cjs +53 -0
- package/scripts/build-sidecar-linux.sh +6 -0
- package/scripts/build-sidecar-win.bat +19 -0
- package/scripts/build-sidecar.sh +184 -0
- package/scripts/embed-llama-ios-app-framework.sh +63 -0
- package/scripts/ensure-desktop-sidecar-bundle.cjs +103 -0
- package/scripts/ensure-llama-ios-xcframework.sh +108 -0
- package/scripts/fix-esm-extensions.cjs +45 -0
- package/scripts/prepare-js-dist.cjs +28 -0
- package/scripts/stage-desktop-resources.cjs +116 -0
- package/sidecar/CMakeLists.txt +192 -0
- package/sidecar/cap-sidecar-main.cpp +68 -0
- package/types/llama-cpp-pro.d.ts +441 -0
package/cpp/cap-tts.h
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#ifndef CAPTTS_H
|
|
2
|
+
#define CAPTTS_H
|
|
3
|
+
|
|
4
|
+
#include <vector>
|
|
5
|
+
#include <string>
|
|
6
|
+
#include "llama.h"
|
|
7
|
+
#include "nlohmann/json.hpp"
|
|
8
|
+
#include "common.h"
|
|
9
|
+
|
|
10
|
+
using json = nlohmann::ordered_json;
|
|
11
|
+
|
|
12
|
+
namespace capllama {
|
|
13
|
+
|
|
14
|
+
// Forward declarations
|
|
15
|
+
struct llama_cap_context;
|
|
16
|
+
|
|
17
|
+
// TTS type enumeration
|
|
18
|
+
enum tts_type {
|
|
19
|
+
UNKNOWN = -1,
|
|
20
|
+
OUTETTS_V0_1 = 0,
|
|
21
|
+
OUTETTS_V0_2 = 1,
|
|
22
|
+
OUTETTS_V0_3 = 2,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Audio completion result structure
|
|
26
|
+
struct llama_cap_audio_completion_result {
|
|
27
|
+
std::string prompt;
|
|
28
|
+
const char *grammar;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// TTS context for TTS-specific functionality
|
|
32
|
+
struct llama_cap_context_tts {
|
|
33
|
+
// TTS state fields
|
|
34
|
+
std::vector<llama_token> audio_tokens;
|
|
35
|
+
std::vector<llama_token> guide_tokens;
|
|
36
|
+
bool next_token_uses_guide_token = true;
|
|
37
|
+
|
|
38
|
+
// Vocoder fields (from llama_cap_context_vocoder)
|
|
39
|
+
common_init_result init_result;
|
|
40
|
+
common_params params;
|
|
41
|
+
llama_model *model = nullptr;
|
|
42
|
+
llama_context *ctx = nullptr;
|
|
43
|
+
tts_type type = UNKNOWN;
|
|
44
|
+
|
|
45
|
+
// Constructor and destructor
|
|
46
|
+
llama_cap_context_tts(const std::string &vocoder_model_path, int batch_size = -1);
|
|
47
|
+
~llama_cap_context_tts();
|
|
48
|
+
|
|
49
|
+
// TTS utility methods
|
|
50
|
+
tts_type getTTSType(llama_cap_context* main_ctx, json speaker = nullptr);
|
|
51
|
+
llama_cap_audio_completion_result getFormattedAudioCompletion(llama_cap_context* main_ctx, const std::string &speaker_json_str, const std::string &text_to_speak);
|
|
52
|
+
std::vector<llama_token> getAudioCompletionGuideTokens(llama_cap_context* main_ctx, const std::string &text_to_speak);
|
|
53
|
+
std::vector<float> decodeAudioTokens(llama_cap_context* main_ctx, const std::vector<llama_token> &tokens);
|
|
54
|
+
void setGuideTokens(const std::vector<llama_token> &tokens);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
#endif /* CAPTTS_H */
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// JSPI async GGUF file read — intercepts libc fread when async mode is enabled.
|
|
2
|
+
// Model bytes stay in JS (Blob / OPFS reader); WASM reads on demand in 1 MB chunks.
|
|
3
|
+
// Ref: ref-code/wllama (wllama-fs.h)
|
|
4
|
+
|
|
5
|
+
#if defined(CAPLLAMA_BUILD_WASM_JSPI) && defined(__EMSCRIPTEN__)
|
|
6
|
+
|
|
7
|
+
#include <algorithm>
|
|
8
|
+
#include <cstdio>
|
|
9
|
+
#include <cstdlib>
|
|
10
|
+
#include <cstring>
|
|
11
|
+
#include <map>
|
|
12
|
+
#include <string>
|
|
13
|
+
#include <vector>
|
|
14
|
+
|
|
15
|
+
#include <emscripten.h>
|
|
16
|
+
|
|
17
|
+
static std::map<FILE *, std::string> s_file_path_map;
|
|
18
|
+
|
|
19
|
+
namespace cap_wasm_fs {
|
|
20
|
+
|
|
21
|
+
// Set from JS via cap_wasm_set_use_async_file() — do not cache getenv once at startup
|
|
22
|
+
// (getenv may run before Module.ENV is applied, locking async off permanently).
|
|
23
|
+
static bool use_async_explicit = false;
|
|
24
|
+
|
|
25
|
+
static const size_t CACHE_SIZE = 1024 * 1024; // 1 MB read-ahead
|
|
26
|
+
|
|
27
|
+
std::vector<uint8_t> cache_data;
|
|
28
|
+
size_t cache_start = 0;
|
|
29
|
+
FILE * cache_file = nullptr;
|
|
30
|
+
|
|
31
|
+
bool use_async_file() {
|
|
32
|
+
if (use_async_explicit) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
return getenv("USE_ASYNC_FILE") != nullptr;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
void set_use_async_file(bool enabled) {
|
|
39
|
+
use_async_explicit = enabled;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
size_t try_cache(FILE *f, char *ptr, size_t req_bytes, size_t fpos) {
|
|
43
|
+
if (f != cache_file || cache_data.empty()) {
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
if (fpos >= cache_start && fpos + req_bytes <= cache_start + cache_data.size()) {
|
|
47
|
+
memcpy(ptr, cache_data.data() + (fpos - cache_start), req_bytes);
|
|
48
|
+
return req_bytes;
|
|
49
|
+
}
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
} // namespace cap_wasm_fs
|
|
54
|
+
|
|
55
|
+
// Implemented in llama_engine.js shim (_cap_js_file_read) — sync EM_JS (no JSPI suspend).
|
|
56
|
+
EM_JS(size_t, cap_js_file_read_impl, (const char *path_ptr, size_t offset, size_t req_size, void *out_ptr), {
|
|
57
|
+
return Number(_cap_js_file_read(UTF8ToString(Number(path_ptr)), Number(offset), Number(req_size), Number(out_ptr)));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
extern "C" {
|
|
61
|
+
|
|
62
|
+
void cap_wasm_set_use_async_file(int enabled) {
|
|
63
|
+
cap_wasm_fs::set_use_async_file(enabled != 0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
FILE *__real_fopen(const char *path, const char *mode);
|
|
67
|
+
int __real_fclose(FILE *f);
|
|
68
|
+
size_t __real_fread(void *ptr, size_t size, size_t nmemb, FILE *f);
|
|
69
|
+
int __real_fseek(FILE *f, long offset, int whence);
|
|
70
|
+
long __real_ftell(FILE *f);
|
|
71
|
+
|
|
72
|
+
FILE *__wrap_fopen(const char *path, const char *mode) {
|
|
73
|
+
FILE *f = __real_fopen(path, mode);
|
|
74
|
+
if (f) {
|
|
75
|
+
s_file_path_map[f] = path;
|
|
76
|
+
}
|
|
77
|
+
return f;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
int __wrap_fclose(FILE *f) {
|
|
81
|
+
if (cap_wasm_fs::cache_file == f) {
|
|
82
|
+
cap_wasm_fs::cache_file = nullptr;
|
|
83
|
+
cap_wasm_fs::cache_data.clear();
|
|
84
|
+
}
|
|
85
|
+
s_file_path_map.erase(f);
|
|
86
|
+
return __real_fclose(f);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
int __wrap_fseek(FILE *f, long offset, int whence) {
|
|
90
|
+
return __real_fseek(f, offset, whence);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
long __wrap_ftell(FILE *f) {
|
|
94
|
+
return __real_ftell(f);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
size_t __wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *f) {
|
|
98
|
+
if (!cap_wasm_fs::use_async_file()) {
|
|
99
|
+
return __real_fread(ptr, size, nmemb, f);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
auto nit = s_file_path_map.find(f);
|
|
103
|
+
if (nit == s_file_path_map.end()) {
|
|
104
|
+
return __real_fread(ptr, size, nmemb, f);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
size_t req_bytes = size * nmemb;
|
|
108
|
+
if (req_bytes == 0) {
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
size_t fpos = static_cast<size_t>(__real_ftell(f));
|
|
113
|
+
|
|
114
|
+
// Large reads (>= 1 MB): write directly into ptr, skip cache entirely.
|
|
115
|
+
if (req_bytes >= cap_wasm_fs::CACHE_SIZE) {
|
|
116
|
+
size_t actual = static_cast<size_t>(cap_js_file_read_impl(
|
|
117
|
+
nit->second.c_str(), fpos, req_bytes, ptr));
|
|
118
|
+
if (actual == 0) {
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
size_t copy_bytes = std::min(req_bytes, actual);
|
|
122
|
+
__real_fseek(f, static_cast<long>(fpos + copy_bytes), SEEK_SET);
|
|
123
|
+
return copy_bytes / size;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Small reads: try cache first.
|
|
127
|
+
size_t cached = cap_wasm_fs::try_cache(f, static_cast<char *>(ptr), req_bytes, fpos);
|
|
128
|
+
if (cached == req_bytes) {
|
|
129
|
+
__real_fseek(f, static_cast<long>(fpos + req_bytes), SEEK_SET);
|
|
130
|
+
return nmemb;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Cache miss: fetch a full CACHE_SIZE block from JS.
|
|
134
|
+
cap_wasm_fs::cache_data.resize(cap_wasm_fs::CACHE_SIZE);
|
|
135
|
+
size_t actual = static_cast<size_t>(cap_js_file_read_impl(
|
|
136
|
+
nit->second.c_str(), fpos, cap_wasm_fs::CACHE_SIZE,
|
|
137
|
+
cap_wasm_fs::cache_data.data()));
|
|
138
|
+
|
|
139
|
+
cap_wasm_fs::cache_data.resize(actual);
|
|
140
|
+
cap_wasm_fs::cache_file = f;
|
|
141
|
+
cap_wasm_fs::cache_start = fpos;
|
|
142
|
+
|
|
143
|
+
if (actual == 0) {
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
size_t copy_bytes = std::min(req_bytes, actual);
|
|
148
|
+
memcpy(ptr, cap_wasm_fs::cache_data.data(), copy_bytes);
|
|
149
|
+
__real_fseek(f, static_cast<long>(fpos + copy_bytes), SEEK_SET);
|
|
150
|
+
|
|
151
|
+
return copy_bytes / size;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
} // extern "C"
|
|
155
|
+
|
|
156
|
+
#endif // CAPLLAMA_BUILD_WASM_JSPI && __EMSCRIPTEN__
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#if defined(CAPLLAMA_BUILD_WASM_JSPI) && defined(__EMSCRIPTEN__)
|
|
2
|
+
|
|
3
|
+
#include "cap-wasm-jspi.h"
|
|
4
|
+
#include <emscripten/emscripten.h>
|
|
5
|
+
|
|
6
|
+
// Dispatches each generated token to Module.__llamaStreamOnToken (set by wasm.engine.ts).
|
|
7
|
+
EM_ASYNC_JS(void, cap_js_token_dispatch_impl, (const char *token_ptr, int index), {
|
|
8
|
+
if (Module.__llamaStreamOnToken) {
|
|
9
|
+
await Module.__llamaStreamOnToken(UTF8ToString(Number(token_ptr)), Number(index));
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
extern "C" void cap_wasm_jspi_token_dispatch(const char *token_text, int token_index) {
|
|
14
|
+
if (token_text) {
|
|
15
|
+
cap_js_token_dispatch_impl(token_text, token_index);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#endif
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// JSPI token streaming for Emscripten WASM builds.
|
|
4
|
+
// Implementation lives in cap-wasm-jspi.cpp (EM_ASYNC_JS must not be in a
|
|
5
|
+
// header included from other translation units — causes em_asm.h conflicts).
|
|
6
|
+
|
|
7
|
+
#if defined(CAPLLAMA_BUILD_WASM_JSPI) && defined(__EMSCRIPTEN__)
|
|
8
|
+
|
|
9
|
+
#ifdef __cplusplus
|
|
10
|
+
extern "C" {
|
|
11
|
+
#endif
|
|
12
|
+
|
|
13
|
+
void cap_wasm_jspi_token_dispatch(const char *token_text, int token_index);
|
|
14
|
+
|
|
15
|
+
#ifdef __cplusplus
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
inline void cap_wasm_jspi_token_callback(
|
|
19
|
+
const char *token_text,
|
|
20
|
+
void * /*user_data*/,
|
|
21
|
+
int token_index)
|
|
22
|
+
{
|
|
23
|
+
if (token_text && token_text[0] != '\0') {
|
|
24
|
+
cap_wasm_jspi_token_dispatch(token_text, token_index);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#endif // __cplusplus
|
|
29
|
+
|
|
30
|
+
#endif // CAPLLAMA_BUILD_WASM_JSPI && __EMSCRIPTEN__
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#if defined(CAPLLAMA_BUILD_WASM) && defined(__EMSCRIPTEN__)
|
|
2
|
+
|
|
3
|
+
#include <emscripten.h>
|
|
4
|
+
|
|
5
|
+
// Must live outside cap-ios-bridge.cpp's extern "C" block (emscripten.h uses C++ templates).
|
|
6
|
+
extern "C" void cap_wasm_ensure_tmp_dir(void) {
|
|
7
|
+
EM_ASM({
|
|
8
|
+
if (typeof FS !== 'undefined') {
|
|
9
|
+
try {
|
|
10
|
+
if (!FS.analyzePath('/tmp').exists) {
|
|
11
|
+
if (typeof FS.createPath === 'function') {
|
|
12
|
+
FS.createPath('/', 'tmp', true, true);
|
|
13
|
+
} else {
|
|
14
|
+
FS.mkdir('/tmp');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
} catch (e) {}
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#endif
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
#include "chat-parser.h"
|
|
2
|
+
#include "common.h"
|
|
3
|
+
#include "log.h"
|
|
4
|
+
#include "regex-partial.h"
|
|
5
|
+
|
|
6
|
+
#include <optional>
|
|
7
|
+
#include <stdexcept>
|
|
8
|
+
#include <string>
|
|
9
|
+
#include <vector>
|
|
10
|
+
|
|
11
|
+
using json = nlohmann::ordered_json;
|
|
12
|
+
|
|
13
|
+
common_chat_msg_parser::common_chat_msg_parser(const std::string & input, bool is_partial, const common_chat_syntax & syntax)
|
|
14
|
+
: input_(input), is_partial_(is_partial), syntax_(syntax)
|
|
15
|
+
{
|
|
16
|
+
result_.role = "assistant";
|
|
17
|
+
|
|
18
|
+
while (true) {
|
|
19
|
+
std::string id = std::to_string(std::rand());
|
|
20
|
+
if (input.find(id) == std::string::npos) {
|
|
21
|
+
healing_marker_ = id;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
std::string common_chat_msg_parser::str(const common_string_range & rng) const {
|
|
28
|
+
LM_GGML_ASSERT(rng.begin <= rng.end);
|
|
29
|
+
return input_.substr(rng.begin, rng.end - rng.begin);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
void common_chat_msg_parser::add_content(const std::string &content) {
|
|
33
|
+
result_.content += content;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
void common_chat_msg_parser::add_reasoning_content(const std::string &reasoning_content) {
|
|
37
|
+
result_.reasoning_content += reasoning_content;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
bool common_chat_msg_parser::add_tool_call(const std::string & name, const std::string & id, const std::string & arguments) {
|
|
41
|
+
if (name.empty()) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
common_chat_tool_call tool_call;
|
|
46
|
+
tool_call.name = name;
|
|
47
|
+
tool_call.arguments = arguments;
|
|
48
|
+
tool_call.id = id;
|
|
49
|
+
|
|
50
|
+
// LOG_DBG("Tool call arguments:\n\traw: %s\n\tresult: %s\n", arguments.c_str(), tool_call.arguments.c_str());
|
|
51
|
+
result_.tool_calls.emplace_back(tool_call);
|
|
52
|
+
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
bool common_chat_msg_parser::add_tool_call(const json & tool_call) {
|
|
56
|
+
std::string name = tool_call.contains("name") ? tool_call.at("name") : "";
|
|
57
|
+
std::string id = tool_call.contains("id") ? tool_call.at("id") : "";
|
|
58
|
+
std::string arguments = "";
|
|
59
|
+
if (tool_call.contains("arguments")) {
|
|
60
|
+
if (tool_call.at("arguments").is_object()) {
|
|
61
|
+
arguments = tool_call.at("arguments").dump();
|
|
62
|
+
} else {
|
|
63
|
+
arguments = tool_call.at("arguments");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return add_tool_call(name, id, arguments);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
bool common_chat_msg_parser::add_tool_calls(const json & arr) {
|
|
71
|
+
for (const auto & item : arr) {
|
|
72
|
+
if (!add_tool_call(item)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
void common_chat_msg_parser::finish() {
|
|
79
|
+
if (!is_partial_ && pos_ != input_.size()) {
|
|
80
|
+
throw std::runtime_error("Unexpected content at end of input");// + input_.substr(pos_));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
bool common_chat_msg_parser::consume_spaces() {
|
|
85
|
+
const auto length = input_.size();
|
|
86
|
+
auto consumed = false;
|
|
87
|
+
while (pos_ < length && std::isspace(input_[pos_])) {
|
|
88
|
+
++pos_;
|
|
89
|
+
consumed = true;
|
|
90
|
+
}
|
|
91
|
+
return consumed;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
bool common_chat_msg_parser::try_consume_literal(const std::string & literal) {
|
|
95
|
+
auto pos = pos_;
|
|
96
|
+
for (auto i = 0u; i < literal.size(); ++i) {
|
|
97
|
+
if (pos >= input_.size()) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
if (input_[pos] != literal[i]) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
++pos;
|
|
104
|
+
}
|
|
105
|
+
pos_ = pos;
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
std::optional<common_chat_msg_parser::find_regex_result> common_chat_msg_parser::try_find_literal(const std::string & literal) {
|
|
110
|
+
auto idx = input_.find(literal, pos_);
|
|
111
|
+
if (idx != std::string::npos) {
|
|
112
|
+
find_regex_result res;
|
|
113
|
+
res.prelude = input_.substr(pos_, idx - pos_);
|
|
114
|
+
auto end = idx + literal.size();
|
|
115
|
+
res.groups.emplace_back(common_string_range{idx, end});
|
|
116
|
+
move_to(end);
|
|
117
|
+
return res;
|
|
118
|
+
}
|
|
119
|
+
if (is_partial_) {
|
|
120
|
+
idx = string_find_partial_stop(input_, literal);
|
|
121
|
+
if (idx != std::string::npos && idx >= pos_) {
|
|
122
|
+
find_regex_result res;
|
|
123
|
+
res.prelude = input_.substr(pos_, idx - pos_);
|
|
124
|
+
auto end = input_.size();
|
|
125
|
+
res.groups.emplace_back(common_string_range{idx, end});
|
|
126
|
+
move_to(end);
|
|
127
|
+
return res;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return std::nullopt;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
void common_chat_msg_parser::consume_literal(const std::string & literal) {
|
|
134
|
+
if (!try_consume_literal(literal)) {
|
|
135
|
+
throw common_chat_msg_partial_exception(literal);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
bool common_chat_msg_parser::try_parse_reasoning(const std::string & start_think, const std::string & end_think) {
|
|
140
|
+
auto handle_reasoning = [&](const std::string & reasoning, bool closed) {
|
|
141
|
+
auto stripped_reasoning = string_strip(reasoning);
|
|
142
|
+
if (stripped_reasoning.empty()) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (syntax_.reasoning_in_content) {
|
|
146
|
+
add_content(syntax_.reasoning_format == COMMON_REASONING_FORMAT_DEEPSEEK ? "<think>" : start_think);
|
|
147
|
+
add_content(stripped_reasoning);
|
|
148
|
+
if (closed) {
|
|
149
|
+
add_content(syntax_.reasoning_format == COMMON_REASONING_FORMAT_DEEPSEEK ? "</think>" : end_think);
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
add_reasoning_content(stripped_reasoning);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
if (syntax_.reasoning_format != COMMON_REASONING_FORMAT_NONE) {
|
|
156
|
+
if (syntax_.thinking_forced_open || try_consume_literal(start_think)) {
|
|
157
|
+
if (auto res = try_find_literal(end_think)) {
|
|
158
|
+
handle_reasoning(res->prelude, /* closed */ true);
|
|
159
|
+
consume_spaces();
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
auto rest = consume_rest();
|
|
163
|
+
if (!rest.empty()) {
|
|
164
|
+
handle_reasoning(rest, /* closed */ !is_partial());
|
|
165
|
+
}
|
|
166
|
+
// Allow unclosed thinking tags, for now (https://github.com/ggml-org/llama.cpp/issues/13812, https://github.com/ggml-org/llama.cpp/issues/13877)
|
|
167
|
+
// if (!syntax_.thinking_forced_open) {
|
|
168
|
+
// throw common_chat_msg_partial_exception(end_think);
|
|
169
|
+
// }
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
std::string common_chat_msg_parser::consume_rest() {
|
|
177
|
+
auto rest = input_.substr(pos_);
|
|
178
|
+
pos_ = input_.size();
|
|
179
|
+
return rest;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Tries to find the regex, consumes it (pos right after it) and gives the prelude (right before it) and the groups to the callback.
|
|
183
|
+
std::optional<common_chat_msg_parser::find_regex_result> common_chat_msg_parser::try_find_regex(const common_regex & regex, size_t from, bool add_prelude_to_content) {
|
|
184
|
+
auto m = regex.search(input_, from == std::string::npos ? pos_ : from);
|
|
185
|
+
if (m.type == COMMON_REGEX_MATCH_TYPE_NONE) {
|
|
186
|
+
return std::nullopt;
|
|
187
|
+
}
|
|
188
|
+
auto prelude = input_.substr(pos_, m.groups[0].begin - pos_);
|
|
189
|
+
pos_ = m.groups[0].end;
|
|
190
|
+
|
|
191
|
+
if (add_prelude_to_content) {
|
|
192
|
+
add_content(prelude);
|
|
193
|
+
}
|
|
194
|
+
if (m.type == COMMON_REGEX_MATCH_TYPE_PARTIAL) {
|
|
195
|
+
if (is_partial()) {
|
|
196
|
+
throw common_chat_msg_partial_exception(regex.str());
|
|
197
|
+
}
|
|
198
|
+
return std::nullopt;
|
|
199
|
+
}
|
|
200
|
+
return find_regex_result{prelude, m.groups};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
common_chat_msg_parser::find_regex_result common_chat_msg_parser::consume_regex(const common_regex & regex) {
|
|
204
|
+
if (auto result = try_consume_regex(regex)) {
|
|
205
|
+
return *result;
|
|
206
|
+
}
|
|
207
|
+
throw common_chat_msg_partial_exception(regex.str());
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
std::optional<common_chat_msg_parser::find_regex_result> common_chat_msg_parser::try_consume_regex(const common_regex & regex) {
|
|
211
|
+
auto m = regex.search(input_, pos_);
|
|
212
|
+
if (m.type == COMMON_REGEX_MATCH_TYPE_NONE) {
|
|
213
|
+
return std::nullopt;
|
|
214
|
+
}
|
|
215
|
+
if (m.type == COMMON_REGEX_MATCH_TYPE_PARTIAL) {
|
|
216
|
+
if (is_partial()) {
|
|
217
|
+
throw common_chat_msg_partial_exception(regex.str());
|
|
218
|
+
}
|
|
219
|
+
return std::nullopt;
|
|
220
|
+
}
|
|
221
|
+
if (m.groups[0].begin != pos_) {
|
|
222
|
+
// Didn't match at the current position.
|
|
223
|
+
return std::nullopt;
|
|
224
|
+
}
|
|
225
|
+
pos_ = m.groups[0].end;
|
|
226
|
+
|
|
227
|
+
return find_regex_result {
|
|
228
|
+
/* .prelude = */ "",
|
|
229
|
+
m.groups,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
std::optional<common_json> common_chat_msg_parser::try_consume_json() {
|
|
234
|
+
auto it = input_.cbegin() + pos_;
|
|
235
|
+
const auto end = input_.cend();
|
|
236
|
+
common_json result;
|
|
237
|
+
if (!common_json_parse(it, end, healing_marker_, result)) {
|
|
238
|
+
return std::nullopt;
|
|
239
|
+
}
|
|
240
|
+
pos_ = std::distance(input_.cbegin(), it);
|
|
241
|
+
if (result.healing_marker.marker.empty()) {
|
|
242
|
+
// No healing marker, just return the parsed json
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
245
|
+
if (!is_partial()) {
|
|
246
|
+
throw common_chat_msg_partial_exception("JSON");
|
|
247
|
+
}
|
|
248
|
+
return result;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
common_json common_chat_msg_parser::consume_json() {
|
|
252
|
+
if (auto result = try_consume_json()) {
|
|
253
|
+
return *result;
|
|
254
|
+
}
|
|
255
|
+
throw common_chat_msg_partial_exception("JSON");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
common_chat_msg_parser::consume_json_result common_chat_msg_parser::consume_json_with_dumped_args(
|
|
259
|
+
const std::vector<std::vector<std::string>> & args_paths,
|
|
260
|
+
const std::vector<std::vector<std::string>> & content_paths
|
|
261
|
+
) {
|
|
262
|
+
if (auto result = try_consume_json_with_dumped_args(args_paths, content_paths)) {
|
|
263
|
+
return *result;
|
|
264
|
+
}
|
|
265
|
+
throw common_chat_msg_partial_exception("JSON");
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
std::optional<common_chat_msg_parser::consume_json_result> common_chat_msg_parser::try_consume_json_with_dumped_args(
|
|
269
|
+
const std::vector<std::vector<std::string>> & args_paths,
|
|
270
|
+
const std::vector<std::vector<std::string>> & content_paths
|
|
271
|
+
) {
|
|
272
|
+
auto partial = try_consume_json();
|
|
273
|
+
if (!partial) {
|
|
274
|
+
return std::nullopt;
|
|
275
|
+
}
|
|
276
|
+
auto is_arguments_path = [&](const std::vector<std::string> & path) {
|
|
277
|
+
return std::find(args_paths.begin(), args_paths.end(), path) != args_paths.end();
|
|
278
|
+
};
|
|
279
|
+
auto is_content_path = [&](const std::vector<std::string> & path) {
|
|
280
|
+
return std::find(content_paths.begin(), content_paths.end(), path) != content_paths.end();
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
if (partial->healing_marker.marker.empty()) {
|
|
284
|
+
if (args_paths.empty()) {
|
|
285
|
+
// No arguments to dump, and JSON was parsed fully.
|
|
286
|
+
return consume_json_result {
|
|
287
|
+
partial->json,
|
|
288
|
+
/* .is_partial = */ false,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
if (is_arguments_path({})) {
|
|
292
|
+
// Entire JSON is the arguments and was parsed fully.
|
|
293
|
+
return consume_json_result {
|
|
294
|
+
partial->json.dump(),
|
|
295
|
+
/* .is_partial = */ false,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
LOG_DBG("Parsed partial JSON: %s (json_healing_marker: %s)\n", partial->json.dump().c_str(), partial->healing_marker.json_dump_marker.c_str());
|
|
301
|
+
|
|
302
|
+
auto found_healing_marker = false;
|
|
303
|
+
std::vector<std::string> path;
|
|
304
|
+
std::function<json(const json &)> remove_unsupported_healings_and_dump_args = [&](const json & j) -> json {
|
|
305
|
+
if (is_arguments_path(path)) {
|
|
306
|
+
auto arguments = j.dump();
|
|
307
|
+
if (is_partial() && !partial->healing_marker.marker.empty()) {
|
|
308
|
+
auto idx = arguments.find(partial->healing_marker.json_dump_marker);
|
|
309
|
+
if (idx != std::string::npos) {
|
|
310
|
+
arguments.resize(idx);
|
|
311
|
+
found_healing_marker = true;
|
|
312
|
+
}
|
|
313
|
+
if (arguments == "\"") {
|
|
314
|
+
// This happens because of completing `:"$magic` after `"arguments"`
|
|
315
|
+
arguments = "";
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return arguments;
|
|
319
|
+
}
|
|
320
|
+
if (is_content_path(path)) {
|
|
321
|
+
if (!j.is_string()) {
|
|
322
|
+
throw std::runtime_error("Content path must be a string");
|
|
323
|
+
}
|
|
324
|
+
std::string str = j;
|
|
325
|
+
auto idx = str.find(partial->healing_marker.marker); // not using json_dump_marker as we're inside a string
|
|
326
|
+
if (idx != std::string::npos) {
|
|
327
|
+
str.resize(idx);
|
|
328
|
+
found_healing_marker = true;
|
|
329
|
+
}
|
|
330
|
+
return str;
|
|
331
|
+
}
|
|
332
|
+
if (j.is_object()) {
|
|
333
|
+
auto obj = json::object();
|
|
334
|
+
for (const auto & p : j.items()) {
|
|
335
|
+
const auto & key = p.key();
|
|
336
|
+
const auto & value = p.value();
|
|
337
|
+
const std::string key_str = key; // NOLINT
|
|
338
|
+
auto idx = key_str.find(healing_marker_);
|
|
339
|
+
if (idx != std::string::npos) {
|
|
340
|
+
found_healing_marker = true;
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
path.push_back(key_str);
|
|
344
|
+
if (value.is_string()) {
|
|
345
|
+
const std::string value_str = value;
|
|
346
|
+
if (value_str.find(healing_marker_) != std::string::npos) {
|
|
347
|
+
found_healing_marker = true;
|
|
348
|
+
if (is_content_path(path)) {
|
|
349
|
+
if (partial->healing_marker.marker == partial->healing_marker.json_dump_marker) {
|
|
350
|
+
// The healing occurred inside the string: good. Otherwise we just ditch the entire key/value pair.
|
|
351
|
+
obj[key] = remove_unsupported_healings_and_dump_args(value);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
obj[key] = value;
|
|
357
|
+
} else {
|
|
358
|
+
obj[key] = remove_unsupported_healings_and_dump_args(value);
|
|
359
|
+
}
|
|
360
|
+
path.pop_back();
|
|
361
|
+
}
|
|
362
|
+
return obj;
|
|
363
|
+
}
|
|
364
|
+
if (j.is_array()) {
|
|
365
|
+
auto arr = json::array();
|
|
366
|
+
for (const auto & value : j) {
|
|
367
|
+
if (value.is_string()) {
|
|
368
|
+
std::string str = value;
|
|
369
|
+
auto idx = str.find(healing_marker_);
|
|
370
|
+
if (idx != std::string::npos) {
|
|
371
|
+
// Don't heal array values that aren't in the arguments.
|
|
372
|
+
found_healing_marker = true;
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
arr.push_back(remove_unsupported_healings_and_dump_args(value));
|
|
377
|
+
}
|
|
378
|
+
return arr;
|
|
379
|
+
}
|
|
380
|
+
return j;
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
auto cleaned = remove_unsupported_healings_and_dump_args(partial->json);
|
|
384
|
+
LOG_DBG("Cleaned up JSON %s to %s (json_healing_marker : '%s')\n", partial->json.dump().c_str(), cleaned.dump().c_str(), partial->healing_marker.json_dump_marker.c_str());
|
|
385
|
+
return consume_json_result {
|
|
386
|
+
cleaned,
|
|
387
|
+
/* .is_partial = */ found_healing_marker,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
void common_chat_msg_parser::clear_tools() {
|
|
392
|
+
result_.tool_calls.clear();
|
|
393
|
+
}
|