Skip to main content

AI delegation orchestration. Tasks as budgeted jobs, not conversations.

Project description

enzu

AI delegation orchestration. Tasks as budgeted jobs, not conversations.

Install

pip install -e .

Basic usage

Single CLI, JSON in and JSON out:

cat task.json | enzu --provider openrouter --model "$OPENROUTER_MODEL"

Minimal task.json:

{
  "task": {
    "task_id": "example-task",
    "input_text": "Summarize this text.",
    "model": "openrouter/auto",
    "budget": { "max_output_tokens": 200 },
    "success_criteria": { "required_substrings": ["Summary"] }
  },
  "provider": "openrouter"
}

RLM mode with a context file:

cat rlm_task.json | enzu --provider openrouter --mode rlm --context-file path/to/context.txt

RLM keeps the prompt in the REPL environment (context) so the model inspects it programmatically.

Automode (filesystem tools, local-only within a root):

enzu --mode automode --provider ollama --model "llama3" --fs-root "$HOME/Desktop" --task "Clean the desktop into folders"

More examples: examples/enzu.md

Modes (CLI)

  • chat (default): single-shot generation, no context required.
  • rlm: iterative goal-oriented execution, requires context/data or --context-file.
  • automode: CLI-only, requires --fs-root and binds filesystem tools to that root.

Sandbox safety

RLM/automode execute Python in-process with restricted builtins and code checks. This is not a security boundary. Do not run untrusted code without external isolation (container, VM, or separate host).

Client quickstart

