fix(swift,rn): honor LoadOptions contextLength and ordered backendPreferences

Merged
SH
21d ago
+285-79

Description

Fixes #882.

Swift and React Native rejected contextLength and ordered backend preferences even though ModelLoadRequest can carry both fields. They also accepted a required backend preference without representing that constraint on the wire.

Both bindings now forward the context length and complete preference list, reject required preferences, and retain the existing rejection of threads and accelerator options. Context values must be non-negative and fit int32; React Native also rejects fractions and non-finite numbers before encoding. Shared core validation rejects negative values from direct native callers too.

React Native reports the backend returned by native loading rather than the first requested backend. A lone unspecified preference leaves the optional framework field absent so Commons can honor the catalog's preferred framework, even when it differs from the model framework. An unspecified entry before later preferences preserves the caller's ordering. Swift capability reporting exposes the remaining required-preference limitation.

The branch incorporates main at f8aabbbf5, retaining the accepted upstream streaming documentation and newer native/schema features. Its documentation-only schema change uses IDL version 1.5.1, with SCHEMA_LOCK regenerated from the complete final set of 41 schemas.

Context configuration remains advisory at the engine boundary, as required by the existing engine contract. MLX and QHexRT do not currently configure session creation from this request field. Native warnings are surfaced through fallbackReason; adding adjustable context support to those runtimes is outside this binding fix. No public runtime callback ABI or SDK release version is changed.

Reviewer guidance: inspect the encoded request, the lone/mixed unspecified preference cases, React Native's actual-backend mapping, and the schema lock relative to main.

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Refactoring

The small Swift request-builder extraction makes the production mapping directly testable; it adds no public API.

Testing

  • Lint passes locally
  • Added/updated tests for changes

Completed on Windows on the local merge of main at f8aabbbf5, retaining the published 14be8154e fixes:

  • React Native core lint and typecheck, including test-source typechecking, passed using Yarn 3.6.1 through the installed Corepack entry point.
  • The complete React Native core Jest suite passed: 15 suites, 85 tests. The focused load-options suite includes 16 passing tests.
  • Pinned TypeScript/C++ generation completed with protoc 35.1: bash idl/codegen/generate_all.sh --only ts,cpp.
  • The schema lock was regenerated from the merged 41-proto inputs with bash idl/codegen/schema_lock.sh --update. Consistency and version-bump validation passed against the exact captured main lock: bash idl/codegen/schema_lock.sh --check --require-bump build/pr950-review/SCHEMA_LOCK.main.
  • The final core/src/core/model_lifecycle.cpp passed a C++20 syntax-only compilation using the configured MinGW compiler and regenerated headers. This was not a linked native build or native test run.
  • git diff --check and git diff --cached origin/main --check passed. The contribution-scope audit compares the final result with the captured main, rather than treating accepted upstream changes as part of this fix.

The commit-time hook reported that Lefthook was unavailable on PATH; the checks listed above were run directly rather than through that hook.

Exact package/test entry points used:

# From bindings/react-native
node "C:/Program Files/nodejs/node_modules/corepack/dist/yarn.js" workspace @runanywhere/core lint
node "C:/Program Files/nodejs/node_modules/corepack/dist/yarn.js" workspace @runanywhere/core typecheck

# From the repository root
node bindings/react-native/node_modules/jest/bin/jest.js --config bindings/react-native/packages/core/jest.config.js --runInBand --silent --json --outputFile build/pr950-review/rn-core-main-tests.json

# Focused syntax-only compilation with the configured compiler/includes
powershell -NoProfile -File build/pr950-review/check-model-lifecycle-syntax.ps1

The full Jest suite passed on the merged tree without new test changes. The source-text assertions use canonical checkout bytes; their files have no contribution diff.

Seven Swift tests cover encoded request mapping, context bounds/default presence, required-preference rejection, capability reporting, and backend ordering. The single-unspecified case uses differing model and preferred frameworks and checks that framework absence survives protobuf encoding. They cannot be executed on this Windows host. Full generate_all.sh was attempted on the merged 41-proto set and stopped at missing protoc-gen-swift; the separate TypeScript/C++ generation above passed. Full all-language generation and its drift gate still require CI validation, and lock consistency alone is not claimed as proof that every language was regenerated locally. Swift builds/tests and strict SwiftLint also remain unverified locally. The existing swift-spm job performs them, and pr-build.yml is eligible to run on a new update now that this PR targets main; check that the jobs actually run and pass before treating Apple validation as complete. The overall lint checkbox remains unchecked because SwiftLint has not run locally. No linked native build, native test execution, device inference, or MLX/QHexRT execution is claimed for this integration.

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)

Apple execution is pending macOS CI; no simulator or device session was run locally.

Kotlin SDK / Android Sample:

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

No Kotlin binding change or Android device execution in this contribution.

Flutter SDK / Flutter Sample:

  • Tested on iOS
  • Tested on Android

No Flutter binding change or Flutter device execution in this contribution.

React Native SDK / React Native Sample:

  • Tested on iOS
  • Tested on Android

Node-hosted core tests and typechecking passed; native device execution has not been performed.

Web SDK / Web Sample:

  • Tested in Chrome (Desktop)
  • Tested in Firefox
  • Tested in Safari
  • WASM backends load (LlamaCpp + ONNX)
  • OPFS storage persistence verified (survives page refresh)
  • Settings persistence verified (localStorage)

No Web binding or browser-storage change; browser execution was outside this validation.

Labels

Please add the appropriate label(s):

SDKs:

  • Swift SDK - Changes to Swift SDK (bindings/swift)
  • Kotlin SDK - Changes to Kotlin SDK (bindings/kotlin)
  • Flutter SDK - Changes to Flutter SDK (bindings/flutter)
  • React Native SDK - Changes to React Native SDK (bindings/react-native)
  • Web SDK - Changes to Web SDK (bindings/web)
  • Commons - Changes to shared native code (core)

Current applied labels already identify these areas: binding:swift, binding:react-native, and core, alongside bug and p1.

Sample Apps:

  • Flutter Sample - Changes to Flutter example app (bindings/flutter/example)
  • React Native Sample - Changes to React Native example app (bindings/react-native/example)
  • Minimal Examples - Changes to an in-repo SDK harness (bindings/{swift,kotlin,web}/example)

No sample or consumer application files are changed.

The iOS, Android, Web, and Electron consumer apps live in their own
repositories (RunanywhereAI/runanywhere-{ios,android,web,electron}) — open
those PRs there.

Checklist

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

No public API migration is required. Previously unsupported required/threads/accelerator options still fail preflight, invalid context values are rejected, and valid requests retain their complete preference order. The runtime context limitation and unperformed platform checks are described above; no changelog or release bump is needed for this existing bug-fix contribution.

Screenshots

No UI layout or rendering changes. Mobile, tablet, and desktop screenshots do not demonstrate the request-encoding and routing behavior; validation evidence is provided under Testing.