@runanywhere/core 0.17.8 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +218 -2
  2. package/RunAnywhereCore.podspec +1 -0
  3. package/android/CMakeLists.txt +24 -2
  4. package/android/build.gradle +61 -9
  5. package/android/src/main/cpp/cpp-adapter.cpp +51 -3
  6. package/android/src/main/include/rac/backends/rac_vlm_llamacpp.h +216 -0
  7. package/android/src/main/include/rac/core/capabilities/rac_lifecycle.h +3 -1
  8. package/android/src/main/include/rac/core/rac_core.h +11 -0
  9. package/android/src/main/include/rac/core/rac_types.h +8 -6
  10. package/android/src/main/include/rac/features/diffusion/rac_diffusion.h +22 -0
  11. package/android/src/main/include/rac/features/diffusion/rac_diffusion_component.h +263 -0
  12. package/android/src/main/include/rac/features/diffusion/rac_diffusion_model_registry.h +358 -0
  13. package/android/src/main/include/rac/features/diffusion/rac_diffusion_service.h +187 -0
  14. package/android/src/main/include/rac/features/diffusion/rac_diffusion_tokenizer.h +167 -0
  15. package/android/src/main/include/rac/features/diffusion/rac_diffusion_types.h +454 -0
  16. package/android/src/main/include/rac/features/llm/rac_tool_calling.h +373 -0
  17. package/android/src/main/include/rac/features/platform/rac_diffusion_platform.h +305 -0
  18. package/android/src/main/include/rac/features/vad/rac_vad_energy.h +1 -1
  19. package/android/src/main/include/rac/features/vlm/rac_vlm.h +16 -0
  20. package/android/src/main/include/rac/features/vlm/rac_vlm_component.h +168 -0
  21. package/android/src/main/include/rac/features/vlm/rac_vlm_service.h +206 -0
  22. package/android/src/main/include/rac/features/vlm/rac_vlm_types.h +417 -0
  23. package/android/src/main/include/rac/infrastructure/model_management/rac_model_registry.h +15 -0
  24. package/android/src/main/include/rac/infrastructure/model_management/rac_model_types.h +3 -0
  25. package/android/src/main/include/rac/utils/rac_image_utils.h +215 -0
  26. package/android/src/main/java/com/margelo/nitro/runanywhere/PlatformAdapterBridge.kt +201 -1
  27. package/android/src/main/jniLibs/arm64-v8a/libc++_shared.so +0 -0
  28. package/android/src/main/jniLibs/arm64-v8a/libomp.so +0 -0
  29. package/android/src/main/jniLibs/arm64-v8a/librac_commons.so +0 -0
  30. package/android/src/main/jniLibs/arm64-v8a/librunanywhere_jni.so +0 -0
  31. package/android/src/main/jniLibs/x86_64/libc++_shared.so +0 -0
  32. package/android/src/main/jniLibs/x86_64/libomp.so +0 -0
  33. package/android/src/main/jniLibs/x86_64/librac_commons.so +0 -0
  34. package/android/src/main/jniLibs/x86_64/librunanywhere_jni.so +0 -0
  35. package/cpp/HybridRunAnywhereCore.cpp +263 -163
  36. package/cpp/HybridRunAnywhereCore.hpp +11 -0
  37. package/cpp/bridges/InitBridge.cpp +234 -3
  38. package/cpp/bridges/PlatformDownloadBridge.h +44 -0
  39. package/cpp/bridges/ToolCallingBridge.cpp +188 -0
  40. package/cpp/bridges/ToolCallingBridge.hpp +98 -0
  41. package/cpp/third_party/nlohmann/json.hpp +24765 -0
  42. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/RACommons.h +18 -4
  43. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_core.h +11 -0
  44. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion.h +22 -0
  45. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion_component.h +263 -0
  46. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion_model_registry.h +358 -0
  47. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion_platform.h +305 -0
  48. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion_service.h +187 -0
  49. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion_tokenizer.h +167 -0
  50. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion_types.h +454 -0
  51. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_endpoints.h +3 -17
  52. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_image_utils.h +215 -0
  53. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_lifecycle.h +3 -1
  54. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_model_assignment.h +4 -20
  55. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_model_registry.h +15 -0
  56. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_model_types.h +3 -0
  57. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_tool_calling.h +373 -0
  58. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_types.h +8 -6
  59. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_vad_energy.h +1 -1
  60. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_vlm.h +16 -0
  61. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_vlm_component.h +168 -0
  62. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_vlm_llamacpp.h +216 -0
  63. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_vlm_service.h +206 -0
  64. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_vlm_types.h +417 -0
  65. package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/RACommons +0 -0
  66. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/RACommons.h +18 -4
  67. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_core.h +11 -0
  68. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion.h +22 -0
  69. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion_component.h +263 -0
  70. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion_model_registry.h +358 -0
  71. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion_platform.h +305 -0
  72. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion_service.h +187 -0
  73. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion_tokenizer.h +167 -0
  74. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion_types.h +454 -0
  75. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_endpoints.h +3 -17
  76. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_image_utils.h +215 -0
  77. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_lifecycle.h +3 -1
  78. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_model_assignment.h +4 -20
  79. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_model_registry.h +15 -0
  80. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_model_types.h +3 -0
  81. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_tool_calling.h +373 -0
  82. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_types.h +8 -6
  83. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_vad_energy.h +1 -1
  84. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_vlm.h +16 -0
  85. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_vlm_component.h +168 -0
  86. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_vlm_llamacpp.h +216 -0
  87. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_vlm_service.h +206 -0
  88. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_vlm_types.h +417 -0
  89. package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/RACommons +0 -0
  90. package/ios/PlatformAdapterBridge.h +24 -1
  91. package/ios/PlatformAdapterBridge.m +243 -0
  92. package/nitrogen/generated/shared/c++/HybridRunAnywhereCoreSpec.cpp +4 -0
  93. package/nitrogen/generated/shared/c++/HybridRunAnywhereCoreSpec.hpp +4 -0
  94. package/package.json +8 -4
  95. package/src/Foundation/Security/SecureStorageService.ts +12 -6
  96. package/src/Public/Extensions/RunAnywhere+Models.ts +5 -3
  97. package/src/Public/Extensions/RunAnywhere+STT.ts +7 -2
  98. package/src/Public/Extensions/RunAnywhere+ToolCalling.ts +472 -0
  99. package/src/Public/Extensions/index.ts +16 -0
  100. package/src/Public/RunAnywhere.ts +18 -0
  101. package/src/index.ts +0 -1
  102. package/src/services/Network/index.ts +0 -1
  103. package/src/services/index.ts +0 -1
  104. package/src/specs/RunAnywhereCore.nitro.ts +72 -0
  105. package/src/types/ToolCallingTypes.ts +198 -0
  106. package/src/types/index.ts +13 -0
