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, requirescontext/dataor--context-file.automode: CLI-only, requires--fs-rootand 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_REFERERandOPENROUTER_APP_NAME(optional OpenRouter headers)OPENAI_API_KEY,OPENAI_ORG,OPENAI_PROJECT(OpenAI)${PROVIDER}_API_KEYfor other providers (e.g.,GROQ_API_KEY)EXA_API_KEYto 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:
dataprovided (including empty string)costorsecondsprovidedgoalprovided- 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 byscripts/export_schema.py, includesbundle.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 queriesllm_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:
- ✅ Python REPL - Full Python sandbox with persistent namespace
- ✅ Recursive sub-LLM calls - Both sequential and parallel execution
- ✅ Context as external variable - prompt stored in
context - ✅ Dynamic imports - When
enable_pip=True, matches paper's capability - ✅ Answer management -
FINAL()andFINAL_VAR()for iterative refinement - ✅ 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
caf9ac500f527feea47cc6a501d99f5c876411d6188c595ed2cc715e8db95099
|
|
| MD5 |
47715681d5d11c8bb220f40331a90be2
|
|
| BLAKE2b-256 |
4468f5e62fab184c4f57d388fa02a8b10525d1f62db5df318f97fa646cc7c44e
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0711319a9a95f8a9898aa0a31abd8834cdb19639546d87f52df266c958048824
|
|
| MD5 |
2b5d30cf25155cb78617433107442a2a
|
|
| BLAKE2b-256 |
e6ab6997715ff4040e505fb4b83422851f164e2368fee3edf7ec1fcad23e613a
|