Skip to content

Sync dev/main#301

Closed
shubhammalhotra28 wants to merge 68 commits intomainfrom
dev
Closed

Sync dev/main#301
shubhammalhotra28 wants to merge 68 commits intomainfrom
dev

Conversation

@shubhammalhotra28
Copy link
Copy Markdown
Contributor

@shubhammalhotra28 shubhammalhotra28 commented Jan 26, 2026

Description

Brief description of the changes made.

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Refactoring

Testing

  • Lint passes locally
  • Added/updated tests for changes

Platform-Specific Testing (check all that apply)

Swift SDK / iOS Sample:

  • Tested on iPhone (Simulator or Device)
  • Tested on iPad / Tablet
  • Tested on Mac (macOS target)

Kotlin SDK / Android Sample:

  • Tested on Android Phone (Emulator or Device)
  • Tested on Android Tablet

Flutter SDK / Flutter Sample:

  • Tested on iOS
  • Tested on Android

React Native SDK / React Native Sample:

  • Tested on iOS
  • Tested on Android

Labels

Please add the appropriate label(s):

SDKs:

  • Swift SDK - Changes to Swift SDK (sdk/runanywhere-swift)
  • Kotlin SDK - Changes to Kotlin SDK (sdk/runanywhere-kotlin)
  • Flutter SDK - Changes to Flutter SDK (sdk/runanywhere-flutter)
  • React Native SDK - Changes to React Native SDK (sdk/runanywhere-react-native)
  • Commons - Changes to shared native code (sdk/runanywhere-commons)

Sample Apps:

  • iOS Sample - Changes to iOS example app (examples/ios)
  • Android Sample - Changes to Android example app (examples/android)
  • Flutter Sample - Changes to Flutter example app (examples/flutter)
  • React Native Sample - Changes to React Native example app (examples/react-native)

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Documentation updated (if needed)

Screenshots

Attach relevant UI screenshots for changes (if applicable):

  • Mobile (Phone)
  • Tablet / iPad
  • Desktop / Mac

Summary by CodeRabbit

Release Notes

  • New Features
    • Tool-calling support: LLMs can now invoke registered external functions during generation
    • Tool Settings UI across all platforms to enable/disable tool calling and manage registered tools
    • Three included demo tools: Weather lookup (via Open-Meteo), current time retrieval, and calculator
    • Tool-calling indicators and detail views in chat interfaces showing tool names, arguments, and results
    • New LFM2 1.2B tool-optimized models (Q4_K_M and Q8_0 variants)

✏️ Tip: You can customize this high-level summary in your review settings.

Greptile Overview

Greptile Summary

Added tool calling support to React Native SDK, enabling LLMs to execute external functions (API calls, device operations). Also includes bug fixes for Swift SDK storage handling.

Major Changes:

  • Implemented C++ ToolCallingBridge for parsing <tool_call> tags from LLM output with robust JSON handling via nlohmann/json library
  • Added TypeScript tool calling orchestration (RunAnywhere+ToolCalling.ts) with automatic execution loop and conversation management
  • Created comprehensive type definitions for tools, parameters, calls, and results
  • Built demo ToolsScreen with step-by-step execution visualization and real weather API integration
  • Updated ChatScreen to use generateWithTools() API for transparent tool execution
  • Fixed Swift SDK calculateDirectorySize to properly handle files vs directories
  • Fixed Swift SDK model deletion to update registry status after removing files

Architecture:

  • C++ handles parsing (single source of truth), TypeScript handles tool registration/execution (needs JS APIs like fetch)
  • Uses iterator pattern with configurable maxToolCalls to prevent infinite loops
  • Supports both auto-execution and manual tool result handling

Issues Found:

  • Missing optional chaining in ChatScreen.tsx weather API handler (line 106) - could crash if API response structure varies

Confidence Score: 4/5

  • Safe to merge with one minor bug fix needed
  • Score of 4 reflects solid implementation with one logic bug that could cause runtime crashes. The tool calling architecture is well-designed with clear separation between C++ parsing and TypeScript execution. The addition of nlohmann/json library is appropriate for robust JSON handling. Swift SDK fixes are straightforward improvements. The only concern is the missing optional chaining in ChatScreen.tsx line 106 that could crash if the weather API returns unexpected data.
  • Pay close attention to examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx - fix the optional chaining bug on line 106 before merging

Important Files Changed

Filename Overview
sdk/runanywhere-react-native/packages/core/cpp/bridges/ToolCallingBridge.cpp Added C++ bridge for LLM tool calling - parses <tool_call> tags from LLM output with robust JSON handling using nlohmann/json library
sdk/runanywhere-react-native/packages/core/cpp/bridges/ToolCallingBridge.hpp Header file for ToolCallingBridge - defines ToolCallParseResult struct and parsing interface
sdk/runanywhere-react-native/packages/core/src/Public/Extensions/RunAnywhere+ToolCalling.ts TypeScript tool calling implementation - handles tool registration, execution, and orchestration with automatic retry loop
sdk/runanywhere-react-native/packages/core/src/types/ToolCallingTypes.ts Type definitions for tool calling - ToolDefinition, ToolCall, ToolResult, and related interfaces
examples/react-native/RunAnywhereAI/src/screens/ToolsScreen.tsx New screen demonstrating tool calling with step-by-step execution log and real weather API integration
examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx Updated chat screen to use generateWithTools() API - enables LLM to call weather and time tools transparently
sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Bridge/Extensions/CppBridge+Storage.swift Fixed calculateDirectorySize to properly handle files vs directories by checking file type first
sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/Storage/RunAnywhere+Storage.swift Updated deleteStoredModel to mark model as not downloaded in registry after deletion

Sequence Diagram

