Skip to main content

Compositional framework for building and orchestrating Compound AI Systems and Networks of Networks (NONs).

Project description

Ember

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

Installation

From PyPI

pip install ember-ai

From Source (Development)

git clone https://github.com/pyember/ember.git
cd ember
uv sync

Quick Setup

Run our interactive setup wizard for the best experience:

# If installed from PyPI
ember setup

# If running from source
uv run ember setup

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

Getting Started

1. Configure API Keys

Ember now reads provider credentials exclusively from its configuration file. Use the CLI to persist secrets:

# Interactive wizard (writes to ~/.ember/config.yaml)
uv run ember setup

# 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 "..."
uv run ember configure set providers.takumi.api_key "tk-..."
uv run ember configure set providers.takumi.base_url "http://127.0.0.1:18080"  # optional override

Environment-variable fallbacks (for example OPENAI_API_KEY, TAKUMI_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

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

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)

If credentials are missing, you'll get a clear error message:

ModelProviderError: No API key found for gpt-4.

To fix this, choose one:

Option 1: Run interactive setup (recommended)
   ember setup

Option 2: Save to config
   ember configure set providers.openai.api_key YOUR_KEY

Get your API key from: https://platform.openai.com/api-keys

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

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"

Quick Start

from ember.api import models

# Direct LLM calls - no setup required
response = models("gpt-4", "Explain quantum computing in one sentence")
print(response)

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
  1. Pull a model the first time (fast option)
ollama run llama3.2:1b
  1. Call from Ember (auto-pull supported)
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 <model> 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.

Gateway Discovery (Takumi)

If you are using the Takumi gateway, you can discover supported models via HTTP:

GET /v1/models               # All models from the catalog
GET /v1/models?provider=openai
GET /v1/models?status=stable
GET /v1/models?provider=anthropic&status=preview

Response shape:

{
  "gpt-4": {
    "provider": "openai",
    "description": "Most capable GPT-4 model",
    "context_window": 8192,
    "status": "stable"
  },
  "claude-4-sonnet": {
    "provider": "anthropic",
    "description": "Latest Claude Sonnet model",
    "context_window": 200000,
    "status": "stable"
  }
}

This endpoint is DRY by design, serving data directly from the same catalog used by the Python API (ember.models.catalog).

Core Patterns

Context Management

Ember uses a unified context system for configuration and state management:

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

The context system provides:

  • Thread-safe and async-safe configuration management
  • Hierarchical configuration with proper isolation
  • Clean scoping for temporary overrides

Progressive Disclosure in APIs

Ember APIs follow a pattern of progressive disclosure - simple things are simple, complex things are possible:

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?")

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

Core Concepts

Ember provides four primitives that compose into powerful AI systems:

1. Models - Direct LLM Access

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?")

# Alternative: Use constants for autocomplete
from ember.api import Models
response = models(Models.GPT_4, "Write a haiku")

2. Operators - Composable AI Building Blocks

from ember.api import operators

# Transform any function into an AI operator
@operators.op
def summarize(text: str) -> str:
    return models("gpt-4", f"Summarize in one sentence: {text}")

@operators.op
def translate(text: str, language: str = "Spanish") -> str:
    return models("gpt-4", f"Translate to {language}: {text}")

# Compose operators naturally
pipeline = summarize >> translate
result = pipeline("Long technical article...")

3. Data - Streaming-First Data Pipeline

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))

4. XCS - Zero-Config Optimization

from ember import xcs

# Automatic JIT compilation
@xcs.jit
def process_batch(items):
    return [models("gpt-4", item) for item in items]

# Automatic parallelization
fast_process = xcs.vmap(process_batch)
results = fast_process(large_dataset)  # Runs in parallel

Real-World Examples

Building a Code Reviewer

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)
""")

Parallel Document Processing

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

Multi-Model Ensemble

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}
    
    Synthesize the best answer combining insights from all models.
    """
    
    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

# 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

# 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

Advanced Configuration

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.

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

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
    
    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(...)

Custom Data Loaders

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

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 for detailed design documentation.

Development

# 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

Contributing

We welcome contributions that align with Ember's philosophy of simplicity and power. See CONTRIBUTING.md for guidelines.

License

MIT License. See 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

keiro_ember-0.1.0.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

keiro_ember-0.1.0-py3-none-any.whl (1.4 MB view details)

Uploaded Python 3

File details

Details for the file keiro_ember-0.1.0.tar.gz.

File metadata

  • Download URL: keiro_ember-0.1.0.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.3

File hashes

Hashes for keiro_ember-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3830744dbd60d910e7c3b1be846c6791144a484004f32494fba1f2ea74feaf32
MD5 c33c53a55a8914edb44958c2773a3651
BLAKE2b-256 33ed00cd64933fc3cea4eb5f0e1ecd9fc66e70e5b1917c6906bb9b8fe85d51c1

See more details on using hashes here.

File details

Details for the file keiro_ember-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for keiro_ember-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 726fad0131cbac6c457ebe0cdf55c93c20e5dd690c24c4dc73010a5a5531c593
MD5 03f7fdcb8e45f71d887c339ed76eb99e
BLAKE2b-256 2e68eb203ac5a7d9064c0a1d72447cab27d96e0c1f668d4e1529444e81e50f55

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page