cactus-react-native 1.4.0 → 1.7.0

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 (226) hide show
  1. package/Cactus.podspec +1 -1
  2. package/README.md +465 -174
  3. package/android/CMakeLists.txt +24 -5
  4. package/android/src/main/jniLibs/arm64-v8a/libcactus.a +0 -0
  5. package/android/src/main/jniLibs/arm64-v8a/libcurl.a +0 -0
  6. package/android/src/main/jniLibs/arm64-v8a/libmbedcrypto.a +0 -0
  7. package/android/src/main/jniLibs/arm64-v8a/libmbedtls.a +0 -0
  8. package/android/src/main/jniLibs/arm64-v8a/libmbedx509.a +0 -0
  9. package/cpp/HybridCactus.cpp +157 -6
  10. package/cpp/HybridCactus.hpp +20 -3
  11. package/cpp/cactus_ffi.h +65 -30
  12. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus.h +0 -1
  13. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_ffi.h +65 -30
  14. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_utils.h +357 -122
  15. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/engine.h +184 -63
  16. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/gemma_tools.h +549 -0
  17. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/graph.h +153 -27
  18. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/kernel.h +90 -178
  19. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/kernel_utils.h +276 -151
  20. package/ios/cactus.xcframework/ios-arm64/cactus.framework/cactus +0 -0
  21. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus.h +0 -1
  22. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_ffi.h +65 -30
  23. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_utils.h +357 -122
  24. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/engine.h +184 -63
  25. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/gemma_tools.h +549 -0
  26. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/graph.h +153 -27
  27. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/kernel.h +90 -178
  28. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/kernel_utils.h +276 -151
  29. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/cactus +0 -0
  30. package/lib/module/classes/CactusLM.js +43 -58
  31. package/lib/module/classes/CactusLM.js.map +1 -1
  32. package/lib/module/classes/CactusSTT.js +64 -38
  33. package/lib/module/classes/CactusSTT.js.map +1 -1
  34. package/lib/module/classes/CactusVAD.js +95 -0
  35. package/lib/module/classes/CactusVAD.js.map +1 -0
  36. package/lib/module/hooks/useCactusLM.js +23 -15
  37. package/lib/module/hooks/useCactusLM.js.map +1 -1
  38. package/lib/module/hooks/useCactusSTT.js +85 -28
  39. package/lib/module/hooks/useCactusSTT.js.map +1 -1
  40. package/lib/module/hooks/useCactusVAD.js +171 -0
  41. package/lib/module/hooks/useCactusVAD.js.map +1 -0
  42. package/lib/module/index.js +2 -3
  43. package/lib/module/index.js.map +1 -1
  44. package/lib/module/modelRegistry.js +52 -0
  45. package/lib/module/modelRegistry.js.map +1 -0
  46. package/lib/module/native/Cactus.js +107 -8
  47. package/lib/module/native/Cactus.js.map +1 -1
  48. package/lib/module/native/CactusIndex.js.map +1 -1
  49. package/lib/module/native/index.js +0 -3
  50. package/lib/module/native/index.js.map +1 -1
  51. package/lib/module/types/CactusLM.js +2 -0
  52. package/lib/module/types/CactusSTT.js +2 -0
  53. package/lib/module/types/CactusVAD.js +4 -0
  54. package/lib/module/types/{CactusModel.js.map → CactusVAD.js.map} +1 -1
  55. package/lib/module/types/common.js +2 -0
  56. package/lib/module/types/{CactusSTTModel.js.map → common.js.map} +1 -1
  57. package/lib/typescript/src/classes/CactusLM.d.ts +8 -6
  58. package/lib/typescript/src/classes/CactusLM.d.ts.map +1 -1
  59. package/lib/typescript/src/classes/CactusSTT.d.ts +11 -6
  60. package/lib/typescript/src/classes/CactusSTT.d.ts.map +1 -1
  61. package/lib/typescript/src/classes/CactusVAD.d.ts +20 -0
  62. package/lib/typescript/src/classes/CactusVAD.d.ts.map +1 -0
  63. package/lib/typescript/src/hooks/useCactusLM.d.ts +3 -3
  64. package/lib/typescript/src/hooks/useCactusLM.d.ts.map +1 -1
  65. package/lib/typescript/src/hooks/useCactusSTT.d.ts +11 -5
  66. package/lib/typescript/src/hooks/useCactusSTT.d.ts.map +1 -1
  67. package/lib/typescript/src/hooks/useCactusVAD.d.ts +15 -0
  68. package/lib/typescript/src/hooks/useCactusVAD.d.ts.map +1 -0
  69. package/lib/typescript/src/index.d.ts +7 -6
  70. package/lib/typescript/src/index.d.ts.map +1 -1
  71. package/lib/typescript/src/modelRegistry.d.ts +5 -0
  72. package/lib/typescript/src/modelRegistry.d.ts.map +1 -0
  73. package/lib/typescript/src/native/Cactus.d.ts +12 -6
  74. package/lib/typescript/src/native/Cactus.d.ts.map +1 -1
  75. package/lib/typescript/src/native/CactusIndex.d.ts +2 -2
  76. package/lib/typescript/src/native/CactusIndex.d.ts.map +1 -1
  77. package/lib/typescript/src/native/index.d.ts +0 -3
  78. package/lib/typescript/src/native/index.d.ts.map +1 -1
  79. package/lib/typescript/src/specs/Cactus.nitro.d.ts +6 -1
  80. package/lib/typescript/src/specs/Cactus.nitro.d.ts.map +1 -1
  81. package/lib/typescript/src/types/CactusIndex.d.ts +2 -2
  82. package/lib/typescript/src/types/CactusIndex.d.ts.map +1 -1
  83. package/lib/typescript/src/types/CactusLM.d.ts +19 -9
  84. package/lib/typescript/src/types/CactusLM.d.ts.map +1 -1
  85. package/lib/typescript/src/types/CactusSTT.d.ts +45 -4
  86. package/lib/typescript/src/types/CactusSTT.d.ts.map +1 -1
  87. package/lib/typescript/src/types/CactusVAD.d.ts +34 -0
  88. package/lib/typescript/src/types/CactusVAD.d.ts.map +1 -0
  89. package/lib/typescript/src/types/common.d.ts +23 -0
  90. package/lib/typescript/src/types/common.d.ts.map +1 -0
  91. package/nitro.json +0 -11
  92. package/nitrogen/generated/android/cactus+autolinking.cmake +0 -5
  93. package/nitrogen/generated/android/cactusOnLoad.cpp +0 -30
  94. package/nitrogen/generated/ios/Cactus-Swift-Cxx-Bridge.cpp +0 -50
  95. package/nitrogen/generated/ios/Cactus-Swift-Cxx-Bridge.hpp +9 -147
  96. package/nitrogen/generated/ios/Cactus-Swift-Cxx-Umbrella.hpp +0 -13
  97. package/nitrogen/generated/ios/CactusAutolinking.mm +0 -26
  98. package/nitrogen/generated/ios/CactusAutolinking.swift +0 -30
  99. package/nitrogen/generated/shared/c++/HybridCactusSpec.cpp +5 -0
  100. package/nitrogen/generated/shared/c++/HybridCactusSpec.hpp +6 -1
  101. package/package.json +3 -3
  102. package/src/classes/CactusLM.ts +59 -74
  103. package/src/classes/CactusSTT.ts +92 -49
  104. package/src/classes/CactusVAD.ts +129 -0
  105. package/src/hooks/useCactusLM.ts +26 -9
  106. package/src/hooks/useCactusSTT.ts +105 -44
  107. package/src/hooks/useCactusVAD.ts +215 -0
  108. package/src/index.tsx +20 -10
  109. package/src/modelRegistry.ts +65 -0
  110. package/src/native/Cactus.ts +130 -14
  111. package/src/native/CactusIndex.ts +2 -2
  112. package/src/native/index.ts +0 -3
  113. package/src/specs/Cactus.nitro.ts +11 -2
  114. package/src/types/CactusIndex.ts +2 -2
  115. package/src/types/CactusLM.ts +20 -9
  116. package/src/types/CactusSTT.ts +50 -4
  117. package/src/types/CactusVAD.ts +39 -0
  118. package/src/types/common.ts +23 -0
  119. package/android/src/main/java/com/margelo/nitro/cactus/HybridCactusCrypto.kt +0 -46
  120. package/android/src/main/java/com/margelo/nitro/cactus/HybridCactusDeviceInfo.kt +0 -27
  121. package/android/src/main/jniLibs/arm64-v8a/libcactus_util.a +0 -0
  122. package/cpp/HybridCactusUtil.cpp +0 -47
  123. package/cpp/HybridCactusUtil.hpp +0 -27
  124. package/cpp/cactus_util.h +0 -25
  125. package/ios/HybridCactusCrypto.swift +0 -37
  126. package/ios/HybridCactusDeviceInfo.swift +0 -32
  127. package/ios/cactus.xcframework/ios-arm64/cactus.framework/Headers/cactus_telemetry.h +0 -656
  128. package/ios/cactus.xcframework/ios-arm64-simulator/cactus.framework/Headers/cactus_telemetry.h +0 -656
  129. package/ios/cactus_util.xcframework/Info.plist +0 -39
  130. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Headers/cactus_util.h +0 -25
  131. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Headers/database.h +0 -27
  132. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Headers/ios_utils.h +0 -10
  133. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Headers/logging.h +0 -25
  134. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/Info.plist +0 -0
  135. package/ios/cactus_util.xcframework/ios-arm64/cactus_util.framework/cactus_util +0 -0
  136. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Headers/cactus_util.h +0 -25
  137. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Headers/database.h +0 -27
  138. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Headers/ios_utils.h +0 -10
  139. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Headers/logging.h +0 -25
  140. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/Info.plist +0 -0
  141. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/_CodeSignature/CodeResources +0 -135
  142. package/ios/cactus_util.xcframework/ios-arm64-simulator/cactus_util.framework/cactus_util +0 -0
  143. package/lib/module/api/Database.js +0 -137
  144. package/lib/module/api/Database.js.map +0 -1
  145. package/lib/module/api/RemoteLM.js +0 -201
  146. package/lib/module/api/RemoteLM.js.map +0 -1
  147. package/lib/module/config/CactusConfig.js +0 -12
  148. package/lib/module/config/CactusConfig.js.map +0 -1
  149. package/lib/module/native/CactusCrypto.js +0 -10
  150. package/lib/module/native/CactusCrypto.js.map +0 -1
  151. package/lib/module/native/CactusDeviceInfo.js +0 -13
  152. package/lib/module/native/CactusDeviceInfo.js.map +0 -1
  153. package/lib/module/native/CactusUtil.js +0 -36
  154. package/lib/module/native/CactusUtil.js.map +0 -1
  155. package/lib/module/specs/CactusCrypto.nitro.js +0 -4
  156. package/lib/module/specs/CactusCrypto.nitro.js.map +0 -1
  157. package/lib/module/specs/CactusDeviceInfo.nitro.js +0 -4
  158. package/lib/module/specs/CactusDeviceInfo.nitro.js.map +0 -1
  159. package/lib/module/specs/CactusUtil.nitro.js +0 -4
  160. package/lib/module/specs/CactusUtil.nitro.js.map +0 -1
  161. package/lib/module/telemetry/Telemetry.js +0 -154
  162. package/lib/module/telemetry/Telemetry.js.map +0 -1
  163. package/lib/module/types/CactusModel.js +0 -2
  164. package/lib/module/types/CactusSTTModel.js +0 -2
  165. package/lib/typescript/src/api/Database.d.ts +0 -18
  166. package/lib/typescript/src/api/Database.d.ts.map +0 -1
  167. package/lib/typescript/src/api/RemoteLM.d.ts +0 -14
  168. package/lib/typescript/src/api/RemoteLM.d.ts.map +0 -1
  169. package/lib/typescript/src/config/CactusConfig.d.ts +0 -7
  170. package/lib/typescript/src/config/CactusConfig.d.ts.map +0 -1
  171. package/lib/typescript/src/native/CactusCrypto.d.ts +0 -5
  172. package/lib/typescript/src/native/CactusCrypto.d.ts.map +0 -1
  173. package/lib/typescript/src/native/CactusDeviceInfo.d.ts +0 -7
  174. package/lib/typescript/src/native/CactusDeviceInfo.d.ts.map +0 -1
  175. package/lib/typescript/src/native/CactusUtil.d.ts +0 -6
  176. package/lib/typescript/src/native/CactusUtil.d.ts.map +0 -1
  177. package/lib/typescript/src/specs/CactusCrypto.nitro.d.ts +0 -8
  178. package/lib/typescript/src/specs/CactusCrypto.nitro.d.ts.map +0 -1
  179. package/lib/typescript/src/specs/CactusDeviceInfo.nitro.d.ts +0 -16
  180. package/lib/typescript/src/specs/CactusDeviceInfo.nitro.d.ts.map +0 -1
  181. package/lib/typescript/src/specs/CactusUtil.nitro.d.ts +0 -10
  182. package/lib/typescript/src/specs/CactusUtil.nitro.d.ts.map +0 -1
  183. package/lib/typescript/src/telemetry/Telemetry.d.ts +0 -34
  184. package/lib/typescript/src/telemetry/Telemetry.d.ts.map +0 -1
  185. package/lib/typescript/src/types/CactusModel.d.ts +0 -13
  186. package/lib/typescript/src/types/CactusModel.d.ts.map +0 -1
  187. package/lib/typescript/src/types/CactusSTTModel.d.ts +0 -8
  188. package/lib/typescript/src/types/CactusSTTModel.d.ts.map +0 -1
  189. package/nitrogen/generated/android/c++/JDeviceInfo.hpp +0 -74
  190. package/nitrogen/generated/android/c++/JHybridCactusCryptoSpec.cpp +0 -65
  191. package/nitrogen/generated/android/c++/JHybridCactusCryptoSpec.hpp +0 -65
  192. package/nitrogen/generated/android/c++/JHybridCactusDeviceInfoSpec.cpp +0 -85
  193. package/nitrogen/generated/android/c++/JHybridCactusDeviceInfoSpec.hpp +0 -66
  194. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/DeviceInfo.kt +0 -50
  195. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusCryptoSpec.kt +0 -58
  196. package/nitrogen/generated/android/kotlin/com/margelo/nitro/cactus/HybridCactusDeviceInfoSpec.kt +0 -62
  197. package/nitrogen/generated/ios/c++/HybridCactusCryptoSpecSwift.cpp +0 -11
  198. package/nitrogen/generated/ios/c++/HybridCactusCryptoSpecSwift.hpp +0 -77
  199. package/nitrogen/generated/ios/c++/HybridCactusDeviceInfoSpecSwift.cpp +0 -11
  200. package/nitrogen/generated/ios/c++/HybridCactusDeviceInfoSpecSwift.hpp +0 -88
  201. package/nitrogen/generated/ios/swift/DeviceInfo.swift +0 -98
  202. package/nitrogen/generated/ios/swift/Func_void_DeviceInfo.swift +0 -47
  203. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +0 -54
  204. package/nitrogen/generated/ios/swift/HybridCactusCryptoSpec.swift +0 -57
  205. package/nitrogen/generated/ios/swift/HybridCactusCryptoSpec_cxx.swift +0 -139
  206. package/nitrogen/generated/ios/swift/HybridCactusDeviceInfoSpec.swift +0 -58
  207. package/nitrogen/generated/ios/swift/HybridCactusDeviceInfoSpec_cxx.swift +0 -164
  208. package/nitrogen/generated/shared/c++/DeviceInfo.hpp +0 -92
  209. package/nitrogen/generated/shared/c++/HybridCactusCryptoSpec.cpp +0 -21
  210. package/nitrogen/generated/shared/c++/HybridCactusCryptoSpec.hpp +0 -63
  211. package/nitrogen/generated/shared/c++/HybridCactusDeviceInfoSpec.cpp +0 -22
  212. package/nitrogen/generated/shared/c++/HybridCactusDeviceInfoSpec.hpp +0 -67
  213. package/nitrogen/generated/shared/c++/HybridCactusUtilSpec.cpp +0 -23
  214. package/nitrogen/generated/shared/c++/HybridCactusUtilSpec.hpp +0 -66
  215. package/src/api/Database.ts +0 -188
  216. package/src/api/RemoteLM.ts +0 -273
  217. package/src/config/CactusConfig.ts +0 -11
  218. package/src/native/CactusCrypto.ts +0 -11
  219. package/src/native/CactusDeviceInfo.ts +0 -18
  220. package/src/native/CactusUtil.ts +0 -43
  221. package/src/specs/CactusCrypto.nitro.ts +0 -6
  222. package/src/specs/CactusDeviceInfo.nitro.ts +0 -15
  223. package/src/specs/CactusUtil.nitro.ts +0 -8
  224. package/src/telemetry/Telemetry.ts +0 -236
  225. package/src/types/CactusModel.ts +0 -15
  226. package/src/types/CactusSTTModel.ts +0 -10