sequenceDiagram
    participant User
    participant ChatScreen as ChatScreen.tsx
    participant ToolCalling as RunAnywhere+ToolCalling.ts
    participant LLM as LLM Engine
    participant Bridge as ToolCallingBridge.cpp
    participant Tool as Tool Executor (Weather API)

    User->>ChatScreen: "What's the weather in Tokyo?"
    ChatScreen->>ToolCalling: generateWithTools(prompt, options)
    
    Note over ToolCalling: Build system prompt with tool definitions
    ToolCalling->>ToolCalling: formatToolsForPrompt(tools)
    
    Note over ToolCalling: Iteration 1: Initial generation
    ToolCalling->>LLM: generateStream(prompt + tools)
    LLM-->>ToolCalling: "<tool_call>{"tool":"get_weather","arguments":{"location":"Tokyo"}}</tool_call>"
    
    ToolCalling->>Bridge: parseToolCallFromOutput(llmOutput)
    Note over Bridge: Parse using nlohmann/json<br/>Extract tool name & arguments<br/>Return clean text
    Bridge-->>ToolCalling: {hasToolCall: true, toolName: "get_weather", arguments: {...}}
    
    alt autoExecute = true
        ToolCalling->>Tool: executeTool(toolCall)
        Tool->>Tool: fetch("https://wttr.in/Tokyo?format=j1")
        Tool-->>ToolCalling: {temperature_c: 15, condition: "Sunny", ...}
        
        Note over ToolCalling: Iteration 2: Generate final response
        ToolCalling->>ToolCalling: Build prompt with tool result
        ToolCalling->>LLM: generateStream(prompt + tool_result)
        LLM-->>ToolCalling: "The weather in Tokyo is 15°C and sunny..."
        
        ToolCalling->>Bridge: parseToolCallFromOutput(response)
        Bridge-->>ToolCalling: {hasToolCall: false, cleanText: "The weather..."}
    end
    
    ToolCalling-->>ChatScreen: {text: "The weather...", toolCalls: [...], toolResults: [...]}
    ChatScreen-->>User: Display final response
Loading

jmakwana06 and others added 15 commits January 24, 2026 21:22
- Add ToolCallingBridge in C++ for parsing tool_call tags from LLM output
- Handle edge cases: missing closing tags, unquoted JSON keys
- Add tool registration and prompt formatting in C++ bridge
- TypeScript orchestration layer calls C++ for parsing, handles execution
- Add Llama 3.2 3B model to example app (suitable for tool calling)
- Update ChatScreen with tool calling demo (weather API example)

Architecture:
- C++ handles: parsing, validation, prompt formatting
- TypeScript handles: tool registration (stores executors), execution (needs JS APIs)

Co-Authored-By: jm
- Replace console.log with SDKLogger for consistency
- Use ?? instead of || for maxToolCalls to respect explicit 0
- Parse argumentsJson if it's a string from C++
- Update comments to accurately reflect architecture (C++ parses, TS handles registry)
- Remove toolsUsed field from analytics (not in type)
- Fix doc comment for parseToolCallFromOutput return format
Signed-off-by: Hyunoh-Yeo <hyunoh.yeo@gmail.com>
Signed-off-by: Hyunoh-Yeo <hyunoh.yeo@gmail.com>
Signed-off-by: Hyunoh-Yeo <hyunoh.yeo@gmail.com>
Signed-off-by: Hyunoh-Yeo <hyunoh.yeo@gmail.com>
Signed-off-by: Hyunoh-Yeo <hyunoh.yeo@gmail.com>
Signed-off-by: Hyunoh-Yeo <hyunoh.yeo@gmail.com>
feat: Add tool calling support with C++
fix: ios swift app is not deleting models once downloaded + Metadata display bug
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 26, 2026

📝 Walkthrough

Walkthrough

Introduces comprehensive tool-calling capabilities across all SDKs (React Native, Android, iOS, Flutter). Adds C++ commons implementation as single source of truth for parsing and prompt formatting, platform-specific bridges, new demo tools (weather, time, calculator), and UI/settings integrations in all sample applications.

Changes

