This release is a pre-release and may not be stable for production use.
jev-lanes
Confidence-based routing and escalation policies for Jev and LangGraph.
v0.1 release candidate: the repository implements confidence-band selection, the
serializable RouteTrace, the Classifier/FallbackModel protocols, offline fakes and
JevRouter, which wires the three lanes and a resumable human review into a LangGraph
StateGraph, plus default adapters for TypeSafe and any LangChain chat model (bring your
own keys). Offline examples and a five-minute notebook demonstrate the full flow.
The 37-case synthetic smoke battery
shows integration behavior; it does not establish decision quality or calibrated
thresholds. A Banking77 evaluation of the
policy on public data found no benefit from the fallback model (see
Evidence). langchain-typesafe itself is an alpha release. The package has not been
published to PyPI; install from this checkout.
Why
Routing needs an explicit policy for uncertainty: when to accept a classifier's decision, ask another model, or request human judgment. This project aims to make that policy testable and auditable, including resuming a graph after human review.
The implemented flow is:
Jev Choice -> confidence band
auto -> validated Jev route
llm -> fallback model -> validated route or human review
human -> interrupt -> validated human decision -> route
flowchart LR
A[Classify] --> B{Confidence band}
B -->|auto| R[Validated route]
B -->|llm| L[Fallback model]
B -->|human| H[Human review interrupt]
L -->|valid route| R
L -->|abstains or unknown route| H
H -->|resume with valid route| R
The fallback model's benefit must be evaluated; the one evaluation so far did not show one (see Evidence). A valid route name alone does not establish a correct decision. Jev confidence is a distribution statistic, not an accuracy guarantee; thresholds depend on the task and its consequences.
Try the current policy locally
Requires Python 3.10+ and uv. From this checkout:
uv sync --locked --dev
uv run python examples/policy.py
For an application environment, python -m pip install . installs the package from
the checkout. No provider keys are needed to import it or run the offline examples.
from jev_lanes import Lanes
# Illustrative thresholds, not calibrated defaults.
lanes = Lanes(auto=0.85, llm=0.60)
assert lanes.lane_for(0.95) == "auto"
assert lanes.lane_for(0.70) == "llm"
assert lanes.lane_for(0.40) == "human"
Try the router offline
examples/router_offline.py runs all three lanes and a human review resumed with a
checkpointer, using fakes instead of providers:
uv run python examples/router_offline.py
from typing import Any, TypedDict
from langgraph.graph import END, START, StateGraph
from jev_lanes import Classification, JevRouter, Lanes
from jev_lanes.testing import FakeFallback, FakeJevClassifier
class State(TypedDict, total=False):
messages: list[str]
support_route: dict[str, Any]
handled_by: str
router = JevRouter(
name="support",
routes={"orders": "Order status questions", "billing": "Invoices and payments"},
lanes=Lanes(auto=0.85, llm=0.60),
classifier=FakeJevClassifier(Classification("orders", 0.95)),
fallback=FakeFallback(),
)
builder = StateGraph(State)
builder.add_node("intake", lambda state: {})
builder.add_node("orders", lambda state: {"handled_by": "orders"})
builder.add_node("billing", lambda state: {"handled_by": "billing"})
builder.add_edge(START, "intake")
router.attach(builder, after="intake") # route names are the target node names
builder.add_edge("orders", END)
builder.add_edge("billing", END)
result = builder.compile().invoke({"messages": ["Where is my parcel?"]})
assert result["handled_by"] == "orders"
- Declare
router.state_key(heresupport_route) in your graph state schema; it holds the serializableRouteTrace. Every invocation starts a new episode. - By default the state's
messagesare sent to the providers; passextract=to send something else or to redact. Case text is never stored in the trace or in the review request. - The fallback model abstaining or naming an unknown route escalates to human review; an
unknown answer is recorded in the trace as
<invalid route>, not verbatim. - Each router attached to a graph needs its own
name. Provider failures raise; they are not converted into a low confidence. - Human review needs a checkpointer and a stable
thread_id. Resume withCommand(resume="<route>"); an unknown route is rejected and can be sent again. Resuming does not classify again. - Sync only; requires
langgraph>=1.2.12. - The trace replaces its previous episode in
<name>_route(no list reducer). Checkpointers retain state snapshots according to their own retention policy, including the case text inmessages.InMemorySaveronly persists within the current process.
Full demos
uv run --offline --no-sync python examples/atendimento/demo.py
uv run --offline --no-sync python examples/manual_routing.py
The customer-service demo handles orders, billing and account questions. It demonstrates fallback abstention, an invalid human response and successful resumption without reclassifying. Human responses are scripted.
The manual example expands the edges that attach()
adds, using the same public node methods. Behavior comparisons cover all three lanes,
invalid review/retry, provider failures, mapped/shared destinations, END and a new
episode. This comparison validates graph wiring, not accuracy or a speed advantage.
Open the five-minute notebook in a notebook editor using the project interpreter, or execute it from the terminal:
uv sync --locked --dev --group notebook
uv run --offline --no-sync python examples/execute_notebook.py
The executed copy goes to build/quickstart.executed.ipynb; source cells stay clean.
Use real providers (bring your own keys)
from jev_lanes.adapters import JevClassifier, LangChainFallback
router = JevRouter(
name="support",
routes={"orders": "...", "billing": "...", "other": "Anything else."},
lanes=Lanes(auto=0.85, llm=0.60),
classifier=JevClassifier(), # reads TYPESAFE_API_KEY
fallback=LangChainFallback("openai:gpt-5-nano"),
)
JevClassifier asks TypeSafe a Choice whose criteria are your routes (add an other
route when they may not cover every input). LangChainFallback takes a BaseChatModel
or an init_chat_model string; install the provider package yourself (for example
langchain-openai) and set that provider's key. Keys are never stored or forwarded by
this package. The case text is sent to TypeSafe and, for medium-confidence cases, to the
fallback provider. examples/byok.py is a complete example; it calls real services and
is not run in CI.
The fallback model is asked for a route name or ABSTAIN in plain text, and the reply
is checked against your routes: anything else escalates to human review.
Evidence
The policy was evaluated once on Banking77
(English banking intents grouped into four routes; thresholds chosen on 231 calibration
cases, then applied once to 770 test cases; gpt-5-nano as fallback). Full method, tables
and limitations: report.
- Jev's confidence is informative: AUROC 0.884 for correct vs wrong routes.
- The 95% automatic-accuracy target was not reached on calibration. At the chosen thresholds the three-lane policy automated 77.4% of cases at 90.6% accuracy; Jev plus human review (no fallback) automated 57.5% at 94.4%.
- The fallback did not help. In the llm lane Jev was right on 25 of 30 in-scope cases and the fallback on 23 (0 fixed, 2 broken). Below the auto threshold overall, it fixed 12 and broke 16 (sign test p = 0.57). Treat the fallback as an unproven option: measure it on your own labelled data before relying on it, and prefer sending medium-confidence cases to people if reviewers have capacity.
- Out-of-scope messages were still routed automatically when Jev was confident.
One dataset, one run, one fallback model, English only: this is not an accuracy claim for your domain. Public data are shared under CC BY 4.0; see the attribution.
The lane policy
Thresholds must satisfy 0 <= llm < auto <= 1. Equality with either threshold
selects the higher band. Invalid confidence raises an error; a provider failure
is not treated as a low-confidence decision. The package itself never calls external
services; only the providers you inject do.
Development
uv run --offline --no-sync ruff check .
uv run --offline --no-sync ruff format --check .
uv run --offline --no-sync mypy
uv run --offline --no-sync pytest
uv build
Install dependencies with uv sync --locked --dev before running offline checks.
The CI workflow targets Python 3.10–3.14. Distribution builds require a cached
build backend or network access.
Repository
src/jev_lanes/: public policy primitives, with type annotations (lanes,trace,protocols,router,adapters, andtestingfakes for offline tests).tests/: deterministic offline tests.examples/: policy, offline router, customer-service and manual wiring examples, a five-minute notebook, and a BYOK example that needs keys.benchmarks/: synthetic smoke results, the Banking77 evaluation, and the protocol for a real-data evaluation in your own domain.- Glossary: domain terminology.
- Contributing: local workflow and evaluation expectations.
- Changelog.
Naming and related work
langgraph-jev-router is an existing
third-party project. This is a separate project centered on an explicit three-band
escalation policy. jev-lanes returned HTTP 404 from PyPI's public project JSON
endpoint on 2026-10-19; that is not a reservation or publication guarantee.
References
MIT licensed. Independent project; not affiliated with TypeSafe or LangChain.
Metadata
Release files for jev-lanes 0.1.0rc1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| jev_lanes-0.1.0rc1.tar.gz | 346.8 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| jev_lanes-0.1.0rc1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 363.9 kB
Release files / jev_lanes-0.1.0rc1.tar.gz
| Download URL | jev_lanes-0.1.0rc1.tar.gz |
|---|---|
| Size | 346.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c888d79d536303f4fefe80ae03c7ab86b133ed6fdd2d4942b088fae0bb698b95
|
|
BLAKE2b-256 checksum How to use checksums |
667e950a919fc4b75d02898cca56f9f57e5ea63884641e3cf3d9754a8df8e8d7
|
| 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 24, 2026.
Transparency logRelease files / jev_lanes-0.1.0rc1-py3-none-any.whl
| Download URL | jev_lanes-0.1.0rc1-py3-none-any.whl |
|---|---|
| Size | 17.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dc5249d2cf487e4557c808dac7b83e8ddb9a703f5cfe07a4ec4cca7f219dc91d
|
|
BLAKE2b-256 checksum How to use checksums |
c314edc263cb7328918ee549bdd3536b360b237002c500a0645b145e174eba3d
|
| 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 24, 2026.
Transparency logSecurity for jev-lanes 0.1.0rc1
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for jev_lanes-0.1.0rc1.tar.gz
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 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.