Skip to main content

Minimal code, maximum automation for AI workflows

Project description

Ombra

Minimal code, maximum automation for AI workflows.

Write regular Python functions. Add two decorators. Get FastAPI endpoints, execution history, and time travel debugging automatically.

Ombra solves the biggest pain point in AI engineering: debugging complex chains. Instead of re-running expensive/slow LLM calls from scratch every time you tweak a prompt, Ombra lets you "time travel" back to any step, edit its inputs, and replay from there using cached results for everything upstream.

Features

  • Instant API: Your Python functions become production-ready FastAPI endpoints.
  • 🔄 Time Travel: Resume execution from any step. Tweaked a prompt in step 3? Replay from step 3, reusing results from steps 1 & 2.
  • 📊 Visual Dashboard: See exactly what happened, when, and why. Inspect inputs/outputs for every step.
  • 💾 Automatic Persistence: All execution history, inputs, and outputs are saved to SQLite.
  • 🤖 LLM Integration: Built-in call_llm helper that handles multimodal inputs (like PDFs) seamlessly.

Quick Start

Installation

pip install ombra
# or
uv add ombra

Requires Python ≥3.12.

Your First Workflow: PDF Analysis & Email Drafting

Let's build a real-world example: A workflow that takes a PDF, analyzes it using Gemini, and drafts a response email.

1. Define Data Models (models.py)

Define structured inputs/outputs using Pydantic.

from pydantic import BaseModel

class DocumentAnalysis(BaseModel):
    """Structured analysis of a document."""
    summary: str
    key_entities: list[str]
    sentiment: str
    requires_action: bool

class EmailDraft(BaseModel):
    """Proposed email draft based on analysis."""
    subject: str
    body: str
    recipient_role: str

2. Create Steps (steps.py)

Write async functions decorated with @step(). Use call_llm for AI tasks.

from ombra import step, File, call_llm, Model, Message, Role
from models import DocumentAnalysis, EmailDraft

@step()
async def analyze_document(file: File) -> DocumentAnalysis:
    """Sends PDF to Gemini for analysis."""
    prompt = """
    Analyze the attached PDF. Provide a summary, key entities, sentiment, 
    and if action is required.
    """

    response = await call_llm(
        model=Model.GEMINI_2_5_FLASH_LITE,
        messages=[
            Message(role=Role.USER, content=[prompt, file]) # Native file support!
        ],
        response_format=DocumentAnalysis # Structured Output!
    )
    
    # Ombra + LiteLLM guarantees the response matches your Pydantic model
    return DocumentAnalysis.model_validate_json(response.content)

@step()
async def draft_response_email(analysis: DocumentAnalysis) -> EmailDraft:
    """Drafts an email based on the analysis."""
    prompt = f"""
    Draft a response based on this analysis:
    Summary: {analysis.summary}
    Sentiment: {analysis.sentiment}
    """
    
    response = await call_llm(
        model=Model.GEMINI_2_5_FLASH_LITE,
        messages=[Message(role=Role.USER, content=prompt)],
        response_format=EmailDraft # Structured Output!
    )
    
    return EmailDraft.model_validate_json(response.content)

3. Connect the Workflow (workflow.py)

Decorate your main function with @workflow.

from ombra import workflow, File
from models import EmailDraft
from steps import analyze_document, draft_response_email

@workflow(name="process_document", description="Analyze PDF and draft email")
async def process_document_workflow(file: File) -> EmailDraft:
    # Step 1: Analyze the PDF
    analysis = await analyze_document(file)
    
    # Step 2: Draft an email based on the analysis
    email_draft = await draft_response_email(analysis)
    
    return email_draft

Run It

Start the development server pointing to your code:

uv run ombra dev --workflows-dir .

You'll see:

INFO:     🚀 Starting Ombra Dev Server at http://127.0.0.1:8000
...
INFO:     ✨ Registered workflow: process_document
INFO:     
INFO:     📖 Run Workflows:    http://localhost:8000/docs
INFO:     👀 View Executions:  http://localhost:8000/workflows
INFO:     

Use It

  1. Execute: Go to http://localhost:8000/docs, find POST /workflows/process_document/execute, upload a PDF, and run it.
  2. Visualize: Go to http://localhost:8000/workflows to see the execution live. You'll see the analyze_document step completing, followed by draft_response_email.
  3. Time Travel:
    • Let's say you don't like the email tone in Step 2.
    • Instead of re-uploading the PDF and re-running the expensive Step 1, just click "Resume" on the draft_response_email step in the UI.
    • You can even edit the inputs (e.g., change the prompt logic in your code) and replay just that step!

Core Concepts

@step()

  • Wraps any async function.
  • Automatically serializes and persists inputs/outputs to SQLite.
  • Handles nesting (steps calling steps).
  • Supports file handling natively.

@workflow()

  • Wraps the entry point function.
  • Automatically generates a FastAPI route based on type hints.
  • Manages the execution context.

call_llm

  • Built-in wrapper around standard LLM APIs.
  • Multimodal: Pass text and File objects directly in the content list. Ombra handles the base64 conversion and formatting for you.
  • Structured Outputs: Pass a Pydantic model to response_format to guarantee valid JSON outputs matching your schema.
  • Visualized: Shows token usage and model details directly in the execution dashboard.

CLI Commands

  • ombra dev: Starts the dev server with hot reloading.
    • --workflows-dir: Specify where your workflow files are (defaults to current dir).
  • ombra serve: Starts a production-ready server.

License

MIT

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

ombra-0.1.4.tar.gz (167.9 kB view details)

Uploaded Source

Built Distribution

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

ombra-0.1.4-py3-none-any.whl (64.1 kB view details)

Uploaded Python 3

File details

Details for the file ombra-0.1.4.tar.gz.

File metadata

  • Download URL: ombra-0.1.4.tar.gz
  • Upload date:
  • Size: 167.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for ombra-0.1.4.tar.gz
Algorithm Hash digest
SHA256 d0488fd47f3c9ed1889dc472243ca1a59bec45e1a20c3a9700a41f85513bfb29
MD5 41cd1461a331395b30b7bec7245629ab
BLAKE2b-256 657456dea3c604ce1fe816605fd5b50d3f29715d5f66c7242e7a08a9794da3cd

See more details on using hashes here.

File details

Details for the file ombra-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: ombra-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 64.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for ombra-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 045675a20c5220f3c6708963119ee1831bbbb838cab5ff538847d32a88a6673b
MD5 fddace0a34c423badbfb548a5ca61a3c
BLAKE2b-256 0236c2cbc996f29c88e2368721712efa2686f59c1f8a16ecf112ba03ba432174

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