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.3.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.3-py3-none-any.whl (64.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ombra-0.1.3.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.3.tar.gz
Algorithm Hash digest
SHA256 b24747d988d87ca83ff9b4d9310254579c611f3a26a56a665d34791272d151c9
MD5 c09684f41e05e7bfd6acedd6c034365c
BLAKE2b-256 7d2f5f33cfff4b6fb274e32d783bc293d2ea9685117d9044750ed36cc6cd31e7

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ombra-0.1.3-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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 3b5fc55bc624e55932c0036fd4a0566dc6e58f2c75d74d4b2869dffaf82b7321
MD5 c0c440e9017e976d9e279b1a7aa08270
BLAKE2b-256 01a616ab1282c36d4ca92634da6de14ade4a810529e2dc742f54f59c21643cb9

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