diff --git a/sdk/runanywhere-android/API_REFERENCE.md b/sdk/runanywhere-android/API_REFERENCE.md new file mode 100644 index 0000000000..f95f9a78ad --- /dev/null +++ b/sdk/runanywhere-android/API_REFERENCE.md @@ -0,0 +1,607 @@ +# RunAnywhere Android SDK API Reference + +## Table of Contents + +1. [RunAnywhereSDK](#runanywheresdk) +2. [Configuration](#configuration) +3. [Models](#models) +4. [Generation](#generation) +5. [Framework Management](#framework-management) +6. [Error Handling](#error-handling) +7. [Services](#services) + +## RunAnywhereSDK + +The main entry point for the RunAnywhere SDK. + +### Properties + +#### `shared: RunAnywhereSDK` +Shared instance of the SDK (singleton pattern). + +#### `VERSION: String` +Current SDK version. + +### Methods + +#### `initialize(configuration: Configuration)` +Initialize the SDK with the provided configuration. + +**Parameters:** +- `configuration`: The configuration to use + +**Throws:** +- `RunAnywhereError.InvalidConfiguration`: If configuration is invalid +- `RunAnywhereError.AlreadyInitialized`: If SDK is already initialized + +#### `loadModel(modelIdentifier: String): ModelInfo` +Load a model by identifier. + +**Parameters:** +- `modelIdentifier`: The model to load + +**Returns:** +- `ModelInfo`: Information about the loaded model + +**Throws:** +- `SDKError.NotInitialized`: If SDK is not initialized +- `SDKError.ModelNotFound`: If model is not found + +#### `unloadModel()` +Unload the currently loaded model. + +**Throws:** +- `SDKError.NotInitialized`: If SDK is not initialized + +#### `generate(prompt: String, options: GenerationOptions? = null): GenerationResult` +Generate text using the loaded model. + +**Parameters:** +- `prompt`: The prompt to generate from +- `options`: Generation options (optional) + +**Returns:** +- `GenerationResult`: The generation result + +**Throws:** +- `SDKError.NotInitialized`: If SDK is not initialized +- `SDKError.ModelNotFound`: If no model is loaded +- `RunAnywhereError.GenerationFailed`: If generation fails + +#### `generateStream(prompt: String, options: GenerationOptions? = null): Flow` +Generate text as a stream. + +**Parameters:** +- `prompt`: The prompt to generate from +- `options`: Generation options (optional) + +**Returns:** +- `Flow`: A flow of generated text chunks + +**Throws:** +- `SDKError.NotInitialized`: If SDK is not initialized +- `SDKError.ModelNotFound`: If no model is loaded + +#### `listAvailableModels(): List` +List available models. + +**Returns:** +- `List`: Array of available models + +**Throws:** +- `SDKError.NotInitialized`: If SDK is not initialized + +#### `downloadModel(modelIdentifier: String): DownloadTask` +Download a model. + +**Parameters:** +- `modelIdentifier`: The model to download + +**Returns:** +- `DownloadTask`: Download task for tracking progress + +**Throws:** +- `SDKError.NotInitialized`: If SDK is not initialized +- `SDKError.ModelNotFound`: If model is not found + +#### `deleteModel(modelIdentifier: String)` +Delete a downloaded model. + +**Parameters:** +- `modelIdentifier`: The model to delete + +**Throws:** +- `SDKError.NotInitialized`: If SDK is not initialized +- `SDKError.ModelNotFound`: If model is not found + +#### `registerFrameworkAdapter(adapter: FrameworkAdapter)` +Register a framework adapter. + +**Parameters:** +- `adapter`: The framework adapter to register + +#### `getRegisteredAdapters(): Map` +Get the list of registered framework adapters. + +**Returns:** +- `Map`: Dictionary of registered adapters + +#### `getAvailableFrameworks(): List` +Get available frameworks on this device. + +**Returns:** +- `List`: Array of available frameworks + +#### `getFrameworkAvailability(): List` +Get detailed framework availability information. + +**Returns:** +- `List`: Array of framework availability details + +#### `getModelsForFramework(framework: LLMFramework): List` +Get models for a specific framework. + +**Parameters:** +- `framework`: The framework to filter models for + +**Returns:** +- `List`: Array of models compatible with the framework + +#### `addModelFromURL(name: String, url: String, framework: LLMFramework, estimatedSize: Long? = null): ModelInfo` +Add a model from URL for download. + +**Parameters:** +- `name`: Display name for the model +- `url`: Download URL for the model +- `framework`: Target framework for the model +- `estimatedSize`: Estimated memory usage (optional) + +**Returns:** +- `ModelInfo`: The created model info + +## Configuration + +### Configuration + +Main configuration class for the SDK. + +#### Constructor + +```kotlin +Configuration( + apiKey: String, + enableRealTimeDashboard: Boolean = true, + telemetryConsent: TelemetryConsent = TelemetryConsent.GRANTED +) +``` + +#### Properties + +- `apiKey: String` - API key for authentication +- `baseURL: URL` - Base URL for API requests +- `enableRealTimeDashboard: Boolean` - Enable real-time dashboard updates +- `routingPolicy: RoutingPolicy` - Routing policy for model selection +- `telemetryConsent: TelemetryConsent` - Telemetry consent +- `privacyMode: PrivacyMode` - Privacy mode settings +- `debugMode: Boolean` - Debug mode flag +- `preferredFrameworks: List` - Preferred frameworks +- `hardwarePreferences: HardwareConfiguration?` - Hardware preferences +- `modelProviders: List` - Model provider configurations +- `memoryThreshold: Long` - Memory threshold for model loading +- `downloadConfiguration: DownloadConfig` - Download configuration + +### DownloadConfig + +Download configuration settings. + +#### Properties + +- `maxConcurrentDownloads: Int` - Maximum concurrent downloads +- `retryAttempts: Int` - Number of retry attempts +- `cacheDirectory: File?` - Custom cache directory +- `timeoutInterval: Long` - Download timeout in seconds + +### ModelProviderConfig + +Model provider configuration. + +#### Properties + +- `provider: String` - Provider name +- `credentials: ProviderCredentials?` - Authentication credentials +- `enabled: Boolean` - Whether this provider is enabled + +### PrivacyMode + +Privacy mode settings. + +#### Values + +- `STANDARD` - Standard privacy protection +- `STRICT` - Enhanced privacy with stricter PII detection +- `CUSTOM` - Custom privacy rules + +### RoutingPolicy + +Routing policy for model selection. + +#### Values + +- `AUTOMATIC` - Automatic routing based on device capabilities +- `ON_DEVICE_ONLY` - Always prefer on-device execution +- `CLOUD_ONLY` - Always prefer cloud execution +- `HYBRID` - Hybrid routing with fallback + +### TelemetryConsent + +Telemetry consent preference. + +#### Values + +- `GRANTED` - Telemetry is granted +- `DENIED` - Telemetry is denied +- `NOT_DETERMINED` - Telemetry consent not yet determined + +## Models + +### ModelInfo + +Information about a model. + +#### Properties + +- `id: String` - Unique model identifier +- `name: String` - Display name +- `format: ModelFormat` - Model format +- `downloadURL: URL?` - Download URL +- `localPath: File?` - Local file path +- `estimatedMemory: Long` - Estimated memory usage +- `contextLength: Int` - Context window size +- `downloadSize: Long?` - Download size +- `checksum: String?` - File checksum +- `compatibleFrameworks: List` - Compatible frameworks +- `preferredFramework: LLMFramework?` - Preferred framework +- `hardwareRequirements: List` - Hardware requirements +- `tokenizerFormat: TokenizerFormat?` - Tokenizer format +- `metadata: ModelInfoMetadata?` - Model metadata +- `alternativeDownloadURLs: List?` - Alternative download URLs +- `additionalProperties: Map` - Additional properties + +### LLMFramework + +Supported LLM frameworks. + +#### Values + +- `TENSORFLOW_LITE` - TensorFlow Lite +- `ONNX` - ONNX Runtime +- `EXECUTORCH` - ExecuTorch +- `LLAMACPP` - llama.cpp +- `FOUNDATION_MODELS` - Foundation Models +- `PICOLLM` - Pico LLM +- `MLC` - MLC +- `MEDIAPIPE` - MediaPipe +- `NCNN` - NCNN +- `OPENVINO` - OpenVINO +- `TFLITE_GPU` - TensorFlow Lite GPU +- `TFLITE_NNAPI` - TensorFlow Lite NNAPI + +### ModelFormat + +Supported model formats. + +#### Values + +- `TFLITE` - TensorFlow Lite +- `ONNX` - ONNX +- `ORT` - ONNX Runtime +- `SAFETENSORS` - SafeTensors +- `GGUF` - GGUF +- `GGML` - GGML +- `PTE` - ExecuTorch +- `BIN` - Binary +- `WEIGHTS` - Weights +- `CHECKPOINT` - Checkpoint +- `UNKNOWN` - Unknown format + +### ExecutionTarget + +Execution target for model inference. + +#### Values + +- `ON_DEVICE` - Execute on device +- `CLOUD` - Execute in the cloud +- `HYBRID` - Hybrid execution + +### HardwareAcceleration + +Hardware acceleration options. + +#### Values + +- `CPU` - CPU execution +- `GPU` - GPU acceleration +- `NPU` - NPU acceleration +- `NNAPI` - NNAPI acceleration +- `OPENCL` - OpenCL acceleration +- `VULKAN` - Vulkan acceleration +- `AUTO` - Automatic selection + +### HardwareConfiguration + +Hardware configuration for framework adapters. + +#### Properties + +- `primaryAccelerator: HardwareAcceleration` - Primary accelerator +- `fallbackAccelerator: HardwareAcceleration?` - Fallback accelerator +- `memoryMode: MemoryMode` - Memory mode +- `threadCount: Int` - Number of threads +- `useQuantization: Boolean` - Use quantization +- `quantizationBits: Int` - Quantization bits + +#### MemoryMode + +- `CONSERVATIVE` - Conservative memory usage +- `BALANCED` - Balanced memory usage +- `AGGRESSIVE` - Aggressive memory usage + +## Generation + +### GenerationOptions + +Options for text generation. + +#### Properties + +- `maxTokens: Int` - Maximum number of tokens to generate +- `temperature: Float` - Temperature for sampling (0.0 - 1.0) +- `topP: Float` - Top-p sampling parameter +- `context: Context?` - Context for the generation +- `enableRealTimeTracking: Boolean` - Enable real-time tracking +- `stopSequences: List` - Stop sequences +- `seed: Int?` - Seed for reproducible generation +- `streamingEnabled: Boolean` - Enable streaming mode +- `tokenBudget: TokenBudget?` - Token budget constraint +- `frameworkOptions: FrameworkOptions?` - Framework-specific options +- `preferredExecutionTarget: ExecutionTarget?` - Preferred execution target + +### Context + +Context for maintaining conversation state. + +#### Properties + +- `messages: List` - Previous messages +- `systemPrompt: String?` - System prompt override +- `maxTokens: Int` - Maximum context window size + +### Message + +Message in a conversation. + +#### Properties + +- `role: Role` - Role of the message sender +- `content: String` - Content of the message +- `timestamp: Long` - Timestamp + +#### Role + +- `USER` - User message +- `ASSISTANT` - Assistant message +- `SYSTEM` - System message + +### GenerationResult + +Result of a text generation request. + +#### Properties + +- `text: String` - Generated text +- `tokensUsed: Int` - Number of tokens used +- `modelUsed: String` - Model used for generation +- `latencyMs: Long` - Latency in milliseconds +- `executionTarget: ExecutionTarget` - Execution target +- `savedAmount: Double` - Amount saved by using on-device execution +- `framework: LLMFramework?` - Framework used for generation +- `hardwareUsed: HardwareAcceleration` - Hardware acceleration used +- `memoryUsed: Long` - Memory used during generation +- `tokenizerFormat: TokenizerFormat?` - Tokenizer format used +- `performanceMetrics: PerformanceMetrics` - Detailed performance metrics +- `metadata: ResultMetadata?` - Additional metadata + +### DownloadTask + +Download task for model downloads. + +#### Properties + +- `id: String` - Download task ID +- `modelId: String` - Model ID +- `status: DownloadStatus` - Download status +- `progress: Flow` - Download progress flow +- `cancel: () -> Unit` - Cancel function + +### DownloadStatus + +Download status. + +#### Values + +- `PENDING` - Download pending +- `DOWNLOADING` - Download in progress +- `COMPLETED` - Download completed +- `FAILED` - Download failed +- `CANCELLED` - Download cancelled + +### DownloadProgress + +Download progress information. + +#### Properties + +- `bytesDownloaded: Long` - Bytes downloaded +- `totalBytes: Long` - Total bytes +- `percentage: Float` - Download percentage +- `speed: Long` - Download speed (bytes per second) +- `estimatedTimeRemaining: Long?` - Estimated time remaining (milliseconds) + +## Framework Management + +### FrameworkAdapter + +Framework adapter interface. + +#### Methods + +- `isAvailable(): Boolean` - Check if framework is available +- `loadModel(modelInfo: ModelInfo): LoadedModel` - Load a model +- `unloadModel(modelId: String)` - Unload a model +- `generate(prompt: String, options: GenerationOptions): GenerationResult` - Generate text +- `generateStream(prompt: String, options: GenerationOptions): Flow` - Generate text stream +- `getSupportedFormats(): List` - Get supported formats +- `getHardwareRequirements(): List` - Get hardware requirements +- `getPerformanceCharacteristics(): PerformanceCharacteristics` - Get performance characteristics + +### FrameworkAvailability + +Detailed information about framework availability. + +#### Properties + +- `framework: LLMFramework` - The framework +- `isAvailable: Boolean` - Whether framework is available +- `unavailabilityReason: String?` - Reason for unavailability +- `requirements: List` - Hardware requirements +- `recommendedFor: List` - Recommended use cases +- `supportedFormats: List` - Supported formats + +### PerformanceCharacteristics + +Performance characteristics for a framework. + +#### Properties + +- `maxTokensPerSecond: Double` - Maximum tokens per second +- `memoryEfficiency: Double` - Memory efficiency (0.0 to 1.0) +- `batteryEfficiency: Double` - Battery efficiency (0.0 to 1.0) +- `latency: Long` - Latency in milliseconds + +## Error Handling + +### RunAnywhereError + +Main public error type for the RunAnywhere SDK. + +#### Error Types + +**Initialization Errors:** +- `NotInitialized` - SDK is not initialized +- `AlreadyInitialized` - SDK is already initialized +- `InvalidConfiguration(detail: String)` - Invalid configuration +- `InvalidAPIKey` - Invalid or missing API key + +**Model Errors:** +- `ModelNotFound(identifier: String)` - Model not found +- `ModelLoadFailed(identifier: String, error: Throwable?)` - Model load failed +- `ModelValidationFailed(identifier: String, errors: List)` - Model validation failed +- `ModelIncompatible(identifier: String, reason: String)` - Model incompatible + +**Generation Errors:** +- `GenerationFailed(reason: String)` - Generation failed +- `GenerationTimeout` - Generation timed out +- `ContextTooLong(provided: Int, maximum: Int)` - Context too long +- `TokenLimitExceeded(requested: Int, maximum: Int)` - Token limit exceeded +- `CostLimitExceeded(estimated: Double, limit: Double)` - Cost limit exceeded + +**Network Errors:** +- `NetworkUnavailable` - Network connection unavailable +- `RequestFailed(error: Throwable)` - Request failed +- `DownloadFailed(url: String, error: Throwable?)` - Download failed + +**Storage Errors:** +- `InsufficientStorage(required: Long, available: Long)` - Insufficient storage +- `StorageFull` - Device storage is full + +**Hardware Errors:** +- `HardwareUnsupported(feature: String)` - Hardware does not support feature +- `MemoryPressure` - System is under memory pressure +- `ThermalStateExceeded` - Device temperature too high + +**Feature Errors:** +- `FeatureNotAvailable(feature: String)` - Feature not available +- `NotImplemented(feature: String)` - Feature not yet implemented + +### SDKError + +SDK-specific errors. + +#### Error Types + +- `NotInitialized` - SDK not initialized +- `NotImplemented` - Feature not implemented +- `ModelNotFound(model: String)` - Model not found +- `LoadingFailed(reason: String)` - Loading failed +- `GenerationFailed(reason: String)` - Generation failed +- `FrameworkNotAvailable(framework: String)` - Framework not available +- `DownloadFailed(error: Throwable)` - Download failed +- `ValidationFailed(error: ValidationError)` - Validation failed +- `RoutingFailed(reason: String)` - Routing failed + +### ValidationError + +Validation error. + +#### Properties + +- `field: String` - Field name +- `message: String` - Error message +- `code: String?` - Error code + +## Services + +### ServiceContainer + +Service container for dependency injection. + +#### Properties + +- `configurationValidator: ConfigurationValidator` - Configuration validator +- `modelRegistry: ModelRegistry` - Model registry +- `modelLoadingService: ModelLoadingService` - Model loading service +- `generationService: GenerationService` - Generation service +- `streamingService: StreamingService` - Streaming service +- `downloadService: DownloadService` - Download service +- `fileManager: SimplifiedFileManager` - File manager +- `adapterRegistry: AdapterRegistry` - Adapter registry +- `performanceMonitor: PerformanceMonitor` - Performance monitor +- `benchmarkRunner: BenchmarkRunner` - Benchmark runner +- `abTestRunner: ABTestRunner` - A/B test runner + +#### Methods + +- `bootstrap(configuration: Configuration)` - Bootstrap all services + +### ModelMetadataStore + +Model metadata store for persistence. + +#### Methods + +- `updateLastUsed(modelId: String)` - Update last used timestamp +- `loadStoredModels(): List` - Load stored models + +### ModelCriteria + +Criteria for filtering models. + +#### Properties + +- `framework: LLMFramework?` - Framework filter +- `format: ModelFormat?` - Format filter +- `maxMemory: Long?` - Maximum memory filter +- `minContextLength: Int?` - Minimum context length filter +- `tags: List` - Tags filter +- `downloaded: Boolean?` - Downloaded filter \ No newline at end of file diff --git a/sdk/runanywhere-android/ARCHITECTURE.md b/sdk/runanywhere-android/ARCHITECTURE.md new file mode 100644 index 0000000000..20bfa54234 --- /dev/null +++ b/sdk/runanywhere-android/ARCHITECTURE.md @@ -0,0 +1,417 @@ +# RunAnywhere Android SDK Architecture + +## Overview + +The RunAnywhere Android SDK is designed with a modular, service-oriented architecture that provides a comprehensive solution for running Large Language Models (LLMs) on Android devices. The architecture emphasizes flexibility, extensibility, and performance while maintaining a clean separation of concerns. + +## Architecture Principles + +### 1. Modularity +- **Service-Oriented Design**: Each major functionality is encapsulated in a dedicated service +- **Loose Coupling**: Services communicate through well-defined interfaces +- **High Cohesion**: Related functionality is grouped together + +### 2. Extensibility +- **Framework Adapter Pattern**: Easy integration of new ML frameworks +- **Plugin Architecture**: Support for custom implementations +- **Configuration-Driven**: Behavior controlled through configuration + +### 3. Performance +- **Async/Await**: Non-blocking operations using Kotlin coroutines +- **Memory Management**: Intelligent memory allocation and cleanup +- **Hardware Acceleration**: Support for GPU, NPU, and specialized hardware + +### 4. Reliability +- **Error Handling**: Comprehensive error types and recovery strategies +- **Validation**: Input validation at multiple levels +- **Fallback Mechanisms**: Graceful degradation when features are unavailable + +## Core Architecture Components + +### 1. Main SDK Entry Point + +``` +RunAnywhereSDK +├── shared (Singleton) +├── initialize() +├── loadModel() +├── generate() +├── generateStream() +└── Service Access Points +``` + +The main SDK class follows the singleton pattern and provides a unified interface to all functionality. + +### 2. Service Container + +``` +ServiceContainer +├── Core Services +│ ├── ConfigurationValidator +│ ├── ModelRegistry +│ ├── ModelLoadingService +│ ├── GenerationService +│ ├── StreamingService +│ ├── DownloadService +│ ├── FileManager +│ └── AdapterRegistry +├── Monitoring Services +│ ├── PerformanceMonitor +│ ├── BenchmarkRunner +│ └── ABTestRunner +└── bootstrap() +``` + +The service container manages all services and provides dependency injection capabilities. + +### 3. Configuration System + +``` +Configuration +├── Basic Settings +│ ├── apiKey +│ ├── baseURL +│ └── debugMode +├── Runtime Settings +│ ├── routingPolicy +│ ├── privacyMode +│ └── telemetryConsent +├── Framework Settings +│ ├── preferredFrameworks +│ └── hardwarePreferences +├── Model Settings +│ ├── modelProviders +│ └── memoryThreshold +└── Download Settings + └── downloadConfiguration +``` + +The configuration system provides centralized control over SDK behavior. + +## Service Architecture + +### 1. Model Registry Service + +**Purpose**: Manages model discovery, registration, and metadata. + +**Responsibilities**: +- Discover local models +- Register new models +- Filter models by criteria +- Maintain model metadata + +**Key Components**: +``` +ModelRegistry +├── models: Map +├── discoverModels() +├── getModel() +├── filterModels() +└── addModelFromURL() +``` + +### 2. Model Loading Service + +**Purpose**: Handles model loading, unloading, and lifecycle management. + +**Responsibilities**: +- Load models into memory +- Unload models to free resources +- Manage model lifecycle +- Handle model validation + +**Key Components**: +``` +ModelLoadingService +├── loadedModels: Map +├── loadModel() +├── unloadModel() +└── validateModel() +``` + +### 3. Generation Service + +**Purpose**: Orchestrates text generation across different frameworks. + +**Responsibilities**: +- Route generation requests +- Manage generation context +- Handle streaming generation +- Track performance metrics + +**Key Components**: +``` +GenerationService +├── currentModel: LoadedModel? +├── generate() +├── generateStream() +└── setCurrentModel() +``` + +### 4. Framework Adapter System + +**Purpose**: Provides a unified interface for different ML frameworks. + +**Design Pattern**: Adapter Pattern + +**Key Interface**: +```kotlin +interface FrameworkAdapter { + val framework: LLMFramework + suspend fun isAvailable(): Boolean + suspend fun loadModel(modelInfo: ModelInfo): LoadedModel + suspend fun generate(prompt: String, options: GenerationOptions): GenerationResult + fun generateStream(prompt: String, options: GenerationOptions): Flow + fun getSupportedFormats(): List + fun getHardwareRequirements(): List + fun getPerformanceCharacteristics(): PerformanceCharacteristics +} +``` + +**Supported Frameworks**: +- TensorFlow Lite +- ONNX Runtime +- ExecuTorch +- llama.cpp +- Foundation Models +- Pico LLM +- MLC +- MediaPipe +- NCNN +- OpenVINO + +### 5. Download Service + +**Purpose**: Manages model downloads with progress tracking. + +**Responsibilities**: +- Download models from URLs +- Track download progress +- Handle download failures +- Manage download queue + +**Key Components**: +``` +DownloadService +├── activeDownloads: Map +├── downloadModel() +├── cancelDownload() +└── getDownloadProgress() +``` + +### 6. Performance Monitoring + +**Purpose**: Tracks and reports performance metrics. + +**Responsibilities**: +- Monitor generation performance +- Track resource usage +- Report metrics to analytics +- Provide performance insights + +**Key Components**: +``` +PerformanceMonitor +├── metrics: PerformanceMetrics +├── startMonitoring() +├── recordMetric() +└── getPerformanceReport() +``` + +## Data Flow Architecture + +### 1. Initialization Flow + +``` +App Startup + ↓ +Configuration Creation + ↓ +ServiceContainer.bootstrap() + ↓ +Service Initialization + ↓ +Framework Discovery + ↓ +SDK Ready +``` + +### 2. Model Loading Flow + +``` +loadModel() Request + ↓ +Model Registry Lookup + ↓ +Framework Selection + ↓ +Model Loading Service + ↓ +Framework Adapter + ↓ +Model Loaded +``` + +### 3. Generation Flow + +``` +generate() Request + ↓ +Model Validation + ↓ +Generation Service + ↓ +Framework Adapter + ↓ +Text Generation + ↓ +Performance Tracking + ↓ +Result Return +``` + +### 4. Streaming Flow + +``` +generateStream() Request + ↓ +Model Validation + ↓ +Streaming Service + ↓ +Framework Adapter + ↓ +Stream Generation + ↓ +Chunk Emission + ↓ +Flow Collection +``` + +## Error Handling Architecture + +### 1. Error Hierarchy + +``` +Exception +├── RunAnywhereError (Public API) +│ ├── Initialization Errors +│ ├── Model Errors +│ ├── Generation Errors +│ ├── Network Errors +│ ├── Storage Errors +│ ├── Hardware Errors +│ └── Feature Errors +└── SDKError (Internal) + ├── NotInitialized + ├── ModelNotFound + ├── GenerationFailed + └── FrameworkNotAvailable +``` + +### 2. Error Recovery Strategies + +- **Retry Logic**: Automatic retry for transient failures +- **Fallback Mechanisms**: Graceful degradation to alternative solutions +- **Resource Cleanup**: Proper cleanup on errors +- **User Feedback**: Clear error messages and recovery suggestions + +## Memory Management + +### 1. Memory Allocation Strategy + +- **Lazy Loading**: Models loaded only when needed +- **Memory Pools**: Efficient memory allocation for large models +- **Garbage Collection**: Proper cleanup of unused resources +- **Memory Monitoring**: Real-time memory usage tracking + +### 2. Resource Management + +- **Model Lifecycle**: Proper loading/unloading of models +- **Thread Management**: Efficient thread pool usage +- **File Management**: Proper file handle management +- **Cache Management**: Intelligent caching strategies + +## Security Architecture + +### 1. Data Protection + +- **On-Device Execution**: Models run locally for privacy +- **Data Encryption**: Secure handling of sensitive data +- **API Key Management**: Secure storage and usage of API keys +- **Privacy Modes**: Configurable privacy protection levels + +### 2. Access Control + +- **Authentication**: API key-based authentication +- **Authorization**: Role-based access control +- **Audit Logging**: Comprehensive logging of operations +- **Secure Communication**: HTTPS for all network requests + +## Performance Optimization + +### 1. Hardware Acceleration + +- **GPU Acceleration**: Support for GPU-based inference +- **NPU Support**: Neural Processing Unit acceleration +- **NNAPI Integration**: Android Neural Networks API +- **Multi-threading**: Efficient use of multiple CPU cores + +### 2. Optimization Techniques + +- **Model Quantization**: Support for quantized models +- **Batch Processing**: Efficient batch inference +- **Caching**: Intelligent result caching +- **Load Balancing**: Dynamic load distribution + +## Testing Architecture + +### 1. Unit Testing + +- **Service Testing**: Individual service testing +- **Mock Objects**: Comprehensive mocking framework +- **Test Coverage**: High test coverage requirements +- **Performance Testing**: Performance regression testing + +### 2. Integration Testing + +- **End-to-End Testing**: Complete workflow testing +- **Framework Testing**: Framework adapter testing +- **Error Scenario Testing**: Error handling validation +- **Performance Benchmarking**: Performance validation + +## Deployment Architecture + +### 1. Library Distribution + +- **AAR Package**: Android Archive format +- **Maven Repository**: Centralized distribution +- **Version Management**: Semantic versioning +- **Dependency Management**: Proper dependency resolution + +### 2. Integration + +- **Gradle Integration**: Easy Gradle integration +- **ProGuard Support**: Code obfuscation support +- **Multi-Module Support**: Support for complex projects +- **Backward Compatibility**: API compatibility guarantees + +## Future Architecture Considerations + +### 1. Scalability + +- **Microservices**: Potential migration to microservices +- **Cloud Integration**: Enhanced cloud service integration +- **Distributed Computing**: Support for distributed inference +- **Edge Computing**: Edge device optimization + +### 2. Extensibility + +- **Plugin System**: Enhanced plugin architecture +- **Custom Frameworks**: Support for custom ML frameworks +- **Third-Party Integrations**: Enhanced third-party support +- **API Evolution**: Backward-compatible API evolution + +## Conclusion + +The RunAnywhere Android SDK architecture provides a robust, scalable, and extensible foundation for running LLMs on Android devices. The modular design ensures maintainability while the service-oriented approach enables easy integration and customization. The architecture prioritizes performance, security, and user experience while maintaining flexibility for future enhancements. \ No newline at end of file diff --git a/sdk/runanywhere-android/README.md b/sdk/runanywhere-android/README.md new file mode 100644 index 0000000000..2fc2bad209 --- /dev/null +++ b/sdk/runanywhere-android/README.md @@ -0,0 +1,337 @@ +# RunAnywhere Android SDK + +The RunAnywhere Android SDK provides a comprehensive solution for running Large Language Models (LLMs) on Android devices. It supports multiple frameworks, offers intelligent routing between on-device and cloud execution, and provides cost optimization features. + +## Features + +### Core Functionality +- **Multi-Framework Support**: TensorFlow Lite, ONNX Runtime, ExecuTorch, llama.cpp, and more +- **Intelligent Routing**: Automatic selection between on-device and cloud execution +- **Cost Optimization**: Real-time cost tracking and savings calculation +- **Model Management**: Download, load, and manage models locally +- **Streaming Generation**: Real-time text generation with streaming support + +### Advanced Features +- **Performance Monitoring**: Real-time performance metrics and monitoring +- **A/B Testing**: Framework and model comparison capabilities +- **Benchmarking**: Comprehensive benchmarking suite +- **Hardware Acceleration**: Support for GPU, NPU, and NNAPI acceleration +- **Memory Management**: Intelligent memory allocation and optimization + +## Installation + +Add the following to your `build.gradle` file: + +```gradle +dependencies { + implementation 'com.runanywhere:sdk:1.0.0' +} +``` + +## Quick Start + +### 1. Initialize the SDK + +```kotlin +import com.runanywhere.sdk.RunAnywhereSDK +import com.runanywhere.sdk.configuration.Configuration + +// Initialize with your API key +val configuration = Configuration( + apiKey = "your-api-key-here", + enableRealTimeDashboard = true +) + +// Initialize the SDK +RunAnywhereSDK.shared.initialize(configuration) +``` + +### 2. Load a Model + +```kotlin +// Load a model by identifier +val modelInfo = RunAnywhereSDK.shared.loadModel("gpt-2-small") +``` + +### 3. Generate Text + +```kotlin +// Generate text with default options +val result = RunAnywhereSDK.shared.generate("Hello, how are you?") + +// Or with custom options +val options = GenerationOptions( + maxTokens = 100, + temperature = 0.7f, + topP = 1.0f +) +val result = RunAnywhereSDK.shared.generate("Hello, how are you?", options) +``` + +### 4. Streaming Generation + +```kotlin +// Generate text as a stream +val stream = RunAnywhereSDK.shared.generateStream("Tell me a story") +stream.collect { chunk -> + println(chunk) // Print each chunk as it's generated +} +``` + +## Configuration + +### Basic Configuration + +```kotlin +val configuration = Configuration( + apiKey = "your-api-key", + enableRealTimeDashboard = true, + telemetryConsent = TelemetryConsent.GRANTED +) +``` + +### Advanced Configuration + +```kotlin +val configuration = Configuration( + apiKey = "your-api-key", + enableRealTimeDashboard = true, + routingPolicy = RoutingPolicy.AUTOMATIC, + privacyMode = PrivacyMode.STANDARD, + debugMode = false, + preferredFrameworks = listOf(LLMFramework.TENSORFLOW_LITE, LLMFramework.ONNX), + hardwarePreferences = HardwareConfiguration( + primaryAccelerator = HardwareAcceleration.GPU, + fallbackAccelerator = HardwareAcceleration.CPU, + memoryMode = HardwareConfiguration.MemoryMode.BALANCED, + threadCount = 4 + ), + memoryThreshold = 500_000_000, // 500MB + downloadConfiguration = DownloadConfig( + maxConcurrentDownloads = 2, + retryAttempts = 3, + timeoutInterval = 300 + ) +) +``` + +## Model Management + +### List Available Models + +```kotlin +val models = RunAnywhereSDK.shared.listAvailableModels() +models.forEach { model -> + println("Model: ${model.name}, Format: ${model.format}") +} +``` + +### Download a Model + +```kotlin +val downloadTask = RunAnywhereSDK.shared.downloadModel("gpt-2-small") +downloadTask.progress.collect { progress -> + println("Download progress: ${progress.percentage}%") +} +``` + +### Add Custom Model + +```kotlin +val modelInfo = RunAnywhereSDK.shared.addModelFromURL( + name = "My Custom Model", + url = "https://example.com/model.tflite", + framework = LLMFramework.TENSORFLOW_LITE, + estimatedSize = 100_000_000 // 100MB +) +``` + +### Delete a Model + +```kotlin +RunAnywhereSDK.shared.deleteModel("gpt-2-small") +``` + +## Framework Management + +### Register Framework Adapters + +```kotlin +// Register a custom framework adapter +val adapter = MyCustomFrameworkAdapter() +RunAnywhereSDK.shared.registerFrameworkAdapter(adapter) +``` + +### Check Framework Availability + +```kotlin +val frameworks = RunAnywhereSDK.shared.getAvailableFrameworks() +val availability = RunAnywhereSDK.shared.getFrameworkAvailability() + +availability.forEach { info -> + println("${info.framework.displayName}: ${if (info.isAvailable) "Available" else "Not Available"}") +} +``` + +### Get Models for Specific Framework + +```kotlin +val tensorFlowModels = RunAnywhereSDK.shared.getModelsForFramework(LLMFramework.TENSORFLOW_LITE) +``` + +## Advanced Features + +### Performance Monitoring + +```kotlin +val monitor = RunAnywhereSDK.shared.performanceMonitor +// Access performance metrics and monitoring capabilities +``` + +### Benchmarking + +```kotlin +val benchmark = RunAnywhereSDK.shared.benchmarkSuite +// Run benchmarks and compare performance +``` + +### A/B Testing + +```kotlin +val abTesting = RunAnywhereSDK.shared.abTesting +// Run A/B tests between different frameworks or models +``` + +### File Management + +```kotlin +val fileManager = RunAnywhereSDK.shared.fileManager +// Access file management capabilities +``` + +## Error Handling + +The SDK provides comprehensive error handling with specific error types: + +```kotlin +try { + val result = RunAnywhereSDK.shared.generate("Hello") +} catch (e: RunAnywhereError) { + when (e) { + is RunAnywhereError.NotInitialized -> { + // Handle not initialized error + } + is RunAnywhereError.ModelNotFound -> { + // Handle model not found error + } + is RunAnywhereError.GenerationFailed -> { + // Handle generation failed error + } + // ... handle other error types + } +} +``` + +## Supported Frameworks + +- **TensorFlow Lite**: Optimized for mobile and embedded devices +- **ONNX Runtime**: Cross-platform inference engine +- **ExecuTorch**: PyTorch-based mobile inference +- **llama.cpp**: Efficient C++ implementation for LLaMA models +- **Foundation Models**: Apple's framework for on-device ML +- **Pico LLM**: Lightweight LLM framework +- **MLC**: Machine Learning Compilation framework +- **MediaPipe**: Google's ML framework +- **NCNN**: Tencent's neural network inference framework +- **OpenVINO**: Intel's deep learning toolkit + +## Model Formats + +- **TensorFlow Lite (.tflite)** +- **ONNX (.onnx)** +- **SafeTensors (.safetensors)** +- **GGUF (.gguf)** +- **GGML (.ggml)** +- **ExecuTorch (.pte)** +- **Binary (.bin)** +- **Weights (.weights)** +- **Checkpoint (.checkpoint)** + +## Hardware Acceleration + +The SDK supports various hardware acceleration options: + +- **CPU**: Standard CPU execution +- **GPU**: GPU acceleration when available +- **NPU**: Neural Processing Unit acceleration +- **NNAPI**: Android Neural Networks API +- **OpenCL**: OpenCL-based acceleration +- **Vulkan**: Vulkan-based acceleration + +## Privacy and Security + +- **On-Device Execution**: Models run locally for enhanced privacy +- **Data Encryption**: Secure handling of sensitive data +- **Privacy Modes**: Configurable privacy protection levels +- **Telemetry Control**: User-controlled telemetry and analytics + +## Performance Optimization + +- **Memory Management**: Intelligent memory allocation +- **Model Quantization**: Support for quantized models +- **Thread Management**: Optimized thread usage +- **Caching**: Intelligent caching strategies +- **Load Balancing**: Dynamic load distribution + +## Troubleshooting + +### Common Issues + +1. **SDK Not Initialized** + - Ensure you call `initialize()` before using any SDK methods + +2. **Model Not Found** + - Check if the model is downloaded or available + - Verify the model identifier + +3. **Insufficient Memory** + - Check available device memory + - Consider using a smaller model or enabling quantization + +4. **Framework Not Available** + - Ensure the required framework is installed + - Check device compatibility + +### Debug Mode + +Enable debug mode for detailed logging: + +```kotlin +val configuration = Configuration( + apiKey = "your-api-key", + debugMode = true +) +``` + +## API Reference + +For detailed API documentation, see the [API Reference](API_REFERENCE.md). + +## Architecture + +For information about the SDK architecture, see the [Architecture Guide](ARCHITECTURE.md). + +## Contributing + +We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details. + +## License + +This SDK is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. + +## Support + +For support and questions: +- Email: support@runanywhere.ai +- Documentation: https://docs.runanywhere.ai +- GitHub Issues: https://github.com/runanywhere/sdk-android/issues \ No newline at end of file diff --git a/sdk/runanywhere-android/build.gradle.kts b/sdk/runanywhere-android/build.gradle.kts index 08a93e28e4..db6e1069f2 100644 --- a/sdk/runanywhere-android/build.gradle.kts +++ b/sdk/runanywhere-android/build.gradle.kts @@ -1,7 +1,6 @@ plugins { alias(libs.plugins.android.library) alias(libs.plugins.kotlin.android) - alias(libs.plugins.detekt) } android { @@ -41,19 +40,37 @@ android { } dependencies { - + // Core Android dependencies implementation(libs.androidx.core.ktx) implementation(libs.androidx.appcompat) implementation(libs.material) + + // Coroutines for async operations + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") + + // Network dependencies + implementation("com.squareup.okhttp3:okhttp:4.12.0") + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-gson:2.9.0") + + // JSON serialization + implementation("com.google.code.gson:gson:2.10.1") + + // File operations + implementation("androidx.documentfile:documentfile:1.0.1") + + // Lifecycle components + implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0") + + // Work manager for background tasks + implementation("androidx.work:work-runtime-ktx:2.9.0") + + // Testing dependencies testImplementation(libs.junit) + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3") + testImplementation("io.mockk:mockk:1.13.8") androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) } - -// Detekt configuration -detekt { - config.setFrom("$projectDir/detekt.yml") - buildUponDefaultConfig = true - allRules = false - baseline = file("$projectDir/detekt-baseline.xml") -} diff --git a/sdk/runanywhere-android/gradle.properties b/sdk/runanywhere-android/gradle.properties new file mode 100644 index 0000000000..3c5735fc87 --- /dev/null +++ b/sdk/runanywhere-android/gradle.properties @@ -0,0 +1,26 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true + +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true + +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official \ No newline at end of file diff --git a/sdk/runanywhere-android/lint-baseline.xml b/sdk/runanywhere-android/lint-baseline.xml new file mode 100644 index 0000000000..9040e20dc7 --- /dev/null +++ b/sdk/runanywhere-android/lint-baseline.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/RunAnywhereSDK.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/RunAnywhereSDK.kt index 63bf48f0d4..465229a28d 100644 --- a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/RunAnywhereSDK.kt +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/RunAnywhereSDK.kt @@ -1,18 +1,288 @@ package com.runanywhere.sdk -class RunAnywhereSDK { +import com.runanywhere.sdk.configuration.Configuration +import com.runanywhere.sdk.errors.SDKError +import com.runanywhere.sdk.models.* +import com.runanywhere.sdk.services.* +import kotlinx.coroutines.flow.Flow - fun initialize(apiKey: String) { - // SDK initialization logic - println("RunAnywhereSDK initialized with API key: ${apiKey.take(5)}...") +/** + * The main entry point for the RunAnywhere SDK + * Provides functionality for loading models, generating text, and managing the SDK lifecycle + */ +class RunAnywhereSDK private constructor() { + + companion object { + @Volatile + private var INSTANCE: RunAnywhereSDK? = null + + /** + * Shared instance of the SDK + */ + val shared: RunAnywhereSDK + get() = INSTANCE ?: synchronized(this) { + INSTANCE ?: RunAnywhereSDK().also { INSTANCE = it } + } + + const val VERSION = "1.0.0" } - - fun execute(prompt: String): String { - // Placeholder implementation - return "Response for: $prompt" + + private var configuration: Configuration? = null + private val serviceContainer = ServiceContainer() + private var currentModel: ModelInfo? = null + private var currentService: LLMService? = null + + init { + setupServices() } - - companion object { - const val VERSION = "0.1.0" + + /** + * Initialize the SDK with the provided configuration + * @param configuration The configuration to use + */ + suspend fun initialize(configuration: Configuration) { + this.configuration = configuration + + // Validate configuration + serviceContainer.configurationValidator.validate(configuration) + + // Bootstrap all services with configuration + serviceContainer.bootstrap(configuration) + + // Start monitoring services if enabled + if (configuration.enableRealTimeDashboard) { + serviceContainer.performanceMonitor.startMonitoring() + } + } + + /** + * Load a model by identifier + * @param modelIdentifier The model to load + * @return Information about the loaded model + */ + suspend fun loadModel(modelIdentifier: String): ModelInfo { + configuration ?: throw SDKError.NotInitialized + + // Load model through the loading service + val loadedModel = serviceContainer.modelLoadingService.loadModel(modelIdentifier) + + currentModel = loadedModel.model + currentService = loadedModel.service + + // Set the loaded model in the generation service + serviceContainer.generationService.setCurrentModel(loadedModel) + + // Update last used date in metadata + val metadataStore = ModelMetadataStore() + metadataStore.updateLastUsed(modelIdentifier) + + return loadedModel.model + } + + /** + * Unload the currently loaded model + */ + suspend fun unloadModel() { + val model = currentModel ?: return + + serviceContainer.modelLoadingService.unloadModel(model.id) + + currentModel = null + currentService = null + + // Clear the model from generation service + serviceContainer.generationService.setCurrentModel(null) + } + + /** + * Generate text using the loaded model + * @param prompt The prompt to generate from + * @param options Generation options + * @return The generation result + */ + suspend fun generate( + prompt: String, + options: GenerationOptions? = null + ): GenerationResult { + configuration ?: throw SDKError.NotInitialized + + currentModel ?: throw SDKError.ModelNotFound("No model loaded") + + return serviceContainer.generationService.generate( + prompt = prompt, + options = options ?: GenerationOptions() + ) + } + + /** + * Generate text as a stream + * @param prompt The prompt to generate from + * @param options Generation options + * @return A flow of generated text chunks + */ + fun generateStream( + prompt: String, + options: GenerationOptions? = null + ): Flow { + configuration ?: throw SDKError.NotInitialized + + currentModel ?: throw SDKError.ModelNotFound("No model loaded") + + return serviceContainer.streamingService.generateStream( + prompt = prompt, + options = options ?: GenerationOptions() + ) + } + + /** + * List available models + * @return Array of available models + */ + suspend fun listAvailableModels(): List { + configuration ?: throw SDKError.NotInitialized + + // Always discover local models to ensure we have the latest + val discoveredModels = serviceContainer.modelRegistry.discoverModels() + + // Also check metadata store for any persisted models + val metadataStore = ModelMetadataStore() + val storedModels = metadataStore.loadStoredModels() + + // Merge and deduplicate + val allModels = discoveredModels.toMutableList() + for (storedModel in storedModels) { + if (!allModels.any { it.id == storedModel.id }) { + allModels.add(storedModel) + } + } + + return allModels + } + + /** + * Download a model + * @param modelIdentifier The model to download + * @return Download task + */ + suspend fun downloadModel(modelIdentifier: String): DownloadTask { + configuration ?: throw SDKError.NotInitialized + + val model = serviceContainer.modelRegistry.getModel(modelIdentifier) + ?: throw SDKError.ModelNotFound(modelIdentifier) + + return serviceContainer.downloadService.downloadModel(model) + } + + /** + * Delete a downloaded model + * @param modelIdentifier The model to delete + */ + suspend fun deleteModel(modelIdentifier: String) { + configuration ?: throw SDKError.NotInitialized + + // Get model info to find the local path + val modelInfo = serviceContainer.modelRegistry.getModel(modelIdentifier) + ?: throw SDKError.ModelNotFound(modelIdentifier) + + val localPath = modelInfo.localPath + ?: throw SDKError.ModelNotFound("Model '$modelIdentifier' not downloaded") + + // Extract model ID from the path + val modelId = localPath.parentFile?.name ?: modelIdentifier + serviceContainer.fileManager.deleteModel(modelId) + } + + /** + * Register a framework adapter + * @param adapter The framework adapter to register + */ + fun registerFrameworkAdapter(adapter: FrameworkAdapter) { + serviceContainer.adapterRegistry.register(adapter) + } + + /** + * Get the list of registered framework adapters + * @return Dictionary of registered adapters by framework + */ + fun getRegisteredAdapters(): Map { + return serviceContainer.adapterRegistry.getRegisteredAdapters() + } + + /** + * Get available frameworks on this device (based on registered adapters) + * @return Array of frameworks that have registered adapters + */ + fun getAvailableFrameworks(): List { + return serviceContainer.adapterRegistry.getAvailableFrameworks() + } + + /** + * Get detailed framework availability information + * @return Array of framework availability details + */ + fun getFrameworkAvailability(): List { + return serviceContainer.adapterRegistry.getFrameworkAvailability() + } + + /** + * Get models for a specific framework + * @param framework The framework to filter models for + * @return Array of models compatible with the framework + */ + fun getModelsForFramework(framework: LLMFramework): List { + val criteria = ModelCriteria(framework = framework) + return serviceContainer.modelRegistry.filterModels(criteria) + } + + /** + * Add a model from URL for download + * @param name Display name for the model + * @param url Download URL for the model + * @param framework Target framework for the model + * @param estimatedSize Estimated memory usage (optional) + * @return The created model info + */ + fun addModelFromURL( + name: String, + url: String, + framework: LLMFramework, + estimatedSize: Long? = null + ): ModelInfo { + return serviceContainer.modelRegistry.addModelFromURL( + name = name, + url = url, + framework = framework, + estimatedSize = estimatedSize + ) + } + + // MARK: - Internal Service Container Access + + /** + * Access to performance monitoring + */ + val performanceMonitor: PerformanceMonitor + get() = serviceContainer.performanceMonitor + + /** + * Access to benchmarking + */ + val benchmarkSuite: BenchmarkRunner + get() = serviceContainer.benchmarkRunner + + /** + * Access to file manager for storage operations + */ + val fileManager: SimplifiedFileManager + get() = serviceContainer.fileManager + + /** + * Access to A/B testing + */ + val abTesting: ABTestRunner + get() = serviceContainer.abTestRunner + + private fun setupServices() { + // Services will be registered in the ServiceContainer } } diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/Configuration.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/Configuration.kt new file mode 100644 index 0000000000..7133f29235 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/Configuration.kt @@ -0,0 +1,92 @@ +package com.runanywhere.sdk.configuration + +import com.runanywhere.sdk.models.LLMFramework +import com.runanywhere.sdk.models.HardwareConfiguration +import java.net.URL + +/** + * SDK Configuration + */ +data class Configuration( + /** + * API key for authentication + */ + val apiKey: String, + + /** + * Base URL for API requests + */ + var baseURL: URL = URL("https://api.runanywhere.ai"), + + /** + * Enable real-time dashboard updates + */ + var enableRealTimeDashboard: Boolean = true, + + /** + * Routing policy for model selection + */ + var routingPolicy: RoutingPolicy = RoutingPolicy.AUTOMATIC, + + /** + * Telemetry consent + */ + var telemetryConsent: TelemetryConsent = TelemetryConsent.GRANTED, + + /** + * Privacy mode settings + */ + var privacyMode: PrivacyMode = PrivacyMode.STANDARD, + + /** + * Debug mode flag + */ + var debugMode: Boolean = false, + + /** + * Preferred frameworks for model execution + */ + var preferredFrameworks: List = emptyList(), + + /** + * Hardware preferences for model execution + */ + var hardwarePreferences: HardwareConfiguration? = null, + + /** + * Model provider configurations + */ + var modelProviders: List = emptyList(), + + /** + * Memory threshold for model loading (in bytes) + */ + var memoryThreshold: Long = 500_000_000, // 500MB default + + /** + * Download configuration + */ + var downloadConfiguration: DownloadConfig = DownloadConfig() +) { + /** + * Convenience constructor for minimal config + */ + constructor( + apiKey: String, + enableRealTimeDashboard: Boolean = true, + telemetryConsent: TelemetryConsent = TelemetryConsent.GRANTED + ) : this( + apiKey = apiKey, + baseURL = URL("https://api.runanywhere.ai"), + enableRealTimeDashboard = enableRealTimeDashboard, + routingPolicy = RoutingPolicy.AUTOMATIC, + telemetryConsent = telemetryConsent, + privacyMode = PrivacyMode.STANDARD, + debugMode = false, + preferredFrameworks = emptyList(), + hardwarePreferences = null, + modelProviders = emptyList(), + memoryThreshold = 500_000_000, + downloadConfiguration = DownloadConfig() + ) +} \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/DownloadConfig.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/DownloadConfig.kt new file mode 100644 index 0000000000..f383767f10 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/DownloadConfig.kt @@ -0,0 +1,28 @@ +package com.runanywhere.sdk.configuration + +import java.io.File + +/** + * Download configuration + */ +data class DownloadConfig( + /** + * Maximum concurrent downloads + */ + val maxConcurrentDownloads: Int = 2, + + /** + * Number of retry attempts + */ + val retryAttempts: Int = 3, + + /** + * Custom cache directory + */ + val cacheDirectory: File? = null, + + /** + * Download timeout in seconds + */ + val timeoutInterval: Long = 300 +) \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/ModelProviderConfig.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/ModelProviderConfig.kt new file mode 100644 index 0000000000..6b5fdc0d91 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/ModelProviderConfig.kt @@ -0,0 +1,31 @@ +package com.runanywhere.sdk.configuration + +/** + * Model provider configuration + */ +data class ModelProviderConfig( + /** + * Provider name (e.g., "HuggingFace", "Kaggle") + */ + val provider: String, + + /** + * Authentication credentials + */ + val credentials: ProviderCredentials? = null, + + /** + * Whether this provider is enabled + */ + val enabled: Boolean = true +) + +/** + * Provider credentials + */ +data class ProviderCredentials( + val apiKey: String? = null, + val username: String? = null, + val password: String? = null, + val token: String? = null +) \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/PrivacyMode.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/PrivacyMode.kt new file mode 100644 index 0000000000..082fcd3bca --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/PrivacyMode.kt @@ -0,0 +1,21 @@ +package com.runanywhere.sdk.configuration + +/** + * Privacy mode settings + */ +enum class PrivacyMode { + /** + * Standard privacy protection + */ + STANDARD, + + /** + * Enhanced privacy with stricter PII detection + */ + STRICT, + + /** + * Custom privacy rules + */ + CUSTOM +} \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/RoutingPolicy.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/RoutingPolicy.kt new file mode 100644 index 0000000000..888798b564 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/RoutingPolicy.kt @@ -0,0 +1,26 @@ +package com.runanywhere.sdk.configuration + +/** + * Routing policy for model selection + */ +enum class RoutingPolicy { + /** + * Automatic routing based on device capabilities and model requirements + */ + AUTOMATIC, + + /** + * Always prefer on-device execution + */ + ON_DEVICE_ONLY, + + /** + * Always prefer cloud execution + */ + CLOUD_ONLY, + + /** + * Hybrid routing with fallback + */ + HYBRID +} \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/TelemetryConsent.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/TelemetryConsent.kt new file mode 100644 index 0000000000..97df7c733e --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/configuration/TelemetryConsent.kt @@ -0,0 +1,21 @@ +package com.runanywhere.sdk.configuration + +/** + * Telemetry consent preference + */ +enum class TelemetryConsent { + /** + * Telemetry is granted + */ + GRANTED, + + /** + * Telemetry is denied + */ + DENIED, + + /** + * Telemetry consent not yet determined + */ + NOT_DETERMINED +} \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/errors/RunAnywhereError.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/errors/RunAnywhereError.kt new file mode 100644 index 0000000000..16d1ec9e50 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/errors/RunAnywhereError.kt @@ -0,0 +1,128 @@ +package com.runanywhere.sdk.errors + +/** + * Main public error type for the RunAnywhere SDK + */ +sealed class RunAnywhereError : Exception() { + // Initialization errors + object NotInitialized : RunAnywhereError() { + override val message: String = "RunAnywhere SDK is not initialized. Call initialize() first." + } + + object AlreadyInitialized : RunAnywhereError() { + override val message: String = "RunAnywhere SDK is already initialized." + } + + data class InvalidConfiguration(val detail: String) : RunAnywhereError() { + override val message: String = "Invalid configuration: $detail" + } + + object InvalidAPIKey : RunAnywhereError() { + override val message: String = "Invalid or missing API key." + } + + // Model errors + data class ModelNotFound(val identifier: String) : RunAnywhereError() { + override val message: String = "Model '$identifier' not found." + } + + data class ModelLoadFailed(val identifier: String, val error: Throwable?) : RunAnywhereError() { + override val message: String = if (error != null) { + "Failed to load model '$identifier': ${error.message}" + } else { + "Failed to load model '$identifier'" + } + } + + data class ModelValidationFailed(val identifier: String, val errors: List) : RunAnywhereError() { + override val message: String = "Model '$identifier' validation failed: ${errors.joinToString(", ") { it.message }}" + } + + data class ModelIncompatible(val identifier: String, val reason: String) : RunAnywhereError() { + override val message: String = "Model '$identifier' is incompatible: $reason" + } + + // Generation errors + data class GenerationFailed(val reason: String) : RunAnywhereError() { + override val message: String = "Text generation failed: $reason" + } + + object GenerationTimeout : RunAnywhereError() { + override val message: String = "Text generation timed out." + } + + data class ContextTooLong(val provided: Int, val maximum: Int) : RunAnywhereError() { + override val message: String = "Context too long: $provided tokens (maximum: $maximum)" + } + + data class TokenLimitExceeded(val requested: Int, val maximum: Int) : RunAnywhereError() { + override val message: String = "Token limit exceeded: requested $requested, maximum $maximum" + } + + data class CostLimitExceeded(val estimated: Double, val limit: Double) : RunAnywhereError() { + override val message: String = "Cost limit exceeded: estimated $${String.format("%.2f", estimated)}, limit $${String.format("%.2f", limit)}" + } + + // Network errors + object NetworkUnavailable : RunAnywhereError() { + override val message: String = "Network connection unavailable." + } + + data class RequestFailed(val error: Throwable) : RunAnywhereError() { + override val message: String = "Request failed: ${error.message}" + } + + data class DownloadFailed(val url: String, val error: Throwable?) : RunAnywhereError() { + override val message: String = if (error != null) { + "Failed to download from '$url': ${error.message}" + } else { + "Failed to download from '$url'" + } + } + + // Storage errors + data class InsufficientStorage(val required: Long, val available: Long) : RunAnywhereError() { + override val message: String = "Insufficient storage: ${formatBytes(required)} required, ${formatBytes(available)} available" + } + + object StorageFull : RunAnywhereError() { + override val message: String = "Device storage is full." + } + + // Hardware errors + data class HardwareUnsupported(val feature: String) : RunAnywhereError() { + override val message: String = "Hardware does not support $feature." + } + + object MemoryPressure : RunAnywhereError() { + override val message: String = "System is under memory pressure." + } + + object ThermalStateExceeded : RunAnywhereError() { + override val message: String = "Device temperature too high for operation." + } + + // Feature errors + data class FeatureNotAvailable(val feature: String) : RunAnywhereError() { + override val message: String = "Feature '$feature' is not available." + } + + data class NotImplemented(val feature: String) : RunAnywhereError() { + override val message: String = "Feature '$feature' is not yet implemented." + } + + companion object { + private fun formatBytes(bytes: Long): String { + val units = arrayOf("B", "KB", "MB", "GB", "TB") + var size = bytes.toDouble() + var unitIndex = 0 + + while (size >= 1024 && unitIndex < units.size - 1) { + size /= 1024 + unitIndex++ + } + + return String.format("%.1f %s", size, units[unitIndex]) + } + } +} \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/errors/SDKError.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/errors/SDKError.kt new file mode 100644 index 0000000000..973d541e2b --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/errors/SDKError.kt @@ -0,0 +1,51 @@ +package com.runanywhere.sdk.errors + +/** + * SDK-specific errors + */ +sealed class SDKError : Exception() { + object NotInitialized : SDKError() { + override val message: String = "SDK not initialized. Call initialize(with:) first." + } + + object NotImplemented : SDKError() { + override val message: String = "This feature is not yet implemented." + } + + data class ModelNotFound(val model: String) : SDKError() { + override val message: String = "Model '$model' not found." + } + + data class LoadingFailed(val reason: String) : SDKError() { + override val message: String = "Failed to load model: $reason" + } + + data class GenerationFailed(val reason: String) : SDKError() { + override val message: String = "Generation failed: $reason" + } + + data class FrameworkNotAvailable(val framework: String) : SDKError() { + override val message: String = "Framework $framework not available" + } + + data class DownloadFailed(val error: Throwable) : SDKError() { + override val message: String = "Download failed: ${error.message}" + } + + data class ValidationFailed(val error: ValidationError) : SDKError() { + override val message: String = "Validation failed: ${error.message}" + } + + data class RoutingFailed(val reason: String) : SDKError() { + override val message: String = "Routing failed: $reason" + } +} + +/** + * Validation error + */ +data class ValidationError( + val field: String, + val message: String, + val code: String? = null +) \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/example/SDKExample.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/example/SDKExample.kt new file mode 100644 index 0000000000..caca3c6db6 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/example/SDKExample.kt @@ -0,0 +1,251 @@ +package com.runanywhere.sdk.example + +import com.runanywhere.sdk.RunAnywhereSDK +import com.runanywhere.sdk.configuration.* +import com.runanywhere.sdk.models.* +import com.runanywhere.sdk.errors.RunAnywhereError +import kotlinx.coroutines.runBlocking + +/** + * Example usage of the RunAnywhere Android SDK + */ +class SDKExample { + + fun runExample() = runBlocking { + try { + // 1. Initialize the SDK + println("Initializing SDK...") + val configuration = Configuration( + apiKey = "your-api-key-here", + enableRealTimeDashboard = true, + telemetryConsent = TelemetryConsent.GRANTED, + routingPolicy = RoutingPolicy.AUTOMATIC, + privacyMode = PrivacyMode.STANDARD, + preferredFrameworks = listOf( + LLMFramework.TENSORFLOW_LITE, + LLMFramework.ONNX + ), + hardwarePreferences = HardwareConfiguration( + primaryAccelerator = HardwareAcceleration.GPU, + fallbackAccelerator = HardwareAcceleration.CPU, + memoryMode = HardwareConfiguration.MemoryMode.BALANCED, + threadCount = 4 + ) + ) + + RunAnywhereSDK.shared.initialize(configuration) + println("SDK initialized successfully!") + + // 2. Check available frameworks + println("\nChecking available frameworks...") + val availableFrameworks = RunAnywhereSDK.shared.getAvailableFrameworks() + println("Available frameworks: ${availableFrameworks.joinToString(", ") { it.displayName }}") + + val frameworkAvailability = RunAnywhereSDK.shared.getFrameworkAvailability() + frameworkAvailability.forEach { info -> + println("${info.framework.displayName}: ${if (info.isAvailable) "✅ Available" else "❌ Not Available"}") + } + + // 3. List available models + println("\nListing available models...") + val models = RunAnywhereSDK.shared.listAvailableModels() + if (models.isEmpty()) { + println("No models available. Adding a sample model...") + + // Add a sample model + val sampleModel = RunAnywhereSDK.shared.addModelFromURL( + name = "GPT-2 Small", + url = "https://example.com/gpt2-small.tflite", + framework = LLMFramework.TENSORFLOW_LITE, + estimatedSize = 500_000_000 // 500MB + ) + println("Added sample model: ${sampleModel.name}") + } else { + models.forEach { model -> + println("Model: ${model.name} (${model.format})") + } + } + + // 4. Load a model + println("\nLoading model...") + val modelInfo = RunAnywhereSDK.shared.loadModel("gpt-2-small") + println("Model loaded: ${modelInfo.name}") + + // 5. Generate text + println("\nGenerating text...") + val generationOptions = GenerationOptions( + maxTokens = 50, + temperature = 0.7f, + topP = 1.0f, + context = Context( + messages = listOf( + Message( + role = Message.Role.USER, + content = "Hello, how are you?" + ) + ), + maxTokens = 2048 + ) + ) + + val result = RunAnywhereSDK.shared.generate( + prompt = "Tell me a short story about a robot", + options = generationOptions + ) + + println("Generated text: ${result.text}") + println("Tokens used: ${result.tokensUsed}") + println("Latency: ${result.latencyMs}ms") + println("Execution target: ${result.executionTarget}") + println("Amount saved: $${result.savedAmount}") + println("Framework used: ${result.framework?.displayName ?: "Cloud"}") + + // 6. Streaming generation + println("\nGenerating text with streaming...") + val stream = RunAnywhereSDK.shared.generateStream( + prompt = "Write a poem about technology", + options = GenerationOptions(maxTokens = 30) + ) + + stream.collect { chunk -> + print(chunk) + } + println() // New line after streaming + + // 7. Performance monitoring + println("\nPerformance monitoring...") + val monitor = RunAnywhereSDK.shared.performanceMonitor + println("Performance monitor available: ${monitor != null}") + + // 8. Benchmarking + println("\nBenchmarking...") + val benchmark = RunAnywhereSDK.shared.benchmarkSuite + println("Benchmark suite available: ${benchmark != null}") + + // 9. A/B Testing + println("\nA/B Testing...") + val abTesting = RunAnywhereSDK.shared.abTesting + println("A/B testing available: ${abTesting != null}") + + // 10. Unload model + println("\nUnloading model...") + RunAnywhereSDK.shared.unloadModel() + println("Model unloaded successfully!") + + println("\n✅ SDK example completed successfully!") + + } catch (e: RunAnywhereError) { + println("❌ RunAnywhere Error: ${e.message}") + when (e) { + is RunAnywhereError.NotInitialized -> { + println("Please initialize the SDK first") + } + is RunAnywhereError.ModelNotFound -> { + println("Model not found. Please check the model identifier") + } + is RunAnywhereError.GenerationFailed -> { + println("Text generation failed. Please try again") + } + is RunAnywhereError.NetworkUnavailable -> { + println("Network connection is required for this operation") + } + else -> { + println("An unexpected error occurred") + } + } + } catch (e: Exception) { + println("❌ Unexpected error: ${e.message}") + e.printStackTrace() + } + } + + /** + * Example of downloading a model + */ + fun downloadModelExample() = runBlocking { + try { + println("Downloading model example...") + + val downloadTask = RunAnywhereSDK.shared.downloadModel("gpt-2-small") + + downloadTask.progress.collect { progress -> + println("Download progress: ${String.format("%.1f", progress.percentage)}%") + println("Downloaded: ${progress.bytesDownloaded} / ${progress.totalBytes} bytes") + println("Speed: ${progress.speed} bytes/sec") + progress.estimatedTimeRemaining?.let { time -> + println("ETA: ${time / 1000} seconds") + } + println("---") + } + + println("Download completed!") + + } catch (e: RunAnywhereError) { + println("Download failed: ${e.message}") + } + } + + /** + * Example of framework adapter registration + */ + fun frameworkAdapterExample() { + println("Framework adapter example...") + + // Example of registering a custom framework adapter + // This would be implemented by the user + /* + val customAdapter = object : FrameworkAdapter { + override val framework: LLMFramework = LLMFramework.CUSTOM + + override suspend fun isAvailable(): Boolean = true + + override suspend fun loadModel(modelInfo: ModelInfo): LoadedModel { + // Implementation + } + + override suspend fun unloadModel(modelId: String) { + // Implementation + } + + override suspend fun generate( + prompt: String, + options: GenerationOptions + ): GenerationResult { + // Implementation + } + + override fun generateStream( + prompt: String, + options: GenerationOptions + ): Flow { + // Implementation + } + + override fun getSupportedFormats(): List = listOf(ModelFormat.CUSTOM) + + override fun getHardwareRequirements(): List = emptyList() + + override fun getPerformanceCharacteristics(): PerformanceCharacteristics { + return PerformanceCharacteristics( + maxTokensPerSecond = 10.0, + memoryEfficiency = 0.8, + batteryEfficiency = 0.7, + latency = 100 + ) + } + } + + RunAnywhereSDK.shared.registerFrameworkAdapter(customAdapter) + */ + + println("Framework adapter example completed!") + } +} + +/** + * Main function to run the example + */ +fun main() { + val example = SDKExample() + example.runExample() +} \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/CostBreakdown.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/CostBreakdown.kt new file mode 100644 index 0000000000..a63d6823bb --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/CostBreakdown.kt @@ -0,0 +1,26 @@ +package com.runanywhere.sdk.models + +/** + * Cost breakdown for generation + */ +data class CostBreakdown( + /** + * Total cost in USD + */ + val totalCost: Double, + + /** + * Savings achieved by using on-device execution + */ + val savingsAchieved: Double, + + /** + * Cloud cost if it had been used + */ + val cloudCost: Double? = null, + + /** + * Device execution cost + */ + val deviceCost: Double? = null +) \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/DownloadTask.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/DownloadTask.kt new file mode 100644 index 0000000000..42070f5983 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/DownloadTask.kt @@ -0,0 +1,36 @@ +package com.runanywhere.sdk.models + +import kotlinx.coroutines.flow.Flow + +/** + * Download task for model downloads + */ +data class DownloadTask( + val id: String, + val modelId: String, + val status: DownloadStatus, + val progress: Flow, + val cancel: () -> Unit +) + +/** + * Download status + */ +enum class DownloadStatus { + PENDING, + DOWNLOADING, + COMPLETED, + FAILED, + CANCELLED +} + +/** + * Download progress + */ +data class DownloadProgress( + val bytesDownloaded: Long, + val totalBytes: Long, + val percentage: Float, + val speed: Long, // bytes per second + val estimatedTimeRemaining: Long? = null // milliseconds +) \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/ExecutionTarget.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/ExecutionTarget.kt new file mode 100644 index 0000000000..267d643c53 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/ExecutionTarget.kt @@ -0,0 +1,21 @@ +package com.runanywhere.sdk.models + +/** + * Execution target for model inference + */ +enum class ExecutionTarget { + /** + * Execute on device + */ + ON_DEVICE, + + /** + * Execute in the cloud + */ + CLOUD, + + /** + * Hybrid execution (partial on-device, partial cloud) + */ + HYBRID +} \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/FrameworkAvailability.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/FrameworkAvailability.kt new file mode 100644 index 0000000000..e6d13e7ef2 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/FrameworkAvailability.kt @@ -0,0 +1,36 @@ +package com.runanywhere.sdk.models + +/** + * Detailed information about framework availability + */ +data class FrameworkAvailability( + /** + * The framework being described + */ + val framework: LLMFramework, + + /** + * Whether this framework is available (has a registered adapter) + */ + val isAvailable: Boolean, + + /** + * Reason why the framework is not available (if applicable) + */ + val unavailabilityReason: String? = null, + + /** + * Hardware requirements for optimal performance + */ + val requirements: List = emptyList(), + + /** + * Recommended use cases for this framework + */ + val recommendedFor: List = emptyList(), + + /** + * Model formats supported by this framework + */ + val supportedFormats: List = emptyList() +) \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/GenerationOptions.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/GenerationOptions.kt new file mode 100644 index 0000000000..c91e13a84a --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/GenerationOptions.kt @@ -0,0 +1,150 @@ +package com.runanywhere.sdk.models + +/** + * Options for text generation + */ +data class GenerationOptions( + /** + * Maximum number of tokens to generate + */ + val maxTokens: Int = 100, + + /** + * Temperature for sampling (0.0 - 1.0) + */ + val temperature: Float = 0.7f, + + /** + * Top-p sampling parameter + */ + val topP: Float = 1.0f, + + /** + * Context for the generation + */ + val context: Context? = null, + + /** + * Enable real-time tracking for cost dashboard + */ + val enableRealTimeTracking: Boolean = true, + + /** + * Stop sequences + */ + val stopSequences: List = emptyList(), + + /** + * Seed for reproducible generation + */ + val seed: Int? = null, + + /** + * Enable streaming mode + */ + val streamingEnabled: Boolean = false, + + /** + * Token budget constraint (for cost control) + */ + val tokenBudget: TokenBudget? = null, + + /** + * Framework-specific options + */ + val frameworkOptions: FrameworkOptions? = null, + + /** + * Preferred execution target + */ + val preferredExecutionTarget: ExecutionTarget? = null +) + +/** + * Context for maintaining conversation state + */ +data class Context( + /** + * Previous messages in the conversation + */ + val messages: List = emptyList(), + + /** + * System prompt override + */ + val systemPrompt: String? = null, + + /** + * Maximum context window size + */ + val maxTokens: Int = 2048 +) + +/** + * Message in a conversation + */ +data class Message( + /** + * Role of the message sender + */ + val role: Role, + + /** + * Content of the message + */ + val content: String, + + /** + * Timestamp + */ + val timestamp: Long = System.currentTimeMillis() +) { + enum class Role { + USER, + ASSISTANT, + SYSTEM + } +} + +/** + * Token budget for cost control + */ +data class TokenBudget( + val maxTokens: Int, + val costLimit: Double? = null +) + +/** + * Framework-specific options + */ +data class FrameworkOptions( + val tensorFlowLiteOptions: TensorFlowLiteOptions? = null, + val onnxOptions: OnnxOptions? = null, + val llamaCppOptions: LlamaCppOptions? = null +) + +/** + * TensorFlow Lite specific options + */ +data class TensorFlowLiteOptions( + val useNNAPI: Boolean = false, + val useGPU: Boolean = false, + val numThreads: Int = 4 +) + +/** + * ONNX specific options + */ +data class OnnxOptions( + val executionProvider: String = "CPUExecutionProvider", + val graphOptimizationLevel: Int = 99 +) + +/** + * Llama.cpp specific options + */ +data class LlamaCppOptions( + val nCtx: Int = 2048, + val nThreads: Int = 4, + val nGpuLayers: Int = 0 +) \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/GenerationResult.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/GenerationResult.kt new file mode 100644 index 0000000000..6e27161a7c --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/GenerationResult.kt @@ -0,0 +1,137 @@ +package com.runanywhere.sdk.models + +/** + * Result of a text generation request + */ +data class GenerationResult( + /** + * Generated text + */ + val text: String, + + /** + * Number of tokens used + */ + val tokensUsed: Int, + + /** + * Model used for generation + */ + val modelUsed: String, + + /** + * Latency in milliseconds + */ + val latencyMs: Long, + + /** + * Execution target (device/cloud/hybrid) + */ + val executionTarget: ExecutionTarget, + + /** + * Amount saved by using on-device execution + */ + val savedAmount: Double, + + /** + * Framework used for generation (if on-device) + */ + val framework: LLMFramework? = null, + + /** + * Hardware acceleration used + */ + val hardwareUsed: HardwareAcceleration = HardwareAcceleration.CPU, + + /** + * Memory used during generation (in bytes) + */ + val memoryUsed: Long = 0, + + /** + * Tokenizer format used + */ + val tokenizerFormat: TokenizerFormat? = null, + + /** + * Detailed performance metrics + */ + val performanceMetrics: PerformanceMetrics, + + /** + * Additional metadata + */ + val metadata: ResultMetadata? = null +) + +/** + * Result metadata for additional strongly-typed information + */ +data class ResultMetadata( + val routingReason: RoutingReasonType, + val fallbackUsed: Boolean = false, + val cacheHit: Boolean = false, + val modelVersion: String? = null, + val experimentId: String? = null, + val debugInfo: DebugInfo? = null +) + +/** + * Strongly typed routing reason + */ +enum class RoutingReasonType { + USER_PREFERENCE, + COST_OPTIMIZATION, + PERFORMANCE_OPTIMIZATION, + RESOURCE_CONSTRAINT, + POLICY_DRIVEN, + FALLBACK, + EXPERIMENTAL +} + +/** + * Debug information for development + */ +data class DebugInfo( + val startTime: Long, + val endTime: Long, + val threadCount: Int, + val deviceLoad: DeviceLoadLevel +) + +/** + * Device load level + */ +enum class DeviceLoadLevel { + IDLE, // 0-20% + LOW, // 20-40% + MODERATE, // 40-60% + HIGH, // 60-80% + CRITICAL; // 80-100% + + companion object { + fun fromPercentage(percentage: Double): DeviceLoadLevel { + return when { + percentage < 0.2 -> IDLE + percentage < 0.4 -> LOW + percentage < 0.6 -> MODERATE + percentage < 0.8 -> HIGH + else -> CRITICAL + } + } + } +} + +/** + * Performance metrics + */ +data class PerformanceMetrics( + val inferenceTime: Long, + val tokenizationTime: Long, + val totalTime: Long, + val tokensPerSecond: Double, + val memoryPeak: Long, + val cpuUsage: Double, + val gpuUsage: Double? = null +) \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/HardwareAcceleration.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/HardwareAcceleration.kt new file mode 100644 index 0000000000..7ca8fa3153 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/HardwareAcceleration.kt @@ -0,0 +1,14 @@ +package com.runanywhere.sdk.models + +/** + * Hardware acceleration options + */ +enum class HardwareAcceleration { + CPU, + GPU, + NPU, + NNAPI, + OPENCL, + VULKAN, + AUTO +} \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/HardwareConfiguration.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/HardwareConfiguration.kt new file mode 100644 index 0000000000..60cc17e9b0 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/HardwareConfiguration.kt @@ -0,0 +1,19 @@ +package com.runanywhere.sdk.models + +/** + * Hardware configuration for framework adapters + */ +data class HardwareConfiguration( + var primaryAccelerator: HardwareAcceleration = HardwareAcceleration.AUTO, + var fallbackAccelerator: HardwareAcceleration? = HardwareAcceleration.CPU, + var memoryMode: MemoryMode = MemoryMode.BALANCED, + var threadCount: Int = Runtime.getRuntime().availableProcessors(), + var useQuantization: Boolean = false, + var quantizationBits: Int = 8 +) { + enum class MemoryMode { + CONSERVATIVE, + BALANCED, + AGGRESSIVE + } +} \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/LLMFramework.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/LLMFramework.kt new file mode 100644 index 0000000000..438cf2f306 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/LLMFramework.kt @@ -0,0 +1,25 @@ +package com.runanywhere.sdk.models + +/** + * Supported LLM frameworks + */ +enum class LLMFramework(val displayName: String) { + TENSORFLOW_LITE("TensorFlow Lite"), + ONNX("ONNX Runtime"), + EXECUTORCH("ExecuTorch"), + LLAMACPP("llama.cpp"), + FOUNDATION_MODELS("Foundation Models"), + PICOLLM("Pico LLM"), + MLC("MLC"), + MEDIAPIPE("MediaPipe"), + NCNN("NCNN"), + OPENVINO("OpenVINO"), + TFLITE_GPU("TensorFlow Lite GPU"), + TFLITE_NNAPI("TensorFlow Lite NNAPI"); + + companion object { + fun fromString(value: String): LLMFramework? { + return values().find { it.name.equals(value, ignoreCase = true) } + } + } +} \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/ModelCriteria.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/ModelCriteria.kt new file mode 100644 index 0000000000..a24a3387a4 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/ModelCriteria.kt @@ -0,0 +1,13 @@ +package com.runanywhere.sdk.models + +/** + * Criteria for filtering models + */ +data class ModelCriteria( + val framework: LLMFramework? = null, + val format: ModelFormat? = null, + val maxMemory: Long? = null, + val minContextLength: Int? = null, + val tags: List = emptyList(), + val downloaded: Boolean? = null +) \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/ModelFormat.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/ModelFormat.kt new file mode 100644 index 0000000000..4d92d98445 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/ModelFormat.kt @@ -0,0 +1,24 @@ +package com.runanywhere.sdk.models + +/** + * Model formats supported + */ +enum class ModelFormat { + TFLITE, + ONNX, + ORT, + SAFETENSORS, + GGUF, + GGML, + PTE, + BIN, + WEIGHTS, + CHECKPOINT, + UNKNOWN; + + companion object { + fun fromString(value: String): ModelFormat { + return values().find { it.name.equals(value, ignoreCase = true) } ?: UNKNOWN + } + } +} \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/ModelInfo.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/ModelInfo.kt new file mode 100644 index 0000000000..781e0d5a6b --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/models/ModelInfo.kt @@ -0,0 +1,69 @@ +package com.runanywhere.sdk.models + +import java.io.File +import java.net.URL + +/** + * Information about a model + */ +data class ModelInfo( + val id: String, + val name: String, + val format: ModelFormat, + val downloadURL: URL? = null, + var localPath: File? = null, + val estimatedMemory: Long = 1_000_000_000, // 1GB default + val contextLength: Int = 2048, + val downloadSize: Long? = null, + val checksum: String? = null, + val compatibleFrameworks: List = emptyList(), + val preferredFramework: LLMFramework? = null, + val hardwareRequirements: List = emptyList(), + val tokenizerFormat: TokenizerFormat? = null, + val metadata: ModelInfoMetadata? = null, + val alternativeDownloadURLs: List? = null, + val additionalProperties: Map = emptyMap() +) + +/** + * Hardware requirement for a model + */ +data class HardwareRequirement( + val type: HardwareType, + val minimumSpecification: String, + val recommendedSpecification: String? = null +) + +/** + * Hardware types + */ +enum class HardwareType { + CPU, + GPU, + NPU, + MEMORY, + STORAGE +} + +/** + * Tokenizer format + */ +enum class TokenizerFormat { + SENTENCEPIECE, + BPE, + WORDPIECE, + UNKNOWN +} + +/** + * Model metadata + */ +data class ModelInfoMetadata( + val version: String? = null, + val description: String? = null, + val author: String? = null, + val license: String? = null, + val tags: List = emptyList(), + val lastUsed: Long? = null, + val downloadDate: Long? = null +) \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/services/FrameworkAdapter.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/services/FrameworkAdapter.kt new file mode 100644 index 0000000000..8be88b6442 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/services/FrameworkAdapter.kt @@ -0,0 +1,70 @@ +package com.runanywhere.sdk.services + +import com.runanywhere.sdk.models.* +import kotlinx.coroutines.flow.Flow + +/** + * Framework adapter interface + */ +interface FrameworkAdapter { + /** + * The framework this adapter supports + */ + val framework: LLMFramework + + /** + * Check if this framework is available on the current device + */ + suspend fun isAvailable(): Boolean + + /** + * Load a model + */ + suspend fun loadModel(modelInfo: ModelInfo): LoadedModel + + /** + * Unload a model + */ + suspend fun unloadModel(modelId: String) + + /** + * Generate text + */ + suspend fun generate( + prompt: String, + options: GenerationOptions + ): GenerationResult + + /** + * Generate text as a stream + */ + fun generateStream( + prompt: String, + options: GenerationOptions + ): Flow + + /** + * Get supported model formats + */ + fun getSupportedFormats(): List + + /** + * Get hardware requirements + */ + fun getHardwareRequirements(): List + + /** + * Get performance characteristics + */ + fun getPerformanceCharacteristics(): PerformanceCharacteristics +} + +/** + * Performance characteristics for a framework + */ +data class PerformanceCharacteristics( + val maxTokensPerSecond: Double, + val memoryEfficiency: Double, // 0.0 to 1.0 + val batteryEfficiency: Double, // 0.0 to 1.0 + val latency: Long // milliseconds +) \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/services/ModelMetadataStore.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/services/ModelMetadataStore.kt new file mode 100644 index 0000000000..0e57b12143 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/services/ModelMetadataStore.kt @@ -0,0 +1,82 @@ +package com.runanywhere.sdk.services + +import com.runanywhere.sdk.models.ModelInfo +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.io.ObjectInputStream +import java.io.ObjectOutputStream +import java.io.Serializable + +/** + * Model metadata store for persisting model information + */ +class ModelMetadataStore { + private val metadataFile = File("model_metadata.dat") + private val metadata = mutableMapOf() + + init { + loadMetadata() + } + + /** + * Update last used timestamp for a model + */ + fun updateLastUsed(modelId: String) { + val currentTime = System.currentTimeMillis() + val modelMetadata = metadata.getOrPut(modelId) { ModelMetadata(modelId) } + modelMetadata.lastUsed = currentTime + saveMetadata() + } + + /** + * Load stored models + */ + fun loadStoredModels(): List { + // This would typically load from persistent storage + // For now, return empty list + return emptyList() + } + + private fun loadMetadata() { + if (metadataFile.exists()) { + try { + FileInputStream(metadataFile).use { fis -> + ObjectInputStream(fis).use { ois -> + @Suppress("UNCHECKED_CAST") + val loadedMetadata = ois.readObject() as? Map + if (loadedMetadata != null) { + metadata.clear() + metadata.putAll(loadedMetadata) + } + } + } + } catch (e: Exception) { + // Handle loading error + } + } + } + + private fun saveMetadata() { + try { + FileOutputStream(metadataFile).use { fos -> + ObjectOutputStream(fos).use { oos -> + oos.writeObject(metadata.toMap()) + } + } + } catch (e: Exception) { + // Handle saving error + } + } +} + +/** + * Model metadata for persistence + */ +data class ModelMetadata( + val modelId: String, + var lastUsed: Long? = null, + var downloadDate: Long? = null, + var usageCount: Int = 0, + var averageLatency: Long = 0 +) : Serializable \ No newline at end of file diff --git a/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/services/ServiceContainer.kt b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/services/ServiceContainer.kt new file mode 100644 index 0000000000..948399c7e9 --- /dev/null +++ b/sdk/runanywhere-android/src/main/java/com/runanywhere/sdk/services/ServiceContainer.kt @@ -0,0 +1,326 @@ +package com.runanywhere.sdk.services + +import com.runanywhere.sdk.configuration.Configuration +import com.runanywhere.sdk.models.ModelInfo +import com.runanywhere.sdk.models.ModelCriteria +import com.runanywhere.sdk.models.LLMFramework +import com.runanywhere.sdk.models.ModelFormat +import com.runanywhere.sdk.models.GenerationOptions +import com.runanywhere.sdk.models.GenerationResult +import com.runanywhere.sdk.models.ExecutionTarget +import com.runanywhere.sdk.models.PerformanceMetrics +import com.runanywhere.sdk.models.DownloadTask +import com.runanywhere.sdk.models.DownloadStatus +import com.runanywhere.sdk.models.DownloadProgress +import com.runanywhere.sdk.models.FrameworkAvailability +import kotlinx.coroutines.flow.Flow + +/** + * Service container for dependency injection + */ +class ServiceContainer { + + // Core services + val configurationValidator = ConfigurationValidator() + val modelRegistry = ModelRegistry() + val modelLoadingService = ModelLoadingService() + val generationService = GenerationService() + val streamingService = StreamingService() + val downloadService = DownloadService() + val fileManager = SimplifiedFileManager() + val adapterRegistry = AdapterRegistry() + + // Monitoring and analytics + val performanceMonitor = PerformanceMonitor() + val benchmarkRunner = BenchmarkRunner() + val abTestRunner = ABTestRunner() + + /** + * Bootstrap all services with configuration + */ + suspend fun bootstrap(configuration: Configuration) { + // Initialize services with configuration + modelRegistry.initialize(configuration) + modelLoadingService.initialize(configuration) + generationService.initialize(configuration) + streamingService.initialize(configuration) + downloadService.initialize(configuration) + fileManager.initialize(configuration) + adapterRegistry.initialize(configuration) + performanceMonitor.initialize(configuration) + benchmarkRunner.initialize(configuration) + abTestRunner.initialize(configuration) + } +} + +/** + * Configuration validator + */ +class ConfigurationValidator { + fun validate(configuration: Configuration) { + if (configuration.apiKey.isBlank()) { + throw IllegalArgumentException("API key cannot be blank") + } + + if (configuration.memoryThreshold <= 0) { + throw IllegalArgumentException("Memory threshold must be positive") + } + + // Add more validation as needed + } +} + +/** + * Model registry service + */ +class ModelRegistry { + private val models = mutableMapOf() + + suspend fun initialize(configuration: Configuration) { + // Initialize model registry + } + + suspend fun discoverModels(): List { + // Discover local models + return models.values.toList() + } + + fun getModel(modelId: String): ModelInfo? { + return models[modelId] + } + + fun filterModels(criteria: ModelCriteria): List { + return models.values.filter { model -> + (criteria.framework == null || criteria.framework == model.preferredFramework) && + (criteria.format == null || criteria.format == model.format) && + (criteria.maxMemory == null || model.estimatedMemory <= criteria.maxMemory) && + (criteria.minContextLength == null || model.contextLength >= criteria.minContextLength) && + (criteria.downloaded == null || (model.localPath != null) == criteria.downloaded) + } + } + + fun addModelFromURL( + name: String, + url: String, + framework: LLMFramework, + estimatedSize: Long? + ): ModelInfo { + val modelInfo = ModelInfo( + id = generateModelId(name), + name = name, + format = ModelFormat.UNKNOWN, + downloadURL = java.net.URL(url), + estimatedMemory = estimatedSize ?: 1_000_000_000, + compatibleFrameworks = listOf(framework), + preferredFramework = framework + ) + + models[modelInfo.id] = modelInfo + return modelInfo + } + + private fun generateModelId(name: String): String { + return name.lowercase().replace(" ", "-").replace("[^a-z0-9-]".toRegex(), "") + } +} + +/** + * Model loading service + */ +class ModelLoadingService { + suspend fun initialize(configuration: Configuration) { + // Initialize model loading service + } + + suspend fun loadModel(modelId: String): LoadedModel { + // Load model implementation + val modelInfo = ModelInfo( + id = modelId, + name = "Test Model", + format = ModelFormat.TFLITE + ) + + val service = LLMService() + return LoadedModel(modelInfo, service) + } + + suspend fun unloadModel(modelId: String) { + // Unload model implementation + } +} + +/** + * Generation service + */ +class GenerationService { + private var currentModel: LoadedModel? = null + + suspend fun initialize(configuration: Configuration) { + // Initialize generation service + } + + fun setCurrentModel(model: LoadedModel?) { + currentModel = model + } + + suspend fun generate( + prompt: String, + options: GenerationOptions + ): GenerationResult { + // Generation implementation + return GenerationResult( + text = "Generated response for: $prompt", + tokensUsed = prompt.length / 4, + modelUsed = currentModel?.model?.name ?: "Unknown", + latencyMs = 100, + executionTarget = ExecutionTarget.ON_DEVICE, + savedAmount = 0.01, + performanceMetrics = PerformanceMetrics( + inferenceTime = 50, + tokenizationTime = 10, + totalTime = 100, + tokensPerSecond = 10.0, + memoryPeak = 100_000_000, + cpuUsage = 0.5 + ) + ) + } +} + +/** + * Streaming service + */ +class StreamingService { + suspend fun initialize(configuration: Configuration) { + // Initialize streaming service + } + + fun generateStream( + prompt: String, + options: GenerationOptions + ): Flow { + // Streaming implementation + return kotlinx.coroutines.flow.flow { + emit("Streaming response for: $prompt") + } + } +} + +/** + * Download service + */ +class DownloadService { + suspend fun initialize(configuration: Configuration) { + // Initialize download service + } + + suspend fun downloadModel(model: ModelInfo): DownloadTask { + // Download implementation + return DownloadTask( + id = "download-${model.id}", + modelId = model.id, + status = DownloadStatus.DOWNLOADING, + progress = kotlinx.coroutines.flow.flow { + emit(DownloadProgress( + bytesDownloaded = 0, + totalBytes = model.downloadSize ?: 0, + percentage = 0f, + speed = 0 + )) + }, + cancel = { /* Cancel download */ } + ) + } +} + +/** + * Simplified file manager + */ +class SimplifiedFileManager { + fun initialize(configuration: Configuration) { + // Initialize file manager + } + + fun deleteModel(modelId: String) { + // Delete model implementation + } +} + +/** + * Adapter registry + */ +class AdapterRegistry { + private val adapters = mutableMapOf() + + fun initialize(configuration: Configuration) { + // Initialize adapter registry + } + + fun register(adapter: FrameworkAdapter) { + adapters[adapter.framework] = adapter + } + + fun getRegisteredAdapters(): Map { + return adapters.toMap() + } + + fun getAvailableFrameworks(): List { + return adapters.keys.toList() + } + + fun getFrameworkAvailability(): List { + return LLMFramework.values().map { framework -> + FrameworkAvailability( + framework = framework, + isAvailable = adapters.containsKey(framework), + unavailabilityReason = if (!adapters.containsKey(framework)) "No adapter registered" else null + ) + } + } +} + +/** + * Performance monitor + */ +class PerformanceMonitor { + fun initialize(configuration: Configuration) { + // Initialize performance monitor + } + + fun startMonitoring() { + // Start monitoring + } +} + +/** + * Benchmark runner + */ +class BenchmarkRunner { + fun initialize(configuration: Configuration) { + // Initialize benchmark runner + } +} + +/** + * A/B test runner + */ +class ABTestRunner { + fun initialize(configuration: Configuration) { + // Initialize A/B test runner + } +} + +/** + * Loaded model wrapper + */ +data class LoadedModel( + val model: ModelInfo, + val service: LLMService +) + +/** + * LLM service interface + */ +class LLMService { + // Service implementation +} \ No newline at end of file