Skip to content

Clarify and standardize SDK configuration system #80

@sanchitmonga22

Description

@sanchitmonga22

Overview

The SDK's configuration system is confusing and needs clarification. We have multiple configuration approaches that overlap:

  1. A RunAnywhereConfig.example.json file that's barely used
  2. ConfigurationData struct with complex remote/local/consumer fallback
  3. SDKInitParams passed during initialization
  4. Hardcoded constants in RunAnywhereConstants

Impact: High - Developers don't understand how to configure the SDK
Priority: P1
Effort: Medium

Problem Statement

Current Confusing State

1. JSON Config File Exists But Isn't Really Used

2. Three Different Configuration Sources

// ConfigurationData has 3 sources:
public enum ConfigurationSource {
    case remote    // From backend API
    case consumer  // From developer overrides  
    case defaults  // SDK built-in defaults
}

The fallback chain in ConfigurationService.swift:26-63:

Remote API → Database → Consumer Config → SDK Defaults

3. Initialization Uses Different Approach
RunAnywhereAIApp.swift:87-92:

try RunAnywhere.initialize(
    apiKey: "dev",
    baseURL: "localhost",
    environment: .development
)

⚠️ No JSON config involved! Just direct parameters.

4. ConfigurationData vs SDKInitParams Confusion

  • SDKInitParams - Used during RunAnywhere.initialize()
  • ConfigurationData - Complex struct with routing, generation, storage, API configs
  • They serve different purposes but it's unclear which is which!

Key Questions to Answer

🔴 Critical Questions:

  1. What is the JSON config file for?

    • Should it be used during initialization?
    • Or is it only for build-time constants?
    • Should we remove it if unused?
  2. When do we use ConfigurationData?

    • Is it only for runtime settings fetched from backend?
    • Can developers provide their own ConfigurationData?
    • How does it relate to SDKInitParams?
  3. What's the intended configuration flow?

    Option A: JSON → SDKInitParams → Initialize → Fetch Remote Config
    Option B: SDKInitParams → Initialize → No JSON needed
    Option C: Something else entirely?
    
  4. Consumer Configuration - What is it?

Current Implementation Analysis

What Actually Happens Today:

Development Mode:

// 1. Initialize with params
RunAnywhere.initialize(apiKey: "dev", baseURL: "localhost", environment: .development)

// 2. No remote fetch, uses SDK defaults
ConfigurationData.sdkDefaults(apiKey: "dev")

// 3. JSON file ignored ❌

Production Mode:

// 1. Initialize with params  
RunAnywhere.initialize(apiKey: key, baseURL: url, environment: .production)

// 2. Tries to fetch from remote API
// 3. Falls back to DB → Consumer → Defaults
// 4. JSON file still ignored ❌

Files Involved:

File Purpose Issues
RunAnywhereConfig.example.json Build-time config ❌ Not used during init
ConfigurationData.swift Runtime settings ❓ Unclear when/how to use
SDKInitParams Init parameters ✅ Clear usage
RunAnywhereConstants.swift Static constants ⚠️ Loads JSON but not connected to init

Proposed Solution

Option 1: Simplify - Remove JSON Config (Recommended)

Reasoning: The JSON isn't actually used. SDKInitParams is clearer.

// Developers initialize directly with params - no JSON needed
try RunAnywhere.initialize(
    apiKey: apiKey,
    baseURL: baseURL,
    environment: .production
)

Changes:

  • Remove RunAnywhereConfig.example.json
  • Remove JSON loading from RunAnywhereConstants
  • Document that init params are the only config needed
  • Keep ConfigurationData for backend-fetched settings

Option 2: Make JSON Actually Work

Reasoning: If we keep the JSON, make it useful.

// Load from JSON + environment-specific overrides
try RunAnywhere.initialize(
    configFile: "RunAnywhereConfig",  // Loads JSON
    environment: .production           // Uses production values from JSON
)

// Or allow programmatic override
try RunAnywhere.initialize(
    apiKey: apiKey,  // Overrides JSON
    environment: .production
)

Changes:

  • Update initialize() to load from JSON first
  • Allow programmatic overrides
  • Document the precedence: Code > Env Vars > JSON > Defaults

Option 3: Separate Concerns Clearly

Reasoning: Different configs for different purposes.

// 1. Build-time config (JSON) - for constants, endpoints
RunAnywhereConstants.load("RunAnywhereConfig.json")

// 2. SDK initialization - for API key, environment  
try RunAnywhere.initialize(
    apiKey: apiKey,
    baseURL: RunAnywhereConstants.apiURLs.production
)

// 3. Runtime config (ConfigurationData) - fetched from backend
let config = await RunAnywhere.getConfiguration()

Document clearly:

  • JSON = Build-time constants
  • SDKInitParams = SDK initialization
  • ConfigurationData = Runtime settings from backend

Implementation Plan

Phase 1: Documentation & Clarity

  • Document current behavior in README
  • Add inline comments explaining each config type
  • Create decision matrix: "When to use X vs Y"

Phase 2: Choose Solution

  • Discuss with team which option to pursue
  • Get stakeholder approval on approach

Phase 3: Implementation

  • Implement chosen solution
  • Add example code showing proper usage
  • Update sample app to demonstrate best practices
  • Add migration guide if breaking changes

Phase 4: Validation

  • Add tests for configuration loading
  • Verify all paths work correctly
  • Update documentation

Success Criteria

  • Clear documentation on when to use JSON vs SDKInitParams vs ConfigurationData
  • Example code showing all configuration scenarios
  • No unused/dead configuration code
  • Consistent behavior between dev and production modes
  • Developers can configure the SDK without confusion

Related Files

Configuration System:

Sample App Usage:


🔵 P1 - Critical for developer experience and SDK adoption

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions