@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.
- package/README.md +218 -2
- package/RunAnywhereCore.podspec +1 -0
- package/android/CMakeLists.txt +24 -2
- package/android/build.gradle +61 -9
- package/android/src/main/cpp/cpp-adapter.cpp +51 -3
- package/android/src/main/include/rac/backends/rac_vlm_llamacpp.h +216 -0
- package/android/src/main/include/rac/core/capabilities/rac_lifecycle.h +3 -1
- package/android/src/main/include/rac/core/rac_core.h +11 -0
- package/android/src/main/include/rac/core/rac_types.h +8 -6
- package/android/src/main/include/rac/features/diffusion/rac_diffusion.h +22 -0
- package/android/src/main/include/rac/features/diffusion/rac_diffusion_component.h +263 -0
- package/android/src/main/include/rac/features/diffusion/rac_diffusion_model_registry.h +358 -0
- package/android/src/main/include/rac/features/diffusion/rac_diffusion_service.h +187 -0
- package/android/src/main/include/rac/features/diffusion/rac_diffusion_tokenizer.h +167 -0
- package/android/src/main/include/rac/features/diffusion/rac_diffusion_types.h +454 -0
- package/android/src/main/include/rac/features/llm/rac_tool_calling.h +373 -0
- package/android/src/main/include/rac/features/platform/rac_diffusion_platform.h +305 -0
- package/android/src/main/include/rac/features/vad/rac_vad_energy.h +1 -1
- package/android/src/main/include/rac/features/vlm/rac_vlm.h +16 -0
- package/android/src/main/include/rac/features/vlm/rac_vlm_component.h +168 -0
- package/android/src/main/include/rac/features/vlm/rac_vlm_service.h +206 -0
- package/android/src/main/include/rac/features/vlm/rac_vlm_types.h +417 -0
- package/android/src/main/include/rac/infrastructure/model_management/rac_model_registry.h +15 -0
- package/android/src/main/include/rac/infrastructure/model_management/rac_model_types.h +3 -0
- package/android/src/main/include/rac/utils/rac_image_utils.h +215 -0
- package/android/src/main/java/com/margelo/nitro/runanywhere/PlatformAdapterBridge.kt +201 -1
- package/android/src/main/jniLibs/arm64-v8a/libc++_shared.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/libomp.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/librac_commons.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/librunanywhere_jni.so +0 -0
- package/android/src/main/jniLibs/x86_64/libc++_shared.so +0 -0
- package/android/src/main/jniLibs/x86_64/libomp.so +0 -0
- package/android/src/main/jniLibs/x86_64/librac_commons.so +0 -0
- package/android/src/main/jniLibs/x86_64/librunanywhere_jni.so +0 -0
- package/cpp/HybridRunAnywhereCore.cpp +263 -163
- package/cpp/HybridRunAnywhereCore.hpp +11 -0
- package/cpp/bridges/InitBridge.cpp +234 -3
- package/cpp/bridges/PlatformDownloadBridge.h +44 -0
- package/cpp/bridges/ToolCallingBridge.cpp +188 -0
- package/cpp/bridges/ToolCallingBridge.hpp +98 -0
- package/cpp/third_party/nlohmann/json.hpp +24765 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/RACommons.h +18 -4
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_core.h +11 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion.h +22 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion_component.h +263 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion_model_registry.h +358 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion_platform.h +305 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion_service.h +187 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion_tokenizer.h +167 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_diffusion_types.h +454 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_endpoints.h +3 -17
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_image_utils.h +215 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_lifecycle.h +3 -1
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_model_assignment.h +4 -20
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_model_registry.h +15 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_model_types.h +3 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_tool_calling.h +373 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_types.h +8 -6
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_vad_energy.h +1 -1
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_vlm.h +16 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_vlm_component.h +168 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_vlm_llamacpp.h +216 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_vlm_service.h +206 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/Headers/rac_vlm_types.h +417 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64/RACommons.framework/RACommons +0 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/RACommons.h +18 -4
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_core.h +11 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion.h +22 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion_component.h +263 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion_model_registry.h +358 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion_platform.h +305 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion_service.h +187 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion_tokenizer.h +167 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_diffusion_types.h +454 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_endpoints.h +3 -17
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_image_utils.h +215 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_lifecycle.h +3 -1
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_model_assignment.h +4 -20
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_model_registry.h +15 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_model_types.h +3 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_tool_calling.h +373 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_types.h +8 -6
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_vad_energy.h +1 -1
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_vlm.h +16 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_vlm_component.h +168 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_vlm_llamacpp.h +216 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_vlm_service.h +206 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/Headers/rac_vlm_types.h +417 -0
- package/ios/Binaries/RACommons.xcframework/ios-arm64_x86_64-simulator/RACommons.framework/RACommons +0 -0
- package/ios/PlatformAdapterBridge.h +24 -1
- package/ios/PlatformAdapterBridge.m +243 -0
- package/nitrogen/generated/shared/c++/HybridRunAnywhereCoreSpec.cpp +4 -0
- package/nitrogen/generated/shared/c++/HybridRunAnywhereCoreSpec.hpp +4 -0
- package/package.json +8 -4
- package/src/Foundation/Security/SecureStorageService.ts +12 -6
- package/src/Public/Extensions/RunAnywhere+Models.ts +5 -3
- package/src/Public/Extensions/RunAnywhere+STT.ts +7 -2
- package/src/Public/Extensions/RunAnywhere+ToolCalling.ts +472 -0
- package/src/Public/Extensions/index.ts +16 -0
- package/src/Public/RunAnywhere.ts +18 -0
- package/src/index.ts +0 -1
- package/src/services/Network/index.ts +0 -1
- package/src/services/index.ts +0 -1
- package/src/specs/RunAnywhereCore.nitro.ts +72 -0
- package/src/types/ToolCallingTypes.ts +198 -0
- 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
package/src/services/index.ts
CHANGED
|
@@ -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
|
}
|