Environment variables (from code):

  • OPENROUTER_API_KEY (OpenRouter)
  • OPENROUTER_REFERER and OPENROUTER_APP_NAME (optional OpenRouter headers)
  • OPENAI_API_KEY, OPENAI_ORG, OPENAI_PROJECT (OpenAI)
  • ${PROVIDER}_API_KEY for other providers (e.g., GROQ_API_KEY)
  • EXA_API_KEY to enable search tools in RLM mode
  • Local providers: ollama (http://localhost:11434/v1), lmstudio (http://localhost:1234/v1)

Minimal CLI task (budget and checks defaulted by the CLI):

{
  "task": {
    "task_id": "example-task",
    "input_text": "Summarize this text.",
    "model": "openrouter/auto"
  },
  "provider": "openrouter"
}

RLM mode with context:

cat rlm_task.json | enzu --provider openrouter --mode rlm --context-file path/to/context.txt

Telemetry

Logfire spans are enabled by default when Logfire is installed. Disable with ENZU_LOGFIRE=0. Silence console output with ENZU_LOGFIRE_CONSOLE=0. Enable token-stream logs with ENZU_LOGFIRE_STREAM=1.

Python API

from enzu import run

text = run(
    "Summarize this text.",
    provider="openrouter",
    model="openrouter/auto",
)

Return the full report when you need details:

from enzu import run

report = run(
    "Summarize this text.",
    provider="openrouter",
    model="openrouter/auto",
    return_report=True,
)

Advanced usage with explicit task specs:

from enzu import Budget, SuccessCriteria, TaskSpec, run

task = TaskSpec(
    task_id="example",
    input_text="Summarize this text.",
    model="openrouter/auto",
    budget=Budget(max_output_tokens=200),
    success_criteria=SuccessCriteria(required_substrings=["Summary"]),
)
report = run(task, provider="openrouter", return_report=True)

run() also accepts the same JSON shape as the CLI:

from enzu import run

payload = {
  "task": {
    "task_id": "example",
    "input_text": "Summarize this text.",
    "model": "openrouter/auto",
    "budget": { "max_output_tokens": 200 },
    "success_criteria": { "required_substrings": ["Summary"] }
  },
  "provider": "openrouter"
}
report = run(payload, return_report=True)

Mode selection (Python)

run() accepts mode="auto" (default), mode="chat", or mode="rlm". Auto mode selects RLM when any of:

  • data provided (including empty string)
  • cost or seconds provided
  • goal provided
  • prompt + data size exceeds ~256k chars (~64k tokens) Otherwise auto mode selects chat.

Force a mode explicitly:

from enzu import run

run("Write a haiku.", model="openrouter/auto", mode="chat")
run("Investigate root cause.", model="openrouter/auto", mode="rlm", data=logs)

Session API

Sessions keep conversation history and prepend it to data on each call.

from enzu import Session, SessionBudgetExceeded

session = Session(
    model="openrouter/auto",
    provider="openrouter",
    max_cost_usd=5.00,
    max_tokens=20000,
)

try:
    answer = session.run("Find the bug.", data=logs, cost=1.00)
    follow_up = session.run("Fix it.")
except SessionBudgetExceeded as exc:
    print(exc)

session.save("debug_session.json")
session = Session.load("debug_session.json")

Notes:

  • History is capped by history_max_chars (default 10,000).
  • History is passed via data, so auto mode resolves to RLM once history exists.
  • Use raise_cost_cap() / raise_token_cap() to increase session caps.
  • Use clear() to reset history.

API contract and schemas

  • Canonical contract: API_CONTRACT.md
  • Background orchestration guide: docs/BACKGROUND_ORCHESTRATION.md
  • Python API reference: docs/PYTHON_API_REFERENCE.md
  • File-based examples: docs/FILE_BASED_CHATBOT.md, docs/FILE_BASED_RESEARCHER.md
  • JSON schemas: docs/schema/ (generated by scripts/export_schema.py, includes bundle.json)
  • CLI schema output: enzu --print-schema
  • Deployment and model guide: docs/INTEGRATION_GUIDE.md
  • Deployment quickstart: docs/DEPLOYMENT_QUICKSTART.md

RLM Features: Optimal Implementation

This implementation follows the optimal design from the PrimeIntellect RLM paper: By default, RLMEngine uses the paper-aligned prompt; set prompt_style="extended" for extra guardrails and tool guidance.

Parallel Sub-LLM Calls with llm_batch()

The RLM sandbox provides both llm_query() and llm_batch() for calling sub-LLMs:

  • llm_query(prompt) - Sequential single call for one-off queries
  • llm_batch(prompts) - Parallel batch execution for multiple independent queries

Performance benefit: llm_batch() runs queries concurrently using asyncio.gather(), reducing latency by N× where N is the number of queries.

# ❌ Slow: Sequential calls
results = [llm_query(f"Classify: {item}") for item in items]  # N× latency

# ✅ Fast: Parallel batch
prompts = [f"Classify: {item}" for item in items]
results = llm_batch(prompts)  # max(latency), not sum(latency)

With prompt_style="extended", the system prompt guides models to use llm_batch() for multiple independent queries.

Dynamic Package Installation with pip_install()

Enable dynamic pip package installation for maximum flexibility:

from enzu.rlm.engine import RLMEngine

engine = RLMEngine(enable_pip=True, prompt_style="extended")

When enabled, the RLM can install any PyPI package on demand:

# Inside RLM sandbox:
pip_install("numpy", "pandas", "scipy")
import numpy as np
import pandas as pd

# Standard library always available (no install needed)
import re, math, json, datetime

Security note: enable_pip=False by default. Only enable for trusted use cases, as it allows arbitrary package installation.

Architecture Alignment with Paper

This implementation provides:

  1. Python REPL - Full Python sandbox with persistent namespace
  2. Recursive sub-LLM calls - Both sequential and parallel execution
  3. Context as external variable - prompt stored in context
  4. Dynamic imports - When enable_pip=True, matches paper's capability
  5. Answer management - FINAL() and FINAL_VAR() for iterative refinement
  6. Async optimization - Implements paper's recommended parallel sub-calls

Tests

  • tests/README.md

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

enzu-0.1.1.tar.gz (85.4 kB view details)

Uploaded Source

Built Distribution

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

enzu-0.1.1-py3-none-any.whl (77.9 kB view details)

Uploaded Python 3

File details

Details for the file enzu-0.1.1.tar.gz.

File metadata

  • Download URL: enzu-0.1.1.tar.gz
  • Upload date:
  • Size: 85.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.16

File hashes

Hashes for enzu-0.1.1.tar.gz
Algorithm Hash digest
SHA256 caf9ac500f527feea47cc6a501d99f5c876411d6188c595ed2cc715e8db95099
MD5 47715681d5d11c8bb220f40331a90be2
BLAKE2b-256 4468f5e62fab184c4f57d388fa02a8b10525d1f62db5df318f97fa646cc7c44e

See more details on using hashes here.

File details

Details for the file enzu-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: enzu-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 77.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.16

File hashes

Hashes for enzu-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0711319a9a95f8a9898aa0a31abd8834cdb19639546d87f52df266c958048824
MD5 2b5d30cf25155cb78617433107442a2a
BLAKE2b-256 e6ab6997715ff4040e505fb4b83422851f164e2368fee3edf7ec1fcad23e613a

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