diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml deleted file mode 100644 index 7b97974e..00000000 --- a/.github/workflows/test-examples.yml +++ /dev/null @@ -1,90 +0,0 @@ -name: Test Examples - -on: - push: - paths: - - 'examples/**' - - 'tests/examples/**' - - 'src/ember/**' - pull_request: - paths: - - 'examples/**' - - 'tests/examples/**' - - 'src/ember/**' - schedule: - # Run daily to catch any issues with examples - - cron: '0 0 * * *' - -jobs: - test-examples: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ['3.11', '3.12', '3.13'] - fail-fast: false - - steps: - - uses: actions/checkout@v4 - - - name: Set up uv with Python ${{ matrix.python-version }} - uses: astral-sh/setup-uv@v6 - with: - enable-cache: true - python-version: ${{ matrix.python-version }} - - - name: Install project and example deps - run: | - uv sync --locked --all-extras - uv pip install -r examples/requirements.txt - uv pip install pytest pytest-timeout pytest-xdist - - - name: Run example tests (replay) - run: | - uv run pytest tests/examples/ -v --timeout=300 - - - name: Validate golden outputs - run: | - uv run python tests/examples/validate_golden.py - - - name: Upload test results - if: always() - uses: actions/upload-artifact@v3 - with: - name: test-results-${{ matrix.python-version }} - path: | - pytest-report.xml - .coverage - - - name: Comment PR with results - if: github.event_name == 'pull_request' && always() - uses: actions/github-script@v6 - with: - script: | - const fs = require('fs'); - const pytest_report = 'pytest-report.xml'; - - if (fs.existsSync(pytest_report)) { - // Parse and format test results - const report = fs.readFileSync(pytest_report, 'utf8'); - // Add comment formatting logic here - } - - lint-examples: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Set up uv - uses: astral-sh/setup-uv@v6 - with: - enable-cache: true - python-version: '3.12' - - - name: Run ruff - run: | - uvx ruff check examples/ - - - name: Run mypy - run: | - uvx mypy examples/ --ignore-missing-imports || true diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index 9c896385..00000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Python tests - -# cancel any prior runs for this workflow and this PR (or branch) -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up uv - uses: astral-sh/setup-uv@v6 - with: - enable-cache: true - python-version: '3.12' - - name: Run pre-commit (ruff/black/mypy) - run: uvx pre-commit run -a - - test: - runs-on: ${{ matrix.os }} - needs: lint - strategy: - matrix: - python-version: - # TODO: 3.9, 3.10: 'ember.api.models' is not a package - - "3.11" - - "3.12" - - "3.13" - os: - - macos-latest - - ubuntu-latest - - windows-latest - # - ubuntu-24.04-arm # TODO: not enabled for private repos at the moment - - steps: - - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - name: Install uv and set the python version - uses: astral-sh/setup-uv@v6 - with: - enable-cache: true - python-version: ${{ matrix.python-version }} - - name: Install the project - run: uv sync --locked --all-extras --dev - - name: Configure setup-wizard - run: cd src/ember/cli/setup-wizard/ && npm ci - - name: Run all tests - run: uv run pytest -n auto diff --git a/.github/workflows/update-pricing.yml b/.github/workflows/update-pricing.yml deleted file mode 100644 index 703c1eac..00000000 --- a/.github/workflows/update-pricing.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Update Model Pricing - -on: - schedule: - # Run weekly on Mondays at 9 AM UTC - - cron: '0 9 * * 1' - workflow_dispatch: # Allow manual trigger - -jobs: - update-pricing: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Set up uv - uses: astral-sh/setup-uv@v6 - with: - enable-cache: true - python-version: '3.12' - - - name: Install project - run: | - uv sync --locked --all-extras - - - name: Update pricing data - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - run: | - uv run python -m ember.models.pricing_updater --dry-run - - - name: Create Pull Request - if: github.event_name == 'workflow_dispatch' - uses: peter-evans/create-pull-request@v5 - with: - commit-message: 'chore: update model pricing data' - title: 'Update Model Pricing Data' - body: | - This PR updates the model pricing data from official sources. - - The update was performed automatically using the pricing updater. - Please review the changes before merging. - branch: update-pricing-${{ github.run_number }} - delete-branch: true diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 065ce263..00000000 --- a/.gitignore +++ /dev/null @@ -1,254 +0,0 @@ -# Python -__pycache__/ -*.py[cod] -*$py.class -*.so -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# Virtual environments -venv/ -ENV/ -env/ -.venv - -# PyCharm -.idea/ - -# VS Code -.vscode/ - -# AI assistant tooling -.claude/ - -# Jupyter Notebook -.ipynb_checkpoints - -# pytest -.pytest_cache/ -.coverage -htmlcov/ - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Environments -.env -.env.local - -# macOS -.DS_Store - -# Logs -*.log - -# Database -*.db -*.sqlite3 - -# Temporary files -*.tmp -*.bak -*.swp -*~ -.tmp*/ -.tmp_* -tmp/ -.tmp*/ -.tmp_*/ - -# Bench & experiment outputs -benchmark_outputs/ -local_bench_outputs/ -local_bench_logs/ -runs/ - -# Model checkpoints and run logs -model_path/ -wandb/ -**/model_path/ -**/wandb/ - -# GraphRouter scratch -embergraphrouter/.venv/ -embergraphrouter/cache/ -embergraphrouter/model/ -embergraphrouter/model_path/ -embergraphrouter/embergraphrouter.egg-info/ - -# Scratch dirs created during agent runs -@tmp/ -tmp_ctx_test*/ -tmp_home/ - -# Package manager transcripts -=* - -# Local planning notes -docs/internal/ - -# Distribution / packaging -.Python -pip-wheel-metadata/ -share/python-wheels/ -*.manifest -*.spec - -# Unit test / coverage reports -coverage.xml -*.cover -.hypothesis/ -nosetests.xml - -# Translations -*.mo -*.pot - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Cython debug symbols -cython_debug/ - -# Deprecated code moved during cleanup -.deprecated/ - -# Documentation backup -.docs_backup/ - -# Backup and temporary files -.backup/ -*.backup -*_backup.py -*_refactored.py -diagnostic_*.json -test_diagnostics.log -test_*.md -*.orig - -# Ruff -.ruff_cache/ - -# # Ember gateway and Takumi (excluded from VCS) -# # Code paths intentionally not tracked in ember-v2 -# src/ember/gateway/ -# src/ember/models/providers/takumi.py -# src/ember/models/providers/takumi/ - -# tox -.tox/ - -# Coverage reports -.coverage.* -coverage/ - -# Credentials (just in case) -credentials.json -*.pem -*.key -*.crt - -# Local development -.local/ -local_tests/ - -# Generated files -*.generated.py - -# Poetry -poetry.lock - -# PDM -.pdm.toml -.pdm-python -__pypackages__/ -# Javascript -node_modules/ - -# Setup-wizard local artifacts -src/ember/cli/setup-wizard/hello_ember*.py - -# Large dataset snapshots -embergraphrouter/data/router_data.csv - -# Large router data files (CSV datasets) -embergraphrouter/data/*.csv -embergraphrouter/data/*.csv.gz -embergraphrouter/data/.router_cache/ -embergraphrouter/data/.router_cache_backup_*/ - -# GraphRouter datasets and checkpoints (download separately) -embergraphrouter/data/** -!embergraphrouter/data/README.md -embergraphrouter/configs/*.pkl -embergraphrouter/configs/config_local.yaml -embergraphrouter_full.tar.gz -embergraphrouter/model_path_eval/ -embergraphrouter/model_path_baseline/ -embergraphrouter/remote_backup_*/ - -# Model checkpoints (weights) -*.pt -*.pth -model_weights/ - -# Archives -*.tar.gz - -# Additional venvs and caches -.venv311/ -.uv-cache/ - -# Calibration outputs -calibration/ -calibration_derived/ -calibration_ensemble/ - -# Run outputs -runs/ -snapshots/ - -# Third-party clones -third_party/ - -# Misc large/generated files -.cache/ -.flowignore - -# Debug and scratch scripts -debug_*.py -inspect_*.py -verify_*.py -reproduce_*.py - -# Analysis outputs and temp files -response.json -*_results.json -task.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index b5e1d811..00000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -repos: - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.5.7 - hooks: - - id: ruff - args: ["--fix"] - - id: ruff-format - - - repo: https://github.com/psf/black - rev: 24.10.0 - hooks: - - id: black - - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.10.0 - hooks: - - id: mypy - args: ["--python-version=3.11"] diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index b1148d22..4424dc13 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,452 +1,978 @@ # Ember Architecture +This document describes Ember's architecture, core components, and design principles. It serves as both a high-level overview for users and a detailed guide for core contributors. + ## Design Philosophy -Ember follows three core principles: +Ember is built on these foundational principles: -1. **Simple by Default** - Zero configuration, direct function calls, no boilerplate -2. **Progressive Disclosure** - Advanced features available when needed, hidden when not -3. **10x Performance** - Automatic optimization without manual tuning +1. **Composability First**: The ability to combine, chain, and nest components (e.g. `Operator` components) is central to Ember's design +2. **Type Safety**: Comprehensive type annotations ensure robustness and IDE support +3. **Testability**: Components are designed with SOLID principles in mind, for easy isolation and testing +4. **Scalability**: support for Parallel execution is built-in at the framework's core. This is more Tensorflow/JAX, than classic Torch spiritually +5. **Extensibility**: Registry-based design makes it simple to add new components +6. **Skeurmophism**: APIs follow familiar patterns from PyTorch/JAX, to somewhat control the learning curve +7. **Simple-over-easy**: Minimal "magic" and a focus on explicitness -## System Overview +## System Architecture +Ember's architecture follows a layered design with clear separations of concern: ``` -┌────────────────────────────────────────────────────────────┐ -│ PUBLIC API │ -├─────────────────┬─────────────────┬────────────────────────┤ -│ models() │ operators() │ data.stream() │ -│ Direct LLM API │ Composable AI │ Streaming Data │ -└────────┬────────┴────────┬────────┴───────┬────────────────┘ - │ │ │ -┌────────▼────────┬────────▼────────┬───────▼───────────────┐ -│ Model Registry │ Operator System │ Data Pipeline │ -│ │ │ │ -│ • Provider │ • Composition │ • Loaders │ -│ Resolution │ • Validation │ • Transformers │ -│ • Cost Tracking│ • JAX Pytrees │ • Samplers │ -└────────┬────────┴────────┬────────┴───────┬───────────────┘ - │ │ │ -┌────────▼─────────────────▼────────────────▼─────────────────┐ -│ XCS ENGINE │ -│ │ -│ • Automatic JIT Compilation │ -│ • Parallelism Detection │ -│ • Execution Optimization │ -└─────────────────────────────────────────────────────────────┘ +┌───────────────────────────────────────────────────────────────────────────────────────────┐ +│ PUBLIC API LAYER │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ api.models │ │ api.operator │ │ api.xcs │ │ +│ │ │ │ │ │ │ │ +│ │ • LLM Interfaces │ │ • Operator Base │ │ • JIT Functions │ │ +│ │ • Model Service │ │ • Specification │ │ • Execution Options │ │ +│ │ • Model Registry │ │ • Input/Output Models │ │ • Graph Controls │ │ +│ │ • Usage Tracking │ │ • Operator Registry │ │ • Transform Functions │ │ +│ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ api.data │ │ api.non │ │ +│ │ │ │ │ │ +│ │ • Dataset Access │ │ • Ensemble Patterns │ │ +│ │ • Data Loaders │ │ • Verification │ │ +│ │ • Transformers │ │ • Synthesis │ │ +│ │ • Evaluators │ │ • Composition Helpers │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ APPLICATION LAYER │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ NON Patterns │ │ Auto Graph Builder │ │ Enhanced JIT │ │ +│ │ │ │ │ │ │ │ +│ │ • UniformEnsemble │ │ • Autograph │ │ • Function Tracing │ │ +│ │ • JudgeSynthesis │ │ • IR Graph Construct │ │ • Optimized Execution │ │ +│ │ • Verifier │ │ • Dependency Tracking │ │ • Parallel Dispatch │ │ +│ │ • VariedEnsemble │ │ • Visualization │ │ │ │ +│ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ CORE COMPONENT LAYER │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ Model Registry │ │ Operator System │ │ Prompt Specifications │ │ +│ │ │ │ │ │ │ │ +│ │ • ModelInfo │ │ • Base Operator │ │ • Template Rendering │ │ +│ │ • ModelService │ │ • Operator Registry │ │ • Input Validation │ │ +│ │ • UsageService │ │ • Core Operators │ │ • Output Validation │ │ +│ │ • Provider Adapters │ │ • Custom Operators │ │ • Schema Generation │ │ +│ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ Data Processing │ │ Evaluation Tools │ │ Application Context │ │ +│ │ │ │ │ │ │ │ +│ │ • Dataset Loaders │ │ • Evaluators │ │ • Config Manager │ │ +│ │ • Transformers │ │ • Metrics │ │ • Dependency Injection │ │ +│ │ • Samplers │ │ • Result Analysis │ │ • Service Registry │ │ +│ │ • Dataset Registry │ │ • Visualization │ │ • Logging Config │ │ +│ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ EXECUTION ENGINE (XCS) │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ Graph Definition │ │ Tracer System │ │ Execution Engine │ │ +│ │ │ │ │ │ │ │ +│ │ • XCSGraph IR │ │ • Function Tracing │ │ • Schedulers │ │ +│ │ • XCSNode Primitive │ │ • Execution Recording │ │ • Execution Plan │ │ +│ │ │ │ • JIT Compilation │ │ • Parallel Dispatch │ │ +│ │ │ │ • Graph Optimization │ │ │ │ +│ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +└───────────────────────────────────────────────────────────────────────────────────────────┘ ``` -### CLI System Integration +## Layer Responsibilities -The CLI provides comprehensive management and introspection capabilities: +### 1. Execution Engine (XCS) -```bash -# Interactive setup with provider selection -ember setup # Launches React-based wizard +The foundational layer providing computation graph definition and execution: -# Configuration management -ember configure get KEY # Get config value -ember configure set KEY VALUE # Set config value -ember configure list # Show all config -ember configure show SECTION # Show section +* **Graph Definition**: Defines the structure of computation +* **Tracer System**: Records execution and enables optimization +* **Execution Engine**: Manages the actual running of operations with parallelization -# Context introspection -ember context view # View resolved configuration -ember context view --format json # Output as JSON -ember context view --filter models # Filter to specific path -ember context validate # Validate configuration +### 2. Core Component Layer -# Registry introspection -ember registry list-models # List available models -ember registry list-models --provider openai # Filter by provider -ember registry list-models --verbose # Detailed information -ember registry list-providers # Show provider status -ember registry info gpt-4 # Detailed model info +The building blocks of Ember's functionality: -# Testing and discovery -ember test [--model MODEL] # Test connection -``` +* **Model Registry**: Management of LLM providers and models +* **Operator System**: Core computational units and their registry +* **Prompt Specifications**: Type-safe template rendering and validation +* **Data Processing**: Dataset handling, transformation, and sampling +* **Evaluation Tools**: Benchmarking and performance analysis +* **Application Context**: Configuration and dependency management -The setup wizard (`@ember-ai/setup`) features: -- React/Ink-based interactive UI -- Provider-specific API key validation -- Automatic configuration file creation -- Integration with EmberContext for credential storage +### 3. Application Layer -## Core Components +High-level abstractions built on the core components: -### 1. Context System +* **NON Patterns**: Ready-to-use Networks of Networks patterns +* **Auto Graph Builder**: Automatic graph construction from code +* **Enhanced JIT**: Just-in-time compilation for optimized execution -Centralized configuration and credential management with thread-safe and async-safe isolation. +## Component Details -The context system provides a simplified, unified API following the principle of "one obvious way": +### Application Context + +The `EmberAppContext` serves as the central dependency injection container: ```python -from ember import context +from ember.core.app_context import get_app_context -# Primary API - simple and clear -ctx = context.get() # Get current context (creates if needed) +# Access global context +context = get_app_context() -# Context manager for temporary overrides -with context.manager(models={"default": "gpt-4", "temperature": 0.9}) as ctx: - # All operations in this block use these settings - response = models("Hello") # Uses gpt-4 with temperature 0.9 - -# Original context automatically restored +# Access services +model_service = context.model_service +usage_service = context.usage_service + +# Access configuration via standardized manager +config_manager = context.config_manager +model_registry_config = config_manager.get_config("model_registry") +app_config = config_manager.get_config("app") + +# Configuration values are accessed via dot notation +api_key = model_registry_config.providers.openai.api_key +``` + +Key responsibilities: +- Initialization and configuration of system components +- Service registration and dependency injection +- Standardized configuration management with schema validation +- Environment variable resolution and config merging +- Logging setup -# Direct configuration access -from ember.context import get_config, set_config -default_model = get_config("models.default", "gpt-3.5-turbo") -set_config("models.temperature", 0.7) +### Model Registry System + +The Model Registry manages connections to LLM providers: + +```python +# Using the simplified API +from ember.api.models import ModelRegistry, ModelInfo, ModelService + +# Register a model +registry = ModelRegistry() +registry.register_model(ModelInfo(id="openai:gpt-4o", ...)) + +# Create a service for model access +service = ModelService(registry=registry) +response = service.invoke_model("openai:gpt-4o", "Hello world") + +# Even simpler with automatic initialization +from ember import initialize_ember + +# Initialize and get the service in one step +service = initialize_ember() +response = service("anthropic:claude-3-sonnet", "Hello Claude") ``` -**Key Features:** -- **Thread-safe and async-safe**: Context propagates correctly across boundaries -- **Hierarchical configuration**: Child contexts inherit from parents -- **Multiple credential sources**: Runtime > Environment > Config file > Defaults -- **Clean scoping**: Context managers ensure proper cleanup +#### Model Registry Component Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Model Registry System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ ModelRegistry │◄────►│ ModelFactory │─────►│ Provider Models │ │ +│ └────────┬────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ │ +│ │ ┌─────────────────┐ ┌─────────────────┐ │ +│ └──────────────►│ ModelService │◄────►│ UsageService │ │ +│ └─────────────────┘ └─────────────────┘ │ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ OpenAI Provider │ │Anthropic Provid.│ │ Other Providers │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` -**Configuration Priority:** -1. Runtime context (highest) -2. Environment variables -3. ~/.ember/config.yaml -4. Internal defaults (lowest) +Key components: +- `ModelRegistry`: Central repository for model metadata +- `ModelService`: High-level API for model invocation +- `UsageService`: Tracks token usage and cost +- Provider implementations: OpenAI, Anthropic, Google, IBM, etc. -**Async Context Propagation:** +### Operator System -The context system uses Python's `contextvars` for proper async isolation: +Operators are the fundamental computational units in Ember: ```python -import asyncio -from ember.context import get_context, create_context - -async def process_with_model(text: str) -> str: - # Context automatically propagates across async boundaries - ctx = get_context() # Gets the correct context - model = ctx.get_config("models.default") - print(f"Task {asyncio.current_task().get_name()}: Using {model}") - - # Context remains isolated even with concurrent execution - await asyncio.sleep(0.1) - return f"Processed '{text}' with {model}" - -async def main(): - # Each task gets its own isolated context - async def task_with_context(name: str, model: str, text: str): - with create_context(models={"default": model}): - return await process_with_model(text) +from ember.api.operators import Operator, Specification, EmberModel + +class SummarizerInput(EmberModel): + text: str + max_words: int = 100 + +class SummarizerOutput(EmberModel): + summary: str + word_count: int + +class SummarizerSpec(Specification): + input_model = SummarizerInput + structured_output = SummarizerOutput + prompt_template = "Summarize the following text in {max_words} words or less:\n\n{text}" + +class SummarizerOperator(Operator[SummarizerInput, SummarizerOutput]): + specification = SummarizerSpec() - # Run tasks concurrently with different contexts - results = await asyncio.gather( - task_with_context("task1", "gpt-4", "Hello"), - task_with_context("task2", "claude-3-opus", "World"), - task_with_context("task3", "gemini-1.5-pro-latest", "Async"), - ) + def forward(self, *, inputs: SummarizerInput) -> SummarizerOutput: + # Implementation + ... +``` + +#### Operator System Component Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Operator System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │OperatorRegistry │◄────►│OperatorFactory │─────►│Operator Instance│ │ +│ └─────────────────┘ └─────────────────┘ └────────┬────────┘ │ +│ │ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌────────▼────────┐ │ +│ │ Base Operator │◄─────┤Prompt Spec. │◄───► │ forward() │ | +│ └────────┬────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Core Operators │ │ Custom Operators │ │ NON Operators │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +Key components: +- `Operator`: Base class for all operators +- `Specification`: Type definitions for operator I/O +- Core operators: Ensemble, Judge, Verifier, etc. +- Operator registry for discovery + +### Prompt Specification System + +Specifications define the contract between inputs and outputs: + +```python +from ember.api.operators import Specification, EmberModel + +class QuestionInput(EmberModel): + question: str + context: str + +class AnswerOutput(EmberModel): + answer: str + confidence: float + +class QASpecification(Specification): + input_model = QuestionInput + structured_output = AnswerOutput + prompt_template = """ + Answer the question based on the context. - for result in results: - print(result) - # Output: - # Task task-1: Using gpt-4 - # Task task-2: Using claude-3-opus - # Task task-3: Using gemini-1.5-pro-latest - # Processed 'Hello' with gpt-4 - # Processed 'World' with claude-3-opus - # Processed 'Async' with gemini-1.5-pro-latest + Context: {context} + Question: {question} + """ +``` + +#### Prompt Specification Component Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Prompt Specification System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Specification │──────┤ Input Model │ │ Output Model │ │ +│ └────────┬────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │Prompt Template │─────►│Template Renderer│─────►│ Input Val. │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │Schema Generation│◄─────┤Output Validation│◄─────┤ Error Handl. │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ ``` -**Thread-Safe Context Usage:** +Key features: +- Type validation for inputs and outputs +- Template rendering with validation +- Automatic placeholder checking +- Support for structured data extraction -The context system uses thread-local storage with proper locking: +### Execution Engine (XCS) + +XCS handles graph-based execution: ```python -import threading -from ember.context import get_context, create_context +from ember.xcs import XCSGraph, execute_graph, execution_options + +# Create execution graph +graph = XCSGraph() +graph.add_node(operator=ensemble, node_id="ensemble") +graph.add_node(operator=judge, node_id="judge") +graph.add_edge(from_id="ensemble", to_id="judge") + +# Execute with parallelization +with execution_options(scheduler="wave", max_workers=4): + result = execute_graph( + graph=graph, + inputs={"query": "What is quantum computing?"} + ) +``` + +#### XCS Engine Component Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Execution Engine (XCS) │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ XCSGraph │─────►│ XCSNode │◄─────┤ Edge │ │ +│ └────────┬────────┘ └────────┬────────┘ └─────────────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Graph Compiler │─────►│ Execution Plan │─────►│ Scheduler │ │ +│ └─────────────────┘ └────────┬────────┘ └────────┬────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Input Mapping │◄─────┤ Parallel Worker │◄─────┤Output Collection│ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +Key components: +- `XCSGraph`: Directed acyclic graph representation +- `ExecutionPlan`: Compiled execution plan +- `Scheduler`: Controls execution strategy +- `Tracer`: Records execution for debugging + +### Enhanced JIT System + +Ember provides three complementary approaches to Just-In-Time optimization: + +#### JIT Strategy Pattern -def worker(name: str, model: str): - # Each thread gets isolated context - with create_context(models={"default": model}): - ctx = get_context() - print(f"{name}: Using {ctx.get_config('models.default')}") - # Do work with thread-local model +The `jit` decorator now uses a pluggable strategy pattern with multiple implementations: -# Launch workers with different models -threads = [ - threading.Thread(target=worker, args=("Worker1", "gpt-4")), - threading.Thread(target=worker, args=("Worker2", "claude-3")), -] -for t in threads: - t.start() -for t in threads: - t.join() +```python +from ember.xcs import jit, JITMode +from ember.api.operators import Operator +from ember.api import non + +# With automatic strategy selection +@jit +class MyEnsemble(Operator): + def forward(self, *, inputs): + # Complex computation automatically traced and optimized + ensemble = non.UniformEnsemble(num_units=3, model_name="openai:gpt-4o") + responses = ensemble(inputs={"query": inputs.query}) + return responses + +# With explicit strategy selection +@jit(mode=JITMode.ENHANCED) +class Pipeline(Operator): + def __init__(self): + self.refiner = QuestionRefinement() + self.ensemble = Ensemble() + self.aggregator = MostCommon() + + def forward(self, *, inputs): + refined = self.refiner(inputs=inputs) + answers = self.ensemble(inputs=refined) + return self.aggregator(inputs=answers) ``` -**Configuration Management:** +The JIT system now supports three strategies: + +1. **Trace Strategy** (`JITMode.TRACE`): Traditional execution tracing for dynamic flows +2. **Structural Strategy** (`JITMode.STRUCTURAL`): Analyzes operator structure without requiring execution +3. **Enhanced Strategy** (`JITMode.ENHANCED`): Combines static and dynamic analysis for optimal parallelization + +#### Autograph Context Manager + +For explicit graph construction: ```python -from ember.context import get_context, with_context -from ember.api import models - -# Get and modify configuration -ctx = get_context() -ctx.set_config("models.temperature", 0.7) -ctx.save() # Persist to disk - -# Temporary configuration overrides -with with_context(models={"temperature": 0.9, "max_tokens": 2000}): - # This block uses high temperature and more tokens - response = models("gpt-4", "Write a creative story") +from ember.xcs import autograph, execute_graph, execution_options + +with autograph() as graph: + intermediate = op1(inputs={"query": "Example"}) + result = op2(inputs=intermediate) -# Back to original settings -response = models("gpt-4", "Summarize this document") # Uses temperature=0.7 +# Execute the graph with optimized scheduling +results = execute_graph( + graph=graph, + options=execution_options(scheduler="wave", max_workers=4) +) +``` + +#### Unified JIT System Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Unified JIT System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ JIT Decorator │─────►│Strategy Selector│─────►│ JIT Cache │ │ +│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Trace Strategy │─────►│ Structural Strat│─────►│Enhanced Strategy│ │ +│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Autograph │─────►│Graph Dependency │─────►│ Unified Engine │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ ``` -### 2. Credential Management +Key features: +- Unified strategy pattern with pluggable implementations: + - `trace`: Optimized for dynamic execution patterns + - `structural`: Static analysis of operator composition + - `enhanced`: Combines static and dynamic analysis for optimal parallelism +- Automatic strategy selection based on operator characteristics +- Consistent caching mechanism across all strategies +- Advanced dependency analysis with wave-based scheduling +- Transformation composition for complex optimizations +- Comprehensive metrics and introspection tools -The context system provides secure, hierarchical credential management: +For a comprehensive explanation of the JIT system, see [JIT Overview](docs/xcs/JIT_OVERVIEW.md). + +### Function Transformation System + +The transformation system provides high-level operations for data and computation transformations: ```python -from ember import context +from ember.xcs import vmap, pmap, compose, DeviceMesh, PartitionSpec, mesh_sharded + +# Vectorized mapping for batch processing +batch_processor = vmap(process_item) +batch_results = batch_processor(inputs={"data": [item1, item2, item3]}) + +# Parallel execution across multiple workers +parallel_processor = pmap(process_item, num_workers=4) +parallel_results = parallel_processor(inputs=complex_data) + +# Combine transformations for complex pipelines +pipeline = compose( + vmap(batch_size=32), + pmap(num_workers=4) +)(process_item) + +# Device mesh sharding for multi-device execution +mesh = DeviceMesh(devices=["gpu:0", "gpu:1", "gpu:2", "gpu:3"], mesh_shape=(2, 2)) +partition = PartitionSpec("batch", "model") +sharded_op = mesh_sharded(pipeline, mesh=mesh, partition_spec=partition) +``` + +#### Transform System Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Transform System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │BaseTransformation│─────►│TransformProtocol│─────►│ BatchingOptions │ │ +│ └────────┬────────┘ └─────────────────┘ └────────┬────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ vmap │─────►│ pmap │─────►│ParallelOptions │ │ +│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ mesh_sharded │─────►│ compose │─────►│ Unified JIT │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` -ctx = context.get() +Key features: +- Common base class (`BaseTransformation`) with consistent interface +- Compositional design for combining transformations +- Integration with the JIT system for optimized execution +- Support for both data parallelism and model parallelism +- Extensible design for custom transformations -# Credential lookup hierarchy (first found wins): -# 1. Runtime context credentials -# 2. Environment variables (OPENAI_API_KEY, etc.) -# 3. Config file (~/.ember/config.yaml) -# 4. Separate credentials file (~/.ember/credentials.yaml) +### Data Processing System -# Get credential with fallback chain -api_key = ctx.get_credential("openai", "OPENAI_API_KEY") +The data module provides tools for dataset management: -# Set credentials at runtime (not persisted) -with context.manager(credentials={"openai_api_key": "sk-temp-key"}): - # This block uses the temporary key - response = models("gpt-4", "Hello") +```python +from ember.core.utils.data.service import DataService +from ember.core.utils.data.base.samplers import RandomSampler + +# Load a benchmark dataset +data_service = DataService() +mmlu_data = data_service.load_dataset( + dataset_name="mmlu", + subset="high_school_mathematics", + sampler=RandomSampler(n=100) +) +``` -# Persist credentials securely -ctx.set_config("credentials.openai_api_key", "sk-prod-key") -ctx.save() # Saves to ~/.ember/config.yaml with proper permissions +#### Data Processing Component Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Data Processing System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ DataService │─────►│ Dataset Reg. │─────►│ Dataset Loaders │ │ +│ └────────┬────────┘ └─────────────────┘ └────────┬────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Dataset Cache │◄─────┤ Dataset Item │◄─────┤ External API │ │ +│ └─────────────────┘ └────────┬────────┘ └─────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Data Transformer│◄─────┤ Data Sampler │─────►│ Data Validator │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ ``` -**Security Features:** -- Credentials never logged or displayed in errors -- Config files created with 0600 permissions (user-only read/write) -- Support for credential rotation without code changes -- Clear error messages that don't expose sensitive data +Key components: +- `DataService`: Central access point for datasets +- Dataset loaders for popular benchmarks +- Transformers for data preprocessing +- Samplers for dataset subsampling -### 3. Models API +### Evaluation System -Direct LLM invocation without client initialization: +The evaluation system measures model performance: ```python -# Simple case - no setup required -response = models("gpt-4", "Hello world") +from ember.core.utils.eval.pipeline import EvaluationPipeline +from ember.core.utils.eval.evaluators import MultipleChoiceEvaluator + +# Create evaluation pipeline +eval_pipeline = EvaluationPipeline( + dataset=test_data, + evaluators=[MultipleChoiceEvaluator()], + model=model +) + +# Run evaluation +results = eval_pipeline.evaluate() +print(f"Accuracy: {results.metrics['accuracy']:.2f}") +``` -# Advanced case - reusable configuration -gpt4 = models.instance("gpt-4", temperature=0.7) +#### Evaluation Component Architecture ``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Evaluation System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Eval Pipeline │─────►│ Eval Registry │─────►│ Evaluator │ │ +│ └────────┬────────┘ └─────────────────┘ └────────┬────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Data Provider │─────►│ Model Runner │─────►│ Result Collector│ │ +│ └─────────────────┘ └─────────────────┘ └────────┬────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │Metric Calculator│◄─────┤ Result Analyzer │◄─────┤ Report Generator│ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +Key components: +- `EvaluationPipeline`: Orchestrates evaluation +- Task-specific evaluators +- Metrics collection +- Result reporting -**Design Decisions:** -- Registry pattern for provider management -- Lazy initialization for fast startup -- Integrated cost and usage tracking -- Thread-safe singleton implementation +## Full System Dependency Flow + +The diagram below illustrates the complete dependency flow between major components: + +``` +┌───────────────────────────────────────────────────────────────────────────────────────────┐ +│ Configuration Layer │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ Config Files │────►│ Config Manager │────►│ Environment │ │ +│ │ (.yaml, .env) │ │ │ │ Variables │ │ +│ └─────────────────────────┘ └───────────┬─────────────┘ └─────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────┐ │ +│ │ EmberAppContext │ │ +│ └───────────┬─────────────┘ │ +│ │ │ +└─────────────────────────────────────────────┼─────────────────────────────────────────────┘ + │ + ▼ +┌───────────────────────────────────────────────────────────────────────────────────────────┐ +│ Service Layer │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ Model Registry │◄───►│ Model Service │◄───►│ Usage Service │ │ +│ └───────────┬─────────────┘ └───────────┬─────────────┘ └─────────────────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ Provider Models │◄───►│ Operator Registry │◄───►│ Data Service │ │ +│ └─────────────────────────┘ └───────────┬─────────────┘ └───────────┬─────────┘ │ +│ │ │ │ +└────────────────────────────────-─────────────┼───────────────────────────────┼─────────────┘ + │ │ + ▼ ▼ +┌───────────────────────────────────────────────────────────────────────────────────────────┐ +│ Component Layer │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ Base Operators │◄───►│ Prompt Specifications│◄───►│ Dataset Loaders │ │ +│ └───────────┬─────────────┘ └─────────────────────────┘ └─────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ Core Operators │◄───►│ NON Patterns │◄───►│ Evaluators │ │ +│ └───────────┬─────────────┘ └───────────┬─────────────┘ └─────────────────────┘ │ +│ │ │ │ +└─────-────────┼───────────────────────────────┼────────────────────────────────────────────┘ + │ │ + ▼ ▼ +┌───────────────────────────────────────────────────────────────────────────────────────────┐ +│ Execution Engine Layer │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ XCSGraph │◄───►│ Graph Compiler │◄───►│ JIT Compiler │ │ +│ └───────────┬─────────────┘ └───────────┬─────────────┘ └───────────┬─────────┘ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ Execution Plan │◄───►│ Scheduler │◄───►│ Parallel Executor │ │ +│ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────┘ │ +│ │ +└───────────────────────────────────────────────────────────────────────────────────────────┘ +``` -### 2. Operators System +## Configuration System -Composable building blocks for AI applications: +Ember's configuration system provides a standardized way to configure all aspects of the framework: ```python -# Function decorator approach -@operators.op -def summarize(text: str) -> str: - return models("gpt-4", f"Summarize: {text}") +from ember.core.configs import ConfigManager, create_config_manager + +# Create configuration manager with standard discovery +config_manager = create_config_manager() + +# Access typed, validated configuration +model_registry_config = config_manager.get_config("model_registry") +openai_api_key = model_registry_config.providers.openai.api_key + +# Configuration sources (in order of precedence): +# 1. Runtime overrides +# 2. Environment variables +# 3. User config files (~/.ember/config.yaml) +# 4. Project config files (./ember.yaml) +# 5. Default config (package defaults) + +# Modify configuration at runtime +config_manager.update_config( + "model_registry", + {"providers": {"openai": {"api_key": "new-key"}}} +) +``` + +Key features: +- Centralized schema-based configuration with Pydantic +- Multiple configuration sources with priority ordering +- Environment variable expansion (${VAR_NAME} syntax) +- Deep config merging with proper override behavior +- Thread-safe configuration access +- Extensible provider system + +## Code Organization + +The code is organized into the following package structure: + +| Package | Purpose | +|---------|---------| +| `ember.api` | Simplified public API for clean imports | +| `ember.api.models` | Models API for LLMs and providers | +| `ember.api.operator` | Operator API for computational units | +| `ember.api.non` | NON patterns API | +| `ember.api.xcs` | Execution engine API | +| `ember.api.data` | Data processing API | +| `ember.core` | Core framework classes and utilities | +| `ember.core.app_context` | Application context and DI container | +| `ember.core.configs` | Standardized configuration system with typed schema validation | +| `ember.core.types` | Type system, protocols, and validation | +| `ember.core.registry.model` | Model registry and provider implementations | +| `ember.core.registry.operator` | Operator system | +| `ember.core.registry.specification` | Prompt specification system | +| `ember.core.utils` | Utility functions and helpers | +| `ember.core.utils.data` | Data processing and datasets | +| `ember.core.utils.eval` | Evaluation and metrics | +| `ember.core.non` | High-level NON patterns | +| `ember.xcs` | Execution engine | +| `ember.xcs.graph` | Graph definition and manipulation | +| `ember.xcs.engine` | Execution scheduling | +| `ember.xcs.tracer` | Tracing and JIT compilation | + +## Import System + +Ember organizes imports through the `ember.api` namespace: -# Class-based with validation -class ValidatedOp(Operator): - input_spec = InputModel - output_spec = OutputModel +```python +from ember.api.operators import Operator, Specification, EmberModel +from ember.xcs import jit, execution_options +from ember.api import models, non +from ember.api.data import DataLoader ``` -**Design Decisions:** -- JAX pytree compatibility for automatic differentiation -- Optional but powerful validation system -- Composition over inheritance -- Zero overhead when validation not used +This approach: +- Separates public API from internal implementation details +- Maintains backward compatibility during internal refactoring +- Follows conventions from our favorite, established frameworks + +## Design Patterns -### 3. Data Pipeline +Ember employs several design patterns that are consistent throughout the codebase: + +### 1. Registry Pattern + +```python +# Registry implementation +class ModelRegistry: + def __init__(self): + self._models = {} + + def register_model(self, model_info: ModelInfo) -> None: + self._models[model_info.id] = model_info + + def get_model_info(self, model_id: str) -> ModelInfo: + return self._models[model_id] + +# Usage +registry = ModelRegistry() +registry.register_model(ModelInfo(id="model1", ...)) +model = registry.get_model_info("model1") +``` -Streaming-first data loading with progressive enhancement: +### 2. Factory Pattern ```python -# Basic streaming -for item in stream("dataset"): - process(item) +class ModelFactory: + def create_model(self, model_info: ModelInfo) -> BaseProviderModel: + provider_name = model_info.provider["name"] + if provider_name == "OpenAI": + return OpenAIModel(model_info) + elif provider_name == "Anthropic": + return AnthropicModel(model_info) + # etc. +``` + +### 3. Dependency Injection -# Chained transformations -stream("dataset").filter(valid).transform(clean).batch(32) +```python +class ModelService: + def __init__(self, registry: ModelRegistry, usage_service: Optional[UsageService] = None): + self.registry = registry + self.usage_service = usage_service ``` -**Design Decisions:** -- Memory-efficient streaming by default -- Explicit materialization when needed -- Protocol-based extensibility -- Built-in caching layer +### 4. Composition Pattern -### 4. XCS Execution Engine +```python +class EnsembleOperator(Operator[EnsembleInput, EnsembleOutput]): + def __init__(self, lm_modules: List[LMModule]): + self.lm_modules = lm_modules + + def forward(self, *, inputs: EnsembleInput) -> EnsembleOutput: + # Use contained modules + responses = [lm(inputs.query) for lm in self.lm_modules] + return EnsembleOutput(responses=responses) +``` -Zero-configuration optimization: +### 5. Strategy Pattern ```python -@xcs.jit -def complex_workflow(data): - # Automatically optimized - return pipeline(data) - -# Automatic parallelization -results = xcs.vmap(process)(batch) -``` - -**Design Decisions:** -- Tracing-based optimization -- Automatic strategy selection -- JAX backend for numerical operations -- Orchestration for I/O-bound tasks - -## Key Design Patterns - -### Registry Pattern -Single source of truth for each resource type: -- `ModelRegistry` - LLM provider management -- `DataRegistry` - Dataset loader management -- Thread-safe with proven single-lock approach - -### Module System -JAX-compatible base class for all operators: -- Automatic parameter detection -- Pytree registration -- Clean composition semantics - -### Progressive Disclosure -Three levels of API complexity: -1. **Simple Functions** - Direct calls for basic use -2. **Decorators** - Enhancement without boilerplate -3. **Classes** - Full control when needed - -### Type-Driven Development -Optional but powerful when used: -- Pydantic models for validation -- Type hints guide system behavior -- Runtime validation from static types - -## Performance Architecture - -### JIT Compilation Strategy -1. Function decorated with `@jit` -2. First call traces execution -3. IR built from trace -4. Optimal backend selected: - - JAX for numerical operations - - Async orchestration for I/O -5. Subsequent calls use compiled version - -### Parallelization Detection -- Automatic detection of map operations -- Data dependency analysis -- Optimal chunking for throughput -- Zero configuration required +class Scheduler(Protocol): + def run_plan(self, plan: ExecutionPlan, global_input: Dict, graph: XCSGraph) -> Any: + ... + +class SerialScheduler: + def run_plan(self, plan: ExecutionPlan, global_input: Dict, graph: XCSGraph) -> Any: + # Serial execution implementation + +class ParallelScheduler: + def run_plan(self, plan: ExecutionPlan, global_input: Dict, graph: XCSGraph) -> Any: + # Parallel execution implementation +``` + +## Performance Considerations + +Ember balances ease of use with high performance: + +### Parallelization Strategy + +1. **Graph-Based Parallelism**: + - The XCS engine automatically identifies independent operations + - Executes them concurrently using thread pools + - Configurable max_workers parameter + +2. **Operator-Level Concurrency**: + - Operators can implement their own internal parallelism + - Example: EnsembleOperator runs multiple models concurrently + +3. **Efficient Resource Usage**: + - Smart thread pooling to avoid over-subscription + - Rate limiting to respect API constraints ### Memory Management -- Streaming by default for data -- Lazy evaluation where possible -- Explicit materialization points -- Automatic garbage collection hints - -## Extension Points - -### Adding Providers -1. Implement `BaseProvider` interface -2. Register with `ModelRegistry` -3. No core changes required - -### Custom Operators -1. Inherit from `Operator` base -2. Define `call()` method -3. Optional validation specs -4. Automatic JAX integration - -### Data Loaders -1. Implement loader protocol -2. Register with `DataRegistry` -3. Streaming support automatic - -## Testing Strategy - -### Unit Tests -- Isolated component testing -- Minimal test doubles -- Type testing utilities - -### Integration Tests -- Cross-module interactions -- Real provider testing -- Performance benchmarks - -### Test Patterns -- Helper modules for common setups -- Simplified imports for isolation -- Comprehensive coverage tracking - -## Security Considerations - -### API Key Management -- Environment variable loading -- No keys in code -- Secure defaults - -### Input Validation -- Optional but recommended -- Pydantic integration -- Type-safe boundaries - -### Rate Limiting -- Provider-level handling -- Automatic retry logic -- Exponential backoff - -## Future Architecture - -### Planned Enhancements -1. **Distributed Execution** - Multi-node XCS -2. **Model Quantization** - Automatic optimization -3. **Streaming Inference** - Token-level streaming -4. **Edge Deployment** - Browser/mobile runtime - -### Design Principles Maintained -- Simple API remains simple -- Advanced features stay optional -- Performance improvements automatic -- Backward compatibility preserved - -## Architecture Decision Records - -### ADR-001: Direct Instantiation -**Decision**: Use direct function calls instead of dependency injection -**Rationale**: Eliminates boilerplate, improves discoverability -**Consequences**: Simpler API, easier testing, less flexibility - -### ADR-002: Registry Pattern -**Decision**: Single registry per resource type -**Rationale**: Clear ownership, thread-safe, extensible -**Consequences**: Centralized management, potential bottleneck - -### ADR-003: JAX Integration -**Decision**: Base operators on JAX pytrees -**Rationale**: Automatic differentiation, JIT compilation -**Consequences**: Power user features, slight complexity - -### ADR-004: Streaming First -**Decision**: Default to streaming for data operations -**Rationale**: Memory efficiency, scalability -**Consequences**: Explicit materialization needed sometimes - -This architecture embodies the principles of simplicity, performance, and extensibility that guide Ember's development. + +1. **Lazy Instantiation**: + - Models are instantiated only when needed + - Heavy resources are loaded on demand + +2. **Caching Strategy**: + - Configuration is cached after initial load + - Discovery results are cached + - Model instances are reused + +### Optimization Techniques + +1. **JIT Compilation**: + - Traces function execution to build optimized graphs + - Identifies parallelizable operations + - Minimizes redundant computations + +2. **Efficient Data Transfer**: + - Minimizes copying of large data between operators + - Uses references when possible + +## Deployment Considerations + +When deploying Ember in production, consider these best practices: + +### 1. Configuration Management + +- Store API keys securely in environment variables +- Use separate configurations for development/production +- Override defaults with environment-specific settings + +``` +# Development configuration +config/ + base.yaml # Base configuration for all environments + development.yaml # Development-specific overrides + production.yaml # Production-specific overrides +``` + +### 2. Resource Planning + +- Set appropriate thread pool sizes (max_workers) +- Monitor token usage with UsageService +- Implement rate limiting strategies +- Set up cost budgets and alerts + +### 3. Error Handling + +- Implement proper error handling at the application level +- Set up exponential backoff for API rate limits +- Use the retry utilities for transient errors +- Log errors comprehensively + +### 4. Monitoring and Observability + +- Set up proper logging with appropriate log levels +- Monitor token and request metrics +- Track performance of individual operators +- Set alerts for abnormal behavior + +### 5. Scaling Strategies + +For high-throughput applications: +- Distribute workloads across multiple processes or machines +- Use horizontal scaling for independent operations +- Consider specialized execution engines for very large workloads +- Use caching for frequently used models or operations + +## Request Flow Diagram + +The following diagram illustrates the flow of a typical request through the Ember system: + +``` +┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ +│ │ │ │ │ │ │ │ +│ User API │─────►│ ModelService │─────►│ ModelRegistry│─────►│ ModelFactory │ +│ Request │ │ │ │ │ │ │ +└──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ + │ │ │ │ + │ │ │ ▼ + │ │ │ ┌──────────────┐ + │ │ │ │ │ + │ │ └─────────────►│ Provider │ + │ │ │ Impl. │ + │ │ └──────┬───────┘ + │ │ │ + │ │ ▼ + │ │ ┌──────────────┐ + │ │ │ │ + │ └───────────────────────────────────►│ UsageService │ + │ │ │ + │ └──────┬───────┘ + │ │ + ▼ ▼ +┌──────────────┐ ┌──────────────┐ +│ │ │ │ +│ User API │◄─────────────────────────────────────────────────┤ Response │ +│ Response │ │ │ +└──────────────┘ └──────────────┘ +``` + +## Architecture Evolution + +The Ember architecture continues to evolve along these paths: + +1. **Distributed Execution**: Support for distributed execution across multiple machines +2. **Enhanced Caching**: Improved caching for models and intermediate results +3. **Custom Hardware Support**: Optimizations for specialized hardware (GPUs, TPUs) +4. **Plugin System**: More comprehensive plugin interfaces for extensions +5. **Advanced Graph Optimizations**: Additional graph transformations and optimizations + +## Additional Resources + +For more detailed information, consult these resources: + +- [Model Registry Documentation](docs/quickstart/model_registry.md) +- [Operator System Documentation](docs/quickstart/operators.md) +- [XCS Execution Engine Documentation](docs/xcs/README.md) +- [Enhanced JIT Documentation](docs/xcs/JIT_OVERVIEW.md) +- [Example Applications](src/ember/examples) \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..495f38a1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,388 @@ +# Contributing to Ember + +Thank you for your interest in contributing to Ember! This document provides guidelines and instructions for contributing to the project. + +## Table of Contents + +- [Getting Started](#getting-started) + - [Development Environment](#development-environment) + - [Project Structure](#project-structure) + - [Running Tests](#running-tests) + - [Code Style and Quality](#code-style-and-quality) +- [Contribution Workflow](#contribution-workflow) + - [Finding Issues](#finding-issues) + - [Creating Issues](#creating-issues) + - [Making Changes](#making-changes) + - [Pull Requests](#pull-requests) + - [Code Review](#code-review) +- [Development Guidelines](#development-guidelines) + - [Documentation](#documentation) + - [Testing](#testing) + - [Performance Considerations](#performance-considerations) + - [Typed Code](#typed-code) +- [Release Process](#release-process) +- [Community](#community) +- [License](#license) + +## Getting Started + +### Development Environment + +1. **Fork and clone the repository**: + ```bash + git clone https://github.com/YOUR-USERNAME/ember.git + cd ember + ``` + +2. **Install uv (recommended)**: + We use uv for dependency management. [Install uv](https://github.com/astral-sh/uv) if you haven't already: + ```bash + # On macOS and Linux + curl -LsSf https://astral.sh/uv/install.sh | sh + + # On Windows + powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" + + # Or with pip + pip install uv + ``` + +3. **Install dependencies**: + ```bash + # Install with all development dependencies + uv pip install -e ".[dev]" + ``` + +4. **Working with the environment**: + ```bash + # Option 1: Run commands directly (recommended) + uv run pytest + uv run python src/ember/examples/basic/minimal_example.py + + # Option 2: Create and activate a virtual environment + uv venv + source .venv/bin/activate # On Windows: .venv\Scripts\activate + ``` + +5. **Set up pre-commit hooks** (recommended): + ```bash + uv run pre-commit install + # Or if you've activated a virtual environment: + pre-commit install + ``` + + +#### Note on Imports + +The project is set up with standard Python packaging, so you should import from `ember` directly, rather than from `src.` generally: + +```python +# Correct way to import +from ember.core import non +from ember.xcs.tracer import jit + +# No need to manipulate sys.path or use symlinks +``` + +### Project Structure + +The Ember codebase is organized into the following structure: + +``` +ember/ +├── core/ # Core framework modules (compatibility with src structure) +│ ├── registry/ # Model registry components +│ └── utils/ # Utility modules +├── docs/ # Documentation +│ ├── design/ # Design documents +│ ├── quickstart/ # Quick start guides +│ └── xcs/ # XCS documentation +├── src/ # Source code +│ └── ember/ # Main Python package +│ ├── api/ # Public API interfaces +│ ├── cli.py # Python CLI entrypoint +│ ├── core/ # Core framework +│ │ ├── config/ # Configuration management +│ │ ├── registry/ # Registry components +│ │ │ ├── model/ # Model registry +│ │ │ ├── operator/ # Operator registry +│ │ │ └── specification/ # Specifications +│ │ ├── types/ # Type definitions +│ │ └── utils/ # Utility functions +│ ├── examples/ # Example applications +│ │ ├── advanced/ # Advanced examples +│ │ ├── basic/ # Basic examples +│ │ ├── data/ # Data handling examples +│ │ ├── models/ # Model usage examples +│ │ └── operators/ # Operator examples +│ ├── xcs/ # Execution engine +│ │ ├── api/ # XCS API +│ │ ├── engine/ # Engine components +│ │ ├── graph/ # Graph representation +│ │ ├── tracer/ # Tracing functionality +│ │ ├── transforms/ # Transformation utilities +│ │ └── utils/ # XCS utilities +│ └── non.py # Non-deterministic operations +├── tests/ # Test suite +│ ├── helpers/ # Test helpers +│ ├── integration/ # Integration tests +│ │ ├── core/ # Core integration tests +│ │ ├── performance/ # Performance tests +│ │ ├── tracer/ # Tracer integration tests +│ │ └── xcs/ # XCS integration tests +│ ├── unit/ # Unit tests +│ │ ├── core/ # Core unit tests +│ │ ├── plugin_system/ # Plugin system tests +│ │ └── xcs/ # XCS unit tests +│ └── fuzzing/ # Fuzzing tests +├── pyproject.toml # Python project configuration +├── poetry.lock # Dependencies lock file (we're transitioning to uv) +├── pytest.ini # Pytest configuration +├── mypy.ini # Type checking configuration +└── README.md # Project overview +``` + +The `.gitignore` file is configured to exclude common development files, caches, and sensitive configuration files. + +### Running Tests + +We use pytest for testing. To run the test suite: + +```bash +# Run all tests +uv run pytest + +# Run specific tests +uv run pytest tests/unit/core + +# Run tests with code coverage +uv run pytest --cov=src/ember + +# Run a specific test file +uv run pytest tests/unit/core/test_app_context.py +``` + +### Code Style and Quality + +We enforce high code quality standards: + +1. **Code Formatting**: + - We use Black for code formatting + - Line length is set to 88 characters + - Run `uvx black src tests` before committing + +2. **Import Sorting**: + - We use isort for import sorting + - Run `uvx isort src tests` before committing + +3. **Linting**: + - We use ruff and pylint for linting + - Run `uvx ruff check src tests` before committing + - Run `uvx pylint src/ember` for more detailed linting + +4. **Type Checking**: + - We use mypy for static type checking + - Run `uvx mypy src` before committing + +All these checks are also performed automatically when you submit a pull request. + +## Contribution Workflow + +### Finding Issues + +- Check our [issue tracker](https://github.com/pyember/ember/issues) for open issues +- Look for issues tagged with [`good first issue`](https://github.com/pyember/ember/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) if you're new to the project +- Feel free to ask questions in the issue comments if you need clarification + +### Creating Issues + +When opening a new issue, please: + +- **Search existing issues** first to avoid duplicates +- **Use a clear and descriptive title** +- **Follow the issue template** if one is provided +- For bug reports, include: + - Steps to reproduce + - Expected behavior + - Actual behavior + - Environment details (OS, Python version, etc.) + - Code samples or error traces when relevant +- For feature requests, explain: + - The problem you're trying to solve + - Your proposed solution + - Alternatives you've considered + +### Making Changes + +1. **Create a feature branch**: + ```bash + git checkout -b feature/your-feature-name + ``` + +2. **Make your changes**: + - Write clean, well-commented code. We attempt to adhere to the `Google Python Style Guide`. + - Please add/update tests to cover your changes + - Remember to update documentation as needed + - Ensure your code passes all tests and style checks + +3. **Commit your changes**: + - Use clear, meaningful commit messages + - Reference issue numbers where applicable + ```bash + git commit -m "Add feature X, fixes #123" + ``` + +4. **Keep your branch updated**: + ```bash + git fetch origin + git rebase origin/main + ``` + +### Pull Requests + +When submitting a pull request: + +1. **Fill out the PR template** completely +2. **Link to related issues** +3. **Describe your changes** in detail +4. **Ensure all tests and checks pass** +5. **Include screenshots or examples** for UI or behavior changes +6. **Request reviews** from maintainers or contributors familiar with the area of code + +### Code Review + +During code review: + +- It is your responsibility to get your code reviewed. Feel free to `chase` reviewers as needed, respectfully of course. +- Be patient and respectful. User error is not the default assumption -- assume any question is designer error (either in the implementation or the documentation) +- Remember that the goal is to improve code quality for all of us. + +## Development Guidelines + +### Documentation + +Good documentation is essential: + +1. **Docstrings**: + - All public modules, classes, and functions must have docstrings + - We follow Google-style docstrings + - Include type hints in docstrings for complex parameters + - Example: + ```python + def process_data(data: List[Dict[str, Any]], options: Optional[Dict[str, Any]] = None) -> Result: + """Process input data with optional configuration. + + Args: + data: List of data dictionaries to process + options: Optional configuration parameters + + Returns: + A Result object containing processed output + + Raises: + ValueError: If data is empty or malformed + """ + ``` + +2. **README and Documentation Files**: + - Update relevant documentation for significant changes + - Keep examples up-to-date + - Add new documentation for new features + +3. **Code Comments**: + - Use comments for complex or non-obvious logic + - Avoid redundant comments that just restate the code + - Use TODO comments for future improvements (with issue references) + +### Testing + +We strive for high test coverage: + +1. **Test Coverage**: + - All new code should have corresponding tests + - We aim for 90%+ code coverage + - Critical paths should have 100% coverage + +2. **Test Types**: + - **Unit tests**: For testing individual functions and classes in isolation + - **Integration tests**: For testing interactions between components + - **Property-based tests**: Using Hypothesis for testing invariants + - **Fuzzing tests**: For finding edge cases and security issues + +3. **Test Naming and Organization**: + - Test files should be named `test_*.py` + - Test classes should be named `Test*` + - Test functions should be named `test_*` + - Group related tests in the same file or directory + +4. **Test Quality**: + - Tests should be deterministic and reliable + - Mock external dependencies appropriately, but not excessively + - Test edge cases and error conditions + - Include both positive and negative test cases + +### Performance Considerations + +Performance is important in Ember: + +1. **Measurement**: + - Use profiling tools to identify bottlenecks + - Include benchmarks for performance-critical code + - Compare before/after performance for optimizations + +2. **Optimizations**: + - Optimize for readability and maintainability first + - Focus optimizations on critical paths + - Document performance trade-offs in comments + - Use appropriate data structures and algorithms + +3. **Concurrency**: + - Ensure thread safety for shared resources + - Use appropriate locking mechanisms + - Consider asynchronous approaches where applicable + +### Typed Code + +We use Python type hints extensively: + +1. **Type Annotations**: + - Annotate all function parameters and return values + - Use appropriate generic types when needed + - Use Optional, Union, and other typing constructs as needed + +2. **Type Checking**: + - Run `mypy` to check for type errors + - Address all type warnings + - Use TypeVar and Generic for polymorphic code + +3. **Custom Types**: + - Define new type aliases for complex types + - Use Protocol for structural typing + - Document type parameters and constraints + +## Release Process + +Our release process follows these steps: + +1. Feature development in feature branches +2. Pull requests to the main branch after code review +3. Continuous integration tests on all PRs +4. Periodic releases with semantic versioning: + - MAJOR version for incompatible API changes + - MINOR version for backwards-compatible functionality + - PATCH version for backwards-compatible bug fixes +5. Release notes summarizing changes and upgrades + +## Community + +- **Discussions**: Join our [GitHub Discussions](https://github.com/pyember/ember/discussions) for questions and ideas +- **Issues**: Use [GitHub Issues](https://github.com/pyember/ember/issues) for bug reports and feature requests +- **Slack**: Join our [Slack](https://join.slack.com/t/ember-y0w7887/shared_invite/zt-31nm1aqdz-JtFcRWaatNg11OiUVEhhUw) for real-time discussion + +--- + +Thank you for contributing to Ember! Your time and effort help make this project better for everyone. + +## License + +By contributing to Ember, you agree that your contributions will be licensed under the project's [MIT License](LICENSE). \ No newline at end of file diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md deleted file mode 100644 index 15156ff6..00000000 --- a/CONTRIBUTORS.md +++ /dev/null @@ -1,31 +0,0 @@ -# Contributors - -This repository is in collaboration with the following early users, contributors, and reviewers: - -## Core Team - -- **Jared Quincy Davis** - Project Lead (Foundry/MLFoundry, Stanford) -- **Siddharth Sharma** (Foundry, Stanford) -- **Marquita Ellis** (IBM Research) - -## Contributors - -Jared Quincy Davis, Marquita Ellis, Diana Arroyo, Pravein Govindan Kannan, Paul Castro, Siddharth Sharma, Lingjiao Chen, Omar Khattab, Alan Zhu, Parth Asawa, Connor Chow, Jason Lee, Jay Adityanag Tipirneni, Chad Ferguson, Kathleen Ge, Kunal Agrawal, Rishab Bhatia, Rohan Penmatcha, Sai Kolasani, Théo Jaffrelot Inizan, Deepak Narayanan, Long Fei, Aparajit Raghavan, Eyal Cidon, Jacob Schein, Prasanth Somasundar, Boris Hanin, James Zou, Alex Dimakis, Joey Gonzalez, Peter Bailis, Ion Stoica, and Matei Zaharia. - -## Affiliated Organizations - -- Foundry (MLFoundry) -- Databricks -- IBM Research -- Stanford University -- UC Berkeley -- MIT -- NVIDIA -- Microsoft -- Anyscale -- Google -- Princeton - -## How to Contribute - -See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on contributing to Ember. diff --git a/DEBUGGING.md b/DEBUGGING.md new file mode 100644 index 00000000..db30929f --- /dev/null +++ b/DEBUGGING.md @@ -0,0 +1,47 @@ +# Ember Examples Debugging + +This document tracks the troubleshooting process for fixing failing examples in the Ember framework. + +## 1. Operator Composition Example (`composition_example.py`) + +### Issue +The example fails with an error when attempting to invoke the "openai:gpt-4o" model. + +### Root Cause Analysis +1. **Incorrect Parameter Name**: The `LMModuleConfig` class expects an `id` field, but the code uses `model_name`: + ```python + self.lm_module = LMModule( + config=LMModuleConfig( + model_name=model_name, # INCORRECT: should be "id" not "model_name" + temperature=temperature, + ) + ) + ``` + +2. **No Error Handling**: The `QuestionRefinement` operator doesn't include any error handling for model invocation, making the example fragile. + +### Fix Plan +1. Update parameter name in `LMModuleConfig` from `model_name` to `id` +2. Add proper error handling to the `QuestionRefinement.forward` method +3. Update the model name in `main()` to ensure it's available (e.g., use "openai:gpt-3.5-turbo" as it's more likely to be available) + +## 2. Transformation Example (`transformation_example.py`) + +### Issue +The example fails with an error related to invalid input/output types in the `SimpleOperator` class within the `demonstrate_vmap` function. + +### Root Cause Analysis +1. **Type Mismatch in vmap**: The `vmap` transformation returns a dictionary of results, but the operator's specification expects a `SimpleOutput` model. + +2. **Missing Type Conversion**: The `_combine_outputs` function in `vmap.py` doesn't convert the combined dictionary results back to the expected model type. + +### Fix Plan +1. Modify the `_combine_outputs` function in `vmap.py` to check the operator's `specification.structured_output` and convert the combined result dictionary to the appropriate model type. +2. Alternatively, update the `SimpleOperator` class to correctly handle the dictionary output from vmap. + +## Architectural Considerations + +1. **Unified Error Handling**: Consider a standardized approach for error handling in operators that use LLMs. +2. **Type Compatibility**: Ensure transformations like `vmap` properly respect the type specifications of operators. +3. **Graceful Degradation**: Examples should have graceful error handling to make them more robust, especially for cases involving external APIs. +4. **Automated Testing**: Add tests to catch these issues before they appear in examples. \ No newline at end of file diff --git a/ENVIRONMENT_MANAGEMENT.md b/ENVIRONMENT_MANAGEMENT.md new file mode 100644 index 00000000..0727aff0 --- /dev/null +++ b/ENVIRONMENT_MANAGEMENT.md @@ -0,0 +1,144 @@ +# Ember Environment Management Guide + +This guide explains how to effectively manage Python environments when working with Ember using uv. + +## Python Environment Management with uv + +uv provides simplified Python environment management with these benefits: + +- **Dependency Isolation**: Prevents conflicts between project dependencies +- **Reproducible Environments**: Ensures consistent behavior across development setups +- **Simplified Workflow**: Reduces the need for explicit environment activation + +## Environment Management Approaches + +### 1. Using uv's Simplified Environment Management (Recommended) + +The simplest approach is to use uv's `run` command, which handles environments automatically: + +```bash +# Install Ember +cd ember +uv pip install -e "." + +# Run Python code without explicit environment activation +uv run python src/ember/examples/basic/minimal_example.py + +# Run tools without explicit environment activation +uv run pytest +``` + +### 2. Traditional Virtual Environment Workflow + +If you prefer a more traditional virtual environment workflow: + +```bash +# Create a virtual environment in the project directory +uv venv + +# Activate the environment (still required for interactive use) +source .venv/bin/activate # On Windows: .venv\Scripts\activate + +# Install Ember in the active environment +uv pip install -e "." + +# Run code in the activated environment +python src/ember/examples/basic/minimal_example.py +``` + +### 3. Using Other Virtual Environment Tools + +If you prefer using other environment managers: + +```bash +# Create environment with venv +python -m venv ember_env +source ember_env/bin/activate # On Windows: ember_env\Scripts\activate + +# Install with uv in this environment +uv pip install -e "." +``` + +## Environment Management Best Practices + +1. **Always use isolated environments** - Never install Ember in your global Python environment +2. **For simple usage, use `uv run`** - This handles environment management automatically +3. **For interactive shell work:** + - Create a virtual environment with `uv venv` + - Activate it with `source .venv/bin/activate` +4. **For running tools directly** - Use `uvx` which runs tools in isolated environments: + ```bash + uvx black src tests + uvx mypy src + ``` + +## Common Environment Commands + +```bash +# Create a virtual environment in the current directory +uv venv + +# Create a virtual environment with a specific Python version +uv venv --python=3.11 + +# Install packages +uv pip install -e "." +uv pip install -e ".[dev]" # With development extras + +# Run in an isolated environment +uv run python script.py +uv run pytest tests/ +``` + +## Python Version Management + +uv can also manage Python versions: + +```bash +# Install Python versions +uv python install 3.10 3.11 3.12 + +# Use a specific Python version +uv venv --python 3.11 +uv run --python 3.11 -- python script.py + +# Pin a Python version for a project +uv python pin 3.11 # Creates .python-version +``` + +## Troubleshooting + +### Python Version Issues + +```bash +# Check Python version +python --version + +# Specify a Python version for a virtual environment +uv venv --python 3.11 + +# Install a specific Python version with uv +uv python install 3.11 +``` + +### Path Issues + +If Python can't find Ember modules: + +```bash +# Ensure you're running from the project root +cd /path/to/ember +uv run python src/ember/examples/basic/minimal_example.py +``` + +### Dependency Resolution Issues + +If you encounter dependency conflicts: + +```bash +# Use cached resolution if available +uv pip install -e "." --cache-only + +# Force re-resolution +uv pip install -e "." --no-cache +``` \ No newline at end of file diff --git a/INSTALLATION_GUIDE.md b/INSTALLATION_GUIDE.md new file mode 100644 index 00000000..8af68373 --- /dev/null +++ b/INSTALLATION_GUIDE.md @@ -0,0 +1,213 @@ +# Ember Installation Guide + +This guide provides detailed instructions for installing Ember in different environments. + +## System Requirements + +- **Python**: 3.9 or newer (3.10, 3.11, and 3.12 supported) +- **Operating System**: macOS, Linux, or Windows + +## Installation Methods + +### Method 1: Basic Installation with uv (Recommended) + +[uv](https://astral.sh/uv) is the recommended package manager for Ember. It is extremely fast (10-100x faster than pip) and simplifies Python environment management. + +1. **Install uv** if you don't have it already: + ```bash + # On macOS and Linux + curl -LsSf https://astral.sh/uv/install.sh | sh + + # On Windows + powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" + + # Or with pip if you prefer + pip install uv + + # Verify the installation + uv --version + ``` + +2. **Install Ember from PyPI**: + ```bash + # Install Ember directly (creates a virtual environment automatically if needed) + uv pip install ember-ai + + # Run examples without activating an environment + ``` + +3. **Install from source**: + ```bash + # Clone the repository + git clone https://github.com/pyember/ember.git + cd ember + + # Install in development mode (editable installation) + uv pip install -e "." + + # Run examples directly without environment activation + uv run python src/ember/examples/basic/minimal_example.py + ``` + + By default, this installs Ember with OpenAI, Anthropic, and Google/Deepmind provider support. + +### Method 2: Development Installation with uv + +If you want to develop or contribute to Ember: + +1. **Clone the repository**: + ```bash + git clone https://github.com/pyember/ember.git + cd ember + ``` + +2. **Install with development dependencies**: + ```bash + # Install including development dependencies + uv pip install -e ".[dev]" + + # Run commands directly with uv + uv run pytest + ``` + +3. **Running tools**: + ```bash + # Run linters, formatters, and other tools without installation + uvx black src tests + uvx mypy src + uvx pytest + ``` + +### Method 3: Traditional pip Installation (Alternative) + +If you prefer using standard pip or don't want to install uv: + +```bash +# Create a virtual environment (recommended) +python -m venv ember_env +source ember_env/bin/activate # On Windows: ember_env\Scripts\activate + +# Install Ember with pip +pip install ember-ai + +# For development installation +pip install -e ".[dev]" +``` + +Note: This method is significantly slower for dependency resolution and doesn't provide the environment management benefits of uv. + +## OS-Specific Installation Notes + +### macOS + +On macOS, you might encounter issues with the default Python installation: + +```bash +# If you encounter Python-related errors: +# Install Python using Homebrew (recommended) +brew install python@3.11 + +# Use the Homebrew Python with uv +/opt/homebrew/bin/python3.11 -m pip install uv +/opt/homebrew/bin/python3.11 -m uv pip install -e "." +``` + +### Windows + +On Windows, ensure you have the latest Python installed from python.org: + +```powershell +# Add uv to your PATH if needed +$env:PATH += ";$env:USERPROFILE\.uv\bin" + +# Install and run directly +uv pip install -e "." +uv run python src/ember/examples/basic/minimal_example.py +``` + +## Troubleshooting + +### Python Version Issues + +If you encounter Python version errors: + +```bash +# Check your Python version +python --version + +# Specify a Python version for uv +uv venv --python=3.11 +source .venv/bin/activate + +# Or run with a specific Python version +uv run --python=3.11 -- python script.py +``` + +### uv Installation Issues + +If you have problems with uv: + +```bash +# Ensure uv is in your PATH +which uv + +# Update uv to the latest version +uv self update + +# Reinstall uv if needed +pip install --upgrade uv +``` + +### Virtual Environment Issues + +If you have problems with virtual environments: + +```bash +# Create a fresh virtual environment +uv venv --force + +# Activate the environment +source .venv/bin/activate # On Windows: .venv\Scripts\activate +``` + +See [ENVIRONMENT_MANAGEMENT.md](ENVIRONMENT_MANAGEMENT.md) for more details on managing environments. + +### Dependency Conflicts + +If you encounter dependency conflicts: + +```bash +# Try reinstalling without using cache +uv pip install -e "." --no-cache + +# Install with specific package versions if needed +uv pip install -e "." --no-deps +uv pip install "specific-package==version" +``` + +### Other Known Installation Issue Resolutions + +When using conda with or without uv, you may encounter known pyarrow installation issues. +``` +# Try installing pyarrow from conda-forge +conda install -c conda-forge pyarrow +``` + +## Testing Your Installation + +After installation, verify everything is working: + +```bash +# From the project root directory, using uv +uv run python src/ember/examples/basic/minimal_example.py + +# Or if you're in an activated virtual environment +python src/ember/examples/basic/minimal_example.py +``` + +## Getting Help + +If you encounter issues with installation: +- Check our [GitHub Issues](https://github.com/pyember/ember/issues) +- Review the [ENVIRONMENT_MANAGEMENT.md](ENVIRONMENT_MANAGEMENT.md) guide +- See the [TESTING_INSTALLATION.md](TESTING_INSTALLATION.md) for verification steps \ No newline at end of file diff --git a/LLM_SPECIFICATIONS.md b/LLM_SPECIFICATIONS.md new file mode 100644 index 00000000..350696d9 --- /dev/null +++ b/LLM_SPECIFICATIONS.md @@ -0,0 +1,592 @@ +# Ember Framework: LLM Specifications + +This document provides precise specifications for building systems with the Ember framework. It defines essential patterns, APIs, and concepts with minimal overhead. + +## Table of Contents + +- [Core Concepts](#core-concepts) +- [Architecture Overview](#architecture-overview) +- [Model Registry](#model-registry) +- [Operators](#operators) +- [Execution Engine (XCS)](#execution-engine-xcs) +- [Network of Networks (NON)](#network-of-networks-non) +- [Data System](#data-system) +- [Context System](#context-system) +- [Code Style Guidelines](#code-style-guidelines) +- [Examples and Templates](#examples-and-templates) + +## Core Concepts + +### EmberModel +Base class for structured input/output with type validation: + +```python +from ember.core.types.ember_model import EmberModel, Field + +class QueryInput(EmberModel): + query: str = Field(..., description="Query to process") + temperature: float = Field(0.7, description="Sampling temperature") + +class AnswerOutput(EmberModel): + answer: str = Field(..., description="Generated response") + confidence: float = Field(..., description="Confidence score 0-1") +``` + +### Operator +Fundamental computational unit with typed I/O: + +```python +from typing import ClassVar +from ember.api.operators import Operator, Specification + +class MySpec(Specification): + input_model = QueryInput + structured_output = AnswerOutput + +class MyOperator(Operator[QueryInput, AnswerOutput]): + specification: ClassVar[Specification] = MySpec() + + def forward(self, *, inputs: QueryInput) -> AnswerOutput: + # Implementation here + return AnswerOutput(answer="...", confidence=0.9) +``` + +### JIT Compilation +Execute optimized computational graphs: + +```python +from ember.xcs import jit + +@jit # Auto-optimize execution path +class FastOperator(Operator[QueryInput, AnswerOutput]): + # Implementation with parallel execution where possible +``` + +## Architecture Overview + +Ember's layered architecture: + +1. **Execution Engine (XCS)** - Base layer providing computation graph definition and execution +2. **Core Component Layer** - Building blocks including model registry, operators, specifications +3. **Application Layer** - High-level abstractions like NON patterns and auto graph building +4. **Public API Layer** - Clean interfaces exposed through the `ember.api` namespace + +## Model Registry + +The model registry provides unified access to LLM providers: + +### Function-Style API (Recommended) + +```python +from ember.api import models + +# Direct invocation +response = models.model("gpt-4o")("What is quantum computing?") + +# Provider namespaces +response = models.openai.gpt4o("What is quantum computing?") + +# Reusable models +gpt4 = models.model("gpt-4o", temperature=0.7) +response1 = gpt4("Question 1") +response2 = gpt4("Question 2") + +# Configuration context +with models.configure(temperature=0.2, max_tokens=100): + response = models.model("gpt-4o")("Write a haiku") +``` + +### Type-Safe Enum References + +```python +from ember.api.models import ModelEnum +response = models.from_enum(ModelEnum.OPENAI_GPT4O)("Hello") +``` + +### Builder Pattern (Alternative) + +```python +from ember.api.models import ModelBuilder +model = (ModelBuilder() + .temperature(0.7) + .max_tokens(100) + .build("anthropic:claude-3-5-sonnet")) +response = model.generate("Explain quantum computing") +``` + +### Custom Contexts + +```python +from ember.api.models import ModelContext, ContextConfig +context = ModelContext(config=ContextConfig( + api_keys={"openai": "your-key"} +)) +response = models.model("gpt-4o", context=context)("Hello") +``` + +## Operators + +### Basic Operator Pattern + +```python +from typing import ClassVar +from ember.api.operators import Operator, Specification, EmberModel +from ember.api import models + +class InputType(EmberModel): + query: str + +class OutputType(EmberModel): + answer: str + +class MySpec(Specification): + input_model = InputType + structured_output = OutputType + +class MyOperator(Operator[InputType, OutputType]): + # Class-level specification + specification: ClassVar[Specification] = MySpec() + + # Declare instance attributes + model: object + + def __init__(self, model_name: str = "gpt-4o"): + self.model = models.model(model_name) + + def forward(self, *, inputs: InputType) -> OutputType: + response = self.model(inputs.query) + return OutputType(answer=str(response)) +``` + +### Composition Pattern + +```python +class Pipeline(Operator[InputType, OutputType]): + specification: ClassVar[Specification] = MySpec() + + # Declare component operators + refiner: QueryRefiner + answerer: AnswerGenerator + + def __init__(self): + self.refiner = QueryRefiner() + self.answerer = AnswerGenerator() + + def forward(self, *, inputs: InputType) -> OutputType: + refined = self.refiner(inputs=inputs) + return self.answerer(inputs=refined) +``` + +### Built-in Operators + +```python +from ember.api.operators import ( + EnsembleOperator, + MostCommonAnswerSelector, + VerifierOperator, + SelectorJudgeOperator, + JudgeSynthesisOperator +) + +# Ensemble of models +ensemble = EnsembleOperator( + operators=[ + MyOperator(model="gpt-4o"), + MyOperator(model="claude-3-5-sonnet"), + ] +) + +# Selector for aggregation +pipeline = MostCommonAnswerSelector( + operator=ensemble +) +``` + +## Execution Engine (XCS) + +### Basic JIT + +```python +from ember.xcs import jit + +@jit +class MyOperator(Operator): + def forward(self, *, inputs): + # Implementation + return result +``` + +### JIT with Strategy Selection + +```python +from ember.xcs import jit + +# Auto-select optimal strategy +@jit +class MyOperator(Operator): + # Implementation... + +# Explicit strategy +@jit(mode="enhanced") +class ComplexOperator(Operator): + # Implementation... +``` + +### Execution Options + +```python +from ember.xcs import execution_options + +# Configure execution parameters +with execution_options(scheduler="wave", max_workers=4): + result = pipeline(query="Complex question...") +``` + +### Transformations + +```python +from ember.xcs import vmap, pmap, compose + +# Vectorized mapping for batch processing +batch_processor = vmap(my_operator) +batch_results = batch_processor(inputs={"data": [item1, item2, item3]}) + +# Parallel execution across multiple workers +parallel_processor = pmap(my_operator, num_workers=4) +parallel_results = parallel_processor(inputs=complex_data) + +# Compose transformations +pipeline = compose(vmap(batch_size=32), pmap(num_workers=4))(my_operator) +``` + +## Network of Networks (NON) + +### Standard API + +```python +from ember.api import non + +# Create ensemble of identical models +ensemble = non.UniformEnsemble( + num_units=3, + model_name="openai:gpt-4o", + temperature=0.7 +) + +# Create judge to synthesize outputs +judge = non.JudgeSynthesis( + model_name="anthropic:claude-3-5-sonnet", + temperature=0.0 +) + +# Create sequential pipeline +pipeline = non.Sequential(operators=[ensemble, judge]) + +# Execute pipeline +result = pipeline(query="What causes tsunamis?") +``` + +### Compact Notation + +```python +from ember.api import non + +# Same pipeline with compact notation +pipeline = non.build_graph([ + "3:E:gpt-4o:0.7", # Ensemble with 3 instances + "1:J:claude-3-5-sonnet:0.0" # Judge synthesis +]) + +# Execute with identical interface +result = pipeline(query="What causes tsunamis?") +``` + +### Component Reuse + +```python +# Define reusable components +components = { + "sub": ["2:E:gpt-4o:0.0", "1:V:gpt-4o:0.0"] # Ensemble → Verifier +} + +# Create branch architecture +nested = non.build_graph([ + "$sub", # First branch + "$sub", # Second branch + "1:J:gpt-4o:0.0" # Final judge +], components=components) +``` + +### Custom Operator Types + +```python +# Create a registry with custom operator types +registry = non.OpRegistry.create_standard_registry() +registry.register( + "CE", # Custom ensemble type + lambda count, model, temp: non.Sequential(operators=[ + non.UniformEnsemble(num_units=count, model_name=model, temperature=temp), + non.MostCommon() # Auto-aggregation + ]) +) + +# Use custom operator type +pipeline = non.build_graph(["3:CE:gpt-4o:0.7"], type_registry=registry) +``` + +## Data System + +### DatasetBuilder Pattern + +```python +from ember.api.data import DatasetBuilder + +# Load and transform a dataset +dataset = (DatasetBuilder() + .from_registry("mmlu") # Use a registered dataset + .subset("physics") # Select a specific subset + .split("test") # Choose the test split + .sample(100) # Random sample of 100 items + .transform( # Apply transformations + lambda x: {"query": f"Question: {x['question']}"} + ) + .build()) +``` + +### Evaluation Pipeline + +```python +from ember.api.eval import EvaluationPipeline, Evaluator + +# Create an evaluation pipeline +eval_pipeline = EvaluationPipeline([ + # Standard metrics + Evaluator.from_registry("accuracy"), + Evaluator.from_registry("response_quality"), + + # Custom metrics + Evaluator.from_function( + lambda prediction, reference: { + "factual_accuracy": score_factual_content(prediction, reference) + } + ) +]) + +# Evaluate a model or operator +results = eval_pipeline.evaluate(my_model, dataset) +print(f"Accuracy: {results['accuracy']:.2f}") +``` + +## Context System + +### Basic Context Usage + +```python +from ember.core.context import current_context + +# Get the current thread's context +ctx = current_context() + +# Get a model +model = ctx.get_model("gpt4o") + +# Generate text +result = model.generate("Hello, world!") +``` + +### Temporary Components + +```python +from ember.core.context import current_context, temp_component + +# Use a temporary component +with temp_component("model", "temp-model", MyModel("temporary")) as model: + # Use the model within this scope + result = model.generate("Hello") +``` + +### Configuration Access + +```python +from ember.core.context import current_context +from ember.core.context.config_integration import config_override + +# Access configuration through context +temperature = ctx.config.model.temperature + +# Override configuration temporarily +with config_override({"model": {"temperature": 0.2}}): + # Config value changed in this scope + new_temp = ctx.config.model.temperature +``` + +## Code Style Guidelines + +1. **Package Structure**: + - Use the `ember.api` namespace for clean imports + - Follow the layered import pattern: + ```python + from ember.api.models import ModelBuilder + from ember.api.operators import Operator + from ember.api.xcs import jit + from ember.api import non + ``` + +2. **Naming Conventions**: + - Classes: `PascalCase` + - Functions: `snake_case` + - Constants: `UPPER_SNAKE_CASE` + - Private attributes: `_leading_underscore` + +3. **Typing**: + - Use explicit type annotations + - Leverage TypeVars for generic operators + - Include descriptions in Field definitions + +4. **Documentation**: + - Follow Google docstring format + - Document parameters, returns, and raises + - Include examples for non-trivial usage + +5. **Error Handling**: + - Use specific exception types + - Include helpful error messages + - Handle API errors gracefully + +## Examples and Templates + +### Basic Operator Template + +```python +from typing import ClassVar +from ember.api.operators import Operator, Specification, EmberModel, Field + +class MyInput(EmberModel): + query: str = Field(..., description="The input query") + +class MyOutput(EmberModel): + result: str = Field(..., description="The computed result") + +class MySpec(Specification): + input_model = MyInput + structured_output = MyOutput + +class MyOperator(Operator[MyInput, MyOutput]): + specification: ClassVar[Specification] = MySpec() + + def __init__(self, param1: str): + self.param1 = param1 + + def forward(self, *, inputs: MyInput) -> MyOutput: + # Implementation logic + return MyOutput(result=f"Processed: {inputs.query}") +``` + +### NON Pattern Template + +```python +from ember.api import non + +def create_ensemble_judge_pipeline( + ensemble_size: int = 3, + model_name: str = "openai:gpt-4o", + judge_model: str = "anthropic:claude-3-5-sonnet" +) -> non.Sequential: + """Create an ensemble-judge pipeline. + + Args: + ensemble_size: Number of ensemble units + model_name: Model to use for ensemble + judge_model: Model to use for judge + + Returns: + A configured pipeline + """ + return non.Sequential(operators=[ + non.UniformEnsemble( + num_units=ensemble_size, + model_name=model_name, + temperature=0.7 + ), + non.JudgeSynthesis( + model_name=judge_model, + temperature=0.0 + ) + ]) +``` + +### Complete Application Example + +```python +"""Minimal Ember application with JIT optimization.""" + +from typing import ClassVar +from ember.api import models, non +from ember.api.operators import Operator, Specification, EmberModel +from ember.xcs import jit + +# Define I/O types +class QuestionInput(EmberModel): + question: str + +class AnswerOutput(EmberModel): + answer: str + confidence: float + +# Define specification +class QuestionSpec(Specification): + input_model = QuestionInput + structured_output = AnswerOutput + +# Define JIT-optimized operator +@jit +class QuestionAnswerer(Operator[QuestionInput, AnswerOutput]): + specification: ClassVar[Specification] = QuestionSpec() + + # Declare instance attributes + ensemble: non.UniformEnsemble + judge: non.JudgeSynthesis + + def __init__(self, width: int = 3): + self.ensemble = non.UniformEnsemble( + num_units=width, + model_name="gpt-4o", + temperature=0.7 + ) + self.judge = non.JudgeSynthesis( + model_name="claude-3-5-sonnet" + ) + + def forward(self, *, inputs: QuestionInput) -> AnswerOutput: + # Get ensemble responses + ensemble_result = self.ensemble(query=inputs.question) + + # Synthesize with judge + synthesis = self.judge( + query=inputs.question, + responses=ensemble_result["responses"] + ) + + # Build response + return AnswerOutput( + answer=synthesis["synthesized_response"], + confidence=float(synthesis.get("confidence", 0.8)) + ) + +# Main entrypoint +def main(): + # Create operator + answerer = QuestionAnswerer(width=5) + + # Process question + result = answerer(inputs=QuestionInput( + question="What is relativity?" + )) + + # Use result + print(f"Answer: {result.answer}") + print(f"Confidence: {result.confidence:.2f}") + +if __name__ == "__main__": + main() +``` \ No newline at end of file diff --git a/QUICKSTART.md b/QUICKSTART.md new file mode 100644 index 00000000..1f9ccbe5 --- /dev/null +++ b/QUICKSTART.md @@ -0,0 +1,217 @@ +# Ember Quickstart Guide + +This guide will help you quickly get started with Ember, the compositional framework for building and orchestrating Compound AI Systems. + +## Installation + +```bash +# Install uv if you don't have it +curl -LsSf https://astral.sh/uv/install.sh | sh # macOS/Linux +# or +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows +# or +pip install uv # Any platform + +# Quick install with uv (recommended) +uv pip install ember-ai + +# Or from source +git clone https://github.com/pyember/ember.git +cd ember +uv pip install -e ".[dev]" # Install with development dependencies + +# Run examples directly with uv +uv run python src/ember/examples/basic/minimal_example.py + +# For CLI tools, you can run directly without installation +uvx ember-ai # If you have CLI commands +``` + +For detailed installation instructions including troubleshooting, please see: +- [INSTALLATION_GUIDE.md](INSTALLATION_GUIDE.md) - Complete installation instructions +- [ENVIRONMENT_MANAGEMENT.md](ENVIRONMENT_MANAGEMENT.md) - Guide to managing Python environments +- [TESTING_INSTALLATION.md](TESTING_INSTALLATION.md) - Steps to verify your installation + +## Setting Up API Keys and Configuration + +Ember supports multiple ways to configure API keys for LLM providers. + +### Option 1: Environment Variables + +Set your API keys as environment variables: + +```bash +# For bash/zsh +export OPENAI_API_KEY="your-openai-key" +export ANTHROPIC_API_KEY="your-anthropic-key" +export GOOGLE_API_KEY="your-google-key" + +# For making environment variables persistent (add to your shell profile) +echo 'export OPENAI_API_KEY="your-openai-key"' >> ~/.bashrc # or ~/.zshrc +``` + +### Option 2: Configuration File + +Create a configuration file at one of these locations (searched in order): + +1. Current directory: `./config.yaml` +2. User home config: `~/.ember/config.yaml` +3. System config: `/etc/ember/config.yaml` + +Example configuration file: + +```yaml +model_registry: + providers: + openai: + api_key: ${OPENAI_API_KEY} # Will use environment variable + organization_id: "your-org-id" # Optional organization ID + anthropic: + api_key: "your-anthropic-key" # Direct value (example) + google: + api_key: ${GOOGLE_API_KEY} # Will use environment variable +``` + +### Option 3: Programmatic Configuration + +Set configuration values directly in your code: + +```python +import ember +from ember.core.config.manager import ConfigManager + +# Initialize with custom configuration +config = ConfigManager() +config.set("model_registry.providers.openai.api_key", "your-openai-key") +config.set("model_registry.providers.anthropic.api_key", "your-anthropic-key") + +# Initialize Ember with this configuration +service = ember.init(config=config) +``` + +### Setting Provider-Specific Options + +You can configure provider-specific options in your configuration file: + +```yaml +model_registry: + providers: + openai: + api_key: ${OPENAI_API_KEY} + base_url: "https://api.openai.com/v1" # Custom API endpoint + timeout: 30 # Timeout in seconds + anthropic: + api_key: ${ANTHROPIC_API_KEY} + max_retries: 3 +``` + +See [Configuration Quickstart](docs/quickstart/configuration.md) for more options and detailed configuration examples. + +## Basic Usage + +Here's how to get started with Ember in just a few lines of code: + +```python +# Import the package +import ember + +# Initialize and get the 'default' model service +service = ember.init() + +# Make a simple model call +response = service("openai:gpt-4o", "What is the capital of France?") +print(response.data) +``` + +## Building Your First Compound AI System + +Let's create a simple example that uses multiple models with parallelization: + +```python +from typing import ClassVar +from ember.api.xcs import jit +from ember.api.operator import Operator, Specification +from ember.api.models import EmberModel +from ember.core import non + +# Define structured input/output models +class QueryInput(EmberModel): + query: str + +class QueryOutput(EmberModel): + answer: str + confidence: float + +# Define the specification +class QuerySpecification(Specification): + input_model = QueryInput + structured_output = QueryOutput + +# Create a compound system using the @jit decorator for optimization +@jit +class ParallelQuerySystem(Operator[QueryInput, QueryOutput]): + # Class-level specification declaration with ClassVar + specification: ClassVar[Specification] = QuerySpecification() + + # Class-level field declarations + ensemble: non.UniformEnsemble + aggregator: non.MostCommon + + def __init__(self, parallel_calls: int = 3, model: str = 'openai: gpt-4o-mini', temp: float = 0.4): + # Init ensemble + self.ensemble = non.UniformEnsemble( + num_units=parallel_calls, + model_name=model, + temperature=temp + ) + + # Aggregate ensemble responses with "Most Common", "voting-bsed" aggregation + self.aggregator = non.MostCommon() + + def forward(self, *, inputs: QueryInput) -> QueryOutput: + # Get responses from multiple models (automatically parallelized) + ensemble_result = self.ensemble(inputs={"query": inputs.query}) + + # Aggregate the results (input dict format for operator invocation, vs. kwargs format in README.md. Both are supported.) + aggregated = self.aggregator(inputs={ + "query": inputs.query, + "responses": ensemble_result["responses"] + }) + + # Return structured output + return QueryOutput( + answer=aggregated["final_answer"], + confidence=aggregated.get("confidence", 0.0) + ) + +# Create and use the system +system = ParallelQuerySystem() +result = system(inputs={"query": "What is the speed of light?"}) + +print(f"Answer: {result.answer}") +print(f"Confidence: {result.confidence:.2f}") +``` + +## Next Steps + +- Explore the [Model Registry](docs/quickstart/model_registry.md) for using different LLM providers +- Learn about [Operators](docs/quickstart/operators.md) for building reusable components +- Check out [Networks of Networks](docs/quickstart/non.md) for complex AI systems +- Set up [Data Processing](docs/quickstart/data.md) for dataset handling +- Configure your application with [Configuration](docs/quickstart/configuration.md) +- Use [Simplified Imports](SIMPLIFIED_IMPORTS.md) for cleaner code + +To see Ember in action, explore these key examples: +- [Minimal Example](src/ember/examples/minimal_example.py) - Get started with basic usage +- [Model API Example](src/ember/examples/model_api_example.py) - Learn the models API +- [Ensemble Operator Example](src/ember/examples/diverse_ensemble_operator_example.py) - Build parallel model ensembles +- [API Operators Example](src/ember/examples/api_operators_example.py) - Use streamlined imports +- [Enhanced JIT Example](src/ember/examples/enhanced_jit_example.py) - Optimize execution with JIT + +For a full walkthrough of Ember's capabilities, see the [Examples Directory](src/ember/examples). + +## Getting Help + +- GitHub Issues: [https://github.com/pyember/ember/issues](https://github.com/pyember/ember/issues) +- Documentation: See the documentation files in the `docs/` directory +- Examples: Explore the examples in `src/ember/examples/` \ No newline at end of file diff --git a/README.md b/README.md index c075a627..36c759b4 100644 --- a/README.md +++ b/README.md @@ -1,565 +1,408 @@ -# Ember +