@@ -0,0 +1,472 @@
1
+ /**
2
+ * RunAnywhere+ToolCalling.ts
3
+ *
4
+ * Tool Calling extension for LLM.
5
+ * Allows LLMs to request external actions (API calls, device functions, etc.)
6
+ *
7
+ * ARCHITECTURE:
8
+ * - C++ (ToolCallingBridge) handles: parsing <tool_call> tags (single source of truth)
9
+ * - TypeScript handles: tool registration, executor storage, prompt formatting, orchestration
10
+ */
11
+
12
+ import { SDKLogger } from '../../Foundation/Logging/Logger/SDKLogger';
13
+ import { generateStream } from './RunAnywhere+TextGeneration';
14
+ import {
15
+ requireNativeModule,
16
+ isNativeModuleAvailable,
17
+ } from '../../native';
18
+ import type {
19
+ ToolDefinition,
20
+ ToolCall,
21
+ ToolResult,
22
+ ToolExecutor,
23
+ RegisteredTool,
24
+ ToolCallingOptions,
25
+ ToolCallingResult,
26
+ } from '../../types/ToolCallingTypes';
27
+
28
+ const logger = new SDKLogger('RunAnywhere.ToolCalling');
29
+
30
+ // =============================================================================
31
+ // PRIVATE STATE - Stores registered tools and executors
32
+ // Executors must stay in TypeScript (they need JS APIs like fetch)
33
+ // =============================================================================
34
+
35
+ const registeredTools: Map<string, RegisteredTool> = new Map();
36
+
37
+ // =============================================================================
38
+ // TOOL REGISTRATION
39
+ // =============================================================================
40
+
41
+ /**
42
+ * Register a tool that the LLM can use
43
+ *
44
+ * @param definition Tool definition (name, description, parameters)
45
+ * @param executor Function that executes the tool (stays in TypeScript)
46
+ */
47
+ export function registerTool(
48
+ definition: ToolDefinition,
49
+ executor: ToolExecutor
50
+ ): void {
51
+ logger.debug(`Registering tool: ${definition.name}`);
52
+ registeredTools.set(definition.name, { definition, executor });
53
+ }
54
+
55
+ /**
56
+ * Unregister a tool
57
+ */
58
+ export function unregisterTool(toolName: string): void {
59
+ registeredTools.delete(toolName);
60
+ }
61
+
62
+ /**
63
+ * Get all registered tool definitions
64
+ */
65
+ export function getRegisteredTools(): ToolDefinition[] {
66
+ return Array.from(registeredTools.values()).map((t) => t.definition);
67
+ }
68
+
69
+ /**
70
+ * Clear all registered tools
71
+ */
72
+ export function clearTools(): void {
73
+ registeredTools.clear();
74
+ }
75
+
76
+ // =============================================================================
77
+ // C++ BRIDGE CALLS - Single Source of Truth
78
+ // =============================================================================
79
+
80
+ /**
81
+ * Parse LLM output for tool calls using C++ ToolCallingBridge
82
+ * C++ is the single source of truth for parsing logic
83
+ */
84
+ async function parseToolCallViaCpp(llmOutput: string): Promise<{
85
+ text: string;
86
+ toolCall: ToolCall | null;
87
+ }> {
88
+ if (!isNativeModuleAvailable()) {
89
+ logger.warning('Native module not available for parseToolCall');
90
+ return { text: llmOutput, toolCall: null };
91
+ }
92
+
93
+ try {
94
+ const native = requireNativeModule();
95
+ const resultJson = await native.parseToolCallFromOutput(llmOutput);
96
+ const result = JSON.parse(resultJson);
97
+
98
+ if (!result.hasToolCall) {
99
+ return { text: result.cleanText || llmOutput, toolCall: null };
100
+ }
101
+
102
+ // Parse argumentsJson if it's a string, otherwise use as-is
103
+ let args: Record<string, unknown> = {};
104
+ if (result.argumentsJson) {
105
+ args = typeof result.argumentsJson === 'string'
106
+ ? JSON.parse(result.argumentsJson)
107
+ : result.argumentsJson;
108
+ }
109
+
110
+ const toolCall: ToolCall = {
111
+ toolName: result.toolName,
112
+ arguments: args,
113
+ callId: `call_${result.callId || Date.now()}`,
114
+ };
115
+
116
+ return { text: result.cleanText || '', toolCall };
117
+ } catch (error) {
118
+ logger.error(`C++ parseToolCall failed: ${error}`);
119
+ return { text: llmOutput, toolCall: null };
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Format tool definitions for LLM prompt
125
+ * Creates a system prompt describing available tools
126
+ *
127
+ * Uses C++ single source of truth via native module.
128
+ * Falls back to synchronous TypeScript implementation if native unavailable.
129
+ *
130
+ * @param tools - Tool definitions (defaults to registered tools)
131
+ * @param format - Tool calling format: 'default' (JSON) or 'lfm2' (Pythonic)
132
+ */
133
+ export function formatToolsForPrompt(tools?: ToolDefinition[], format?: string): string {
134
+ const toolsToFormat = tools || getRegisteredTools();
135
+ const toolFormat = format?.toLowerCase() || 'default';
136
+
137
+ if (toolsToFormat.length === 0) {
138
+ return '';
139
+ }
140
+
141
+ // Serialize tools to JSON for C++ consumption
142
+ const toolsJson = JSON.stringify(toolsToFormat.map((tool) => ({
143
+ name: tool.name,
144
+ description: tool.description,
145
+ parameters: tool.parameters.map((p) => ({
146
+ name: p.name,
147
+ type: p.type,
148
+ description: p.description,
149
+ required: p.required,
150
+ ...(p.enum ? { enumValues: p.enum } : {}),
151
+ })),
152
+ })));
153
+
154
+ // Use async C++ bridge version internally
155
+ // For sync callers, we return a placeholder and log a warning
156
+ // Prefer using formatToolsForPromptAsync for new code
157
+ logger.warning('formatToolsForPrompt is sync but C++ bridge is async. Use formatToolsForPromptAsync() for full C++ integration.');
158
+
159
+ return toolsJson; // Return raw JSON - actual formatting done by buildInitialPrompt
160
+ }
161
+
162
+ /**
163
+ * Format tool definitions for LLM prompt (async version)
164
+ * Uses C++ single source of truth for consistent formatting across all platforms.
165
+ *
166
+ * @param tools - Tool definitions (defaults to registered tools)
167
+ * @param format - Tool calling format: 'default' (JSON) or 'lfm2' (Pythonic)
168
+ */
169
+ export async function formatToolsForPromptAsync(tools?: ToolDefinition[], format?: string): Promise<string> {
170
+ const toolsToFormat = tools || getRegisteredTools();
171
+ const toolFormat = format?.toLowerCase() || 'default';
172
+
173
+ if (toolsToFormat.length === 0) {
174
+ return '';
175
+ }
176
+
177
+ // Serialize tools to JSON for C++ consumption
178
+ const toolsJson = JSON.stringify(toolsToFormat.map((tool) => ({
179
+ name: tool.name,
180
+ description: tool.description,
181
+ parameters: tool.parameters.map((p) => ({
182
+ name: p.name,
183
+ type: p.type,
184
+ description: p.description,
185
+ required: p.required,
186
+ ...(p.enum ? { enumValues: p.enum } : {}),
187
+ })),
188
+ })));
189
+
190
+ if (!isNativeModuleAvailable()) {
191
+ logger.warning('Native module not available, returning raw tools JSON');
192
+ return toolsJson;
193
+ }
194
+
195
+ try {
196
+ const native = requireNativeModule();
197
+ return await native.formatToolsForPrompt(toolsJson, toolFormat);
198
+ } catch (error) {
199
+ logger.error(`C++ formatToolsForPrompt failed: ${error}`);
200
+ return toolsJson;
201
+ }
202
+ }
203
+
204
+ // =============================================================================
205
+ // TOOL EXECUTION (TypeScript - needs JS APIs)
206
+ // =============================================================================
207
+
208
+ /**
209
+ * Execute a tool call
210
+ * Stays in TypeScript because executors need JS APIs (fetch, etc.)
211
+ */
212
+ export async function executeTool(toolCall: ToolCall): Promise<ToolResult> {
213
+ const tool = registeredTools.get(toolCall.toolName);
214
+
215
+ if (!tool) {
216
+ return {
217
+ toolName: toolCall.toolName,
218
+ success: false,
219
+ error: `Unknown tool: ${toolCall.toolName}`,
220
+ callId: toolCall.callId,
221
+ };
222
+ }
223
+
224
+ try {
225
+ logger.debug(`Executing tool: ${toolCall.toolName}`);
226
+ const result = await tool.executor(toolCall.arguments);
227
+
228
+ return {
229
+ toolName: toolCall.toolName,
230
+ success: true,
231
+ result,
232
+ callId: toolCall.callId,
233
+ };
234
+ } catch (error) {
235
+ const errorMessage = error instanceof Error ? error.message : String(error);
236
+ logger.error(`Tool execution failed: ${errorMessage}`);
237
+
238
+ return {
239
+ toolName: toolCall.toolName,
240
+ success: false,
241
+ error: errorMessage,
242
+ callId: toolCall.callId,
243
+ };
244
+ }
245
+ }
246
+
247
+ // =============================================================================
248
+ // MAIN API: GENERATE WITH TOOLS
249
+ // =============================================================================
250
+
251
+ // =============================================================================
252
+ // C++ BRIDGE HELPERS - Use C++ single source of truth for prompt building
253
+ // =============================================================================
254
+
255
+ /**
256
+ * Build initial prompt using C++ bridge
257
+ * Falls back to simple concatenation if native unavailable
258
+ */
259
+ async function buildInitialPromptViaCpp(
260
+ userPrompt: string,
261
+ toolsJson: string,
262
+ options?: ToolCallingOptions
263
+ ): Promise<string> {
264
+ if (!isNativeModuleAvailable()) {
265
+ // Fallback: simple concatenation
266
+ return `${toolsJson}\n\nUser: ${userPrompt}`;
267
+ }
268
+
269
+ try {
270
+ const native = requireNativeModule();
271
+ const optionsJson = JSON.stringify({
272
+ maxToolCalls: options?.maxToolCalls ?? 5,
273
+ autoExecute: options?.autoExecute ?? true,
274
+ temperature: options?.temperature ?? 0.7,
275
+ maxTokens: options?.maxTokens ?? 1024,
276
+ format: options?.format ?? 'default',
277
+ replaceSystemPrompt: options?.replaceSystemPrompt ?? false,
278
+ keepToolsAvailable: options?.keepToolsAvailable ?? false,
279
+ systemPrompt: options?.systemPrompt,
280
+ });
281
+ return await native.buildInitialPrompt(userPrompt, toolsJson, optionsJson);
282
+ } catch (error) {
283
+ logger.error(`C++ buildInitialPrompt failed: ${error}`);
284
+ return `${toolsJson}\n\nUser: ${userPrompt}`;
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Build follow-up prompt using C++ bridge
290
+ * Falls back to template string if native unavailable
291
+ */
292
+ async function buildFollowupPromptViaCpp(
293
+ originalPrompt: string,
294
+ toolsPrompt: string,
295
+ toolName: string,
296
+ resultJson: string,
297
+ keepToolsAvailable: boolean
298
+ ): Promise<string> {
299
+ if (!isNativeModuleAvailable()) {
300
+ // Fallback: simple template
301
+ if (keepToolsAvailable) {
302
+ return `${toolsPrompt}\n\nUser: ${originalPrompt}\n\nTool ${toolName} returned: ${resultJson}`;
303
+ }
304
+ return `The user asked: "${originalPrompt}"\n\nYou used ${toolName} and got: ${resultJson}\n\nRespond naturally.`;
305
+ }
306
+
307
+ try {
308
+ const native = requireNativeModule();
309
+ return await native.buildFollowupPrompt(
310
+ originalPrompt,
311
+ toolsPrompt,
312
+ toolName,
313
+ resultJson,
314
+ keepToolsAvailable
315
+ );
316
+ } catch (error) {
317
+ logger.error(`C++ buildFollowupPrompt failed: ${error}`);
318
+ return `The user asked: "${originalPrompt}"\n\nYou used ${toolName} and got: ${resultJson}`;
319
+ }
320
+ }
321
+
322
+ // =============================================================================
323
+ // MAIN API: GENERATE WITH TOOLS
324
+ // =============================================================================
325
+
326
+ /**
327
+ * Generate a response with tool calling support
328
+ * Uses C++ for parsing AND prompt building (single source of truth)
329
+ *
330
+ * ARCHITECTURE:
331
+ * - Parsing & Prompts: C++ ToolCallingBridge (single source of truth)
332
+ * - Registry & Execution: TypeScript (needs JS APIs like fetch)
333
+ * - Orchestration: This function manages the generate-parse-execute loop
334
+ */
335
+ export async function generateWithTools(
336
+ prompt: string,
337
+ options?: ToolCallingOptions
338
+ ): Promise<ToolCallingResult> {
339
+ const tools = options?.tools ?? getRegisteredTools();
340
+ const maxToolCalls = options?.maxToolCalls ?? 5;
341
+ const autoExecute = options?.autoExecute ?? true;
342
+ const keepToolsAvailable = options?.keepToolsAvailable ?? false;
343
+ const format = options?.format || 'default';
344
+
345
+ logger.debug(`[ToolCalling] Starting with format: ${format}, tools: ${tools.length}`);
346
+
347
+ // Serialize tools to JSON for C++ consumption
348
+ const toolsJson = JSON.stringify(tools.map((tool) => ({
349
+ name: tool.name,
350
+ description: tool.description,
351
+ parameters: tool.parameters.map((p) => ({
352
+ name: p.name,
353
+ type: p.type,
354
+ description: p.description,
355
+ required: p.required,
356
+ ...(p.enum ? { enumValues: p.enum } : {}),
357
+ })),
358
+ })));
359
+
360
+ // Build initial prompt using C++ single source of truth
361
+ let fullPrompt = await buildInitialPromptViaCpp(prompt, toolsJson, options);
362
+ logger.debug(`[ToolCalling] Initial prompt built (${fullPrompt.length} chars)`);
363
+
364
+ // Get formatted tools prompt for follow-up (if keepToolsAvailable)
365
+ const toolsPrompt = keepToolsAvailable
366
+ ? await formatToolsForPromptAsync(tools, format)
367
+ : '';
368
+
369
+ const allToolCalls: ToolCall[] = [];
370
+ const allToolResults: ToolResult[] = [];
371
+ let finalText = '';
372
+ let iterations = 0;
373
+
374
+ while (iterations < maxToolCalls) {
375
+ iterations++;
376
+ logger.debug(`[ToolCalling] === Iteration ${iterations} ===`);
377
+
378
+ // Generate response
379
+ let responseText = '';
380
+ const streamResult = await generateStream(fullPrompt, {
381
+ maxTokens: options?.maxTokens,
382
+ temperature: options?.temperature,
383
+ });
384
+
385
+ for await (const token of streamResult.stream) {
386
+ responseText += token;
387
+ }
388
+
389
+ logger.debug(`[ToolCalling] Raw response (${responseText.length} chars): ${responseText.substring(0, 300)}`);
390
+
391
+ // Parse for tool calls using C++ (single source of truth)
392
+ const { text, toolCall } = await parseToolCallViaCpp(responseText);
393
+ finalText = text;
394
+ logger.debug(`[ToolCalling] Parsed - hasToolCall: ${!!toolCall}, cleanText (${finalText.length} chars): "${finalText.substring(0, 150)}"`);
395
+
396
+ if (!toolCall) {
397
+ // No tool call, we're done - LLM provided a natural response
398
+ logger.debug('[ToolCalling] No tool call found, breaking loop with finalText');
399
+ break;
400
+ }
401
+
402
+ logger.debug(`[ToolCalling] Tool call: ${toolCall.toolName}(${JSON.stringify(toolCall.arguments)})`);
403
+ allToolCalls.push(toolCall);
404
+
405
+ if (!autoExecute) {
406
+ // Return tool calls for manual execution
407
+ return {
408
+ text: finalText,
409
+ toolCalls: allToolCalls,
410
+ toolResults: [],
411
+ isComplete: false,
412
+ };
413
+ }
414
+
415
+ // Execute the tool (in TypeScript - needs JS APIs)
416
+ logger.debug(`[ToolCalling] Executing tool: ${toolCall.toolName}...`);
417
+ const result = await executeTool(toolCall);
418
+ allToolResults.push(result);
419
+ logger.debug(`[ToolCalling] Tool result success: ${result.success}`);
420
+ if (result.success) {
421
+ logger.debug(`[ToolCalling] Tool data: ${JSON.stringify(result.result)}`);
422
+ } else {
423
+ logger.debug(`[ToolCalling] Tool error: ${result.error}`);
424
+ }
425
+
426
+ // Build follow-up prompt using C++ single source of truth
427
+ const resultData = result.success ? result.result : { error: result.error };
428
+ fullPrompt = await buildFollowupPromptViaCpp(
429
+ prompt,
430
+ toolsPrompt,
431
+ toolCall.toolName,
432
+ JSON.stringify(resultData),
433
+ keepToolsAvailable
434
+ );
435
+
436
+ logger.debug(`[ToolCalling] Continuing to iteration ${iterations + 1} with tool result...`);
437
+ }
438
+
439
+ logger.debug(`[ToolCalling] === DONE === finalText (${finalText.length} chars): "${finalText.substring(0, 200)}"`);
440
+ logger.debug(`[ToolCalling] toolCalls: ${allToolCalls.length}, toolResults: ${allToolResults.length}`);
441
+
442
+ return {
443
+ text: finalText,
444
+ toolCalls: allToolCalls,
445
+ toolResults: allToolResults,
446
+ isComplete: true,
447
+ };
448
+ }
449
+
450
+ /**
451
+ * Continue generation after manual tool execution
452
+ */
453
+ export async function continueWithToolResult(
454
+ previousPrompt: string,
455
+ toolCall: ToolCall,
456
+ toolResult: ToolResult,
457
+ options?: ToolCallingOptions
458
+ ): Promise<ToolCallingResult> {
459
+ const resultJson = toolResult.success
460
+ ? JSON.stringify(toolResult.result)
461
+ : `Error: ${toolResult.error}`;
462
+
463
+ const continuedPrompt = `${previousPrompt}\n\nTool Result for ${toolCall.toolName}: ${resultJson}\n\nBased on the tool result, please provide your response:`;
464
+
465
+ return generateWithTools(continuedPrompt, {
466
+ ...options,
467
+ maxToolCalls: (options?.maxToolCalls ?? 5) - 1,
468
+ });
469
+ }
470
+
471
+ // Legacy export for backwards compatibility
472
+ export { parseToolCallViaCpp as parseToolCall };
@@ -119,10 +119,12 @@ export { getStorageInfo, clearCache } from './RunAnywhere+Storage';
119
119
  export {
120
120
  getAvailableModels,
121
121
  getModelInfo,
122
+ getModelPath,
122
123
  isModelDownloaded,
123
124
  downloadModel,
124
125
  cancelDownload,
125
126
  deleteModel,
127
+ registerModel,
126
128
  } from './RunAnywhere+Models';
127
129
 
128
130
  // Audio Utilities
@@ -149,3 +151,17 @@ export type {
149
151
 
150
152
  // Re-export Audio as namespace for RunAnywhere.Audio access
151
153
  export * as Audio from './RunAnywhere+Audio';
154
+
155
+ // Tool Calling
156
+ export {
157
+ registerTool,
158
+ unregisterTool,
159
+ getRegisteredTools,
160
+ clearTools,
161
+ parseToolCall,
162
+ executeTool,
163
+ formatToolsForPrompt,
164
+ formatToolsForPromptAsync,
165
+ generateWithTools,
166
+ continueWithToolResult,
167
+ } from './RunAnywhere+ToolCalling';
@@ -47,6 +47,7 @@ import * as VoiceAgent from './Extensions/RunAnywhere+VoiceAgent';
47
47
  import * as VoiceSession from './Extensions/RunAnywhere+VoiceSession';
48
48
  import * as StructuredOutput from './Extensions/RunAnywhere+StructuredOutput';
49
49
  import * as Audio from './Extensions/RunAnywhere+Audio';
50
+ import * as ToolCalling from './Extensions/RunAnywhere+ToolCalling';
50
51
 
51
52
  const logger = new SDKLogger('RunAnywhere');
52
53
 
@@ -598,6 +599,21 @@ export const RunAnywhere = {
598
599
  extractEntities: StructuredOutput.extractEntities,
599
600
  classify: StructuredOutput.classify,
600
601
 
602
+ // ============================================================================
603
+ // Tool Calling (Delegated to Extension)
604
+ // ============================================================================
605
+
606
+ registerTool: ToolCalling.registerTool,
607
+ unregisterTool: ToolCalling.unregisterTool,
608
+ getRegisteredTools: ToolCalling.getRegisteredTools,
609
+ clearTools: ToolCalling.clearTools,
610
+ parseToolCall: ToolCalling.parseToolCall,
611
+ executeTool: ToolCalling.executeTool,
612
+ formatToolsForPrompt: ToolCalling.formatToolsForPrompt,
613
+ formatToolsForPromptAsync: ToolCalling.formatToolsForPromptAsync,
614
+ generateWithTools: ToolCalling.generateWithTools,
615
+ continueWithToolResult: ToolCalling.continueWithToolResult,
616
+
601
617
  // ============================================================================
602
618
  // Storage Management (Delegated to Extension)
603
619
  // ============================================================================
@@ -611,10 +627,12 @@ export const RunAnywhere = {
611
627
 
612
628
  getAvailableModels: Models.getAvailableModels,
613
629
  getModelInfo: Models.getModelInfo,
630
+ getModelPath: Models.getModelPath,
614
631
  isModelDownloaded: Models.isModelDownloaded,
615
632
  downloadModel: Models.downloadModel,
616
633
  cancelDownload: Models.cancelDownload,
617
634
  deleteModel: Models.deleteModel,
635
+ registerModel: Models.registerModel,
618
636
 
619
637
  // ============================================================================
620
638
  // Utilities
package/src/index.ts CHANGED
@@ -183,7 +183,6 @@ export type {
183
183
  HTTPServiceConfig,
184
184
  DevModeConfig,
185
185
  NetworkConfig,
186
- TelemetryEvent,
187
186
  APIEndpointKey,
188
187
  APIEndpointValue,
189
188
  } from './services';
@@ -26,4 +26,3 @@ export type { APIEndpointKey, APIEndpointValue } from './APIEndpoints';
26
26
 
27
27
  // Telemetry
28
28
  export { TelemetryService, TelemetryCategory } from './TelemetryService';
29
- export type { TelemetryEvent } from './TelemetryService';
@@ -58,7 +58,6 @@ export {
58
58
  // Telemetry
59
59
  TelemetryService,
60
60
  TelemetryCategory,
61
- type TelemetryEvent,
62
61
  // Endpoints
63
62
  APIEndpoints,
64
63
  type APIEndpointKey,
@@ -624,4 +624,76 @@ export interface RunAnywhereCore
624
624
  * Cleanup voice agent resources
625
625
  */
626
626
  cleanupVoiceAgent(): Promise<void>;
627
+
628
+ // ============================================================================
629
+ // Tool Calling Capability
630
+ //
631
+ // ARCHITECTURE:
632
+ // - C++ (ToolCallingBridge): Parses <tool_call> tags from LLM output.
633
+ // This is the SINGLE SOURCE OF TRUTH for parsing, ensuring consistency.
634
+ //
635
+ // - TypeScript (RunAnywhere+ToolCalling.ts): Handles tool registry, executor
636
+ // storage, prompt formatting, and orchestration. Executors MUST stay in
637
+ // TypeScript because they need JavaScript APIs (fetch, device APIs, etc.).
638
+ //
639
+ // C++ (ToolCallingBridge) implements: parseToolCallFromOutput, formatToolsPrompt,
640
+ // buildInitialPrompt, buildFollowupPrompt. TypeScript handles: tool registry,
641
+ // executor storage (needs JS APIs like fetch), orchestration.
642
+ // ============================================================================
643
+
644
+ /**
645
+ * Parse LLM output for tool call (IMPLEMENTED in C++ ToolCallingBridge)
646
+ *
647
+ * This is the single source of truth for parsing <tool_call> tags from LLM output.
648
+ * Ensures consistent parsing behavior across all platforms.
649
+ *
650
+ * @param llmOutput Raw LLM output text that may contain <tool_call> tags
651
+ * @returns JSON with {hasToolCall, cleanText, toolName, argumentsJson, callId}
652
+ * TypeScript layer converts this to {text, toolCall} format
653
+ */
654
+ parseToolCallFromOutput(llmOutput: string): Promise<string>;
655
+
656
+ /**
657
+ * Format tool definitions for LLM prompt (IMPLEMENTED in C++ ToolCallingBridge)
658
+ *
659
+ * Creates a system prompt describing available tools with format-specific instructions.
660
+ * Uses C++ single source of truth for consistent formatting across all platforms.
661
+ *
662
+ * @param toolsJson JSON array of tool definitions
663
+ * @param format Tool calling format: 'default' or 'lfm2'
664
+ * @returns Formatted prompt string with tool instructions
665
+ */
666
+ formatToolsForPrompt(toolsJson: string, format: string): Promise<string>;
667
+
668
+ /**
669
+ * Build initial prompt with tools (IMPLEMENTED in C++ ToolCallingBridge)
670
+ *
671
+ * Combines user prompt with tool definitions and system instructions.
672
+ *
673
+ * @param userPrompt The user's question/request
674
+ * @param toolsJson JSON array of tool definitions
675
+ * @param optionsJson JSON with options (maxToolCalls, temperature, etc.)
676
+ * @returns Complete formatted prompt ready for LLM
677
+ */
678
+ buildInitialPrompt(userPrompt: string, toolsJson: string, optionsJson: string): Promise<string>;
679
+
680
+ /**
681
+ * Build follow-up prompt after tool execution (IMPLEMENTED in C++ ToolCallingBridge)
682
+ *
683
+ * Creates continuation prompt with tool result for next LLM generation.
684
+ *
685
+ * @param originalPrompt The original user prompt
686
+ * @param toolsPrompt Tool definitions (if keepToolsAvailable) or empty
687
+ * @param toolName Name of the executed tool
688
+ * @param resultJson JSON result from tool execution
689
+ * @param keepToolsAvailable Whether to include tools in follow-up
690
+ * @returns Follow-up prompt string
691
+ */
692
+ buildFollowupPrompt(
693
+ originalPrompt: string,
694
+ toolsPrompt: string,
695
+ toolName: string,
696
+ resultJson: string,
697
+ keepToolsAvailable: boolean
698
+ ): Promise<string>;
627
699
  }