Cohort / File(s) Summary
C++ Commons Tool Calling Core
sdk/runanywhere-commons/CMakeLists.txt, sdk/runanywhere-commons/include/rac/features/llm/rac_tool_calling.h, sdk/runanywhere-commons/src/features/llm/tool_calling.cpp
New tool-calling C API defining types, parsing, formatting, and prompt-building functions. Supports DEFAULT and LFM2 formats with auto-detection. Serves as single source of truth for parsing tool calls from LLM output and generating tool-inclusive prompts.
C++ Commons Swift/Kotlin Integration
sdk/runanywhere-commons/src/jni/runanywhere_commons_jni.cpp, sdk/runanywhere-swift/Sources/RunAnywhere/CRACommons/include/...
JNI bindings exposing tool-calling C API to Android. Swift includes header for tool calling with same type definitions as C commons.
React Native SDK Tool Calling
sdk/runanywhere-react-native/packages/core/cpp/HybridRunAnywhereCore.*, sdk/runanywhere-react-native/packages/core/cpp/bridges/ToolCallingBridge.*
C++ bridge implementation delegating to commons C API. Exposes four Promise-based methods (parseToolCallFromOutput, formatToolsForPrompt, buildInitialPrompt, buildFollowupPrompt) to TypeScript layer.
React Native SDK Types & Extensions
sdk/runanywhere-react-native/packages/core/src/types/ToolCallingTypes.ts, sdk/runanywhere-react-native/packages/core/src/Public/Extensions/RunAnywhere+ToolCalling.ts, sdk/runanywhere-react-native/packages/core/src/Public/Extensions/index.ts, sdk/runanywhere-react-native/packages/core/src/Public/RunAnywhere.ts
Complete TypeScript tool-calling types (ToolDefinition, ToolCall, ToolResult, ToolCallingOptions). Extends RunAnywhere with tool lifecycle (register/unregister/clear/execute) and orchestrator (generateWithTools/continueWithToolResult) with C++ as parsing source of truth.
React Native SDK Gradle & Specs
sdk/runanywhere-react-native/packages/core/android/CMakeLists.txt, sdk/runanywhere-react-native/packages/core/RunAnywhereCore.podspec, sdk/runanywhere-react-native/packages/core/src/specs/RunAnywhereCore.nitro.ts
Android CMake adds nlohmann/json dependency and third_party includes. Podspec adds header search paths. Nitro spec adds four tool-calling methods as interface definitions.
React Native Sample Chat & Tools
examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx
Introduces registerChatTools, detectToolCallFormat, tool-enabled generation workflow (generateWithTools), UI indicator (ToolCallingBadge), model-status logging for tool registration, and analytics updates for tool-calling results.
React Native Sample Settings & Types
examples/react-native/RunAnywhereAI/src/screens/SettingsScreen.tsx, examples/react-native/RunAnywhereAI/src/types/chat.ts, examples/react-native/RunAnywhereAI/src/utils/mathParser.ts
New ToolCallInfo interface added to Message type. SettingsScreen adds persistent tool-calling toggle, demo tool registration (weather via Open-Meteo, time, calculator), and UI for managing tools. Math parser provides safe expression evaluation without eval().
React Native Sample UI Components
examples/react-native/RunAnywhereAI/src/components/chat/MessageBubble.tsx, examples/react-native/RunAnywhereAI/src/components/chat/ToolCallIndicator.tsx, examples/react-native/RunAnywhereAI/src/components/chat/index.ts
New ToolCallIndicator and ToolCallingBadge components for displaying tool call results and tool availability. Components show success/failure status with icons and optional detail sheets.
React Native Sample Config
examples/react-native/RunAnywhereAI/react-native.config.js, examples/react-native/RunAnywhereAI/ios/RunAnywhereAI.xcodeproj/project.pbxproj, examples/react-native/RunAnywhereAI/ios/RunAnywhereAI/PrivacyInfo.xcprivacy
Config adds Android autolinking exemptions for audio libraries. Xcode project updates DEVELOPMENT_TEAM identifier. Privacy config reorders API access categories.
React Native Sample Models & Navigation
examples/react-native/RunAnywhereAI/App.tsx, examples/react-native/RunAnywhereAI/src/navigation/TabNavigator.tsx, examples/react-native/RunAnywhereAI/src/types/index.ts
Adds four new tool-optimized LLM model registrations (Llama 3.2, LiquidAI LFM2 variants). Updates tab labels and navigation comments to reflect tool-calling support.
Android SDK Tool Calling
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/extensions/LLM/ToolCallingTypes.kt, sdk/runanywhere-kotlin/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/native/bridge/RunAnywhereBridge.kt, sdk/runanywhere-kotlin/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/foundation/bridge/extensions/CppBridgeToolCalling.kt, sdk/runanywhere-kotlin/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/public/extensions/LLM/RunAnywhereToolCalling.kt
Kotlin-multiplatform tool-calling types (ToolValue, ToolDefinition, ToolCall, ToolResult, ToolCallFormat, ToolCallingOptions). JNI bindings expose C API. CppBridgeToolCalling wraps native calls. RunAnywhereToolCalling orchestrates tool lifecycle with thread-safe registry and generation loop.
Android Sample Chat & Models
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/domain/models/ChatMessage.kt, examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/RunAnywhereApplication.kt
ChatMessage adds ToolCallInfo field. RunAnywhereApplication registers two new tool-optimized LFM2 models (1.2B Q4_K_M and Q8_0).
Android Sample Chat UI & ViewModel
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/chat/ChatScreen.kt, examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/chat/ChatViewModel.kt, examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/chat/components/ToolCallViews.kt
ChatScreen adds ToolCallingBadge UI indicator. ChatViewModel adds generateWithToolCalling flow with format detection, tool execution, and result attachment. ToolCallViews provides ToolCallIndicator, ToolCallDetailSheet, and ToolCallingActiveIndicator composables.
Android Sample Settings
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/ToolSettingsViewModel.kt, examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsScreen.kt
ToolSettingsViewModel manages tool registration, demo tools (weather, time, calculator) with real API integration, and state persistence. SettingsScreen renders tool-calling UI section with toggle, registered tools list, and action buttons.
Android Build Configuration
sdk/runanywhere-kotlin/modules/runanywhere-core-llamacpp/build.gradle.kts, sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts
Gradle configurations add pickFirsts for duplicate native libraries (libomp.so, libc++_shared.so, librac_commons.so) to resolve conflicts during test builds.
iOS SDK Tool Calling
sdk/runanywhere-swift/Sources/RunAnywhere/CRACommons/include/CRACommons.h, sdk/runanywhere-swift/Sources/RunAnywhere/CRACommons/include/rac_tool_calling.h, sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/LLM/ToolCallingTypes.swift, sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/LLM/RunAnywhere+ToolCalling.swift, sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Bridge/Extensions/CppBridge+ToolCalling.swift
Comprehensive Swift tool-calling types (ToolValue, ToolDefinition, ToolCall, ToolResult, ToolCallingOptions). CppBridge wraps C API. RunAnywhere extension adds tool lifecycle and orchestration (generateWithTools/continueWithToolResult) with Actor-based registry.
iOS Sample Chat & Models
examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Chat/Models/Message.swift, examples/ios/RunAnywhereAI/RunAnywhereAI/App/RunAnywhereAIApp.swift
Message model adds ToolCallInfo field. App registers two new tool-optimized LFM2 models (1.2B Q4_K_M and Q8_0).
iOS Sample Chat UI & ViewModels
examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Chat/Views/ChatInterfaceView.swift, examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Chat/Views/ChatMessageComponents.swift, examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Chat/Views/ToolCallViews.swift, examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Chat/ViewModels/LLMViewModel.swift, examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Chat/ViewModels/LLMViewModel+ToolCalling.swift, examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Chat/ViewModels/LLMViewModel+Analytics.swift
ChatInterfaceView adds toolCallingBadge. ChatMessageComponents renders tool call indicators and detail sheets. ToolCallViews provides ToolCallIndicator, ToolCallDetailSheet, and ToolCallingActiveIndicator. LLMViewModel adds useToolCalling computed property and generation flow switching. Extension adds detectToolCallFormat, generateWithToolCalling, and message updating logic.
iOS Sample Settings
examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Settings/CombinedSettingsView.swift, examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Settings/ToolSettingsView.swift, examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Models/ModelSelectionSheet.swift
CombinedSettingsView integrates ToolSettingsViewModel and passes to content views. ToolSettingsView provides complete tool-calling UI with demo tools, registration, and WeatherService for Open-Meteo API. ModelSelectionSheet adjusts setCurrentModel call site and actor context.
iOS Storage & File Management
sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Bridge/Extensions/CppBridge+Storage.swift, sdk/runanywhere-swift/Sources/RunAnywhere/Infrastructure/FileManagement/Services/SimplifiedFileManager.swift, sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/Storage/RunAnywhere+Storage.swift
Storage calculation adds explicit file/directory detection. File deletion adds logging for missing models. Storage extension updates model registry to mark as not downloaded when deleted.
Flutter SDK Tool Calling
sdk/runanywhere-flutter/packages/runanywhere/lib/native/ffi_types.dart, sdk/runanywhere-flutter/packages/runanywhere/lib/native/dart_bridge_tool_calling.dart, sdk/runanywhere-flutter/packages/runanywhere/lib/public/types/tool_calling_types.dart, sdk/runanywhere-flutter/packages/runanywhere/lib/public/runanywhere_tool_calling.dart
FFI types add RacToolCallStruct and RacToolCallingOptionsStruct. DartBridgeToolCalling wraps C API with ToolCallParseResult data class. Comprehensive tool-calling types in Dart (ToolValue hierarchy, ToolDefinition, ToolCall, ToolResult, ToolCallingOptions). RunAnywhereToolCalling extension adds full tool lifecycle and orchestration.
Flutter Sample Chat & Models
examples/flutter/RunAnywhereAI/lib/features/chat/chat_interface_view.dart, examples/flutter/RunAnywhereAI/lib/features/chat/tool_call_views.dart, examples/flutter/RunAnywhereAI/lib/app/runanywhere_ai_app.dart
ChatInterfaceView adds tool-calling workflow with format detection and UI indicators. ToolCallViews provides ToolCallIndicator, ToolCallDetailSheet, ToolCallingActiveIndicator, and ToolCallingBadge. App registers two new tool-optimized LFM2 models.
Flutter Sample Settings & Tools
examples/flutter/RunAnywhereAI/lib/features/settings/combined_settings_view.dart, examples/flutter/RunAnywhereAI/lib/features/settings/tool_settings_view_model.dart, examples/flutter/RunAnywhereAI/lib/features/tools/tools_view.dart, examples/flutter/RunAnywhereAI/lib/app/content_view.dart, examples/flutter/RunAnywhereAI/pubspec.yaml
CombinedSettingsView adds tool-calling UI section with demo tools management. ToolSettingsViewModel manages tool state, demo tools (weather, time, calculator), and SharedPreferences persistence. ToolsView provides end-to-end tool-calling demo with execution logging and response display. ContentView adds new Tools tab. Pubspec adds http dependency for API calls.
LlamaCPP Backend Adaptive Sizing
sdk/runanywhere-commons/src/backends/llamacpp/llamacpp_backend.cpp
Adds model size detection heuristics and adaptive context sizing. Pre-load GPU layer sizing (24 for large models), post-load parameter verification, and context selection logic based on model parameters (2048 for 7B+, 4096 for 3-7B, max_default for <3B).