+ Ember Logo +

+

+ Ember +

-Build AI systems with the elegance of print("Hello World"). +

+Contributors +

-## Installation - -### From PyPI - -```bash -pip install ember-ai -``` - -### From Source (Development) - -```bash -git clone https://github.com/pyember/ember.git -cd ember -uv sync -``` - -## Quick Setup - -Run our interactive setup wizard for the best experience: - -```bash -# If installed from PyPI -ember setup - -# If running from source -uv run ember setup -``` +

+This repository is in collaboration with the following early users, contributors, and reviewers: +

-This will: -- Help you choose an AI provider (OpenAI, Anthropic, or Google) -- Configure your API keys securely -- Test your connection -- Save configuration to ~/.ember/config.yaml +

+Jared Quincy DavisF,S, Marquita EllisI, Diana ArroyoI, Pravein Govindan KannanI, Paul CastroI, Siddharth SharmaF,S, Lingjiao ChenMS, Omar KhattabD,MT, Alan ZhuB, Parth AsawaB, Connor ChowB, Jason LeeB, Jay Adityanag TipirneniB, Chad FergusonB, Kathleen GeB, Kunal AgrawalB, Rishab BhatiaB, Rohan PenmatchaB, Sai KolasaniB, Théo Jaffrelot InizanB, Deepak NarayananN, Long FeiF, Aparajit RaghavanF, Eyal CidonF, Jacob ScheinF, Prasanth SomasundarF, Boris HaninF,P, James ZouS, Alex DimakisB, Joey GonzalezB, Peter BailisG,S, Ion StoicaA,B,D, Matei ZahariaD,B +