@@ -0,0 +1,549 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+ #include <vector>
5
+ #include <algorithm>
6
+ #include <cctype>
7
+ #include <map>
8
+ #include <set>
9
+
10
+ namespace gemma {
11
+
12
+ inline std::string to_upper(const std::string& s) {
13
+ std::string result = s;
14
+ for (auto& c : result) c = std::toupper(c);
15
+ return result;
16
+ }
17
+
18
+ inline std::string escape(const std::string& s) {
19
+ return "<escape>" + s + "<escape>";
20
+ }
21
+
22
+ inline void skip_whitespace(const std::string& json, size_t& pos) {
23
+ while (pos < json.length() && std::isspace(json[pos])) pos++;
24
+ }
25
+
26
+ inline std::string extract_json_string(const std::string& json, size_t& pos) {
27
+ std::string value;
28
+ while (pos < json.length() && json[pos] != '"') {
29
+ if (json[pos] == '\\' && pos + 1 < json.length()) {
30
+ pos++;
31
+ if (json[pos] == 'n') value += '\n';
32
+ else if (json[pos] == 't') value += '\t';
33
+ else if (json[pos] == 'r') value += '\r';
34
+ else if (json[pos] == '"') value += '"';
35
+ else if (json[pos] == '\\') value += '\\';
36
+ else value += json[pos];
37
+ } else {
38
+ value += json[pos];
39
+ }
40
+ pos++;
41
+ }
42
+ if (pos < json.length()) pos++;
43
+ return value;
44
+ }
45
+
46
+ std::string format_argument(const std::string& json, size_t& pos, bool escape_keys);
47
+ std::string format_parameters(const std::string& properties_json, const std::string& /*required_json*/);
48
+
49
+ inline std::string format_argument(const std::string& json, size_t& pos, bool escape_keys = true) {
50
+ skip_whitespace(json, pos);
51
+ if (pos >= json.length()) return "";
52
+
53
+ char c = json[pos];
54
+
55
+ if (c == '"') {
56
+ std::string value = extract_json_string(json, pos);
57
+ return escape(value);
58
+ } else if (c == '{') {
59
+ std::string result = "{";
60
+ pos++;
61
+ bool first = true;
62
+
63
+ while (pos < json.length()) {
64
+ skip_whitespace(json, pos);
65
+ if (pos >= json.length() || json[pos] == '}') { pos++; break; }
66
+ if (json[pos] == ',') { pos++; continue; }
67
+
68
+ if (json[pos] != '"') break;
69
+ pos++;
70
+ std::string key = extract_json_string(json, pos);
71
+
72
+ skip_whitespace(json, pos);
73
+ if (pos < json.length() && json[pos] == ':') pos++;
74
+
75
+ std::string value = format_argument(json, pos, escape_keys);
76
+
77
+ if (!first) result += ",";
78
+ first = false;
79
+ if (escape_keys) {
80
+ result += escape(key) + ":" + value;
81
+ } else {
82
+ result += key + ":" + value;
83
+ }
84
+ }
85
+ result += "}";
86
+ return result;
87
+ } else if (c == '[') {
88
+ std::string result = "[";
89
+ pos++;
90
+ bool first = true;
91
+
92
+ while (pos < json.length()) {
93
+ skip_whitespace(json, pos);
94
+ if (pos >= json.length() || json[pos] == ']') { pos++; break; }
95
+ if (json[pos] == ',') { pos++; continue; }
96
+
97
+ std::string value = format_argument(json, pos, escape_keys);
98
+
99
+ if (!first) result += ",";
100
+ first = false;
101
+ result += value;
102
+ }
103
+ result += "]";
104
+ return result;
105
+ } else if (json.compare(pos, 4, "true") == 0) {
106
+ pos += 4;
107
+ return "true";
108
+ } else if (json.compare(pos, 5, "false") == 0) {
109
+ pos += 5;
110
+ return "false";
111
+ } else if (json.compare(pos, 4, "null") == 0) {
112
+ pos += 4;
113
+ return "null";
114
+ } else {
115
+ size_t start = pos;
116
+ while (pos < json.length() && (std::isdigit(json[pos]) || json[pos] == '.' ||
117
+ json[pos] == '-' || json[pos] == '+' || json[pos] == 'e' || json[pos] == 'E')) {
118
+ pos++;
119
+ }
120
+ return json.substr(start, pos - start);
121
+ }
122
+ }
123
+
124
+ inline std::map<std::string, std::string> parse_json_object_raw(const std::string& json, size_t& pos) {
125
+ std::map<std::string, std::string> result;
126
+ skip_whitespace(json, pos);
127
+ if (pos >= json.length() || json[pos] != '{') return result;
128
+ pos++;
129
+
130
+ while (pos < json.length()) {
131
+ skip_whitespace(json, pos);
132
+ if (pos >= json.length() || json[pos] == '}') { pos++; break; }
133
+ if (json[pos] == ',') { pos++; continue; }
134
+
135
+ if (json[pos] != '"') break;
136
+ pos++;
137
+ std::string key = extract_json_string(json, pos);
138
+
139
+ skip_whitespace(json, pos);
140
+ if (pos < json.length() && json[pos] == ':') pos++;
141
+ skip_whitespace(json, pos);
142
+
143
+ size_t value_start = pos;
144
+ if (json[pos] == '"') {
145
+ pos++;
146
+ while (pos < json.length() && json[pos] != '"') {
147
+ if (json[pos] == '\\') pos++;
148
+ pos++;
149
+ }
150
+ pos++;
151
+ } else if (json[pos] == '{') {
152
+ int depth = 1;
153
+ pos++;
154
+ while (pos < json.length() && depth > 0) {
155
+ if (json[pos] == '{') depth++;
156
+ else if (json[pos] == '}') depth--;
157
+ else if (json[pos] == '"') {
158
+ pos++;
159
+ while (pos < json.length() && json[pos] != '"') {
160
+ if (json[pos] == '\\') pos++;
161
+ pos++;
162
+ }
163
+ }
164
+ pos++;
165
+ }
166
+ } else if (json[pos] == '[') {
167
+ int depth = 1;
168
+ pos++;
169
+ while (pos < json.length() && depth > 0) {
170
+ if (json[pos] == '[') depth++;
171
+ else if (json[pos] == ']') depth--;
172
+ else if (json[pos] == '"') {
173
+ pos++;
174
+ while (pos < json.length() && json[pos] != '"') {
175
+ if (json[pos] == '\\') pos++;
176
+ pos++;
177
+ }
178
+ }
179
+ pos++;
180
+ }
181
+ } else {
182
+ while (pos < json.length() && json[pos] != ',' && json[pos] != '}') pos++;
183
+ }
184
+ result[key] = json.substr(value_start, pos - value_start);
185
+ }
186
+ return result;
187
+ }
188
+
189
+ inline std::string get_json_string_value(const std::string& json, size_t pos) {
190
+ skip_whitespace(json, pos);
191
+ if (pos < json.length() && json[pos] == '"') {
192
+ pos++;
193
+ return extract_json_string(json, pos);
194
+ }
195
+ return "";
196
+ }
197
+
198
+ inline std::string format_parameters(const std::string& properties_json, const std::string& /*required_json*/) {
199
+ static const std::set<std::string> standard_keys = {"description", "type", "properties", "required", "nullable"};
200
+
201
+ size_t pos = 0;
202
+ auto properties = parse_json_object_raw(properties_json, pos);
203
+
204
+ std::string result;
205
+ bool first = true;
206
+
207
+ for (const auto& [key, value_json] : properties) {
208
+ if (standard_keys.count(key)) continue;
209
+
210
+ if (!first) result += ",";
211
+ first = false;
212
+
213
+ size_t prop_pos = 0;
214
+ auto prop_obj = parse_json_object_raw(value_json, prop_pos);
215
+
216
+ result += key + ":{";
217
+
218
+ if (prop_obj.count("description")) {
219
+ std::string desc = get_json_string_value(prop_obj["description"], 0);
220
+ result += "description:" + escape(desc);
221
+ }
222
+
223
+ std::string type_val;
224
+ if (prop_obj.count("type")) {
225
+ type_val = get_json_string_value(prop_obj["type"], 0);
226
+ }
227
+
228
+ if (to_upper(type_val) == "STRING") {
229
+ if (prop_obj.count("enum")) {
230
+ size_t enum_pos = 0;
231
+ std::string enum_formatted = format_argument(prop_obj["enum"], enum_pos, true);
232
+ result += ",enum:" + enum_formatted;
233
+ }
234
+ } else if (to_upper(type_val) == "OBJECT") {
235
+ if (prop_obj.count("properties")) {
236
+ std::string nested_required;
237
+ if (prop_obj.count("required")) {
238
+ nested_required = prop_obj["required"];
239
+ }
240
+ result += ",properties:{" + format_parameters(prop_obj["properties"], nested_required) + "}";
241
+ }
242
+ if (prop_obj.count("required")) {
243
+ result += ",required:[";
244
+ size_t req_pos = 0;
245
+ skip_whitespace(prop_obj["required"], req_pos);
246
+ if (req_pos < prop_obj["required"].length() && prop_obj["required"][req_pos] == '[') {
247
+ req_pos++;
248
+ bool req_first = true;
249
+ while (req_pos < prop_obj["required"].length()) {
250
+ skip_whitespace(prop_obj["required"], req_pos);
251
+ if (prop_obj["required"][req_pos] == ']') break;
252
+ if (prop_obj["required"][req_pos] == ',') { req_pos++; continue; }
253
+ if (prop_obj["required"][req_pos] == '"') {
254
+ req_pos++;
255
+ std::string req_item = extract_json_string(prop_obj["required"], req_pos);
256
+ if (!req_first) result += ",";
257
+ req_first = false;
258
+ result += escape(req_item);
259
+ }
260
+ }
261
+ }
262
+ result += "]";
263
+ }
264
+ } else if (to_upper(type_val) == "ARRAY") {
265
+ if (prop_obj.count("items")) {
266
+ result += ",items:{";
267
+ size_t items_pos = 0;
268
+ auto items_obj = parse_json_object_raw(prop_obj["items"], items_pos);
269
+ bool items_first = true;
270
+
271
+ for (const auto& [item_key, item_value] : items_obj) {
272
+ if (!items_first) result += ",";
273
+ items_first = false;
274
+
275
+ if (item_key == "properties") {
276
+ std::string items_required;
277
+ if (items_obj.count("required")) {
278
+ items_required = items_obj["required"];
279
+ }
280
+ result += "properties:{" + format_parameters(item_value, items_required) + "}";
281
+ } else if (item_key == "required") {
282
+ result += "required:[";
283
+ size_t req_pos = 0;
284
+ skip_whitespace(item_value, req_pos);
285
+ if (req_pos < item_value.length() && item_value[req_pos] == '[') {
286
+ req_pos++;
287
+ bool req_first = true;
288
+ while (req_pos < item_value.length()) {
289
+ skip_whitespace(item_value, req_pos);
290
+ if (item_value[req_pos] == ']') break;
291
+ if (item_value[req_pos] == ',') { req_pos++; continue; }
292
+ if (item_value[req_pos] == '"') {
293
+ req_pos++;
294
+ std::string req_item = extract_json_string(item_value, req_pos);
295
+ if (!req_first) result += ",";
296
+ req_first = false;
297
+ result += escape(req_item);
298
+ }
299
+ }
300
+ }
301
+ result += "]";
302
+ } else if (item_key == "type") {
303
+ std::string item_type = get_json_string_value(item_value, 0);
304
+ result += "type:" + escape(to_upper(item_type));
305
+ } else {
306
+ size_t val_pos = 0;
307
+ result += item_key + ":" + format_argument(item_value, val_pos, true);
308
+ }
309
+ }
310
+ result += "}";
311
+ }
312
+ }
313
+
314
+ if (!type_val.empty()) {
315
+ result += ",type:" + escape(to_upper(type_val));
316
+ }
317
+
318
+ result += "}";
319
+ }
320
+
321
+ return result;
322
+ }
323
+
324
+ inline std::string format_function_declaration(const std::string& name,
325
+ const std::string& description,
326
+ const std::string& params_json) {
327
+ std::string result = "declaration:" + name + "{";
328
+ result += "description:" + escape(description);
329
+
330
+ if (!params_json.empty()) {
331
+ result += ",parameters:{";
332
+
333
+ size_t pos = 0;
334
+ auto params = parse_json_object_raw(params_json, pos);
335
+
336
+ if (params.count("properties")) {
337
+ std::string required_json;
338
+ if (params.count("required")) {
339
+ required_json = params["required"];
340
+ }
341
+ result += "properties:{" + format_parameters(params["properties"], required_json) + "}";
342
+ }
343
+
344
+ if (params.count("required")) {
345
+ result += ",required:[";
346
+ size_t req_pos = 0;
347
+ skip_whitespace(params["required"], req_pos);
348
+ if (req_pos < params["required"].length() && params["required"][req_pos] == '[') {
349
+ req_pos++;
350
+ bool first = true;
351
+ while (req_pos < params["required"].length()) {
352
+ skip_whitespace(params["required"], req_pos);
353
+ if (params["required"][req_pos] == ']') break;
354
+ if (params["required"][req_pos] == ',') { req_pos++; continue; }
355
+ if (params["required"][req_pos] == '"') {
356
+ req_pos++;
357
+ std::string item = extract_json_string(params["required"], req_pos);
358
+ if (!first) result += ",";
359
+ first = false;
360
+ result += escape(item);
361
+ }
362
+ }
363
+ }
364
+ result += "]";
365
+ }
366
+
367
+ if (params.count("type")) {
368
+ std::string type_val = get_json_string_value(params["type"], 0);
369
+ result += ",type:" + escape(to_upper(type_val));
370
+ }
371
+
372
+ result += "}";
373
+ }
374
+
375
+ result += "}";
376
+ return result;
377
+ }
378
+
379
+ template<typename ToolFunction>
380
+ inline std::string format_tools(const std::vector<ToolFunction>& tools) {
381
+ if (tools.empty()) return "";
382
+
383
+ std::string result;
384
+ for (const auto& tool : tools) {
385
+ result += "<start_function_declaration>";
386
+ std::string params_json;
387
+ auto it = tool.parameters.find("schema");
388
+ if (it != tool.parameters.end()) {
389
+ params_json = it->second;
390
+ }
391
+
392
+ result += format_function_declaration(tool.name, tool.description, params_json);
393
+ result += "<end_function_declaration>";
394
+ }
395
+ return result;
396
+ }
397
+
398
+
399
+ inline std::string unescape(const std::string& s) {
400
+ const std::string ESCAPE_TAG = "<escape>";
401
+ std::string result = s;
402
+ size_t pos = 0;
403
+ while ((pos = result.find(ESCAPE_TAG, pos)) != std::string::npos) {
404
+ result.erase(pos, ESCAPE_TAG.length());
405
+ }
406
+ return result;
407
+ }
408
+
409
+ inline std::string args_to_json(const std::string& args_content) {
410
+ std::string result = "{";
411
+ size_t pos = 0;
412
+ bool first = true;
413
+
414
+ if (!args_content.empty() && args_content[0] == '{') pos = 1;
415
+
416
+ while (pos < args_content.length()) {
417
+ while (pos < args_content.length() && std::isspace(args_content[pos])) pos++;
418
+ if (pos >= args_content.length() || args_content[pos] == '}') break;
419
+ if (args_content[pos] == ',') { pos++; continue; }
420
+
421
+ size_t key_start = pos;
422
+ while (pos < args_content.length() && args_content[pos] != ':') pos++;
423
+ std::string key = args_content.substr(key_start, pos - key_start);
424
+ if (pos < args_content.length()) pos++;
425
+
426
+ std::string value;
427
+ while (pos < args_content.length() && std::isspace(args_content[pos])) pos++;
428
+
429
+ if (pos < args_content.length()) {
430
+ if (args_content.compare(pos, 8, "<escape>") == 0) {
431
+ pos += 8;
432
+ size_t val_end = args_content.find("<escape>", pos);
433
+ if (val_end != std::string::npos) {
434
+ value = "\"" + args_content.substr(pos, val_end - pos) + "\"";
435
+ pos = val_end + 8;
436
+ }
437
+ } else if (args_content[pos] == '{') {
438
+ int depth = 1;
439
+ size_t start = pos;
440
+ pos++;
441
+ while (pos < args_content.length() && depth > 0) {
442
+ if (args_content[pos] == '{') depth++;
443
+ else if (args_content[pos] == '}') depth--;
444
+ pos++;
445
+ }
446
+ value = args_to_json(args_content.substr(start, pos - start));
447
+ } else if (args_content[pos] == '[') {
448
+ int depth = 1;
449
+ size_t start = pos;
450
+ pos++;
451
+ while (pos < args_content.length() && depth > 0) {
452
+ if (args_content[pos] == '[') depth++;
453
+ else if (args_content[pos] == ']') depth--;
454
+ pos++;
455
+ }
456
+ std::string arr_content = args_content.substr(start + 1, pos - start - 2);
457
+ value = "[";
458
+ size_t arr_pos = 0;
459
+ bool first_item = true;
460
+ while (arr_pos < arr_content.length()) {
461
+ while (arr_pos < arr_content.length() && (std::isspace(arr_content[arr_pos]) || arr_content[arr_pos] == ',')) arr_pos++;
462
+ if (arr_pos >= arr_content.length()) break;
463
+
464
+ if (!first_item) value += ",";
465
+ first_item = false;
466
+
467
+ if (arr_content.compare(arr_pos, 8, "<escape>") == 0) {
468
+ arr_pos += 8;
469
+ size_t end = arr_content.find("<escape>", arr_pos);
470
+ if (end != std::string::npos) {
471
+ value += "\"" + arr_content.substr(arr_pos, end - arr_pos) + "\"";
472
+ arr_pos = end + 8;
473
+ }
474
+ } else {
475
+ size_t end = arr_content.find_first_of(",]", arr_pos);
476
+ if (end == std::string::npos) end = arr_content.length();
477
+ value += arr_content.substr(arr_pos, end - arr_pos);
478
+ arr_pos = end;
479
+ }
480
+ }
481
+ value += "]";
482
+ } else {
483
+ size_t val_start = pos;
484
+ while (pos < args_content.length() && args_content[pos] != ',' && args_content[pos] != '}') {
485
+ pos++;
486
+ }
487
+ value = args_content.substr(val_start, pos - val_start);
488
+ while (!value.empty() && std::isspace(value.back())) value.pop_back();
489
+ }
490
+ }
491
+
492
+ if (!first) result += ",";
493
+ first = false;
494
+ result += "\"" + key + "\":" + value;
495
+ }
496
+
497
+ result += "}";
498
+ return result;
499
+ }
500
+
501
+ inline void parse_function_calls(std::string& response, std::vector<std::string>& function_calls) {
502
+ const std::string CALL_START = "<start_function_call>";
503
+ const std::string CALL_END = "<end_function_call>";
504
+ size_t pos = 0;
505
+
506
+ while ((pos = response.find(CALL_START, pos)) != std::string::npos) {
507
+ size_t content_start = pos + CALL_START.length();
508
+ size_t call_end_pos = response.find(CALL_END, content_start);
509
+
510
+ size_t content_end = (call_end_pos != std::string::npos) ? call_end_pos : response.length();
511
+ std::string call_content = response.substr(content_start, content_end - content_start);
512
+
513
+ if (call_content.compare(0, 5, "call:") == 0) {
514
+ size_t brace_pos = call_content.find('{');
515
+
516
+ if (brace_pos == std::string::npos) {
517
+ size_t sep_pos = call_content.find_first_of(", ", 5);
518
+ if (sep_pos != std::string::npos) {
519
+ std::string func_name = call_content.substr(5, sep_pos - 5);
520
+ size_t args_start = sep_pos + 1;
521
+ while (args_start < call_content.length() &&
522
+ (call_content[args_start] == ' ' || call_content[args_start] == ',')) {
523
+ args_start++;
524
+ }
525
+ std::string args_content = "{" + call_content.substr(args_start);
526
+ if (args_content.back() != '}') args_content += "}";
527
+
528
+ std::string args_json = args_to_json(args_content);
529
+ std::string json_call = "{\"name\":\"" + func_name + "\",\"arguments\":" + args_json + "}";
530
+ function_calls.push_back(json_call);
531
+ }
532
+ } else {
533
+ std::string func_name = call_content.substr(5, brace_pos - 5);
534
+ std::string args_content = call_content.substr(brace_pos);
535
+ if (args_content.back() != '}') args_content += "}";
536
+
537
+ std::string args_json = args_to_json(args_content);
538
+ std::string json_call = "{\"name\":\"" + func_name + "\",\"arguments\":" + args_json + "}";
539
+ function_calls.push_back(json_call);
540
+ }
541
+ }
542
+
543
+ size_t erase_end = (call_end_pos != std::string::npos) ?
544
+ call_end_pos + CALL_END.length() : response.length();
545
+ response.erase(pos, erase_end - pos);
546
+ }
547
+ }
548
+
549
+ } // namespace gemma