Sequence Diagram

sequenceDiagram
    participant User as User
    participant UI as Chat UI
    participant SDK as RunAnywhere SDK
    participant CppBridge as C++ Bridge<br/>(Commons)
    participant LLM as LLM Engine
    participant ToolReg as Tool Registry
    participant Executor as Tool Executor

    User->>UI: Enter prompt + registered tools enabled
    UI->>SDK: generateWithTools(prompt, options)
    
    SDK->>ToolReg: getRegisteredTools()
    ToolReg-->>SDK: [tool definitions]
    
    SDK->>CppBridge: formatToolsForPrompt(tools, format)
    CppBridge-->>SDK: formatted system prompt
    
    SDK->>CppBridge: buildInitialPrompt(userPrompt, tools, options)
    CppBridge-->>SDK: combined initial prompt
    
    SDK->>LLM: generate(combined prompt)
    LLM-->>SDK: llm_output (may contain tool_call tags)
    
    SDK->>CppBridge: parseToolCallFromOutput(llm_output)
    CppBridge-->>SDK: {hasToolCall, toolName, arguments, cleanText}
    
    alt Tool Call Detected & AutoExecute
        SDK->>ToolReg: getTool(toolName)
        ToolReg->>Executor: executor(arguments)
        Executor-->>ToolReg: tool_result
        ToolReg-->>SDK: ToolResult
        
        SDK->>CppBridge: buildFollowupPrompt(originalPrompt, toolsPrompt, toolName, result)
        CppBridge-->>SDK: followup_prompt
        
        Note over SDK: Loop continues if maxToolCalls not reached
        SDK->>LLM: generate(followup_prompt)
        LLM-->>SDK: next_output
    else No Tool Call or ManualExecute
        SDK->>UI: ToolCallingResult {text, toolCalls, toolResults}
        UI->>User: Display response + tool indicators
    end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Possibly related PRs

  • Introduces core tool-calling feature across multiple SDK platforms (React Native, Android, iOS, Flutter) and the C++ commons layer, requiring review of intricate cross-language integration, multiple orchestration flows, and substantial new public APIs.

  • Primary concerns: C++ commons parsing/formatting logic as single source of truth; correct delegation across JNI/Swift/Kotlin/TypeScript/Dart bridges; tool lifecycle state management in platform-specific implementations; demo tool implementations with real HTTP integrations; UI/ViewModel state management across four platforms; model registration updates; and proper error handling/logging throughout.

  • RunanywhereAI/runanywhere-sdks#293: Implements the same cross-platform tool-calling feature; touches identical core components (ToolCallingBridge, HybridRunAnywhereCore, C++ commons, TypeScript extension, and example UI).

  • RunanywhereAI/runanywhere-sdks#280: Modifies tool-calling/settings surface with ToolSettingsViewModel and tool-settings UI wiring in iOS views.

  • RunanywhereAI/runanywhere-sdks#204: Extends React Native SDK with comprehensive tool-calling features built on the same sdk/runanywhere-react-native surface and example app modifications.

Suggested labels

feature-tool-calling, cross-platform, sdk-core, sdk-react-native, sdk-android, sdk-ios, sdk-flutter, c++-commons, sample-apps


🐰 Behold, a tool-calling revolution hops forth!
Parsing in C++, orchestrating with care,
From Firebase to Flutter, iOS to Android there,
Tools execute, results bloom, and the prompts dance north!
Four platforms aligned, one source of truth gleams bright—
Let the LLM command, and let tools take flight! 🚀

🚥 Pre-merge checks | ❌ 3
❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is largely the template with unchecked placeholder boxes and no substantive content filled in by the author. Complete the PR description by filling in the actual changes made, selecting the appropriate Type of Change and Platform-Specific Testing checkboxes, adding relevant labels (Swift SDK, Kotlin SDK, Flutter SDK, React Native SDK, Commons, iOS/Android/Flutter/React Native Samples), and providing a clear summary of the changes.
Docstring Coverage ⚠️ Warning Docstring coverage is 51.24% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Sync dev/main' is vague and does not clearly communicate the main changes to developers scanning the commit history. Replace with a more descriptive title such as 'Add tool calling support to React Native SDK and fix Swift SDK storage handling' to clearly convey the primary change.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

country: area?.country?.[0]?.value || '',
temperature_f: parseInt(current.temp_F, 10),
temperature_c: parseInt(current.temp_C, 10),
condition: current.weatherDesc[0].value,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing optional chaining - could crash if weatherDesc array is empty or null

Suggested change
condition: current.weatherDesc[0].value,
condition: current.weatherDesc?.[0]?.value || 'Unknown',
Prompt To Fix With AI
This is a comment left during a code review.
Path: examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx
Line: 106:106