-## Getting Started +

+F Foundry (MLFoundry), D Databricks, I IBM Research, S Stanford University, B UC Berkeley, MT MIT, N NVIDIA, MS Microsoft, A Anyscale, G Google, P Princeton +

-### 1. Configure API Keys +# Ember: A Compositional Framework for Compound AI Systems -Ember now reads provider credentials exclusively from its configuration file. -Use the CLI to persist secrets: +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) -```bash -# Interactive wizard (writes to ~/.ember/config.yaml) -uv run ember setup +## Ember in a Nutshell -# Or set values directly -uv run ember configure set providers.openai.api_key "sk-..." -uv run ember configure set providers.anthropic.api_key "sk-ant-..." -uv run ember configure set providers.google.api_key "..." -``` +Aspirationally, Ember is to Networks of Networks (NONs) Compound AI Systems development what PyTorch +and XLA are to Neural Networks (NN) development. It's a compositional framework with both eager +execution affordances and graph execution optimization capabilities. It enables users to compose +complex NONs, and supports automatic parallelization and optimization of these. -Environment-variable fallbacks (for example `OPENAI_API_KEY`) -are deprecated and no longer read at runtime. Migrate any existing shell scripts -or CI jobs to use `ember configure` so credentials remain deterministic. -**Option 3: Runtime Context** -```python -from ember.api import models -from ember.context import context - -with context.manager(providers={"openai": {"api_key": "sk-..."}}): - response = models("gpt-4", "Hello!") -``` - -### 2. Verify Setup +Ember's vision is to enable development of **compound AI systems composed of, one day, millions-billions of inference calls** and beyond. Simple constructs--like **best-of-N graphs**, **verifier-prover structures**, and **ensembles with “voting-based” aggregation**--work surprisingly well in many regimes. ```python -from ember.api import models - -# Discover available models -print(models.list()) # Shows all available models -print(models.providers()) # Shows available providers - -# Get detailed model information -info = models.discover() -for model_id, details in info.items(): - print(f"{model_id}: {details['description']} (context: {details['context_window']})") - -# This will work once credentials are configured via `ember setup` / `ember configure` -response = models("gpt-4", "Hello, world!") -print(response) +# With Ember's "compact notation" it is one line to build a simple parallel system with 101 GPT-4o instances synthesized by Claude +system = non.build_graph(["101:E:gpt-4o:0.7", "1:J:claude-3-5-sonnet:0.0"]) # Automatically parallelized +result = system(query="What's the most effective climate change solution?") ``` -If credentials are missing, you'll get a clear error message: -``` -ModelProviderError: No API key found for gpt-4. - -To fix this, choose one: +This led us to believe that there is a rich architecture space for constructing and optimizing what we call “networks of networks” graphs, or **NONs**. This is analogous to how neural network architecture research uncovered many emergent properties of systems composed of simple artificial neurons. It would be frictionful to conduct NN research if we had to implement architectures from scratch via for-loops or implement bespoke libraries for vectorization and efficient execution. Similarly, it can be challenging at present to compose NON architectures of many calls, despite the **rapidly falling cost-per-token of intelligence**. -Option 1: Run interactive setup (recommended) - ember setup +Ember's goal is to help unlock research and practice along this new frontier. -Option 2: Save to config - ember configure set providers.openai.api_key YOUR_KEY +## Documentation & Examples -Get your API key from: https://platform.openai.com/api-keys -``` +- [Architecture Overview](ARCHITECTURE.md) +- [Quick Start Guide](QUICKSTART.md) +- [LLM Specifications](LLM_SPECIFICATIONS.md) +- [Model Registry Guide](docs/quickstart/model_registry.md) +- [Operators Guide](docs/quickstart/operators.md) +- [NON Patterns](docs/quickstart/non.md) +- [Data Processing](docs/quickstart/data.md) +- [Configuration](docs/quickstart/configuration.md) +- [Examples Directory](src/ember/examples) -If you use an unknown model name, you'll see available options: -``` -ModelNotFoundError: Cannot determine provider for model 'claude-3'. -Available models: claude-4-sonnet, claude-3.5-sonnet-latest, claude-3.5-haiku-latest, -gemini-2.5-pro, gemini-2.5-flash, gemini-1.5-pro-latest, gpt-5, gpt-4.1, gpt-4o, -gpt-4o-mini, ... -``` - -### 3. Choose Your Style: Strings or Constants +## Simple Example: Ensemble Reasoning with Automatic Parallelization ```python -from ember.api import models, Models - -# Option 1: Direct strings (simple, works everywhere) -response = models("gpt-4", "Hello, world!") -response = models("claude-4-sonnet", "Write a haiku") - -# Option 2: Constants for IDE autocomplete and typo prevention -response = models(Models.GPT_4, "Hello, world!") -response = models(Models.CLAUDE_3_OPUS, "Write a haiku") - -# Both are exactly equivalent - Models.GPT_4 == "gpt-4" -``` +class QueryInput(EmberModel): + query: str + +class ConfidenceOutput(EmberModel): + answer: str + confidence: float -## Quick Start +class ReasonerSpec(Specification): + input_model = QueryInput + structured_output = ConfidenceOutput -```python -from ember.api import models - -# Direct LLM calls - no setup required -response = models("gpt-4", "Explain quantum computing in one sentence") -print(response) +@jit # Autonomically optimize execution with JIT compilation (e.g. TopoSort with Parallel Dispatch) +class EnsembleReasoner(Operator[QueryInput, ConfidenceOutput]): + specification = ReasonerSpec() + + def __init__(self, width: int = 3): + self.ensemble = non.UniformEnsemble( + num_units=width, + model_name="openai:gpt-4o", + temperature=0.7 + ) + + self.judge = non.JudgeSynthesis( + model_name="anthropic:claude-3-5-sonnet", + ) + + def forward(self, *, inputs: QueryInput) -> ReasonedOutput: + # These operations are automatically parallelized by Ember's XCS system + ensemble_result = self.ensemble(query=inputs.query) + + synthesis = self.judge( + query=inputs.query, + responses=ensemble_result["responses"] + ) + + return ConfidenceOutput( + answer=synthesis["final_answer"], + confidence=float(synthesis.get("confidence", 0.0)) + ) + +# Use it like any Python function +compound_system = EnsembleReasoner() +result = compound_system(query="What causes the northern lights?") +print(f"Answer: {result.answer}") +print(f"Confidence: {result.confidence:.2f}") + +# Alternatively, build the same pipeline with compact notation +pipeline = non.build_graph(["3:E:gpt-4o:0.7", "1:J:claude-3-5-sonnet:0.2"]) +result = pipeline(query="What causes the northern lights?") ``` -### Local, No API Keys (Ollama) - -Try Ember without creating any cloud accounts by using a local model via Ollama: - -1) Install and run Ollama - -- macOS: `brew install ollama && ollama serve` -- Linux: `curl -fsSL https://ollama.com/install.sh | sh && ollama serve` +## Compact Notation -2) Pull a model the first time (fast option) - -``` -ollama run llama3.2:1b -``` - -3) Call from Ember (auto-pull supported) +Ember's compact notation allows expression of complex AI architectures in minimal code: ```python -from ember.api import models -print(models("ollama/llama3.2:1b", "Say hi from Ember", autopull=True)) -``` - -Troubleshooting -- Connection refused: ensure `ollama serve` is running, or set `OLLAMA_BASE_URL` if using a non-default host/port. -- Model not found: run `ollama run ` once to download it locally. -- Slow/timeout: increase timeout via `EMBER_OLLAMA_TIMEOUT_MS` or pass `timeout=60` in the call. -- Streaming: `stream=True` is aggregated in this version; streaming iterator support is planned. - -### Available Models - -Common model identifiers: -- **OpenAI**: `gpt-5`, `gpt-4.1`, `gpt-4o`, `o1`, `gpt-4o-mini` -- **Anthropic**: `claude-4-sonnet`, `claude-opus-4`, `claude-3.5-sonnet-latest` -- **Google**: `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-1.5-pro-latest`, `gemini-1.5-flash-latest` - -Discovery runs by default, so as soon as your API key can see a newly released model (for example `gemini-2.5-flash` or `claude-4-sonnet`), Ember learns about it without code changes. - -Models are automatically routed to the correct provider based on their name. - -## Core Patterns - -### Context Management - -Ember uses a unified context system for configuration and state management: - -```python -from ember.context import context - -# Get the current context -ctx = context.get() - -# Temporary configuration overrides -with context.manager(models={"default": "gpt-4", "temperature": 0.9}) as ctx: - # All operations in this block use these settings - response = models("Hello") # Uses gpt-4 with temperature 0.9 +# Compact notation: "count:type:model:temperature" - each component precisely specified + +# BASIC: Single-line systems with automatic parallelization +basic = non.build_graph(["7:E:gpt-4o:0.7"]) # 7-model ensemble +voting = non.build_graph(["7:E:gpt-4o:0.7", "1:M"]) # With majority voting +judged = non.build_graph(["7:E:gpt-4o:0.7", "1:J:claude-3-5-sonnet:0.0"]) # With judge synthesis + +# STANDARD API: Equivalent to compact notation but with explicit objects +standard_system = non.Sequential(operators=[ + non.UniformEnsemble(num_units=7, model_name="gpt-4o", temperature=0.7), + non.JudgeSynthesis(model_name="claude-3-5-sonnet", temperature=0.0) +]) + +# ADVANCED: Reusable components for complex architectures +components = { + # Define building blocks once, reuse everywhere + "reasoning": ["3:E:gpt-4o:0.7", "1:V:gpt-4o:0.0"], # Verification pipeline + "research": ["3:E:claude-3-5-sonnet:0.5", "1:V:claude-3-5-sonnet:0.0"] # Different models +} + +# Build sophisticated multi-branch architecture in just 4 lines +advanced = non.build_graph([ + "$reasoning", # First branch: reasoning with verification + "$research", # Second branch: research with verification + "1:J:claude-3-5-opus:0.0" # Final synthesis of both branches +], components=components) # Automatically optimized for parallel execution + +# HORIZONTAL SCALING: Systematically explore scaling behavior +systems = { + # Scaling with MostCommon aggregation + "width_3_voting": non.build_graph(["3:E:gpt-4o:0.7", "1:M"]), + "width_7_voting": non.build_graph(["7:E:gpt-4o:0.7", "1:M"]), + "width_11_voting": non.build_graph(["11:E:gpt-4o:0.7", "1:M"]), + + # Scaling with judge synthesis + "width_3_judge": non.build_graph(["3:E:gpt-4o:0.7", "1:J:claude-3-5-sonnet:0.0"]), + "width_7_judge": non.build_graph(["7:E:gpt-4o:0.7", "1:J:claude-3-5-sonnet:0.0"]), + "width_11_judge": non.build_graph(["11:E:gpt-4o:0.7", "1:J:claude-3-5-sonnet:0.0"]), +} + +# Execute with full parallelism (XCS optimizes the execution graph automatically) +query = "What's the most effective climate change solution?" +results = {name: system(query=query) for name, system in systems.items()} ``` -The context system provides: -- Thread-safe and async-safe configuration management -- Hierarchical configuration with proper isolation -- Clean scoping for temporary overrides +## Core Elements -### Progressive Disclosure in APIs +1. **Composable Operators with Rigorous Specification**: Build reliable compound AI systems from + type-safe, reusable components with validated inputs and outputs +2. **Automatic Parallelization**: Independent operations are automatically executed concurrently + across a full computational graph +3. **XCS Optimization Framework**: "Accelerated Compound Systems" Just-in-time tracing and execution optimization with multiple strategies (trace, structural, enhanced). XCS is inspired by XLA, but intended more for accelerating compound systems vs. linear algebra operations, tuned for models and dicts, vs for vectors and numerical computation. +4. **Multi-Provider Support**: Unified API across OpenAI, Anthropic, Claude, Gemini, and more + with standardized usage tracking +5. **Transformation System**: Function transformations for vectorization (vmap), parallelization (pmap), and device sharding (mesh), with a composable interface for building complex transformations -Ember APIs follow a pattern of progressive disclosure - simple things are simple, complex things are possible: +## XCS Architecture -```python -from ember.api import models - -# Level 1: Simple one-off calls -response = models("gpt-4", "Hello world") - -# Level 2: Reusable configured instances -assistant = models.instance("gpt-4", temperature=0.7, system="You are helpful") -response = assistant("How do I center a div?") -``` +The Accelerated Compound Systems (XCS) module provides a computational graph-based system for building, optimizing, and executing complex operator pipelines: -This pattern appears throughout Ember: -- `models()` for quick calls, `models.instance()` for configured instances -- `operators.op` for simple functions, full `Operator` classes for complex needs -- Direct data access for simple cases, streaming pipelines for scale +1. **Unified JIT System**: Multiple compilation strategies under a consistent interface: + - `trace`: Traditional execution tracing + - `structural`: Structure-based analysis + - `enhanced`: Improved parallelism detection and code analysis -## Core Concepts +2. **Scheduler Framework**: Pluggable scheduler implementations for different execution patterns: + - `sequential`: Serial execution for debugging and determinism + - `parallel`: Thread-based parallel execution + - `wave`: Execution wave scheduling for optimal parallelism + - `topological`: Dependency-based execution ordering -Ember provides four primitives that compose into powerful AI systems: +3. **Transform System**: High-level operations for data and computation transformations: + - `vmap`: Vectorized mapping for batch processing + - `pmap`: Parallel mapping across multiple workers + - `mesh`: Device mesh-based sharding for multi-device execution -### 1. Models - Direct LLM Access +4. **Dependency Analysis**: Automatic extraction of dependencies between operations: + - Transitive closure calculation for complete dependency mapping + - Topological sorting with cycle detection + - Execution wave computation for parallel scheduling -```python -from ember.api import models - -# Simple invocation with string model names -response = models("claude-4-sonnet", "Write a haiku about programming") - -# Reusable configuration -assistant = models.instance("gpt-4", temperature=0.7, system="You are helpful") -response = assistant("How do I center a div?") +## Installation -# Alternative: Use constants for autocomplete -from ember.api import Models -response = models(Models.GPT_4, "Write a haiku") -``` +Ember uses [uv](https://github.com/astral-sh/uv) as its recommended package manager for significantly faster installations and dependency resolution. -### 2. Operators - Composable AI Building Blocks +```bash +# First, install uv if you don't have it +curl -LsSf https://astral.sh/uv/install.sh | sh # macOS/Linux +# or +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows +# or +pip install uv # Any platform -```python -from ember.api import operators +# Quick install using uv (recommended) +uv pip install ember-ai -# Transform any function into an AI operator -@operators.op -def summarize(text: str) -> str: - return models("gpt-4", f"Summarize in one sentence: {text}") +# Run examples directly with uv (no activation needed) +uv run python -c "import ember; print(ember.__version__)" -@operators.op -def translate(text: str, language: str = "Spanish") -> str: - return models("gpt-4", f"Translate to {language}: {text}") +# Install from source for development +git clone https://github.com/pyember/ember.git +cd ember +uv pip install -e ".[dev]" -# Compose operators naturally -pipeline = summarize >> translate -result = pipeline("Long technical article...") +# Traditional pip installation (alternative, slower) +pip install ember-ai ``` -### 3. Data - Streaming-First Data Pipeline +For detailed installation instructions, troubleshooting, and environment management, see our [Installation Guide](INSTALLATION_GUIDE.md). -```python -from ember.api import data - -# Stream data efficiently -for example in data.stream("mmlu"): - answer = models("gpt-4", example["question"]) - print(f"Q: {example['question']}") - print(f"A: {answer}") - -# Chain transformations -results = (data.stream("gsm8k") - .filter(lambda x: x["difficulty"] > 7) - .transform(preprocess) - .batch(32)) -``` +## Model Registry & Provider Integration -### 4. XCS - Zero-Config Optimization +Access models from any provider through a unified interface: ```python -from ember import xcs - -# Automatic JIT compilation -@xcs.jit -def process_batch(items): - return [models("gpt-4", item) for item in items] +from ember import initialize_ember +from ember.api.models import ModelEnum -# Automatic parallelization -fast_process = xcs.vmap(process_batch) -results = fast_process(large_dataset) # Runs in parallel -``` - -## Real-World Examples +# Initialize with multiple providers +service = initialize_ember(usage_tracking=True) -### Building a Code Reviewer +# Access models from different providers with the same API +response = service(ModelEnum.gpt_4o, "What is quantum computing?") +print(response.data) -```python -from ember.api import models, operators - -@operators.op -def review_code(code: str) -> dict: - """AI-powered code review""" - prompt = f"""Review this code for: - 1. Bugs and errors - 2. Performance issues - 3. Best practices - - Code: - {code} - """ - -review = models("claude-4-sonnet", prompt) - - # Extract structured feedback - return { - "summary": models("gpt-4", f"Summarize in one line: {review}"), - "issues": review, - "severity": models("gpt-4", f"Rate severity 1-10: {review}") - } - -# Use directly -feedback = review_code(""" -def fibonacci(n): - if n <= 1: - return n - return fibonacci(n-1) + fibonacci(n-2) -""") +# Track usage across providers +usage = service.usage_service.get_total_usage() +print(f"Total cost: ${usage.cost:.4f}") ``` -### Parallel Document Processing - -```python -from ember import xcs -from ember.api import data, models - -# Define processing pipeline -@xcs.jit -def analyze_document(doc: dict) -> dict: - # Extract key information - summary = models("gpt-4", f"Summarize: {doc['content']}") - entities = models("gpt-4", f"Extract entities: {doc['content']}") - sentiment = models("gpt-4", f"Analyze sentiment: {doc['content']}") - - return { - "id": doc["id"], - "summary": summary, - "entities": entities, - "sentiment": sentiment - } - -# Process documents in parallel -documents = data.stream("research_papers").first(1000) -results = xcs.vmap(analyze_document)(documents) - -# Results computed optimally with automatic parallelization -``` +## NON Patterns & Ensembling -### Multi-Model Ensemble +Build compound AI system architectures using the Network of Networks (NON) pattern with pre-built components: ```python -from ember.api import models, operators - -@operators.op -def consensus_answer(question: str) -> str: - """Get consensus from multiple models""" - # Query different models - gpt4_answer = models("gpt-4", question) - claude_answer = models("claude-4-sonnet", question) -gemini_answer = models("gemini-1.5-pro-latest", question) - - # Synthesize consensus - synthesis_prompt = f""" - Question: {question} - - Model answers: - - GPT-4: {gpt4_answer} - - Claude: {claude_answer} - - Gemini: {gemini_answer} +from ember.api import non + +# Standard API: Create a verification pipeline of ensemble→judge→verifier +pipeline = non.Sequential(operators=[ + # 1. Ensemble of 5 model instances running in parallel + non.UniformEnsemble( + num_units=5, + model_name="openai:gpt-4o-mini", + temperature=0.7 + ), - Synthesize the best answer combining insights from all models. - """ + # 2. Judge to synthesize the ensemble responses + non.JudgeSynthesis( + model_name="anthropic:claude-3-5-sonnet", + temperature=0.2 + ), - return models("gpt-4", synthesis_prompt) - -# Use for critical decisions -answer = consensus_answer("What's the best approach to distributed systems?") -``` - -## Command Line Interface - -Ember provides a comprehensive CLI for setup, configuration, and introspection. - -**Note:** If you installed Ember from PyPI, use `ember` directly. If running from source, prefix commands with `uv run`. - -### Setup and Configuration - -```bash -# Interactive setup wizard (recommended for first-time setup) -ember setup # or: uv run ember setup - -# Test your API connection -ember test # or: uv run ember test -ember test --model claude-4-sonnet - -# Configuration management -ember configure get models.default # Get a config value -ember configure set models.default "gpt-4" # Set a config value -ember configure list # Show all configuration -ember configure show credentials # Show specific section - -# Version information -ember version # or: uv run ember version -``` - -### Introspection Commands - -```bash -# Context introspection -ember context view # View current configuration -ember context view --format json # Output as JSON -ember context view --filter models # Show only models config -ember context validate # Validate configuration - -# Registry introspection -ember registry list-models # List available models -ember registry list-models --provider openai # Filter by provider -ember registry list-models --verbose # Detailed information -ember registry list-providers # Show provider status -ember registry info gpt-4 # Detailed model info + # 3. Verifier for quality control and fact-checking + non.Verifier( + model_name="anthropic:claude-3-5-haiku", + temperature=0.0 + ) +]) + +# Alternatively, create the same pipeline with compact notation +pipeline = non.build_graph([ + "5:E:gpt-4o-mini:0.7", # Ensemble with 5 instances + "1:J:claude-3-5-sonnet:0.2", # Judge synthesis + "1:V:claude-3-5-haiku:0.0" # Verification +]) + +# Build advanced architectures like NestedNetwork from example_architectures.py +# Define reusable SubNetwork component +components = { + "sub": ["2:E:gpt-4o:0.0", "1:V:gpt-4o:0.0"] # Ensemble → Verifier +} + +# Create a NestedNetwork with identical structure to the OOP implementation +nested = non.build_graph([ + "$sub", # First SubNetwork branch + "$sub", # Second SubNetwork branch + "1:J:gpt-4o:0.0" # Judge to synthesize results +], components=components) + +# Extend with custom operator types +custom_registry = non.OpRegistry.create_standard_registry() +custom_registry.register( + "CE", # Custom ensemble type + lambda count, model, temp: non.Sequential(operators=[ + non.UniformEnsemble(num_units=count, model_name=model, temperature=temp), + non.MostCommon() # Auto-aggregation + ]) +) + +# Use custom operators +advanced = non.build_graph(["3:CE:gpt-4o:0.7"], type_registry=custom_registry) + +# Execute with a single call +result = pipeline(query="What causes tsunamis?") ``` -### Advanced Configuration +## Graph Optimization & Execution -The context system supports multiple configuration sources with priority: - -1. **Runtime context** (highest priority) -2. **Configuration file** (`~/.ember/config.yaml`) + credential store -3. **Defaults** (lowest priority) - -Environment variables are supported for non-sensitive toggles (and to point at a -config file via `EMBER_CONFIG_PATH`), but provider credentials are read from the -centralized config/credential store. - -```python -from ember.api import models -from ember.context import context - -# Use context manager for temporary overrides -with context.manager( - models={"default": "gpt-4", "temperature": 0.7}, -): - # Production operations here - response = models("gpt-4", "Production query") -``` - -## Advanced Features - -### Type-Safe Operators +Ember's XCS system provides JAX/XLA-inspired tracing, transformation, and automatic parallelization: ```python +from ember.xcs import jit, execution_options, vmap, pmap, compose, explain_jit_selection from ember.api.operators import Operator -from pydantic import BaseModel - -class CodeInput(BaseModel): - language: str - code: str - -class CodeOutput(BaseModel): - is_valid: bool - errors: list[str] - suggestions: list[str] -class CodeValidator(Operator): - input_spec = CodeInput - output_spec = CodeOutput +# Basic JIT compilation with automatic strategy selection +@jit +class SimplePipeline(Operator): + # ... operator implementation ... + +# JIT with explicit mode selection +@jit(mode="enhanced") +class ComplexPipeline(Operator): + def __init__(self): + self.op1 = SubOperator1() + self.op2 = SubOperator2() + self.op3 = SubOperator3() - def call(self, input: CodeInput) -> CodeOutput: - prompt = f"Validate this {input.language} code: {input.code}" - result = models("gpt-4", prompt) - # Automatic validation against output_spec - return CodeOutput(...) + def forward(self, *, inputs): + # These operations will be automatically parallelized + result1 = self.op1(inputs=inputs) + result2 = self.op2(inputs=inputs) + + # Combine the parallel results + combined = self.op3(inputs={"r1": result1, "r2": result2}) + return combined + +# Configure execution parameters +with execution_options(scheduler="wave", max_workers=4): + result = pipeline(query="Complex question...") + +# Get explanation for JIT strategy selection +explanation = explain_jit_selection(pipeline) +print(f"JIT strategy: {explanation['strategy']}") +print(f"Rationale: {explanation['rationale']}") + +# Vectorized mapping for batch processing +batch_processor = vmap(my_operator) +batch_results = batch_processor(inputs={"data": [item1, item2, item3]}) + +# Parallel execution across multiple workers +parallel_processor = pmap(my_operator, num_workers=4) +parallel_results = parallel_processor(inputs=complex_data) + +# Compose transformations (vectorization + parallelism) +pipeline = compose(vmap(batch_size=32), pmap(num_workers=4))(my_operator) ``` -### Custom Data Loaders +## Data Handling & Evaluation -```python -from ember.api import data - -# Register custom dataset -@data.register("my-dataset") -def load_my_data(): - with open("data.jsonl") as f: - for line in f: - yield json.loads(line) - -# Use like built-in datasets -for item in data.stream("my-dataset"): - process(item) -``` - -### Performance Profiling +Ember provides a comprehensive data processing and evaluation framework with pre-built datasets and metrics: ```python -from ember import xcs - -# Automatic profiling -with xcs.profile() as prof: - results = expensive_operation() - -print(prof.report()) -# Shows execution time, parallelism achieved, bottlenecks -``` - -## Design Principles - -1. **Simple by Default** - Basic usage requires no configuration -2. **Progressive Disclosure** - Complexity available when needed -3. **Composition Over Configuration** - Build complex from simple -4. **Performance Without Sacrifice** - Fast by default, no manual tuning - -## Architecture - -Ember uses a registry-based architecture with four main components: - -- **Model Registry** - Manages LLM providers and connections -- **Operator System** - Composable computation units with JAX integration -- **Data Pipeline** - Streaming-first data loading and transformation -- **XCS Engine** - Automatic optimization and parallelization - -See [ARCHITECTURE.md](ARCHITECTURE.md) for detailed design documentation. - -## Development - -```bash -# Clone and install development dependencies -git clone https://github.com/pyember/ember.git -cd ember -uv sync --all-extras - -# Run tests -uv run pytest - -# Type checking -uv run mypy src/ - -# Benchmarks -uv run python -m benchmarks.suite +from ember.api.data import DatasetBuilder +from ember.api.eval import EvaluationPipeline, Evaluator + +# Load a dataset with the builder pattern +dataset = (DatasetBuilder() + .from_registry("mmlu") # Use a registered dataset + .subset("physics") # Select a specific subset + .split("test") # Choose the test split + .sample(100) # Random sample of 100 items + .transform( # Apply transformations + lambda x: {"query": f"Question: {x['question']}"} + ) + .build()) + +# Create a comprehensive evaluation pipeline +eval_pipeline = EvaluationPipeline([ + # Standard metrics + Evaluator.from_registry("accuracy"), + Evaluator.from_registry("response_quality"), + + # Custom evaluation metrics + Evaluator.from_function( + lambda prediction, reference: { + "factual_accuracy": score_factual_content(prediction, reference) + } + ) +]) + +# Evaluate a model or operator +results = eval_pipeline.evaluate(my_model, dataset) +print(f"Accuracy: {results['accuracy']:.2f}") +print(f"Response Quality: {results['response_quality']:.2f}") +print(f"Factual Accuracy: {results['factual_accuracy']:.2f}") ``` -## Contributing - -We welcome contributions that align with Ember's philosophy of simplicity and power. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. - ## License -MIT License. See [LICENSE](LICENSE) for details. - -## Acknowledgments - -Ember is inspired by the engineering excellence of: -- JAX's functional transformations -- PyTorch's intuitive API -- Langchain's comprehensive features (but simpler) -- The Unix philosophy of composable tools - -Built with principles from leaders who shaped modern computing. +Ember is released under the [MIT License](LICENSE). diff --git a/TESTING_INSTALLATION.md b/TESTING_INSTALLATION.md new file mode 100644 index 00000000..b58c2ceb --- /dev/null +++ b/TESTING_INSTALLATION.md @@ -0,0 +1,197 @@ +# Testing Ember Installation + +This document outlines a systematic process for testing the Ember installation process in a clean environment. This is useful for verifying that the package can be installed and used by new users without any issues. + +## Prerequisites + +Before testing the installation, ensure you have the following: + +- Python 3.9 or newer (3.10, 3.11, and 3.12 supported) +- uv installed (recommended) or any Python package manager +- Access to a terminal/command prompt +- Internet connection to download packages + +## Testing Process + +### 1. Creating a Clean Environment + +#### Using uv (recommended) + +```bash +# Create a new directory for testing +mkdir ember_test && cd ember_test + +# Install uv if needed +curl -LsSf https://astral.sh/uv/install.sh | sh # macOS/Linux +# or +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows + +# Create a virtual environment with uv +uv venv + +# Activate the environment (only needed for interactive use) +source .venv/bin/activate # On Windows: .venv\Scripts\activate +``` + +#### Using Python's venv + +```bash +# Create a new directory for testing +mkdir ember_test && cd ember_test + +# Create a virtual environment with Python 3.9+ +python3 -m venv test_env + +# Activate the environment +source test_env/bin/activate # On Windows: test_env\Scripts\activate + +# Install uv in the environment +pip install uv +``` + +#### Using pyenv for Python version management + +```bash +# Install pyenv if not already installed +# macOS: brew install pyenv +# Linux: curl https://pyenv.run | bash + +# Install Python using pyenv (3.9, 3.10, 3.11, or 3.12) +pyenv install 3.11.x + +# Create a directory for testing +mkdir ember_test && cd ember_test + +# Set local Python version +pyenv local 3.11.x + +# Use uv to create a virtual environment +uv venv +source .venv/bin/activate +``` + +#### Using Homebrew Python on macOS + +```bash +# Install Python via Homebrew +brew install python@3.11 + +# Verify the installation +/opt/homebrew/bin/python3.11 --version + +# Create a directory for testing +mkdir ember_test && cd ember_test + +# Use the Homebrew Python with uv +/opt/homebrew/bin/python3.11 -m pip install uv +/opt/homebrew/bin/python3.11 -m uv venv +source .venv/bin/activate +``` + +#### Using conda + +```bash +# Create a new conda environment with Python 3.11 +conda create -n ember_test python=3.11 + +# Activate the environment +conda activate ember_test + +# Install uv in the conda environment +pip install uv +``` + +### 2. Installing Ember + +#### Option A: Install from PyPI + +```bash +# Minimal installation (OpenAI only) +uv pip install "ember-ai[minimal]" + +# Full installation +# uv pip install "ember-ai[all]" +``` + +#### Option B: Install from local repository + +```bash +# Clone the repository if testing a local version +git clone https://github.com/pyember/ember.git +cd ember + +# Install dependencies with development extras +uv pip install -e ".[dev]" +``` + +### 3. Testing the Installation + +Run the minimal examples to verify the installation: + +```bash +# Check if the package imports correctly +uv run python -c "import ember; print(ember.__version__)" + +# For a local repository installation +uv run python src/ember/examples/basic/minimal_example.py +uv run python src/ember/examples/basic/minimal_operator_example.py + +# Or if you're in an activated environment +python -c "import ember; print(ember.__version__)" +python src/ember/examples/basic/minimal_example.py +``` + +### 4. Verification Checklist + +- [ ] Python 3.9+ requirement is enforced +- [ ] All dependencies are correctly resolved +- [ ] Core LLM providers (OpenAI, Anthropic, Google/Deepmind) are installed +- [ ] No errors during installation process +- [ ] Examples run without errors +- [ ] Import statements work correctly +- [ ] Basic functionality is operational + +## Common Issues and Resolutions + +### Python Version + +If you encounter errors related to Python version compatibility: + +``` +ERROR: Package 'ember-ai' requires a different Python: 3.9.6 not in '<3.13,>=3.9' +``` + +**Resolution**: Install Python 3.9 or newer and create a new virtual environment. + +### Dependency Conflicts + +If you encounter dependency resolution problems: + +**Resolution**: +```bash +# Try reinstalling with no cache to force re-resolution +uv pip install -e "." --no-cache + +# Or specify exact versions if needed +uv pip install -e "." --no-deps +uv pip install "dependency==specific.version" +``` + +### Installation Speed + +If you're experiencing slow installation (unlikely with uv): + +**Resolution**: +```bash +# Use the minimal installation if you only need basic functionality +uv pip install "ember-ai[minimal]" +``` + +## Reporting Issues + +If you encounter any issues during the installation testing process, please: + +1. Document the exact steps to reproduce the issue +2. Include your environment details (OS, Python version, uv version) +3. Copy the complete error message +4. Report the issue on the [GitHub repository](https://github.com/pyember/ember/issues) \ No newline at end of file diff --git a/conftest.py b/conftest.py new file mode 100644 index 00000000..a5bf79d9 --- /dev/null +++ b/conftest.py @@ -0,0 +1,126 @@ +""" +Root conftest.py for pytest configuration +""" + +import importlib +import logging +import os +import sys +import warnings +from pathlib import Path + +import pytest + + +# Configure logging to handle closed streams during Python interpreter shutdown +def _patch_logging_for_shutdown(): + """Patch logging handlers to gracefully handle closed streams at shutdown.""" + if not hasattr(logging.StreamHandler, "_ember_patched"): + # Save the original emit method + original_emit = logging.StreamHandler.emit + + # Create a safer version that handles closed file errors + def safe_emit(self, record): + try: + original_emit(self, record) + except (ValueError, IOError, OSError) as e: + if "closed" not in str(e).lower() and "closed file" not in str(e).lower(): + raise + + # Apply the patch + logging.StreamHandler.emit = safe_emit + logging.StreamHandler._ember_patched = True + + # Configure problematic loggers + for name in ["httpcore.connection", "httpcore.http11"]: + logging.getLogger(name).setLevel(logging.INFO) + + +# Apply logging patch +_patch_logging_for_shutdown() + +# Setup paths +PROJECT_ROOT = Path(__file__).parent.absolute() +SRC_PATH = PROJECT_ROOT / "src" + +print(f"Unit test Python path: {sys.path}") +print(f"Unit test current directory: {os.getcwd()}") + +# Add src directory to path +sys.path.insert(0, str(SRC_PATH)) +sys.path.insert(0, str(PROJECT_ROOT)) + +# Configure asyncio +pytest_plugins = ["pytest_asyncio"] + +# Silence common warnings +warnings.filterwarnings("ignore", message=".*XCS functionality partially unavailable.*") + +# Configure pytest-asyncio +def pytest_configure(config): + """Configure pytest-asyncio and register custom marks.""" + import pytest_asyncio + + # Use session-scoped event loops by default + pytest_asyncio.LOOP_SCOPE = "session" + + # Register custom marks + config.addinivalue_line("markers", "discovery: mark tests that interact with model discovery") + config.addinivalue_line("markers", "xcs: mark tests related to XCS functionality") + config.addinivalue_line("markers", "performance: mark tests that measure performance characteristics") + +@pytest.hookimpl(tryfirst=True) +def pytest_collection_modifyitems(config, items): + """Modify test items based on command line options.""" + run_all = config.getoption("--run-all-tests") + run_api = config.getoption("--run-api-tests") + run_perf = config.getoption("--run-perf-tests") + + for item in items: + skip_marks = [mark for mark in item.own_markers if mark.name == "skip"] + skipif_marks = [mark for mark in item.own_markers if mark.name == "skipif"] + + # Special handling for different test types + if any(mark.name == "performance" for mark in item.own_markers): + if run_all or run_perf: + for mark in skip_marks: + item.own_markers.remove(mark) + elif any("API_KEY" in str(mark.args) for mark in skipif_marks): + if run_api: + for mark in skip_marks: + item.own_markers.remove(mark) + elif run_all: + for mark in skip_marks: + item.own_markers.remove(mark) + +def pytest_addoption(parser): + """Add custom command line options to pytest.""" + parser.addoption( + "--run-perf-tests", + action="store_true", + default=False, + help="Run performance tests that are skipped by default", + ) + parser.addoption( + "--run-all-tests", + action="store_true", + default=False, + help="Run all tests including skipped tests (except those requiring API keys)", + ) + parser.addoption( + "--run-api-tests", + action="store_true", + default=False, + help="Run tests that require API keys and external services", + ) + +@pytest.fixture(scope="session", autouse=True) +def _add_config_helper(request): + """Add config attribute to pytest module for backward compatibility.""" + pytest.config = request.config + +@pytest.fixture(scope="session") +def event_loop_policy(): + """Return the event loop policy to use.""" + import asyncio + return asyncio.get_event_loop_policy() \ No newline at end of file diff --git a/docs/CONTEXT_SYSTEM.md b/docs/CONTEXT_SYSTEM.md new file mode 100644 index 00000000..812accb6 --- /dev/null +++ b/docs/CONTEXT_SYSTEM.md @@ -0,0 +1,285 @@ +# Ember Context System + +## Overview + +The Ember Context System provides a lightweight, zero-overhead approach to component discovery and dependency management. This redesigned system eliminates circular dependencies, improves thread safety, and enhances performance while significantly reducing complexity. + +## Key Concepts + +### Registry + +The `Registry` is the only global abstraction in the system. It provides a thread-local dictionary that components use to discover each other: + +```python +from ember.core.context import Registry + +# Get current thread's registry +registry = Registry.current() + +# Register a component +registry.register("my_component", component_instance) + +# Get a component +component = registry.get("my_component") +``` + +### Component + +The `Component` base class provides common functionality for all components: + +```python +from ember.core.context import Component + +class MyComponent(Component): + def _register(self): + """Register in registry.""" + self._registry.register("my_component", self) + + def _initialize(self): + """Initialize lazily.""" + # Initialization logic +``` + +### Core Components + +The system includes these core components: + +- **ConfigComponent**: Configuration management +- **ModelComponent**: Model discovery and creation +- **DataComponent**: Dataset management +- **MetricsComponent**: Performance metrics collection + +## Migration Guide + +### Old API vs New API + +Old API (EmberContext): + +```python +from ember.core.app_context import get_app_context + +# Get context +context = get_app_context() + +# Get model and dataset +model = context.get_model("my_model") +dataset = context.get_dataset("my_dataset") +``` + +New API (Component-based): + +```python +from ember.core.context.model import ModelComponent +from ember.core.context.data import DataComponent + +# Get components +model_component = ModelComponent() +data_component = DataComponent() + +# Get model and dataset +model = model_component.get_model("my_model") +dataset = data_component.get_dataset("my_dataset") +``` + +### Step 1: Update Imports + +Change your imports from: + +```python +from ember.core.app_context import get_app_context, EmberContext +``` + +To: + +```python +from ember.core.context.compatibility import current_context, EmberContext +``` + +This provides compatibility with the old API while using the new implementation. + +### Step 2: Migrate to Component-Based API + +For each usage of `get_app_context()`, consider migrating to the direct component API: + +Before: + +```python +context = get_app_context() +model = context.get_model("gpt-4") +``` + +After: + +```python +from ember.core.context.model import ModelComponent +model_component = ModelComponent() +model = model_component.get_model("gpt-4") +``` + +### Step 3: Update Mocks in Tests + +Update test mocks to mock the component directly rather than the context: + +Before: + +```python +# Mock EmberContext +context_mock = MagicMock() +context_mock.get_model.return_value = model_mock +monkeypatch.setattr("ember.core.app_context.get_app_context", lambda: context_mock) +``` + +After: + +```python +# Mock ModelComponent +model_component_mock = MagicMock() +model_component_mock.get_model.return_value = model_mock +monkeypatch.setattr("ember.core.context.model.ModelComponent.get", + lambda cls: model_component_mock) +``` + +Or use the scoped registry for cleaner tests: + +```python +from ember.core.context import scoped_registry +from ember.core.context.model import ModelComponent + +# Create isolated registry for test +with scoped_registry() as registry: + # Create component with explicit registry + model = ModelComponent(registry) + + # Register mock model + model.register_model("test_model", mock_model) + + # Test code that uses model + result = test_function() # Will use mock_model +``` + +## Best Practices + +1. **Direct Component Usage**: Access components directly instead of through EmberContext +2. **Explicit Dependencies**: Pass components as arguments instead of implicitly accessing them +3. **Scoped Testing**: Use `scoped_registry()` for isolated tests +4. **Lazy Loading**: Let components initialize themselves when first accessed +5. **Thread Safety**: Design components to be thread-safe using the double-checked locking pattern + +## Performance Considerations + +The new context system is designed for optimal performance: + +- Thread-local storage eliminates most contention +- Lazy initialization reduces startup costs +- Component caching accelerates repeated lookups +- Direct component interaction reduces indirection + +## Thread Safety + +Thread safety is achieved through: + +1. **Thread-Local Storage**: Each thread has its own isolated registry +2. **Double-Checked Locking**: Efficient lazy initialization pattern +3. **Fine-Grained Locking**: Component-specific locks for minimal contention + +With this approach, most operations require no locking, and only registration and initialization need synchronization. + +## Advanced Usage + +### Custom Components + +Creating custom components is straightforward: + +```python +from ember.core.context import Component, Registry + +class MyCustomComponent(Component): + def __init__(self, registry=None): + super().__init__(registry) + self._data = {} + + def _register(self): + self._registry.register("my_custom", self) + + def _initialize(self): + # Lazy initialization logic + config = self._registry.get("config") + if config: + self._data = config.get_config("my_custom") or {} + + def get_item(self, key): + self._ensure_initialized() + return self._data.get(key) +``` + +### Registry Scoping + +For isolated execution contexts: + +```python +from ember.core.context import scoped_registry +from ember.core.context.config import ConfigComponent + +def isolated_function(): + with scoped_registry() as registry: + # Create components with isolated registry + config = ConfigComponent(registry, config_data={"custom": {"key": "value"}}) + + # Function logic using isolated components + result = process_with_config(config) + + return result +``` + +This ensures that components created within the function don't affect the rest of the application. + +## Architecture + +The new architecture simplifies the design to a single abstraction with direct component interaction: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ User Code │ +│ │ +│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ +│ │ ModelComponent│ │ DataComponent │ │ConfigComponent│ │ +│ │ get_model() │ │ get_dataset() │ │ get_config() │ │ +│ └───────────────┘ └───────────────┘ └───────────────┘ │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Thread-Local Registry │ +│ │ +│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ +│ │ Thread 1 │ │ Thread 2 │ │ Thread 3 │ │ +│ │ Registry │ │ Registry │ │ Registry │ │ +│ └───────────────┘ └───────────────┘ └───────────────┘ │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Component Registration │ +│ │ +│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ +│ │ "model" → │ │ "data" → │ │ "config" → │ │ +│ │ ModelComponent│ │ DataComponent │ │ConfigComponent│ │ +│ └───────────────┘ └───────────────┘ └───────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +This design: +- Eliminates circular dependencies +- Reduces indirection +- Improves component discoverability +- Enhances thread safety +- Optimizes performance + +## Implementation Status + +- ✅ Core thread-local registry - Fully implemented with `Registry` class +- ✅ Component base class - Common functionality for all components +- ✅ Core components - Config, Model, Data, and Metrics implementations +- ✅ Management utilities - Scoped registry and temporary components +- ✅ Compatibility layer - Integration with existing code +- ✅ Documentation - Migration guide and best practices \ No newline at end of file diff --git a/docs/assets/ember_icon_400.png b/docs/assets/ember_icon_400.png new file mode 100644 index 00000000..d5a8d655 Binary files /dev/null and b/docs/assets/ember_icon_400.png differ diff --git a/docs/assets/ember_icon_400@2x.svg b/docs/assets/ember_icon_400@2x.svg new file mode 100644 index 00000000..db39303e --- /dev/null +++ b/docs/assets/ember_icon_400@2x.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/assets/ember_workmark.png b/docs/assets/ember_workmark.png new file mode 100644 index 00000000..f5fa3bb8 Binary files /dev/null and b/docs/assets/ember_workmark.png differ diff --git a/docs/assets/ember_workmark.svg b/docs/assets/ember_workmark.svg new file mode 100644 index 00000000..8950ee9f --- /dev/null +++ b/docs/assets/ember_workmark.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs/assets/logo_ember_icon@2x.png b/docs/assets/logo_ember_icon@2x.png new file mode 100644 index 00000000..050d1821 Binary files /dev/null and b/docs/assets/logo_ember_icon@2x.png differ diff --git a/docs/assets/logos/anyscale-logo.png b/docs/assets/logos/anyscale-logo.png new file mode 100644 index 00000000..2bf945c3 Binary files /dev/null and b/docs/assets/logos/anyscale-logo.png differ diff --git a/docs/assets/logos/berkeley-logo.png b/docs/assets/logos/berkeley-logo.png new file mode 100644 index 00000000..02a2987c Binary files /dev/null and b/docs/assets/logos/berkeley-logo.png differ diff --git a/docs/assets/logos/databricks-logo.png b/docs/assets/logos/databricks-logo.png new file mode 100644 index 00000000..923e8cdf Binary files /dev/null and b/docs/assets/logos/databricks-logo.png differ diff --git a/docs/assets/logos/foundry-logo.avif b/docs/assets/logos/foundry-logo.avif new file mode 100644 index 00000000..b7dfda32 Binary files /dev/null and b/docs/assets/logos/foundry-logo.avif differ diff --git a/docs/assets/logos/google-logo.png b/docs/assets/logos/google-logo.png new file mode 100644 index 00000000..39b1e869 Binary files /dev/null and b/docs/assets/logos/google-logo.png differ diff --git a/docs/assets/logos/ibm-logo.svg b/docs/assets/logos/ibm-logo.svg new file mode 100644 index 00000000..3758a0e1 --- /dev/null +++ b/docs/assets/logos/ibm-logo.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/logos/microsoft-logo.jpeg b/docs/assets/logos/microsoft-logo.jpeg new file mode 100644 index 00000000..60dbab3b Binary files /dev/null and b/docs/assets/logos/microsoft-logo.jpeg differ diff --git a/docs/assets/logos/nvidia-log.png b/docs/assets/logos/nvidia-log.png new file mode 100644 index 00000000..40fd014b Binary files /dev/null and b/docs/assets/logos/nvidia-log.png differ diff --git a/docs/assets/logos/princeton-logo.png b/docs/assets/logos/princeton-logo.png new file mode 100644 index 00000000..c902cab8 Binary files /dev/null and b/docs/assets/logos/princeton-logo.png differ diff --git a/docs/assets/logos/stanford-logo.png b/docs/assets/logos/stanford-logo.png new file mode 100644 index 00000000..e8a0eb1b Binary files /dev/null and b/docs/assets/logos/stanford-logo.png differ diff --git a/docs/cli/CLI_STATUS.md b/docs/cli/CLI_STATUS.md new file mode 100644 index 00000000..0fce38fc --- /dev/null +++ b/docs/cli/CLI_STATUS.md @@ -0,0 +1,32 @@ +# Ember CLI Status + +## Current Status + +The Ember CLI is currently being developed separately from the core Python framework. It has been excluded from the main development workflow and git tracking to allow for independent development and prevent integration issues. + +## Structure + +The CLI is built with: +- TypeScript/Node.js +- Commander.js for command-line parsing +- Python-bridge for communication with the Python framework + +## Key Components + +1. **Command Modules** + - model.ts - Manage LLM models + - provider.ts - Manage providers + - invoke.ts - Invoke models + - config.ts - Manage configuration + - project.ts - Project scaffolding + - version.ts - Version information + +2. **Services** + - config-manager.ts - Manage CLI configuration + - python-bridge.ts - Interface with the Python framework + +3. **UI Components** + - Spinners, progress bars, banners + - Interactive prompts + +The CLI is currently excluded from the standard installation. When development resumes, it will be available as a separate package or optional component. \ No newline at end of file diff --git a/docs/cli/DEVELOPERS.md b/docs/cli/DEVELOPERS.md new file mode 100644 index 00000000..f2e4bf05 --- /dev/null +++ b/docs/cli/DEVELOPERS.md @@ -0,0 +1,430 @@ +# Ember CLI Developer Guide + +This guide is intended for developers who want to contribute to the Ember CLI or extend it with plugins and custom functionality. + +## Architecture Overview + +The Ember CLI uses a hybrid architecture: + +1. **Frontend**: Node.js/TypeScript CLI interface built with Commander.js +2. **Backend**: Python Ember core framework accessed via python-bridge +3. **Configuration**: Local storage using the conf package with encryption + +``` +┌─────────────────────────────────────────┐ +│ Node.js Frontend │ +├─────────────┬───────────────┬───────────┤ +│ UI/UX │ Command │ Config │ +│ Components │ Handlers │ Manager │ +├─────────────┴───────┬───────┴───────────┤ +│ Python Bridge │ +├─────────────────────┼───────────────────┤ +│ Python Backend (Ember Core) │ +└─────────────────────────────────────────┘ +``` + +### Key Components + +- **CLI Entry Point** (`src/cli/index.ts`): Main entry point that sets up commands +- **Command Modules** (`src/cli/commands/`): Individual command implementations +- **Python Bridge** (`src/cli/bridge/`): Interface between TypeScript and Python +- **UI Components** (`src/cli/ui/`): User interface elements +- **Services** (`src/cli/services/`): Shared functionality +- **Utilities** (`src/cli/utils/`): Helper functions + +## Development Setup + +### Prerequisites + +- Node.js 16+ +- Python 3.11+ +- TypeScript 4.9+ +- Ember AI package + +### Installation + +```bash +# Clone the repository +git clone https://github.com/pyember/ember.git +cd ember + +# Install dependencies +npm install + +# Build the CLI +npm run build + +# Create a link for local development +npm link +``` + +### Development Workflow + +```bash +# Run in development mode with watch +npm run watch + +# Test your changes +ember --debug + +# Lint code +npm run lint + +# Run tests +npm test +``` + +## Adding a New Command + +To add a new command to the CLI, follow these steps: + +1. Create a new file in `src/cli/commands/` for your command +2. Implement the command with the Commander.js pattern +3. Register your command in `src/cli/index.ts` + +Here's an example of a new command: + +```typescript +// src/cli/commands/example.ts +import { Command } from 'commander'; +import chalk from 'chalk'; +import ora from 'ora'; + +import { getPythonBridge } from '../bridge/python-bridge'; +import { isJsonOutput } from '../utils/options'; +import { displaySection, displaySuccess } from '../ui/intro'; + +/** + * Register example command with the CLI program + * + * @param program The commander program instance + */ +export function registerExampleCommand(program: Command): void { + program + .command('example') + .description('Example command to demonstrate development') + .option('-n, --name ', 'Name parameter') + .action(async (options) => { + await runExample(options); + }); +} + +/** + * Run the example command + * + * @param options Command options + */ +async function runExample(options: any): Promise { + const spinner = ora('Running example...').start(); + + try { + // Get name from options or use default + const name = options.name || 'world'; + + // Get Python bridge + const bridge = getPythonBridge(); + await bridge.initialize(); + + // Call Python backend (example) + const version = await bridge.getVersion(); + + // Stop spinner + spinner.stop(); + + // Format and display result + if (isJsonOutput()) { + // JSON output + console.log(JSON.stringify({ + message: `Hello, ${name}!`, + version + }, null, 2)); + } else { + // Human-readable output + displaySection('Example Command'); + console.log(`Hello, ${chalk.cyan(name)}!`); + console.log(`Ember version: ${version}`); + displaySuccess('Command completed successfully'); + } + } catch (error: any) { + // Handle errors + spinner.fail('Command failed'); + console.error(chalk.red('Error:'), error.message); + } +} +``` + +Then register your command in `src/cli/index.ts`: + +```typescript +// src/cli/index.ts +import { registerExampleCommand } from './commands/example'; + +// Register commands +registerVersionCommand(program); +registerProviderCommands(program); +registerModelCommands(program); +registerProjectCommands(program); +registerInvokeCommand(program); +registerConfigCommands(program); +registerExampleCommand(program); // Add your new command here +``` + +## Extending the Python Bridge + +If you need to add new functionality to the Python bridge: + +1. Add a method to the `EmberPythonBridge` interface in `src/cli/bridge/python-bridge.ts` +2. Implement the method in the `PythonBridgeImpl` class +3. Add corresponding Python code that will be executed by the bridge + +Example: + +```typescript +// Add to the EmberPythonBridge interface +/** + * Run a custom function in the Python backend + */ +runCustomFunction(name: string, args: Record): Promise; + +// Implement in the PythonBridgeImpl class +async runCustomFunction(name: string, args: Record): Promise { + await this.ensureInitialized(); + + const argsJson = JSON.stringify(args); + + return await this.bridge.eval` +import json +try: + # Call the function dynamically + result = getattr(service, ${name})(**json.loads(${argsJson})) + json.dumps(result) +except Exception as e: + json.dumps({"error": str(e)}) +`; +} +``` + +## UI Components + +The CLI uses several UI components to create a beautiful user experience: + +- **Banner**: Displays the Ember CLI logo +- **Spinners**: Shows progress for async operations +- **Tables**: Formats tabular data +- **Colors**: Highlights important information +- **Emoji**: Adds visual cues + +When creating new UI components, follow these guidelines: + +1. Use the `chalk` library for colors +2. Use `ora` for spinners +3. Use `table` for tabular data +4. Use `emoji` for visual cues +5. Always respect the `--quiet` and `--no-color` flags + +## Configuration Management + +The CLI uses the `conf` library to store configuration. Key features: + +- **Encryption**: Sensitive data is encrypted +- **Schema Validation**: Configuration follows a defined schema +- **Persistence**: Configuration is stored between runs + +When accessing configuration, always use the `ConfigManager` class: + +```typescript +// Get config manager singleton +const configManager = ConfigManager.getInstance(); + +// Get a setting +const value = configManager.getSetting('my.setting', defaultValue); + +// Set a setting +configManager.setSetting('my.setting', newValue); +``` + +## Error Handling + +Follow these guidelines for error handling: + +1. Always catch exceptions in async functions +2. Use `try/catch` blocks around Python bridge calls +3. Show user-friendly error messages +4. Include technical details in debug mode +5. Use spinners to indicate progress/failure + +Example: + +```typescript +try { + // Code that might throw + const result = await riskyOperation(); + // Handle success +} catch (error: any) { + // Handle error + console.error(chalk.red('Error:'), error.message); + if (isDebugMode()) { + console.error(error.stack); + } +} +``` + +## Testing + +The CLI includes a comprehensive test suite: + +- **Unit Tests**: Test individual components +- **Integration Tests**: Test command flows +- **Mock Tests**: Test with mocked Python bridge + +To write tests: + +1. Create test files in the `__tests__` directory +2. Use Jest for testing +3. Mock external dependencies +4. Test both success and failure cases + +Example test: + +```typescript +// __tests__/commands/version.test.ts +import { registerVersionCommand } from '../../src/cli/commands/version'; +import { getPythonBridge } from '../../src/cli/bridge/python-bridge'; + +// Mock the Python bridge +jest.mock('../../src/cli/bridge/python-bridge'); + +describe('Version Command', () => { + beforeEach(() => { + // Setup mocks + (getPythonBridge as jest.Mock).mockImplementation(() => ({ + initialize: jest.fn().mockResolvedValue(undefined), + getVersion: jest.fn().mockResolvedValue('0.1.0') + })); + }); + + it('should display version information', async () => { + // Create a mock Commander instance + const program = { + command: jest.fn().mockReturnThis(), + description: jest.fn().mockReturnThis(), + option: jest.fn().mockReturnThis(), + action: jest.fn().mockReturnThis() + }; + + // Register command + registerVersionCommand(program as any); + + // Verify command was registered + expect(program.command).toHaveBeenCalledWith('version'); + + // Get the action callback + const actionCallback = program.action.mock.calls[0][0]; + + // Create a mock console.log + const originalLog = console.log; + console.log = jest.fn(); + + // Run the action + await actionCallback({}); + + // Verify output + expect(console.log).toHaveBeenCalled(); + expect(getPythonBridge().getVersion).toHaveBeenCalled(); + + // Restore console.log + console.log = originalLog; + }); +}); +``` + +## Building and Publishing + +To build and publish the CLI: + +```bash +# Build the CLI +npm run build + +# Test the build +node dist/index.js version + +# Publish to npm +npm publish +``` + +## Style Guide + +Follow these coding style guidelines: + +1. Use TypeScript for all JavaScript code +2. Use async/await for asynchronous operations +3. Document all public functions and classes with JSDoc +4. Use SOLID principles for code organization +5. Use semantic versioning for releases + +## Best Practices + +1. **Security**: + - Never log API keys or sensitive information + - Always encrypt stored credentials + - Validate user input + +2. **Performance**: + - Minimize Python bridge calls + - Batch operations when possible + - Use streaming for large responses + +3. **User Experience**: + - Always show progress for long operations + - Provide clear error messages + - Include helpful tips and examples + +4. **Code Quality**: + - Write unit and integration tests + - Use TypeScript types strictly + - Document complex code + - Follow the SOLID principles + +## Troubleshooting Development Issues + +### Python Bridge Issues + +If you encounter problems with the Python bridge: + +1. Check that Python 3.11+ is installed and accessible +2. Verify Ember AI is installed in the Python environment +3. Use debug mode to see Python errors +4. Check that Python bridge is being initialized correctly + +### TypeScript Compilation Issues + +For TypeScript errors: + +1. Run `npm run lint` to find code issues +2. Check import paths (case-sensitive) +3. Ensure type definitions are correct +4. Run `tsc --noEmit` to type-check without building + +## Getting Help + +For development questions: + +1. Check the existing code for examples +2. Review the documentation in code comments +3. Open an issue on GitHub for unanswered questions + +## Contributing + +We welcome contributions to the Ember CLI! Follow these steps: + +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Write tests for your changes +5. Run the test suite +6. Submit a pull request + +## License + +The Ember CLI is licensed under the MIT License. \ No newline at end of file diff --git a/docs/cli/ERROR_HANDLING.md b/docs/cli/ERROR_HANDLING.md new file mode 100644 index 00000000..450f8486 --- /dev/null +++ b/docs/cli/ERROR_HANDLING.md @@ -0,0 +1,160 @@ +# Error Handling in Ember CLI + +Ember CLI includes a robust error handling system that provides structured errors, detailed information, and helpful suggestions to users. This document describes how error handling works and how to use it when developing new commands or features. + +## Key Features + +- **Structured Errors**: All errors extend a base `EmberCliError` class +- **Error Categorization**: Errors are categorized by type with specific error codes +- **Rich Error Information**: Errors can include suggestions, documentation links, and context +- **Python Error Mapping**: Python exceptions are properly mapped to TypeScript errors +- **Consistent Display**: Errors are displayed consistently across the CLI + +## Error Class Hierarchy + +The Ember CLI error classes follow this hierarchy: + +``` +EmberCliError (base class) +├── PythonBridgeError - For Python bridge communication issues +├── ModelError - For model and provider errors +├── ProjectError - For project-related errors +├── ValidationError - For user input validation errors +├── ConfigurationError - For configuration errors +├── AuthorizationError - For authentication and authorization errors +└── NetworkError - For network-related errors +``` + +## Error Codes + +Errors are assigned unique error codes for identification and documentation: + +- **1000-1999**: General CLI errors +- **2000-2999**: Python bridge errors +- **3000-3999**: Model and provider errors +- **4000-4999**: Project errors + +## Using Error Handling in Commands + +### Creating and Throwing Errors + +When you need to create an error in your command: + +```typescript +import { createModelError, ModelErrorCodes } from '../errors'; + +// Create and throw an error +throw createModelError( + 'Model not found: gpt-4', + ModelErrorCodes.MODEL_NOT_FOUND, + { + suggestions: [ + 'Run `ember models` to list available models', + 'Check that your OpenAI API key is set correctly' + ] + } +); +``` + +### Using the Try-Catch Helper + +You can use the `tryCatch` helper to handle errors consistently: + +```typescript +import { tryCatch } from '../errors'; + +await tryCatch( + async () => { + // Your code here + const result = await someAsyncFunction(); + return result; + }, + {}, // Error format options + true // Exit process on error +); +``` + +### Handling Errors in Command Actions + +For command actions, wrap your function in a try-catch block: + +```typescript +.action(async (options) => { + try { + await commandFunction(options); + } catch (error) { + handleError(error, {}, true); + } +}); +``` + +## Error Format Options + +When displaying errors with `handleError`, you can customize the output: + +```typescript +handleError(error, { + includeCode: true, // Include error code in output + includeSuggestions: true, // Include suggestions + includeDocsLinks: true, // Include documentation links + includeStack: false, // Include stack trace + useColor: true, // Use colored output + asJson: false // Format as JSON +}); +``` + +## Python Error Translation + +The Python bridge translates Python exceptions to TypeScript errors: + +``` +Python Exception → TypeScript Error +----------------- --------------- +ModelNotFoundError → ModelError (MODEL_NOT_FOUND) +ProviderAPIError → ModelError (PROVIDER_API_ERROR) +ValidationError → ValidationError (INVALID_ARGUMENT) +FileNotFoundError → ValidationError (FILE_NOT_FOUND) +``` + +## Best Practices + +1. **Use Specific Error Types**: Use the most specific error type for the situation +2. **Include Helpful Suggestions**: Always include suggestions to help users resolve the issue +3. **Add Context**: Include relevant context information for debugging +4. **Clean Up Resources**: Always clean up resources in error handlers (like spinners) +5. **Validate Early**: Validate user input early to avoid deeper errors +6. **Handle All Errors**: Never let errors go unhandled or display as generic errors +7. **Add Documentation Links**: For complex issues, include links to documentation + +## Example: Command Error Handling + +Here's a complete example of error handling in a command: + +```typescript +async function myCommand(options: any): Promise { + const spinner = ora('Loading...').start(); + + try { + // Validate input + if (!options.required) { + throw createValidationError( + 'Missing required option', + GeneralErrorCodes.MISSING_REQUIRED_ARGUMENT + ); + } + + // Do something that might fail + const result = await someAsyncOperation(); + + // Handle success + spinner.succeed('Operation completed'); + console.log(result); + } catch (error) { + // Stop spinner + spinner.stop(); + + // Rethrow (will be handled by command wrapper) + throw error; + } +} +``` \ No newline at end of file diff --git a/docs/cli/QUICKREF.md b/docs/cli/QUICKREF.md new file mode 100644 index 00000000..3791fe96 --- /dev/null +++ b/docs/cli/QUICKREF.md @@ -0,0 +1,167 @@ +# Ember CLI Quick Reference + +This quick reference guide covers the most common Ember CLI commands and usage patterns. + +## Getting Started + +```bash +# Install the CLI +npm install -g ember-cli + +# Check version +ember version + +# Get help +ember help +``` + +## Provider Management + +```bash +# List providers +ember provider list + +# Configure a provider +ember provider configure openai + +# Set default provider +ember provider use openai +``` + +## Model Management + +```bash +# List models +ember model list + +# List models for a specific provider +ember model list --provider openai + +# Get model information +ember model info openai:gpt-4o + +# Set default model +ember model use openai:gpt-4o +``` + +## Invoking Models + +```bash +# Basic invocation (uses default model if set) +ember invoke --prompt "Hello, world!" + +# Invoke specific model +ember invoke --model openai:gpt-4o --prompt "Hello, world!" + +# Read prompt from file +ember invoke --model openai:gpt-4o --file myprompt.txt + +# Add system prompt +ember invoke --model openai:gpt-4o --prompt "List 5 capitals" --system "You are a geography expert" + +# Save output to file +ember invoke --model openai:gpt-4o --prompt "Write a poem" --output poem.txt + +# Show token usage +ember invoke --model openai:gpt-4o --prompt "Explain quantum computing" --show-usage + +# Stream response +ember invoke --model openai:gpt-4o --prompt "Write a story" --stream +``` + +## Project Management + +```bash +# Create new project +ember project new myproject + +# Create project with specific template +ember project new myproject --template api + +# List available templates +ember project templates + +# Analyze project +ember project analyze ./myproject +``` + +## Configuration Management + +```bash +# List configuration +ember config list + +# Set configuration +ember config set defaultModel openai:gpt-4o + +# Get specific configuration +ember config get defaultProvider + +# Export/import configuration +ember config export config.json +ember config import config.json + +# Reset configuration +ember config reset +``` + +## JSON Output (for scripting) + +```bash +# Get providers as JSON +ember provider list --json + +# Get models as JSON +ember model list --json + +# Run model and get JSON result +ember invoke --model openai:gpt-4o --prompt "Hello" --json > result.json +``` + +## Environment Variables + +```bash +# Set API keys +export OPENAI_API_KEY="your-api-key" +export ANTHROPIC_API_KEY="your-api-key" + +# Set defaults +export EMBER_DEFAULT_PROVIDER="openai" +export EMBER_DEFAULT_MODEL="openai:gpt-4o" + +# Other options +export EMBER_DEBUG=1 +export EMBER_NO_COLOR=1 +``` + +## Common Options + +```bash +# Debug mode +ember --debug + +# Disable colors +ember --no-color + +# Quiet mode (minimal output) +ember --quiet + +# JSON output +ember --json +``` + +## Shell Completion + +```bash +# Install shell completion +ember completion install + +# Generate completion for a specific shell +ember completion bash +ember completion zsh +ember completion fish +ember completion powershell + +# Output to a file +ember completion bash ~/.bash_completion.d/ember +``` \ No newline at end of file diff --git a/docs/cli/README.md b/docs/cli/README.md new file mode 100644 index 00000000..dc8dfe6c --- /dev/null +++ b/docs/cli/README.md @@ -0,0 +1,551 @@ +# Ember CLI Documentation + +The Ember CLI is a powerful command-line interface for interacting with the Ember AI framework. It provides a beautiful, intuitive interface for managing models, providers, configurations, and projects. + +## Installation + +### Prerequisites + +- Node.js 16.0 or higher +- Python 3.11 or higher +- Ember AI package installed (`uv pip install ember-ai`) + +### Installing the CLI + +```bash +# Global installation +npm install -g ember-cli + +# Local installation +npm install ember-cli +``` + +## Getting Started + +### Quick Start + +```bash +# Display the version +ember version + +# List available providers +ember provider list + +# Configure a provider with your API key +ember provider configure openai + +# List available models +ember model list + +# Invoke a model +ember invoke --model openai:gpt-4o-mini --prompt "Hello, world!" +``` + +### Basic Concepts + +Ember CLI organizes functionality around these core concepts: + +1. **Providers**: AI service providers like OpenAI, Anthropic, etc. +2. **Models**: Specific LLM models offered by providers, referenced as `provider:model` +3. **Projects**: Ember applications that utilize the framework +4. **Configuration**: Settings for CLI, providers, and models + +## Command Reference + +### Global Options + +These options work with all commands: + +| Option | Description | +|--------|-------------| +| `--debug` | Enable debug mode with detailed logs | +| `--json` | Output results as JSON | +| `--quiet` | Suppress non-essential output | +| `--no-color` | Disable colored output | + +### Shell Completion + +Ember CLI supports shell completion for Bash, Zsh, Fish, and PowerShell. This provides tab completion for commands, options, and even dynamic values like model IDs and provider names. + +```bash +# To install shell completion for your current shell +ember completion install + +# Generate completion script for a specific shell +ember completion bash > ~/.bash_completion.d/ember +ember completion zsh > ~/.zsh/completion/_ember +ember completion fish > ~/.config/fish/completions/ember.fish +``` + +For detailed instructions, see [Shell Completion Documentation](SHELL_COMPLETION.md). + +### Core Commands + +#### Version + +Display version information about the CLI and backend. + +```bash +ember version [options] + +Options: + --check Check for updates +``` + +#### Providers + +Manage LLM providers in Ember. + +```bash +# List available providers +ember provider list + +# Configure a provider with API key +ember provider configure [options] +Options: + -k, --key API key (omit to be prompted securely) + -f, --force Overwrite existing configuration + +# Display provider information +ember provider info + +# Set a provider as default +ember provider use +``` + +#### Models + +Manage LLM models in Ember. + +```bash +# List available models +ember model list [options] +Options: + -p, --provider Filter models by provider + +# Display model information +ember model info + +# Set a model as default +ember model use + +# Benchmark a model's performance +ember model benchmark [options] +Options: + -t, --tests Number of tests to run (default: 5) + -c, --concurrency Concurrency level (default: 1) +``` + +#### Invoke + +Invoke a model with a prompt directly from the CLI. + +```bash +ember invoke [options] + +Options: + -m, --model Model ID to use + -p, --prompt Prompt text to send to the model + -f, --file Read prompt from file + -s, --system System prompt (for chat models) + -t, --temperature Temperature setting (0.0-2.0) (default: 1.0) + -u, --show-usage Show token usage statistics + -o, --output Save output to file + -r, --raw Display raw output without formatting + --stream Stream the response token by token +``` + +#### Projects + +Create and manage Ember projects. + +```bash +# Create a new project +ember project new [options] +Options: + -t, --template