Skip to main content
Yanked

This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
Consider using release 0.1.1 instead.
Reason given by maintainers: Price keys used plain prefix matching, so a different model could borrow another's price (gpt-4 priced gpt-4o-mini). Fixed in 0.1.1.

evenkeel

Keeps a LangChain agent on an even keel when things fail: failures are classified and handled by kind, bad output is retried with a hint, spend is tracked in dollars with a budget, and failures that need a person pause the run for approval.

Ported from keel, a durable execution engine for AI agents. An independent project, not affiliated with LangChain. Experimental: 0.x, expect changes.

What it adds to LangChain's built-in middleware

Need Built in EvenKeelMiddleware
Retries ModelRetryMiddleware, ToolRetryMiddleware retry with the same input Classifies the failure first: back off, retry with a hint, fail at once, or escalate
Limits ModelCallLimitMiddleware counts calls Tracks dollars from token usage and pauses at a budget
Approvals HumanInTheLoopMiddleware asks before chosen tools Escalates when a failure needs a person, from any model or tool call

Use it alongside the built-ins: ModelFallbackMiddleware for switching models, HumanInTheLoopMiddleware for approvals fixed in advance.

Install

pip install evenkeel          # rule-based classification
pip install "evenkeel[jev]"   # adds TypeSafe's Jev classifier

Use

from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
from evenkeel import EvenKeelMiddleware, ModelPrice, PriceTable

agent = create_agent(
    "openai:gpt-4o-mini",
    tools=[...],
    middleware=[
        EvenKeelMiddleware(
            budget_usd=0.50,
            prices=PriceTable({"gpt-4o-mini": ModelPrice(input_per_mtok=0.15, output_per_mtok=0.60)}),
        )
    ],
    checkpointer=InMemorySaver(),  # needed for pauses
)

With Jev (needs TYPESAFE_API_KEY):

from typesafe_sdk import TypeSafeClient
from evenkeel import EvenKeelMiddleware, JevClassifier

EvenKeelMiddleware(classifier=JevClassifier(TypeSafeClient()))

How failures are handled

Kind Example Action
transient 429, 503, timeout, dropped connection Back off and retry the same call
bad_output Malformed output, a call that breaks the schema (recognised by Jev, or raised as BadOutputError) Retry with a hint saying what was wrong
bad_input Input a tool rejects (BadInputError, HTTP 400 or 422, a pydantic ValidationError) Model call: fail. Tool call: return the error to the model so it fixes its arguments
needs_human Refund over a limit, a policy block Pause with interrupt() and wait for a decision
fatal A bug, bad credentials Re-raise the original error at once

Retries and escalations stop at max_attempts (default 4). Each failure is recorded (error, kind, confidence, which classifier decided, action): in the agent's state under evenkeel_attempts when the call ends in a result, and on the raised error as error.evenkeel_attempts when it finally fails.

Some failures never reach the middleware, because LangChain turns them into messages for the model itself: a call to a tool that does not exist, and tool arguments that fail the tool's schema.

Pauses and how to resume

A failure that needs a person:

from langgraph.types import Command

agent.invoke(Command(resume={"decision": "retry", "hint": "approved by finance"}), config)
agent.invoke(Command(resume={"decision": "fail"}), config)
agent.invoke(Command(resume={"decision": "skip", "message": "Refunded by hand."}), config)  # tool calls only

A retry with a hint on a tool call sends the reviewer's words to the model, which can call the tool again; a tool cannot take a hint itself. A call that still needs a person after one approved retry fails. An answer that is not one of these values does not raise: the run pauses again, with an error field in the payload saying what was wrong.

Over budget:

agent.invoke(Command(resume={"approve": True, "budget_usd": 1.00}), config)
agent.invoke(Command(resume={"approve": False}), config)  # ends the run

The budget applies to each run: every new invoke on a thread starts with zero spend and the configured budget.

Limitations

  • Budgets can overshoot by one call. The check runs before a model call, but a call's cost is known only after it. keel has the same limitation.
  • No built-in prices. You supply them; a model without a price, or a response without token usage, is an error rather than a silent $0. Dated or versioned names (gpt-4o-mini-2024-07-18, claude-3-5-sonnet-20241022, gpt-4-0613, ...-latest) use the price of their base name; any other variant (gpt-4o-mini against gpt-4, gpt-4-turbo) needs its own entry.
  • On resume after an escalation, the failing call runs once more before the decision applies, because LangGraph re-runs the paused node. For a tool with side effects, make it idempotent or use skip.
  • Classification is only as good as the classifier. Rules only recognise explicit signals (status codes, network errors, evenkeel's error classes): on keel's 75 error messages from public SDK issues they pick the right kind 29 times and the right action 39 times. Jev reads the message itself; see keel's results for its accuracy on real error messages, and evals/ to measure it here.

Develop

uv sync --all-extras
uv run pytest

Metadata

Release files for evenkeel 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for evenkeel 0.1.0
File Size Uploaded
evenkeel-0.1.0.tar.gz 25.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for evenkeel 0.1.0
File Interpreter ABI Platform
evenkeel-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 42.6 kB

Release files / evenkeel-0.1.0.tar.gz

Download URL evenkeel-0.1.0.tar.gz
Size 25.4 kB
Tags Source
SHA-256 checksum
How to use checksums
62c7f6546b09890c9088c06b2ca974c2dd334e5657a5a37f0881e183b4b7bbd8
BLAKE2b-256 checksum
How to use checksums
587bec70a1dd298ca82dcd3ab4ca92b65cbc4dd5c463bf62662026c8153f5b1c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / evenkeel-0.1.0-py3-none-any.whl

Download URL evenkeel-0.1.0-py3-none-any.whl
Size 17.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3c32c555b81e25a9bb23234d75eb5efd14d35bb1868681a803b797060af008c9
BLAKE2b-256 checksum
How to use checksums
fb4815f7fe8bb7ea12dc552b7bdf883309c27235e7b3f16c69bb47d759ff29c7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page