Comment:
Missing optional chaining - could crash if `weatherDesc` array is empty or null

```suggestion
          condition: current.weatherDesc?.[0]?.value || 'Unknown',
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Fix all issues with AI agents
In `@examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx`:
- Around line 356-372: The code in ChatScreen.tsx currently logs raw user
prompts and tool results (prompt, result.toolCalls, result.toolResults) when
calling RunAnywhere.generateWithTools; remove or guard these logs to avoid
exposing sensitive data by either deleting the console.log lines that print the
raw prompt and toolResults or wrapping them behind a strict debug flag (e.g.,
process.env.DEBUG_LOGS) and always mask sensitive content (log only tool names,
counts, or sanitized summaries). Update the logging around
RunAnywhere.generateWithTools so you only log non-sensitive info like
result.toolCalls.map(t => t.toolName) or result.toolCalls.length unless explicit
debug mode is enabled and ensure any debug path documents it is off in
production.
- Around line 84-138: The code logs user-provided data in the get_weather tool
(console.log('[Tool] get_weather called for:', location)) and in
get_current_time (console.log('[Tool] get_current_time called')), which can
expose PII in production; update these to only log when in development or to
redact/sanitize inputs: wrap or replace the console.log calls in the get_weather
handler and the get_current_time registration with a __DEV__ check (or an
environment-based feature flag), or log a non-identifying placeholder (e.g.,
'[Tool] get_weather called' without the location) and avoid returning unredacted
logs to console; ensure the identifiers referenced are the get_weather async
handler, the location variable, and the get_current_time handler so you change
the right statements.

In `@examples/react-native/RunAnywhereAI/src/screens/ToolsScreen.tsx`:
- Around line 88-138: The code logs user-provided or sensitive values (location
in the get_weather tool and timestamps in get_current_time) which can be PII;
update the RunAnywhere.registerTool handlers (the tool with name 'get_weather'
and the tool with name 'get_current_time') to avoid emitting raw user data to
console in production by either gating logs with __DEV__ (e.g., only call
console.log/console.error when __DEV__ is true) or redact the values before
logging, and ensure error logs do not include the full location string but
instead include limited context or the error message only.
- Around line 69-86: In registerDemoTools, remove or change the PII-leaking
console log inside the get_weather tool executor: locate the console.log('[Tool]
get_weather called for:', location) and either delete it or replace it with a
non-sensitive message such as console.log('[Tool] get_weather called') (or mask
the input) so the user-provided location is not printed; ensure this change is
applied in the get_weather executor function registered via
RunAnywhere.registerTool.

In `@sdk/runanywhere-react-native/.gitignore`:
- Line 14: The .gitignore contains the rule '**/ios/xcframeworks/' which
conflicts with the note that xcframeworks are bundled for npm; remove that
blanket ignore or restrict it to build-only artifacts (e.g., a subpath like
'**/ios/xcframeworks/build/' or other temporary build dirs) so the actual
xcframework deliverables are tracked and shipped; update or delete the
'**/ios/xcframeworks/' entry and ensure the note lines about bundling remain
consistent with the ignore rules.

In `@sdk/runanywhere-react-native/packages/core/android/CMakeLists.txt`:
- Around line 8-20: The CMake script uses FetchContent_MakeAvailable which
requires CMake ≥3.14; update the project CMake minimum or vendor the dependency:
change the cmake_minimum_required declaration to at least 3.14.0 (so
FetchContent_MakeAvailable is supported) or alternatively remove
FetchContent_MakeAvailable/FetchContent_Declare and vendor the nlohmann/json
headers manually; look for the cmake_minimum_required line and the
FetchContent_Declare/FetchContent_MakeAvailable blocks to apply the change.

In
`@sdk/runanywhere-react-native/packages/core/cpp/bridges/ToolCallingBridge.cpp`:
- Around line 52-65: The quote-escape check in the loop using jsonStr[i-1] !=
'\\' fails for sequences with multiple backslashes (e.g., \\\") — change the
logic where the code toggles inString (around the for loop over jsonStr and the
if (c == '"' ...) block) to count the number of consecutive backslashes
immediately preceding the quote in jsonStr and treat the quote as escaped only
if that count is odd; update the branch that currently uses jsonStr[i-1] to use
this parity test so inString is toggled correctly for double-escaped
backslashes.

In
`@sdk/runanywhere-react-native/packages/core/src/Public/Extensions/RunAnywhere`+ToolCalling.ts:
- Around line 362-365: The continuation call to generateWithTools decrements
options?.maxToolCalls and can reach 0 or negative, causing no generation; update
the call (in RunAnywhere+ToolCalling.ts where generateWithTools is invoked) to
compute maxToolCalls as Math.max(1, (options?.maxToolCalls ?? 5) - 1) (or
equivalent) so the continued invocation always uses at least 1 tool call; keep
the rest of options spread as-is to preserve other settings.
🧹 Nitpick comments (9)
examples/react-native/RunAnywhereAI/ios/RunAnywhereAI.xcodeproj/project.pbxproj (1)

479-479: Consider externalizing DEVELOPMENT_TEAM to avoid breaking local builds.

Hardcoding a team ID in the project file makes builds fail for contributors or CI under different Apple accounts. Prefer setting this in an .xcconfig or per-user build settings.

Also applies to: 508-508

sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Bridge/Extensions/CppBridge+Storage.swift (1)

236-247: Reuse FileOperationsUtilities.fileSize to avoid duplication
Optional: leverage the existing helper for file-size retrieval to keep consistency and reduce duplicate logic.

♻️ Proposed refactor
-            if let attrs = try? fm.attributesOfItem(atPath: url.path),
-               let fileSize = attrs[.size] as? Int64 {
-                return fileSize
-            } else {
-                return 0
-            }
+            return FileOperationsUtilities.fileSize(at: url) ?? 0
examples/react-native/RunAnywhereAI/src/types/index.ts (1)

25-33: Update the top-level tab list comment to include Tools.

The new tab is documented below, but the header still lists only the original tabs. Consider syncing it for clarity.

✏️ Suggested doc tweak
- * Tabs: Chat, STT, TTS, Voice (VoiceAssistant), Settings
+ * Tabs: Chat, STT, TTS, Voice (VoiceAssistant), Tools, Settings
sdk/runanywhere-react-native/packages/core/cpp/bridges/ToolCallingBridge.cpp (1)

248-256: callId is hardcoded to 0 — document the limitation or implement proper ID generation.

If the system ever needs to support multiple tool calls in a single response or correlate tool calls with results, a static callId = 0 won't work. Consider either:

  1. Documenting this as a known limitation (single tool call per response)
  2. Generating unique IDs (e.g., incrementing counter or hash)
sdk/runanywhere-react-native/packages/core/cpp/bridges/ToolCallingBridge.hpp (1)

35-41: ToolCallParseResult struct is defined but unused — consider removing or using it.

The ToolCallParseResult struct is declared but parseToolCall() returns a JSON string instead of this struct. This creates confusion about the API design.

Either:

  1. Remove the unused struct
  2. Use the struct internally and serialize to JSON at the boundary
sdk/runanywhere-react-native/packages/core/src/types/ToolCallingTypes.ts (1)

33-37: Widen ToolParameter.enum type to support numeric and boolean enums. The ParameterType definition allows 'number' and 'boolean', but enum is restricted to string[], creating a type mismatch. When a parameter type is number or boolean, developers cannot define enum-constrained values for it.

♻️ Suggested type change
-  enum?: string[];
+  enum?: Array<string | number | boolean>;
sdk/runanywhere-react-native/packages/core/src/Public/Extensions/RunAnywhere+ToolCalling.ts (3)

47-53: Consider logging or warning on tool overwrite.

When registering a tool with a name that already exists, the current implementation silently overwrites it. This might be intentional, but a debug log indicating the overwrite could help with troubleshooting.

💡 Optional: Add overwrite detection
 export function registerTool(
   definition: ToolDefinition,
   executor: ToolExecutor
 ): void {
+  if (registeredTools.has(definition.name)) {
+    logger.debug(`Overwriting existing tool: ${definition.name}`);
+  }
   logger.debug(`Registering tool: ${definition.name}`);
   registeredTools.set(definition.name, { definition, executor });
 }

110-114: Minor: Date.now() may produce duplicate callIds.

If multiple tool calls are parsed within the same millisecond, Date.now() could generate identical callIds. Consider using a counter or adding randomness for uniqueness.

💡 Optional: Improve callId uniqueness
+let callIdCounter = 0;
+
 // Inside parseToolCallViaCpp:
     const toolCall: ToolCall = {
       toolName: result.toolName,
       arguments: args,
-      callId: `call_${result.callId || Date.now()}`,
+      callId: `call_${result.callId || `${Date.now()}_${++callIdCounter}`}`,
     };

241-246: conversationHistory is populated but never used.

The conversationHistory array is built throughout the generation loop (lines 246, 278, 307-308) but is never actually utilized in prompt construction. The fullPrompt is manually constructed each iteration without referencing this history. This appears to be dead code or an incomplete feature.

♻️ Suggestion: Either remove or integrate conversationHistory

If this is intended for future use or debugging, consider:

  1. Adding a comment explaining its purpose
  2. Including it in the ToolCallingResult for debugging
  3. Using it to build prompts for better context preservation

If unneeded, remove lines 242, 246, 278, and 307-308.

Comment on lines +84 to +138
async (args) => {
// Handle both 'location' and 'city' parameter names (models vary)
const location = (args.location || args.city) as string;
console.log('[Tool] get_weather called for:', location);

try {
const url = `https://wttr.in/${encodeURIComponent(location)}?format=j1`;
const response = await fetch(url);

