-
Notifications
You must be signed in to change notification settings - Fork 26
Fix #80: Clarify and standardize SDK configuration system #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Added configuration presets, public API methods, comprehensive docs, and fixed ConfigurationData storage bug.
|
@CodeRabbit review |
WalkthroughAdds a new Gradle properties file, expands Swift SDK configuration docs, broadens ConfigurationData with new fields and defaults, adjusts SDK constants, introduces SDKInitParams factory methods, adds configuration presets and setters/getters on RunAnywhere, and updates initialization to asynchronously load configuration at startup. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant App
participant RunAnywhere
participant ConfigService as ConfigurationService
participant Storage as Local DB
participant Backend as Remote API
App->>RunAnywhere: initialize(apiKey, baseURL, env)
RunAnywhere->>RunAnywhere: Setup local services
Note over RunAnywhere: Fire-and-forget async config load
RunAnywhere-->>ConfigService: loadConfiguration()
alt Remote available
ConfigService->>Backend: fetch()
Backend-->>ConfigService: ConfigurationData (source=remote)
else Remote unavailable
ConfigService->>Storage: read()
Storage-->>ConfigService: ConfigurationData? (source=database)
opt No DB entry
ConfigService->>RunAnywhere: consumer overrides?
RunAnywhere-->>ConfigService: yes/no
ConfigService->>ConfigService: fallback to SDK defaults
end
end
ConfigService-->>RunAnywhere: ConfigurationData (with source)
RunAnywhere->>RunAnywhere: set configurationData
RunAnywhere-->>App: initialize() returns (isInitialized = true)
sequenceDiagram
autonumber
participant App
participant RunAnywhere
participant ConfigService as ConfigurationService
App->>RunAnywhere: updateConfiguration(preset)
RunAnywhere->>RunAnywhere: generateConfiguration(basedOn: preset)
RunAnywhere->>ConfigService: save(config, source=consumer, syncPending=true)
ConfigService-->>RunAnywhere: ack
RunAnywhere-->>App: success
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
sdk/runanywhere-swift/Sources/RunAnywhere/Core/Models/Configuration/ConfigurationData.swift (2)
145-154: Make configuration ID deterministic (align with DB fetch-by-id).
sdkDefaults(apiKey:)generates a random ID ("default-<uuid>") while the codebase fetches configuration by a constant ID (see use ofSDKConstants.ConfigurationDefaults.configurationIdin ConfigurationService). This breaks referential consistency and makes later updates harder.Use a stable ID.
public static func sdkDefaults(apiKey: String) -> ConfigurationData { - return ConfigurationData( - id: "default-\(UUID().uuidString)", - apiKey: apiKey.isEmpty ? "dev-mode" : apiKey, - source: .defaults - ) + return ConfigurationData( + id: SDKConstants.ConfigurationDefaults.configurationId, + apiKey: apiKey.isEmpty ? "dev-mode" : apiKey, + source: .defaults + ) }
41-110: Avoid persisting API keys to the database.The model is
PersistableRecord, soapiKeyrisks being saved to local storage. Treat API keys as secrets; persist only in Keychain (you already do that elsewhere).Override GRDB persistence to omit
apiKey.@@ public struct ConfigurationData: Codable, RepositoryEntity, FetchableRecord, PersistableRecord, Sendable { @@ public var apiKey: String? @@ } // MARK: - GRDB Configuration @@ } +// MARK: - Persistence: Omit secrets +extension ConfigurationData { + public func encode(to container: inout PersistenceContainer) { + container["id"] = id + container["routing"] = routing + container["generation"] = generation + container["storage"] = storage + container["api"] = api + container["download"] = download + container["hardware"] = hardware + container["debugMode"] = debugMode + // Do NOT persist apiKey + container["allowUserOverride"] = allowUserOverride + container["source"] = source + container["createdAt"] = createdAt + container["updatedAt"] = updatedAt + container["syncPending"] = syncPending + } +}Optionally also exclude
apiKeyfromColumnsto prevent accidental queries.sdk/runanywhere-swift/Sources/RunAnywhere/Public/RunAnywhere.swift (2)
81-86: Makeinitialize(with:)public to match docs and SDKInitParams helpers.Docs and new
SDKInitParamsfactories expectRunAnywhere.initialize(with:)to be callable. It'sprivatenow.- private static func initialize(with params: SDKInitParams) throws { + public static func initialize(with params: SDKInitParams) throws {
141-149: Replace NSLock with Swift concurrency (actors).
NSLockviolates the Swift code guideline ("Do not use NSLock"). Use an actor to guard registration state.As per coding guidelines
Minimal pattern:
actor RegistrationState { var isRegistering = false var cachedDeviceId: String? } private static let registrationState = RegistrationState()Then replace lock sections with
await registrationState.isRegisteringchecks and updates. This removes busy-wait loops and aligns with Swift 6 concurrency.sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/RunAnywhere+Configuration.swift (1)
82-91: Default routing policy should be deviceOnly (privacy-first)Current default is
.automatic, conflicting with SDK constants and privacy posture. Use the SDK default.Apply:
- /// - Returns: Current routing policy, defaults to .automatic + /// - Returns: Current routing policy, defaults to .deviceOnly @@ - let policy = RunAnywhere.configurationData?.routing.policy ?? .automatic + let policy = RunAnywhere.configurationData?.routing.policy + ?? SDKConstants.ConfigurationDefaults.routingPolicy
🧹 Nitpick comments (17)
examples/intellij-plugin-demo/plugin/gradle.properties (4)
11-14: Remove deprecated/no-op org.gradle.configureondemand.This property was removed in Gradle 8+ and has no effect.
-# Gradle daemon settings for stability -org.gradle.daemon=true -org.gradle.parallel=true -org.gradle.configureondemand=false +# Gradle daemon settings +org.gradle.daemon=true +org.gradle.parallel=true
2-2: Avoid capping MaxMetaspaceSize unless you’ve measured it.A 512m cap can cause classloader OOMs on larger builds; default uncapped metaspace is safer.
-org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
16-19: kotlin.incremental is already the default.You can omit it to reduce noise; code style setting is fine.
-# Kotlin compiler settings -kotlin.code.style=official -kotlin.incremental=true +# Kotlin compiler settings +kotlin.code.style=official
20-22: Drop Android-specific properties from the IntelliJ plugin module’s gradle.properties
In examples/intellij-plugin-demo/plugin/gradle.properties, remove:-# Android/IntelliJ compatibility -android.useAndroidX=true -android.enableJetifier=truesdk/runanywhere-swift/Sources/RunAnywhere/Core/Models/Configuration/ConfigurationData.swift (1)
128-141: Columns enum incomplete (optional).Add
api,download,hardware, anddebugModetoColumnsfor type-safe queries.public enum Columns: String, ColumnExpression { case id case routing case generation case storage + case api + case download + case hardware + case debugMode case apiKey case allowUserOverride case source case createdAt case updatedAt case syncPending }sdk/runanywhere-swift/README.md (2)
97-106: Initialization is synchronous; removeawait.
RunAnywhere.initializeisthrows, notasync throws. Usingawaithere is incorrect.-try await RunAnywhere.initialize( +try RunAnywhere.initialize( apiKey: "dev", // Any string works in dev mode - baseURL: "localhost", // Not used in dev mode + baseURL: "http://localhost", // Parsed but unused in dev mode environment: .development )Alternatively, use
SDKInitParams.development()and a publicinitialize(with:)overload (see related comment in RunAnywhere.swift).
217-281: Docs/API mismatch: public initializer overload missing.README references presets and Layer 3 APIs correctly. However, throughout docs you use
RunAnywhere.initialize(with: params), which is currently private. Either:
- Make
initialize(with:)public, or- Update docs to call existing public overloads.
Would you like me to update the docs PR-wide after making
initialize(with:)public?sdk/runanywhere-swift/Sources/RunAnywhere/Public/RunAnywhere.swift (1)
116-121: Fire-and-forget configuration load: expose readiness signal.Asynchronous load can race early reads. Provide a readiness API or event (e.g.,
SDKConfigurationEvent.loaded) so apps can await configuration before reads, instead of relying on sleeps.Example:
- Publish
EventBus.shared.publish(SDKConfigurationEvent.loaded(source: config.source))- Add
public static func waitUntilConfigurationLoaded(timeout:) async throwssdk/runanywhere-swift/docs/CONFIGURATION_GUIDE.md (4)
162-176: Docs callRunAnywhere.initialize(with:)but it’s private.Either make the API public (preferred) or update examples to existing overloads.
27-48: Add fenced code language to satisfy markdown lint.Set the diagram block language to
text.-``` +```text (diagram)--- `469-469`: **Add fenced code language.** ```diff -``` +```text // Example precedence diagram--- `714-715`: **Replace bare URL with a markdown link.** ```diff -Open an issue on GitHub: https://github.com/RunanywhereAI/runanywhere-sdks/issues +Open an issue on GitHub: [RunanywhereAI/runanywhere-sdks issues](https://github.com/RunanywhereAI/runanywhere-sdks/issues)sdk/runanywhere-swift/Sources/RunAnywhere/Public/Configuration/SDKEnvironment.swift (2)
156-166: Enforce HTTPS for production URLs.Validate scheme to avoid insecure HTTP in production.
- guard let url = URL(string: urlString) else { + guard let url = URL(string: urlString), url.scheme?.lowercased() == "https" else { throw SDKError.validationFailed("Invalid production URL from constants: \(urlString)") }Want a similar change for staging?
172-178: Also enforce HTTPS for staging.- guard let url = URL(string: urlString) else { + guard let url = URL(string: urlString), url.scheme?.lowercased() == "https" else { throw SDKError.validationFailed("Invalid staging URL from constants: \(urlString)") }sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/RunAnywhere+Configuration.swift (3)
108-129: Publish a configuration-updated event after applying presetConsider emitting an event (e.g.,
.updated(config)or.presetApplied(preset)) to notify observers.Example:
events.publish(.configurationUpdated(config: newConfig))
134-158: Consider routing-policy updated eventEmit an event after update to improve observability and reactive UIs.
Example:
events.publish(.routingPolicyRetrieved(policy: policy)) // or a dedicated `.routingPolicyUpdated`
194-218: Consider storage-configuration updated eventEmit a storage update event for symmetry with getters and better observability.
Example:
events.publish(.storageConfigurationUpdated(storage: storage))
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
examples/intellij-plugin-demo/plugin/gradle.properties(1 hunks)sdk/runanywhere-swift/README.md(1 hunks)sdk/runanywhere-swift/Sources/RunAnywhere/Core/Models/Configuration/ConfigurationData.swift(1 hunks)sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Constants/SDKConstants.swift(1 hunks)sdk/runanywhere-swift/Sources/RunAnywhere/Public/Configuration/SDKEnvironment.swift(2 hunks)sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/RunAnywhere+Configuration.swift(2 hunks)sdk/runanywhere-swift/Sources/RunAnywhere/Public/RunAnywhere.swift(1 hunks)sdk/runanywhere-swift/docs/CONFIGURATION_GUIDE.md(1 hunks)sdk/runanywhere-swift/docs/PUBLIC_API_REFERENCE.md(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
{sdk/runanywhere-swift,examples/ios}/**/*.swift
📄 CodeRabbit inference engine (CLAUDE.md)
{sdk/runanywhere-swift,examples/ios}/**/*.swift: Always use the latest Swift 6 APIs and syntax (including modern concurrency features)
Do not use NSLock in Swift code
Files:
sdk/runanywhere-swift/Sources/RunAnywhere/Public/Configuration/SDKEnvironment.swiftsdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Constants/SDKConstants.swiftsdk/runanywhere-swift/Sources/RunAnywhere/Core/Models/Configuration/ConfigurationData.swiftsdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/RunAnywhere+Configuration.swiftsdk/runanywhere-swift/Sources/RunAnywhere/Public/RunAnywhere.swift
sdk/runanywhere-swift/**/*.swift
📄 CodeRabbit inference engine (CLAUDE.md)
Use async/await for async APIs in the iOS SDK
Files:
sdk/runanywhere-swift/Sources/RunAnywhere/Public/Configuration/SDKEnvironment.swiftsdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Constants/SDKConstants.swiftsdk/runanywhere-swift/Sources/RunAnywhere/Core/Models/Configuration/ConfigurationData.swiftsdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/RunAnywhere+Configuration.swiftsdk/runanywhere-swift/Sources/RunAnywhere/Public/RunAnywhere.swift
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
PR: RunanywhereAI/runanywhere-sdks#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-07T00:42:41.855Z
Learning: Applies to sdk/runanywhere-swift/**/Configuration.swift : Provide configuration-based initialization for the iOS SDK (API key and optional settings)
📚 Learning: 2025-10-07T00:42:41.855Z
Learnt from: CR
PR: RunanywhereAI/runanywhere-sdks#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-07T00:42:41.855Z
Learning: Applies to sdk/runanywhere-swift/**/Configuration.swift : Provide configuration-based initialization for the iOS SDK (API key and optional settings)
Applied to files:
sdk/runanywhere-swift/docs/CONFIGURATION_GUIDE.mdsdk/runanywhere-swift/Sources/RunAnywhere/Public/Configuration/SDKEnvironment.swiftsdk/runanywhere-swift/README.mdsdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Constants/SDKConstants.swiftsdk/runanywhere-swift/Sources/RunAnywhere/Core/Models/Configuration/ConfigurationData.swiftsdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/RunAnywhere+Configuration.swiftsdk/runanywhere-swift/Sources/RunAnywhere/Public/RunAnywhere.swift
📚 Learning: 2025-10-07T00:42:41.855Z
Learnt from: CR
PR: RunanywhereAI/runanywhere-sdks#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-07T00:42:41.855Z
Learning: Applies to sdk/runanywhere-android/**/Configuration.kt : Provide configuration-based initialization for the Android SDK (API key and optional settings)
Applied to files:
sdk/runanywhere-swift/Sources/RunAnywhere/Public/Configuration/SDKEnvironment.swift
📚 Learning: 2025-10-07T00:42:41.855Z
Learnt from: CR
PR: RunanywhereAI/runanywhere-sdks#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-07T00:42:41.855Z
Learning: Applies to sdk/runanywhere-swift/**/RunAnywhereSDK.swift : Expose the iOS SDK main entry via RunAnywhereSDK.shared (singleton)
Applied to files:
sdk/runanywhere-swift/Sources/RunAnywhere/Public/RunAnywhere.swift
🧬 Code graph analysis (3)
sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Constants/SDKConstants.swift (1)
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/data/privacy/PrivacyManager.kt (1)
privacyModeEnabled(551-562)
sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/RunAnywhere+Configuration.swift (5)
sdk/runanywhere-swift/Sources/RunAnywhere/Public/Events/EventBus.swift (12)
publish(75-78)publish(81-84)publish(87-90)publish(93-96)publish(99-102)publish(105-108)publish(111-114)publish(117-120)publish(123-126)publish(129-132)publish(135-138)publish(141-168)sdk/runanywhere-swift/Sources/RunAnywhere/Core/Models/Configuration/ConfigurationData.swift (1)
sdkDefaults(147-153)sdk/runanywhere-swift/Sources/RunAnywhere/Data/Services/ConfigurationService.swift (2)
updateConfiguration(83-115)setConsumerConfiguration(73-81)sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Logging/Logger/SDKLogger.swift (1)
info(26-28)sdk/runanywhere-swift/Sources/RunAnywhere/Data/Repositories/ConfigurationRepositoryImpl.swift (1)
setConsumerConfiguration(95-97)
sdk/runanywhere-swift/Sources/RunAnywhere/Public/RunAnywhere.swift (2)
sdk/runanywhere-swift/Sources/RunAnywhere/Data/Services/ConfigurationService.swift (1)
loadConfigurationOnLaunch(26-63)sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Logging/Logger/SDKLogger.swift (1)
debug(21-23)
🪛 LanguageTool
sdk/runanywhere-swift/docs/CONFIGURATION_GUIDE.md
[grammar] ~3-~3: There might be a mistake here.
Context: ...uide Last Updated: October 14, 2025 SDK Version: 1.0.0 --- ## Table of...
(QB_NEW_EN)
[grammar] ~10-~10: There might be a mistake here.
Context: ... --- ## Table of Contents 1. Overview 2. [Three-Layer Configuration Architecture](...
(QB_NEW_EN)
[grammar] ~11-~11: There might be a mistake here.
Context: ... Three-Layer Configuration Architecture 3. [Layer 1: Build-Time Constants](#layer-1-...
(QB_NEW_EN)
[grammar] ~12-~12: There might be a mistake here.
Context: ...cture) 3. Layer 1: Build-Time Constants 4. [Layer 2: SDK Initialization](#layer-2-sd...
(QB_NEW_EN)
[grammar] ~13-~13: There might be a mistake here.
Context: ...nstants) 4. Layer 2: SDK Initialization 5. [Layer 3: Runtime Configuration](#layer-3...
(QB_NEW_EN)
[grammar] ~14-~14: There might be a mistake here.
Context: ...tion) 5. Layer 3: Runtime Configuration 6. [Configuration Presets](#configuration-pr...
(QB_NEW_EN)
[grammar] ~15-~15: There might be a mistake here.
Context: ...configuration) 6. Configuration Presets 7. [Common Configuration Scenarios](#common-...
(QB_NEW_EN)
[grammar] ~16-~16: There might be a mistake here.
Context: ...sets) 7. Common Configuration Scenarios 8. [Configuration Precedence](#configuration...
(QB_NEW_EN)
[grammar] ~17-~17: There might be a mistake here.
Context: ...-scenarios) 8. Configuration Precedence 9. API Reference 10. [Trou...
(QB_NEW_EN)
[grammar] ~18-~18: There might be a mistake here.
Context: ...figuration-precedence) 9. API Reference 10. Troubleshooting --- ...
(QB_NEW_EN)
[grammar] ~63-~63: There might be a mistake here.
Context: ...o configure? | Use Which Layer? | How? | |--------------------------------|------...
(QB_NEW_EN)
[grammar] ~64-~64: There might be a mistake here.
Context: ...-------------|------------------|------| | API URLs per environment | Layer 1 | E...
(QB_NEW_EN)
[grammar] ~65-~65: There might be a mistake here.
Context: ...ayer 1 | Edit RunAnywhereConfig.json | | API key and environment mode | Layer 2...
(QB_NEW_EN)
[grammar] ~66-~66: There might be a mistake here.
Context: ...| Layer 2 | RunAnywhere.initialize() | | Temperature, max tokens | Layer 3 | `R...
(QB_NEW_EN)
[grammar] ~67-~67: There might be a mistake here.
Context: ...ywhere.setDefaultGenerationSettings()` | | Routing policy (device vs cloud) | Lay...
(QB_NEW_EN)
[grammar] ~68-~68: There might be a mistake here.
Context: ...r 3 | RunAnywhere.setRoutingPolicy() | | Feature flags | Layer 1 | Edit `RunAny...
(QB_NEW_EN)
[grammar] ~69-~69: There might be a mistake here.
Context: ...ayer 1 | Edit RunAnywhereConfig.json | | Apply preset (creative, precise) | Lay...
(QB_NEW_EN)
[grammar] ~121-~121: There might be a mistake here.
Context: ...endpoint URLs for different environments - Feature flags that apply to all users - ...
(QB_NEW_EN)
[grammar] ~122-~122: There might be a mistake here.
Context: ... - Feature flags that apply to all users - Timeout values and retry policies - Back...
(QB_NEW_EN)
[grammar] ~123-~123: There might be a mistake here.
Context: ...sers - Timeout values and retry policies - Backend service endpoints - Build-specif...
(QB_NEW_EN)
[grammar] ~124-~124: There might be a mistake here.
Context: ...try policies - Backend service endpoints - Build-specific configuration ❌ **Don't ...
(QB_NEW_EN)
[grammar] ~128-~128: There might be a mistake here.
Context: ... For:** - User preferences (use Layer 3) - API keys (use Layer 2) - Settings that c...
(QB_NEW_EN)
[grammar] ~129-~129: There might be a mistake here.
Context: ...s (use Layer 3) - API keys (use Layer 2) - Settings that change frequently (use Lay...
(QB_NEW_EN)
[grammar] ~180-~180: There might be a mistake here.
Context: ...tion | API Calls | Telemetry | Logging | |------|-------------|-----------|------...
(QB_NEW_EN)
[grammar] ~181-~181: There might be a mistake here.
Context: ...-----|-----------|-----------|---------| | .development | Local testing | ❌ Non...
(QB_NEW_EN)
[grammar] ~182-~182: There might be a mistake here.
Context: ...sting | ❌ None | ❌ Disabled | 📝 Debug | | .staging | Integration testing | ✅ S...
(QB_NEW_EN)
[grammar] ~183-~183: There might be a mistake here.
Context: ...| ✅ Staging API | .production | Live app | ✅ Productio...
(QB_NEW_EN)
[grammar] ~184-~184: There might be a mistake here.
Context: ...✅ Production API | ✅ Full |
(QB_NEW_EN)
[grammar] ~189-~189: There might be a mistake here.
Context: ...* - Setting API authentication (API key) - Choosing environment mode (dev/staging/p...
(QB_NEW_EN)
[grammar] ~190-~190: There might be a mistake here.
Context: ...sing environment mode (dev/staging/prod) - Providing backend URL - Initial SDK boot...
(QB_NEW_EN)
[grammar] ~191-~191: There might be a mistake here.
Context: ...ev/staging/prod) - Providing backend URL - Initial SDK bootstrap ❌ **Don't Use For...
(QB_NEW_EN)
[grammar] ~195-~195: There might be a mistake here.
Context: ...anging generation settings (use Layer 3) - Updating routing policy (use Layer 3) - ...
(QB_NEW_EN)
[grammar] ~196-~196: There might be a mistake here.
Context: ... - Updating routing policy (use Layer 3) - User preferences (use Layer 3) --- ## ...
(QB_NEW_EN)
[grammar] ~210-~210: There might be a mistake here.
Context: ... Fetched from API (production mode only) 2. Database Cache - Previously saved conf...
(QB_NEW_EN)
[grammar] ~211-~211: There might be a mistake here.
Context: ...Cache** - Previously saved configuration 3. Consumer Overrides - Settings you set ...
(QB_NEW_EN)
[grammar] ~212-~212: There might be a mistake here.
Context: ...des** - Settings you set via SDK methods 4. SDK Defaults - Fallback values ### Re...
(QB_NEW_EN)
[grammar] ~271-~271: There might be a mistake here.
Context: ...ion parameters (temperature, max tokens) - Routing policy (device vs cloud) - Stora...
(QB_NEW_EN)
[grammar] ~272-~272: There might be a mistake here.
Context: ...kens) - Routing policy (device vs cloud) - Storage limits - User preferences - Feat...
(QB_NEW_EN)
[grammar] ~273-~273: There might be a mistake here.
Context: ...olicy (device vs cloud) - Storage limits - User preferences - Feature-specific sett...
(QB_NEW_EN)
[grammar] ~274-~274: There might be a mistake here.
Context: ...oud) - Storage limits - User preferences - Feature-specific settings ❌ **Don't Use...
(QB_NEW_EN)
[grammar] ~278-~278: There might be a mistake here.
Context: ...on't Use For:** - API keys (use Layer 2) - Environment selection (use Layer 2) - De...
(QB_NEW_EN)
[grammar] ~279-~279: There might be a mistake here.
Context: ...2) - Environment selection (use Layer 2) - Deployment settings (use Layer 1) --- ...
(QB_NEW_EN)
[grammar] ~297-~297: There might be a mistake here.
Context: ...tion(preset: .creative) ``` Settings: - Temperature: 0.9 (high randomness) - Max...
(QB_NEW_EN)
[grammar] ~298-~298: There might be a mistake here.
Context: ...:** - Temperature: 0.9 (high randomness) - Max Tokens: 1024 (longer responses) - To...
(QB_NEW_EN)
[grammar] ~299-~299: There might be a mistake here.
Context: ...s) - Max Tokens: 1024 (longer responses) - Top-P: 0.95 (diverse vocabulary) - Routi...
(QB_NEW_EN)
[grammar] ~300-~300: There might be a mistake here.
Context: ...nses) - Top-P: 0.95 (diverse vocabulary) - Routing: Automatic --- #### .precise...
(QB_NEW_EN)
[grammar] ~312-~312: There might be a mistake here.
Context: ...ation(preset: .precise) ``` Settings: - Temperature: 0.3 (focused, deterministic...
(QB_NEW_EN)
[grammar] ~313-~313: There might be a mistake here.
Context: ...emperature: 0.3 (focused, deterministic) - Max Tokens: 512 (concise responses) - To...
(QB_NEW_EN)
[grammar] ~314-~314: There might be a mistake here.
Context: ...c) - Max Tokens: 512 (concise responses) - Top-P: 0.8 (conservative vocabulary) - R...
(QB_NEW_EN)
[grammar] ~315-~315: There might be a mistake here.
Context: ...) - Top-P: 0.8 (conservative vocabulary) - Routing: Automatic --- #### `.balanced...
(QB_NEW_EN)
[grammar] ~327-~327: There might be a mistake here.
Context: ...tion(preset: .balanced) ``` Settings: - Temperature: 0.7 (moderate randomness) -...
(QB_NEW_EN)
[grammar] ~328-~328: There might be a mistake here.
Context: ...- Temperature: 0.7 (moderate randomness) - Max Tokens: 512 (moderate length) - Top-...
(QB_NEW_EN)
[grammar] ~329-~329: There might be a mistake here.
Context: ...ess) - Max Tokens: 512 (moderate length) - Top-P: 0.9 (balanced vocabulary) - Routi...
(QB_NEW_EN)
[grammar] ~330-~330: There might be a mistake here.
Context: ...ngth) - Top-P: 0.9 (balanced vocabulary) - Routing: Automatic --- #### `.privacyF...
(QB_NEW_EN)
[grammar] ~342-~342: There might be a mistake here.
Context: ...reset: .privacyFocused) ``` Settings: - Temperature: 0.7 - Max Tokens: 512 - **R...
(QB_NEW_EN)
[grammar] ~343-~343: There might be a mistake here.
Context: ...d) ``` Settings: - Temperature: 0.7 - Max Tokens: 512 - **Routing: Device-only...
(QB_NEW_EN)
[grammar] ~344-~344: There might be a mistake here.
Context: ...:** - Temperature: 0.7 - Max Tokens: 512 - Routing: Device-only (never uses cloud...
(QB_NEW_EN)
[grammar] ~356-~356: There might be a mistake here.
Context: ...reset: .cloudPreferred) ``` Settings: - Temperature: 0.7 - Max Tokens: 1024 - **...
(QB_NEW_EN)
[grammar] ~357-~357: There might be a mistake here.
Context: ...d) ``` Settings: - Temperature: 0.7 - Max Tokens: 1024 - **Routing: Prefer Clo...
(QB_NEW_EN)
[grammar] ~358-~358: There might be a mistake here.
Context: ...** - Temperature: 0.7 - Max Tokens: 1024 - Routing: Prefer Cloud (uses cloud when...
(QB_NEW_EN)
[grammar] ~585-~585: There might be a mistake here.
Context: ...s()` returns default values Solution: 1. Configuration loads asynchronously after...
(QB_NEW_EN)
[grammar] ~606-~606: There might be a mistake here.
Context: ... are lost after app restart Solution: - In development mode, configuration i...
(QB_NEW_EN)
[grammar] ~607-~607: There might be a mistake here.
Context: ... mode**, configuration is not persisted to backend - In production mode, call ...
(QB_NEW_EN)
[grammar] ~621-~621: There might be a mistake here.
Context: ...rently between environments Solution: - Different environments load different La...
(QB_NEW_EN)
[grammar] ~637-~637: There might be a mistake here.
Context: ...spite setting .deviceOnly Solution: - Check if a preset was applied after sett...
(QB_NEW_EN)
[grammar] ~658-~658: There might be a mistake here.
Context: ...PI key errors in production Solution: - Layer 2 is for API keys, not Layer 3 -...
(QB_NEW_EN)
[grammar] ~701-~701: There might be a mistake here.
Context: ...d-time constants for deployment settings 2. Layer 2: Initialization parameters for...
(QB_NEW_EN)
[grammar] ~702-~702: There might be a mistake here.
Context: ...zation parameters for API authentication 3. Layer 3: Runtime configuration for dyn...
(QB_NEW_EN)
[grammar] ~707-~707: There might be a mistake here.
Context: ...tomatically. For more information, see: - SDK README - [Public API ...
(QB_NEW_EN)
[grammar] ~708-~708: There might be a mistake here.
Context: ...For more information, see: - SDK README - [Public API Reference](./PUBLIC_API_REFER...
(QB_NEW_EN)
[grammar] ~709-~709: There might be a mistake here.
Context: ...E](../README.md) - Public API Reference - [Architecture Documentation](./ARCHITECTU...
(QB_NEW_EN)
sdk/runanywhere-swift/README.md
[grammar] ~223-~223: There might be a mistake here.
Context: ... | What to Configure | Method | Layer | |-------------------|--------|-------| |...
(QB_NEW_EN)
[grammar] ~224-~224: There might be a mistake here.
Context: ...| |-------------------|--------|-------| | API Key & Environment | `RunAnywhe...
(QB_NEW_EN)
[grammar] ~225-~225: There might be a mistake here.
Context: ...nywhere.initialize()| Layer 2 (Init) | | **Temperature, Max Tokens** |RunAnyw...
(QB_NEW_EN)
[grammar] ~226-~226: There might be a mistake here.
Context: ...erationSettings()| Layer 3 (Runtime) | | **Routing Policy** |RunAnywhere.setR...
(QB_NEW_EN)
[grammar] ~227-~227: There might be a mistake here.
Context: ...etRoutingPolicy()| Layer 3 (Runtime) | | **Apply Preset** |RunAnywhere.update...
(QB_NEW_EN)
[grammar] ~276-~276: There might be a mistake here.
Context: ...PI URLs, feature flags (from JSON files) 2. Layer 2: SDK Initialization - API key,...
(QB_NEW_EN)
[grammar] ~277-~277: There might be a mistake here.
Context: ..., environment mode (set once at startup) 3. Layer 3: Runtime Configuration - Tempe...
(QB_NEW_EN)
[grammar] ~280-~280: There might be a mistake here.
Context: ...lete configuration documentation, see:** [Configuration Guide](docs/CONFIGURATION...
(QB_NEW_EN)
[grammar] ~280-~280: There might be a mistake here.
Context: ...cumentation, see:** Configuration Guide ## Advanced Features ### Voice AI Pipeline...
(QB_NEW_EN)
🪛 markdownlint-cli2 (0.18.1)
sdk/runanywhere-swift/docs/CONFIGURATION_GUIDE.md
27-27: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
469-469: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
715-715: Bare URL used
(MD034, no-bare-urls)
🔇 Additional comments (11)
examples/intellij-plugin-demo/plugin/gradle.properties (1)
4-9: Review comment is inapplicable to the current codebase.The suggested follow-up presumes a
build.gradlefile exists in the plugin module where toolchain declarations can be added. However, theexamples/intellij-plugin-demo/plugin/directory contains onlygradle.properties—no build script files exist. The gradle.properties configuration shown is sufficient for its purpose and does not require companion build script declarations.Likely an incorrect or invalid review comment.
sdk/runanywhere-swift/Sources/RunAnywhere/Public/Configuration/SDKEnvironment.swift (1)
70-107: Excellent Layer 2 docs.Clear separation of concerns and examples; aligns with the three-layer model.
sdk/runanywhere-swift/docs/PUBLIC_API_REFERENCE.md (5)
378-384: LGTM: Clear example for default generation settingsExample matches new API shape (async/await; async throws).
388-394: LGTM: Storage configuration exampleConsistent with setStorageConfiguration(_:).
402-403: LGTM: Added getCurrentConfiguration() usageMatches new async API.
409-414: LGTM: Preset usage examplesPreset names and calls align with new API.
416-417: Relative link verification passedThe file
./CONFIGURATION_GUIDE.mdexists and resolves correctly from the documentation directory.sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/RunAnywhere+Configuration.swift (4)
23-61: LGTM: Preset generation logicReasonable defaults; marks source/updatedAt/syncPending appropriately.
71-80: LGTM: Generation settings getterPublishes request/retrieval events and falls back to defaults.
95-101: LGTM: getCurrentConfiguration() fallbackReturns sdkDefaults if not loaded; good for first-run scenarios.
220-233: LGTM: Sync delegates to service and publishes eventsClear success/failure signaling.
| # Force use of JDK 17 for all Gradle operations | ||
| org.gradle.java.home=/opt/homebrew/Cellar/openjdk@17/17.0.16/libexec/openjdk.jdk/Contents/Home | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove machine-specific org.gradle.java.home; use Gradle Toolchains for JDK 17.
This absolute path will break CI and other dev machines. Prefer toolchains or JAVA_HOME.
-# Force use of JDK 17 for all Gradle operations
-org.gradle.java.home=/opt/homebrew/Cellar/openjdk@17/17.0.16/libexec/openjdk.jdk/Contents/Home
+# Use Gradle Toolchains (declare in build scripts) to require JDK 17; avoid hardcoded paths.
+# org.gradle.java.home=<removed>🤖 Prompt for AI Agents
In examples/intellij-plugin-demo/plugin/gradle.properties around lines 4-6 the
file pins org.gradle.java.home to a machine-specific absolute path which will
break CI and other developers; remove that org.gradle.java.home entry and
instead configure JDK 17 via Gradle Toolchains in the project build (add a java
toolchain block in build.gradle or build.gradle.kts specifying languageVersion =
JavaLanguageVersion.of(17)) or rely on JAVA_HOME in CI by documenting and
exporting the JDK 17 path in CI pipelines; ensure the repo contains no
machine-specific paths and update README/CI config to state the required JDK or
toolchain behavior.
| # Disable toolchain auto-detection to prevent conflicts | ||
| org.gradle.java.installations.auto-detect=false | ||
| org.gradle.java.installations.auto-download=false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-enable toolchain discovery/auto-download for reproducible builds.
Disabling these undermines portability. Let Gradle resolve JDKs consistently.
-# Disable toolchain auto-detection to prevent conflicts
-org.gradle.java.installations.auto-detect=false
-org.gradle.java.installations.auto-download=false
+# Enable toolchain discovery/auto-download for consistent builds
+org.gradle.java.installations.auto-detect=true
+org.gradle.java.installations.auto-download=true🤖 Prompt for AI Agents
In examples/intellij-plugin-demo/plugin/gradle.properties around lines 7 to 9
the Gradle Java toolchain auto-detection and auto-download have been disabled;
re-enable toolchain discovery by removing these two properties or setting
org.gradle.java.installations.auto-detect=true and
org.gradle.java.installations.auto-download=true so Gradle can resolve and
download JDKs for reproducible, portable builds.
| ### Configuration Loading | ||
|
|
||
| The SDK automatically loads configuration in this order: | ||
|
|
||
| 1. **Remote Backend** - Fetched from API (production mode only) | ||
| 2. **Database Cache** - Previously saved configuration | ||
| 3. **Consumer Overrides** - Settings you set via SDK methods | ||
| 4. **SDK Defaults** - Fallback values | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix precedence order (contradiction in guide).
This section lists: 1) Remote, 2) DB, 3) Consumer, 4) Defaults. Elsewhere (and in code) precedence is: 1) Consumer, 2) Remote, 3) DB, 4) Defaults. Align to the latter.
-1. **Remote Backend** - Fetched from API (production mode only)
-2. **Database Cache** - Previously saved configuration
-3. **Consumer Overrides** - Settings you set via SDK methods
-4. **SDK Defaults** - Fallback values
+1. **Consumer Overrides** - Settings you set via SDK methods
+2. **Remote Backend** - Fetched from API (production mode only)
+3. **Database Cache** - Previously saved configuration
+4. **SDK Defaults** - Fallback values📝 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.
| ### Configuration Loading | |
| The SDK automatically loads configuration in this order: | |
| 1. **Remote Backend** - Fetched from API (production mode only) | |
| 2. **Database Cache** - Previously saved configuration | |
| 3. **Consumer Overrides** - Settings you set via SDK methods | |
| 4. **SDK Defaults** - Fallback values | |
| ### Configuration Loading | |
| The SDK automatically loads configuration in this order: | |
| 1. **Consumer Overrides** - Settings you set via SDK methods | |
| 2. **Remote Backend** - Fetched from API (production mode only) | |
| 3. **Database Cache** - Previously saved configuration | |
| 4. **SDK Defaults** - Fallback values | |
🧰 Tools
🪛 LanguageTool
[grammar] ~210-~210: There might be a mistake here.
Context: ... Fetched from API (production mode only) 2. Database Cache - Previously saved conf...
(QB_NEW_EN)
[grammar] ~211-~211: There might be a mistake here.
Context: ...Cache** - Previously saved configuration 3. Consumer Overrides - Settings you set ...
(QB_NEW_EN)
[grammar] ~212-~212: There might be a mistake here.
Context: ...des** - Settings you set via SDK methods 4. SDK Defaults - Fallback values ### Re...
(QB_NEW_EN)
🤖 Prompt for AI Agents
In sdk/runanywhere-swift/docs/CONFIGURATION_GUIDE.md around lines 206 to 214,
the documented configuration-loading precedence is incorrect; update the
numbered list to match the code and other docs by listing precedence as: 1)
Consumer Overrides (settings set via SDK methods), 2) Remote Backend (fetched
from API, production mode), 3) Database Cache (previously saved configuration),
4) SDK Defaults (fallback values); keep the same brief descriptions and ensure
wording/ordering matches other docs and code references.
| // Update routing policy | ||
| try await RunAnywhere.setRoutingPolicy(.preferDevice) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incorrect enum case in example: use .deviceOnly
Codebase uses .deviceOnly/.preferCloud/.automatic. .preferDevice isn’t used in the shown code and likely won’t compile.
Apply:
-try await RunAnywhere.setRoutingPolicy(.preferDevice)
+try await RunAnywhere.setRoutingPolicy(.deviceOnly)🤖 Prompt for AI Agents
In sdk/runanywhere-swift/docs/PUBLIC_API_REFERENCE.md around lines 385 to 387,
the example uses an incorrect enum case `.preferDevice`; replace it with the
correct case `.deviceOnly` (since the codebase exposes
`.deviceOnly`/`.preferCloud`/`.automatic`) so the example compiles and matches
the documented API.
| // SDK configuration - Safe defaults that can be overridden via RunAnywhere.updateConfiguration() | ||
| // Note: These are FALLBACK values used only when configuration hasn't been loaded yet | ||
| // To change these at runtime, use: RunAnywhere.setRoutingPolicy() or RunAnywhere.updateConfiguration(preset:) | ||
| public static let cloudRoutingEnabled: Bool = false // Safe default: Device-only until user configures | ||
| public static let privacyModeEnabled: Bool = true // Safe default: Privacy-first approach | ||
| public static let routingPolicy = RoutingPolicy.deviceOnly // Safe default: Device-only | ||
| public static let allowUserOverride: Bool = true // Allow user to override configuration | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default routing fallback conflicts with getter (.automatic) — privacy risk
SDK defaults set routingPolicy/deviceOnly, but getCurrentRoutingPolicy() returns .automatic when unset. This can route to cloud before config loads. Align the getter to SDKConstants.ConfigurationDefaults.routingPolicy (deviceOnly).
Apply this fix in RunAnywhere+Configuration.swift:
- /// - Returns: Current routing policy, defaults to .automatic
+ /// - Returns: Current routing policy, defaults to .deviceOnly
@@
- let policy = RunAnywhere.configurationData?.routing.policy ?? .automatic
+ let policy = RunAnywhere.configurationData?.routing.policy
+ ?? SDKConstants.ConfigurationDefaults.routingPolicyCommittable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Constants/SDKConstants.swift
around lines 73-80, the SDK default routingPolicy is set to
RoutingPolicy.deviceOnly but the configuration getter in
RunAnywhere+Configuration.swift returns .automatic when unset, creating a
privacy risk; modify getCurrentRoutingPolicy() (in
RunAnywhere+Configuration.swift) to return
SDKConstants.ConfigurationDefaults.routingPolicy (i.e., deviceOnly) as the
fallback instead of .automatic so the runtime routing aligns with the SDK
constant, and ensure any related comments/documentation reflect the deviceOnly
fallback.
| // Analytics configuration - Can be configured via ConfigurationData | ||
| public static let analyticsEnabled: Bool = true | ||
| public static let enableLiveMetrics: Bool = true // Enable live metrics for better real-time tracking | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Analytics/live metrics default ON with privacy mode default ON — verify no data egress
With privacyModeEnabled = true, having analyticsEnabled/enableLiveMetrics = true may contradict “privacy‑first” unless telemetry never leaves device. Confirm network egress is disabled under privacy mode or gate these defaults accordingly.
Run this to locate telemetry send paths tied to these flags:
🏁 Script executed:
#!/bin/bash
rg -n -C3 -g '!**/build/**' -P '\b(analyticsEnabled|enableLiveMetrics)\b|telemetry|metrics|analytics' --type swiftLength of output: 174365
Gate analytics egress under privacy mode
AnalyticsQueueManager and TelemetryService ignore privacyModeEnabled, so events (APIEndpoint.telemetry) will still be sent when privacy mode is on. Add a guard on RunAnywhere.configurationData?.privacyModeEnabled (or equivalent) to skip enqueuing or syncing telemetry when privacyModeEnabled == true.
🤖 Prompt for AI Agents
In
sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Constants/SDKConstants.swift
around lines 81-84, analytics currently can still egress when privacy mode is
enabled; update AnalyticsQueueManager and TelemetryService to check
RunAnywhere.configurationData?.privacyModeEnabled and short-circuit when true:
add a guard at the start of any enqueue/event-recording methods to return early
if privacyModeEnabled == true, and add the same guard before any telemetry
sync/network send operations so no telemetry is transmitted while privacy mode
is on; keep existing feature flags intact and ensure the guards are null-safe
(handle nil configuration as current behavior).
| static func setDefaultGenerationSettings(_ settings: DefaultGenerationSettings) async throws { | ||
| guard isSDKInitialized else { | ||
| throw SDKError.notInitialized | ||
| } | ||
|
|
||
| let logger = SDKLogger(category: "RunAnywhere.Configuration") | ||
| logger.info("Setting default generation settings") | ||
|
|
||
| events.publish(SDKConfigurationEvent.settingsRetrieved(settings: settings)) | ||
|
|
||
| // Get current config or create default | ||
| var config = await getCurrentConfiguration() | ||
|
|
||
| // Update generation settings | ||
| config.generation.defaults = settings | ||
| config.source = .consumer | ||
| config.updatedAt = Date() | ||
| config.syncPending = true | ||
|
|
||
| // Store the updated configuration | ||
| RunAnywhere.configurationData = config | ||
|
|
||
| // Persist to configuration service | ||
| try await serviceContainer.configurationService.setConsumerConfiguration(config) | ||
|
|
||
| logger.info("✅ Default generation settings updated successfully") | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Event name is misleading during update
Publishing settingsRetrieved on a setter is confusing. Either introduce settingsUpdated (preferred) or remove this publish.
Apply:
- events.publish(SDKConfigurationEvent.settingsRetrieved(settings: settings))
+ // Consider: events.publish(SDKConfigurationEvent.settingsUpdated(settings: settings))🤖 Prompt for AI Agents
In
sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/RunAnywhere+Configuration.swift
around lines 163–189, the code publishes SDKConfigurationEvent.settingsRetrieved
while performing a setter; change this to publish a new/appropriate
SDKConfigurationEvent.settingsUpdated(settings: settings) (preferred) or remove
the publish entirely. Add the settingsUpdated case to the SDKConfigurationEvent
definition (or reuse an existing update event) so it accepts the settings
payload, update any event construction call sites, and adjust
subscribers/handlers expecting settingsRetrieved to handle settingsUpdated
instead.
Fix #80: Clarify and Standardize SDK Configuration System
Closes #80
Problem
The SDK had a confusing configuration system with multiple overlapping approaches:
Solution
Enhanced the existing three-layer architecture with:
What's New
Configuration Presets (5)
Configuration Methods (5)
Convenience Methods (3)
Changes
Documentation
Testing - Development Mode ✅
Build complete! 1.90s)TODO: Production Testing
Once backend API is implemented, test:
1. Remote Configuration Fetch (GET /v1/configuration)
2. Configuration Sync (POST /v1/configuration)
RunAnywhere.updateConfiguration(preset: .creative)RunAnywhere.syncUserPreferences()/v1/configurationin network logs3. Console → Device Flow
getCurrentGenerationSettings().temperature == 0.54. Offline Mode
5. User Override Flow
updateConfiguration(preset: .privacyFocused)syncUserPreferences()6. End-to-End Scenarios
.preferCloud→ Device uses cloud routing.deviceOnly→ Overrides console settingArchitecture
Three-layer configuration system (now clearly documented):
Layer 1: Build-Time Constants
RunAnywhereConstantsLayer 2: SDK Initialization
RunAnywhere.initialize(...)Layer 3: Runtime Configuration
RunAnywhere.updateConfiguration(...)/setRoutingPolicy(...)/ etc.Migration Guide
No breaking changes - all existing code continues to work.
To use new features:
Backend API Requirements
SDK is ready for production. Backend needs these endpoints:
GET /v1/configuration
ConfigurationDataJSONPOST /v1/configuration
syncUserPreferences()ConfigurationDataJSONRelated
thoughts/shared/plans/issue_80_configuration_system.mdthoughts/shared/plans/issue_80_resolution_summary.mdthoughts/shared/plans/issue_80_pr_checklist.mdSummary by CodeRabbit