Tools your agents can actually run: Mellea v0.7.0
For most of Mellea's life, an agent could describe a computation but not run one. You could ask a model to write Python that fits a curve or draw a plot, get back a code block, and then you were on your own. Executing that code safely, checking it did what you asked, keeping the transcript from overflowing the context window: all of that was left to you.
Mellea v0.7.0, released July 13, 2026, changes that. This release gives agents tools they can actually run: a sandboxed Python interpreter and a shell tool with a safety denylist. It gives you a library of executable requirements that check the output before you trust it. And it lands the plumbing that keeps long agent runs healthy: context compaction for the ReACT loop, model-aware sliding-window contexts, and a plugin-based telemetry stack you can extend. Roughly 120 PRs went into it.
Breaking Changes
One breaking change lands in the telemetry surface (#1181). Tracing was still pre-1.0, so it ships without a deprecation shim.
-
What changed:
MELLEA_TRACE_*environment variables are renamed to the pluralMELLEA_TRACES_*, aligning withOTEL_EXPORTER_OTLP_TRACES_ENDPOINTand the existingMELLEA_METRICS_*vars. A newMELLEA_TRACES_ENABLEDumbrella flag and opt-inMELLEA_TRACES_OTLPare added.- The deprecated
gen_ai.systemspan attribute is removed; readgen_ai.provider.nameinstead. is_application_tracing_enabled()andis_backend_tracing_enabled()collapse into a singleis_tracing_enabled().add_span_event,start_backend_span,end_backend_span, andtrace_backendare removed frommellea.telemetry. Backend spans are now emitted automatically byBackendTracingPlugin; application spans still usetrace_application(unchanged).- The
mellea.telemetry.backend_instrumentationmodule is deleted.
-
Who is affected: anyone who set
MELLEA_TRACE_*env vars, read thegen_ai.systemattribute in a trace consumer, or called the removed helper functions directly. -
Migration: rename
MELLEA_TRACE_*→MELLEA_TRACES_*in your environment, switch trace consumers fromgen_ai.systemtogen_ai.provider.name, and drop any direct calls to the removed span helpers. Backend spans now emit on their own.
Run code, don't just generate it
Before v0.7.0, "let the agent run a shell command" meant wiring up your own
executor and hoping the model didn't emit something destructive. The new
shell tool (#1107)
gives you a bash_executor with a conservative safety denylist built in: no
sudo, no rm -rf, no destructive git operations, no writes to /etc,
/sys, or /proc. You can also constrain writes with working_dir and
allowed_paths.
from mellea.stdlib.tools.shell import bash_executor
result = bash_executor("ls -la")
print(result.success, result.stdout)
You can hand it to a model as a MelleaTool for agentic tool-calling, or call
it directly. Commands use argv-friendly syntax: compose multiple commands in
Python rather than relying on pipes or redirects, which keeps the attack
surface small. For untrusted code, the docs are explicit: add container- or
VM-level isolation at the application layer.
Alongside it, the Python code interpreter got a rewrite
(#1190) built on
the new sandbox runtime and capability-policy system
(#1171), which
lets you declare what generated code is allowed to do rather than trusting it
by default. Follow-on hardening tightened the default execution tier
(#1271) and added
a chmod/umask guard to the interpreter
(#1372).
The requirements work below depends on this. Once an agent can run code, you can validate what it produced.
Requirements that execute the output
Mellea's requirements let you assert properties of a model's response. In v0.7.0 that vocabulary grows past "does this text match a rule" into requirements that actually exercise generated code.
Python requirements (#1128) validate that generated Python parses, imports cleanly, and behaves, turning "the model wrote some code" into "the code runs." Matplotlib requirements (#1208) go domain-specific: check that plotting code uses a headless backend, that it actually saves a file, and that its dependencies are available.
from mellea.core import ModelOutputThunk
from mellea.stdlib.context import ChatContext
from mellea.stdlib.requirements.plotting import MatplotlibHeadlessBackend
code = """```python
import matplotlib
matplotlib.use('Agg') # headless backend, safe on a server
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [1, 4, 9])
```"""
context = ChatContext().add(ModelOutputThunk(value=code))
result = MatplotlibHeadlessBackend().validation_fn(context)
print(result.as_bool(), result.reason)
A model that emits matplotlib.use('TkAgg') and plt.show() (code that would
hang waiting for a display on a headless server) fails the check instead of
failing in production.
To make these easy to reach for, v0.7.0 adds sampling presets for Python code generation (#1265), bundling the right requirements and feedback loop so "generate code that plots this data and actually saves the figure" is a preset, not a project.
Groundedness: catch the answer that isn't in the documents
RAG systems fail quietly when the model asserts something the retrieved
documents don't support. The new GroundednessRequirement
(#773) validates
that an assistant response is fully backed by citations to the documents it
was given, using a four-step pipeline: generate citations, decide which spans
need a citation, assess how well each span is supported, and declare the
response grounded only if every span that needs support gets it.
from mellea.backends.huggingface import LocalHFBackend
from mellea.stdlib.components import Document, Message
from mellea.stdlib.context import ChatContext
from mellea.stdlib.requirements.rag import GroundednessRequirement
backend = LocalHFBackend(model_id="ibm-granite/granite-4.0-micro")
# ...build a ChatContext with your Documents and the assistant response...
requirement = GroundednessRequirement()
See the full example for the end-to-end wiring against Granite.
Keep long agent runs from overflowing context
A ReACT loop that runs for many turns accumulates tool observations until it
blows past the context window. v0.7.0 adds context compaction strategies
(#996) with two
complementary integration points: a per-add compactor on ChatContext for
cheap strategies like WindowCompactor, and a per-turn compactor= argument
to react(...) for heavier strategies that should fire only at turn
boundaries. pin_react_initiator keeps the goal and tool registration alive
across compaction, so the agent doesn't forget what it was doing.
from mellea.stdlib.context.compactor import WindowCompactor
# cheap, fires on every append
context = ChatContext(compactor=WindowCompactor(...))
# or heavier, once per ReACT iteration:
# react(..., compactor=my_compactor)
Model-aware sliding-window context (#1270) sizes the window to the target model's actual context length instead of a hard-coded guess, so the same code does the right thing whether you point it at a small local model or a long-context hosted one.
Multimodal m serve
m serve now handles images end-to-end (#1184):
you can send images to a served model over an OpenAI-compatible endpoint, with
examples for streaming, response formats, and a PII-redaction server. Related
work lets you pass images as URLs on supported backends
(#1260) instead of
inlining base64, and re-exports the serve types from the public mellea.*
namespace (#1243)
so you can build typed clients without reaching into internal modules.
Telemetry you can extend, and debugging you can turn on
The telemetry rework (#1181,
see Breaking Changes) moves backend tracing off inline calls scattered across
five backends and onto a BackendTracingPlugin that subscribes to generation
hooks. Spans now stay live on the OpenTelemetry context across the API call,
so nested instrumentation (httpx, LangChain) parents correctly under the
backend span instead of floating at the root. Follow-on PRs wired metrics
plugins to the new batch hooks (#1254)
and migrated application spans and stream-chunking telemetry onto the same
plugin/hook pattern (#1289,
#1361).
For debugging, v0.7.0 adds built-in debug plugin collections (#1251): drop-in diagnostics for generation tracing, sampling, and validation failures, with a how-to guide and examples for each. When a sampling loop or a validation isn't behaving, you turn on a plugin instead of adding print statements.
Other Improvements
Backends & generation
- Stopping sequences are now a first-class model option across all backends. (#1112)
- Concurrency in the base sampling strategy speeds up sampling that issues independent generations. (#1175)
- Consolidated to llguidance from xgrammar for constrained decoding. (#1077)
- Standardized logits on the
ModelOutputThunk, uniform across backends. (#1261) - Public
errorandgenerate_logsurface onModelOutputThunkfor inspecting what happened. (#1307) do_sample=Truewhen a seed is set on HF backends, so seeding behaves as expected. (#1149)- AWS Bedrock via the standard credentials chain: the Bedrock backend now
authenticates through IAM roles,
~/.aws/credentials, or environment variables (through LiteLLM), alongside a bearer-token path for Bedrock Mantle — no proxy or manual request signing. (#578)
Intrinsics / adapters (Epic #929)
- New Adapter/Identity/IOContract/WeightsBinding scaffolding and a rewritten
call_intrinsic, migrating RAG and Guardian intrinsics onto the new types. (#1158, #1269, #1321, #1323) - Catalog entries pinned to Hugging Face revision SHAs for reproducibility. (#1157)
CLI & serve
- Health-check endpoint for
m serve. (#1100) m aloraguards the HF dependency with a friendly error. (#1102)
Docs
- Migrated from Mintlify to Docusaurus 3. (#1174)
- Guardian docs moved from the deprecated
GuardianCheckto the Intrinsics API. (#935)
Upgrading
pip install --upgrade mellea
If you use tracing, rename your MELLEA_TRACE_* environment variables to
MELLEA_TRACES_* and switch trace consumers from gen_ai.system to
gen_ai.provider.name. See Breaking Changes above.
See the full release notes for the complete changelog.