if (!response.ok) {
return { error: `Weather API error: ${response.status}` };
}

const data = await response.json();
const current = data.current_condition[0];
const area = data.nearest_area?.[0];

return {
location: area?.areaName?.[0]?.value || location,
country: area?.country?.[0]?.value || '',
temperature_f: parseInt(current.temp_F, 10),
temperature_c: parseInt(current.temp_C, 10),
condition: current.weatherDesc[0].value,
humidity: `${current.humidity}%`,
wind_mph: `${current.windspeedMiles} mph`,
feels_like_f: parseInt(current.FeelsLikeF, 10),
};
} catch (error) {
const msg = error instanceof Error ? error.message : String(error);
console.error('[Tool] Weather fetch failed:', msg);
return { error: msg };
}
}
);

// Current time tool
RunAnywhere.registerTool(
{
name: 'get_current_time',
description: 'Gets the current date and time',
parameters: [],
},
async () => {
console.log('[Tool] get_current_time called');
const now = new Date();
return {
date: now.toLocaleDateString(),
time: now.toLocaleTimeString(),
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
};
}
);

console.log('[ChatScreen] Tools registered: get_weather, get_current_time');
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid logging user-provided locations/time in production. These can be PII; gate behind __DEV__ or redact.

🔧 Suggested fix (guard logs)
-      console.log('[Tool] get_weather called for:', location);
+      if (__DEV__) {
+        console.log('[Tool] get_weather called for:', location);
+      }
...
-      console.log('[Tool] get_current_time called');
+      if (__DEV__) {
+        console.log('[Tool] get_current_time called');
+      }
...
-  console.log('[ChatScreen] Tools registered: get_weather, get_current_time');
+  if (__DEV__) {
+    console.log('[ChatScreen] Tools registered: get_weather, get_current_time');
+  }
🤖 Prompt for AI Agents
In `@examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx` around lines
84 - 138, The code logs user-provided data in the get_weather tool
(console.log('[Tool] get_weather called for:', location)) and in
get_current_time (console.log('[Tool] get_current_time called')), which can
expose PII in production; update these to only log when in development or to
redact/sanitize inputs: wrap or replace the console.log calls in the get_weather
handler and the get_current_time registration with a __DEV__ check (or an
environment-based feature flag), or log a non-identifying placeholder (e.g.,
'[Tool] get_weather called' without the location) and avoid returning unredacted
logs to console; ensure the identifiers referenced are the get_weather async
handler, the location variable, and the get_current_time handler so you change
the right statements.

Comment on lines 356 to 372
try {
console.log('[ChatScreen] Starting streaming generation for:', prompt);
console.log('[ChatScreen] Starting generation with tools for:', prompt);

// Use streaming generation (matches Swift SDK: RunAnywhere.generateStream)
const streamingResult = await RunAnywhere.generateStream(prompt, {
// Use tool-enabled generation
// If the LLM needs to call a tool (like weather API), it happens automatically
const result = await RunAnywhere.generateWithTools(prompt, {
autoExecute: true,
maxToolCalls: 3,
maxTokens: 1000,
temperature: 0.7,
});

let fullResponse = '';

// Stream tokens in real-time (matches Swift's for await loop)
for await (const token of streamingResult.stream) {
fullResponse += token;

// Update assistant message content as tokens arrive
updateMessage(
{
...assistantMessage,
content: fullResponse,
},
currentConversation.id
);

// Scroll to keep up with new content
flatListRef.current?.scrollToEnd({ animated: false });
// Log tool usage for debugging
if (result.toolCalls.length > 0) {
console.log('[ChatScreen] Tools used:', result.toolCalls.map(t => t.toolName));
console.log('[ChatScreen] Tool results:', result.toolResults);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not log raw user prompts/tool results by default. Prompts can contain sensitive data; guard or remove these logs.

🔧 Suggested fix (guard logs)
-      console.log('[ChatScreen] Starting generation with tools for:', prompt);
+      if (__DEV__) {
+        console.log('[ChatScreen] Starting generation with tools for:', prompt);
+      }
...
-        console.log('[ChatScreen] Tools used:', result.toolCalls.map(t => t.toolName));
-        console.log('[ChatScreen] Tool results:', result.toolResults);
+        if (__DEV__) {
+          console.log('[ChatScreen] Tools used:', result.toolCalls.map(t => t.toolName));
+          console.log('[ChatScreen] Tool results:', result.toolResults);
+        }
🤖 Prompt for AI Agents
In `@examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx` around lines
356 - 372, The code in ChatScreen.tsx currently logs raw user prompts and tool
results (prompt, result.toolCalls, result.toolResults) when calling
RunAnywhere.generateWithTools; remove or guard these logs to avoid exposing
sensitive data by either deleting the console.log lines that print the raw
prompt and toolResults or wrapping them behind a strict debug flag (e.g.,
process.env.DEBUG_LOGS) and always mask sensitive content (log only tool names,
counts, or sanitized summaries). Update the logging around
RunAnywhere.generateWithTools so you only log non-sensitive info like
result.toolCalls.map(t => t.toolName) or result.toolCalls.length unless explicit
debug mode is enabled and ensure any debug path documents it is off in
production.

# iOS
ios/build/
**/ios/Binaries/
**/ios/xcframeworks/
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Conflict with “do not gitignore xcframeworks” note.

Line 14 ignores **/ios/xcframeworks/, but Lines 17–22 state xcframeworks are bundled for npm publish and should not be ignored. This will likely exclude required artifacts from source control/npm packages. Please remove this rule or narrow it to build-only output paths that are not shipped. Based on learnings, xcframeworks are required deliverables.

🤖 Prompt for AI Agents
In `@sdk/runanywhere-react-native/.gitignore` at line 14, The .gitignore contains
the rule '**/ios/xcframeworks/' which conflicts with the note that xcframeworks
are bundled for npm; remove that blanket ignore or restrict it to build-only
artifacts (e.g., a subpath like '**/ios/xcframeworks/build/' or other temporary
build dirs) so the actual xcframework deliverables are tracked and shipped;
update or delete the '**/ios/xcframeworks/' entry and ensure the note lines
about bundling remain consistent with the ignore rules.

Comment on lines +8 to +20
# =============================================================================
# nlohmann/json - Header-only JSON library for robust JSON parsing
# Used by ToolCallingBridge for parsing tool call JSON from LLM output
# =============================================================================
include(FetchContent)
FetchContent_Declare(
nlohmann_json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.11.3
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(nlohmann_json)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -name "CMakeLists.txt" -type f | head -20

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 558


🌐 Web query:

FetchContent CMake minimum version requirement

💡 Result:

  • The FetchContent module itself is available starting in CMake 3.11 (“New in version 3.11”). [1][2]
  • If you use the common modern helper FetchContent_MakeAvailable(), that command is available starting in CMake 3.14 (“Added in version 3.14”). [3]

So, in practice:

  • Minimum = 3.11 if you only rely on include(FetchContent) + FetchContent_Declare() + FetchContent_Populate(). [1][2]
  • Minimum = 3.14 if you use FetchContent_MakeAvailable(). [3]

Note: In CMake 4.0+, cmake_minimum_required(VERSION ...) must specify at least 3.5 (older compatibility is removed). [4]

Sources:
[1] CMake FetchContent docs (v3.20): (cmake.org)
[2] CMake FetchContent docs (v3.23): (cmake.org)
[3] CMake FetchContent docs (git-stage/latest): (cmake.org)
[4] CMake cmake_minimum_required() docs (latest): (cmake.org)

Citations:


🏁 Script executed:

cat -n ./sdk/runanywhere-react-native/packages/core/android/CMakeLists.txt | head -30

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 1513


FetchContent_MakeAvailable requires CMake 3.14, not 3.11.

The code uses FetchContent_MakeAvailable() (line 19), which requires CMake 3.14. Current minimum is 3.9, causing build failures. Bump cmake_minimum_required to 3.14.0 or vendor the dependency.

✅ Correct fix
-cmake_minimum_required(VERSION 3.9.0)
+cmake_minimum_required(VERSION 3.14.0)
🤖 Prompt for AI Agents
In `@sdk/runanywhere-react-native/packages/core/android/CMakeLists.txt` around
lines 8 - 20, The CMake script uses FetchContent_MakeAvailable which requires
CMake ≥3.14; update the project CMake minimum or vendor the dependency: change
the cmake_minimum_required declaration to at least 3.14.0 (so
FetchContent_MakeAvailable is supported) or alternatively remove
FetchContent_MakeAvailable/FetchContent_Declare and vendor the nlohmann/json
headers manually; look for the cmake_minimum_required line and the
FetchContent_Declare/FetchContent_MakeAvailable blocks to apply the change.

Comment on lines +52 to +65
for (size_t i = 0; i < jsonStr.size(); i++) {
char c = jsonStr[i];

// Track if we're inside a string
if (c == '"' && (i == 0 || jsonStr[i-1] != '\\')) {
inString = !inString;
result += c;
continue;
}

if (inString) {
result += c;
continue;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Edge case: double-escaped backslashes may cause incorrect string boundary tracking.

The escape detection jsonStr[i-1] != '\\' doesn't handle double-escaped backslashes like \\". For example, in {"key": "value\\"}, the final " after \\ is a real quote (not escaped), but this code would treat it as escaped.

This is a minor edge case since LLM outputs rarely contain such patterns, but worth noting for robustness.

🔧 Suggested fix for proper escape handling
         // Track if we're inside a string
-        if (c == '"' && (i == 0 || jsonStr[i-1] != '\\')) {
+        if (c == '"') {
+            // Count preceding backslashes to determine if quote is escaped
+            size_t backslashCount = 0;
+            size_t k = i;
+            while (k > 0 && jsonStr[k-1] == '\\') {
+                backslashCount++;
+                k--;
+            }
+            // Quote is escaped only if preceded by odd number of backslashes
+            if (backslashCount % 2 == 0) {
+                inString = !inString;
+            }
+            result += c;
+            continue;
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (size_t i = 0; i < jsonStr.size(); i++) {
char c = jsonStr[i];
// Track if we're inside a string
if (c == '"' && (i == 0 || jsonStr[i-1] != '\\')) {
inString = !inString;
result += c;
continue;
}
if (inString) {
result += c;
continue;
}
for (size_t i = 0; i < jsonStr.size(); i++) {
char c = jsonStr[i];
// Track if we're inside a string
if (c == '"') {
// Count preceding backslashes to determine if quote is escaped
size_t backslashCount = 0;
size_t k = i;
while (k > 0 && jsonStr[k-1] == '\\') {
backslashCount++;
k--;
}
// Quote is escaped only if preceded by odd number of backslashes
if (backslashCount % 2 == 0) {
inString = !inString;
}
result += c;
continue;
}
if (inString) {
result += c;
continue;
}
🤖 Prompt for AI Agents
In `@sdk/runanywhere-react-native/packages/core/cpp/bridges/ToolCallingBridge.cpp`
around lines 52 - 65, The quote-escape check in the loop using jsonStr[i-1] !=
'\\' fails for sequences with multiple backslashes (e.g., \\\") — change the
logic where the code toggles inString (around the for loop over jsonStr and the
if (c == '"' ...) block) to count the number of consecutive backslashes
immediately preceding the quote in jsonStr and treat the quote as escaped only
if that count is odd; update the branch that currently uses jsonStr[i-1] to use
this parity test so inString is toggled correctly for double-escaped
backslashes.

Comment on lines +362 to +365
return generateWithTools(continuedPrompt, {
...options,
maxToolCalls: (options?.maxToolCalls ?? 5) - 1,
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Edge case: maxToolCalls could become zero or negative.

When options?.maxToolCalls is 1, the computed value becomes 0, causing generateWithTools to skip the generation loop entirely. This could produce unexpected results where the continuation returns without generating any response.

🔧 Suggested fix: Ensure minimum of 1 tool call for continuation
   return generateWithTools(continuedPrompt, {
     ...options,
-    maxToolCalls: (options?.maxToolCalls ?? 5) - 1,
+    maxToolCalls: Math.max(1, (options?.maxToolCalls ?? 5) - 1),
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return generateWithTools(continuedPrompt, {
...options,
maxToolCalls: (options?.maxToolCalls ?? 5) - 1,
});
return generateWithTools(continuedPrompt, {
...options,
maxToolCalls: Math.max(1, (options?.maxToolCalls ?? 5) - 1),
});
🤖 Prompt for AI Agents
In
`@sdk/runanywhere-react-native/packages/core/src/Public/Extensions/RunAnywhere`+ToolCalling.ts
around lines 362 - 365, The continuation call to generateWithTools decrements
options?.maxToolCalls and can reach 0 or negative, causing no generation; update
the call (in RunAnywhere+ToolCalling.ts where generateWithTools is invoked) to
compute maxToolCalls as Math.max(1, (options?.maxToolCalls ?? 5) - 1) (or
equivalent) so the continued invocation always uses at least 1 tool call; keep
the rest of options spread as-is to preserve other settings.

sanchitmonga22 and others added 12 commits January 26, 2026 13:02
SDK Changes:
- Add ToolValue enum for type-safe JSON representation (string, number, bool, array, object, null)
- Add ToolCallingTypes.swift with type definitions using ToolValue
- Add ToolCallParser.swift with pure Swift parser for <tool_call> tags
- Add RunAnywhere+ToolCalling.swift with public API (registerTool, executeTool, generateWithTools)

Example App Changes:
- Add ToolCallInfo to Message model using ToolValue for serialization
- Add ToolCallViews.swift with minimal UI (indicator + detail sheet)
- Add ToolSettingsView.swift with tool registration settings and 3 demo tools
- Update ChatMessageComponents to show tool call indicator on messages
- Update ChatInterfaceView to show "Tools enabled" badge
- Update LLMViewModel to integrate tool calling into generation flow

Bug Fixes:
- Fix LLMViewModel+Analytics.swift nil coalescing warnings
- Simplify ModelSelectionSheet VLM handling
…ved argument handling

- Updated ToolCallViews to use ToolValue for arguments and results.
- Refactored ToolSettingsView to implement real API calls for weather and time tools using Open-Meteo API.
- Improved ToolCallParser to extract tool names and arguments with multiple fallback strategies.
- Added WeatherService for fetching real-time weather data and handling geocoding.
- Enhanced error handling in tool execution and argument parsing.
josuediazflores and others added 28 commits February 1, 2026 16:40
- Add SDKTestApp: minimal iOS test app (Status, Chat, TTS tabs)
  - List/download/load LLM and TTS models with progress
  - Chat: send messages and get LLM responses
  - TTS: speak text with Piper voices
- Add swift-spm-example: SPM consumer example
- Point swift-spm-example and validation/swift-spm-consumer at RunanywhereAI/runanywhere-sdks
- SDK: clearer Foundation Models error messages; RunAnywhereAI README chat/LLM notes
…ge.swift v0.17.5

- swift-auto-tag.yml: auto-tag swift-v* on push to main
- swift-sdk-build-release.yml: Phase 2 – build on swift-v* tag, create release + semver tag
- swift-sdk-release.yml: tag trigger removed in favor of Phase 2
- Package.swift: remote binaries for v0.17.5 for consumers
- CppBridge+Device/ModelAssignment: write to temp pointers in Task, copy to outResponse after wait
- CppBridge+Platform: TTS create use handlePtr; generate use responsePtr for strdup
- AlamofireDownloadService: capture requiresExtraction in local let for Task
- LiveTranscriptionSession: use Sendable Ref for onTermination to avoid capturing self
…divergent history

- Save tag build commit (git rev-parse HEAD) before checkout
- Fetch origin main (git fetch)
- Compare tag commit vs origin/main (git rev-parse origin/main)
- Fail fast if they differ to avoid creating divergent history
- Use git pull --ff-only origin main for safe fast-forward only
…ult setup note

- Switch c-cpp from autobuild to manual (no build system at repo root)
- Add Build C/C++ step: cmake in sdk/runanywhere-commons with minimal opts
- Comment: disable Default setup in repo settings when using this workflow
@shubhammalhotra28
Copy link
Copy Markdown
Contributor Author

just opened to sync the dev and see the changes - not needed as of now - will oepen later if needed. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants