Catalog PyPI
Back to packageRELEASE DETAILS

0.1.0

PyPI

agenttrafficcop

Python SDK for AgentTrafficCop — a runtime circuit breaker and schema shield for multi-agent systems.

agentsaicircuit-breakergovernancelanggraphllmmulti-agentobservabilityorchestration
Published14 Oct 2026
Direct dependencies4
Transitive dependenciesNot calculated

README

Version 0.1.0 documentation

pip install "agenttrafficcop[langgraph]"

Quick Start

import asyncio
from agenttrafficcop import Guard, LoopDetected

async def main():
    async with Guard(
        url="http://localhost:8000",
        api_key="your-api-key",
    ) as guard:
        try:
            result = await guard.check(
                session_id="run-42",
                sender="coder",
                recipient="reviewer",
                payload={"diff": "fix typo", "file": "app.py"},
            )
            print("approved at step", result.step)
        except LoopDetected as e:
            print("loop caught:", e.error_code)
            print("  session:", e.session_id)
            print("  step:", e.diagnostics.get("step"))

asyncio.run(main())

API Reference

Guard(url, api_key, *, timeout=10.0)

Async client. Use as a context manager so the underlying HTTP client is closed cleanly.

MethodPurpose
await guard.check(session_id, sender, recipient, payload, intent="handoff", metadata=None)Route one message. Returns RouteResult on success.
await guard.health()Call GET /health. No auth.
await guard.reset_session(session_id)Delete a session. Returns bool.
await guard.close()Close the HTTP client. Called by __aexit__.

RouteResult

AttributeTypeMeaning
approvedboolAlways True on success.
session_idstrSession this message belongs to.
stepint1-indexed step number.
payload_hashstrSHA-256 hex digest (64 chars).
messagestrHuman-readable confirmation.
rawdictOriginal response body.

Exceptions

All inherit from AgentTrafficCopError:

ExceptionWhen
LoopDetectedRepeated or cyclic payload.
StepLimitExceededSession hit the step cap.
SchemaRejectedServer rejected the message schema.
AuthErrorMissing or invalid API key (401).
ConnectionErrorCould not reach the server.
AgentTrafficCopErrorBase class — catch this for everything.

Every exception exposes .error_code, .session_id, and .diagnostics.

Catching Everything

try:
    await guard.check(...)
except AgentTrafficCopError as e:
    log.error("governance: %s session=%s", e.error_code, e.session_id)
    # ... decide what to do

LangGraph Integration

If you're using LangGraph, the SDK ships an optional adapter that wraps any node so its handoff passes through AgentTrafficCop before the node runs.

Install the extra

pip install -e "./sdk[langgraph]"

Wrap any node in one line

from agenttrafficcop import Guard
from agenttrafficcop.langgraph import guarded_node

guard = Guard(url="http://localhost:8000", api_key="your-key")

graph.add_node(
    "reviewer",
    guarded_node(
        reviewer_fn,
        guard=guard,
        sender="coder",
        recipient="reviewer",
        # Both of these can be static values OR callables that take
        # the LangGraph state and return the value.
        session_id=lambda state: state["run_id"],
        payload=lambda state: {"draft": state["draft"]},
    ),
)

That's it. Every time LangGraph invokes the reviewer node, AgentTrafficCop sees a handoff. If the breaker trips, the node raises before doing any work.

What if I don't supply payload=?

The wrapper falls back to hashing the entire state dict (minus a small denylist of known-noise keys like messages, history, trace). This works for small graphs, but for real graphs you should supply an explicit payload= extractor — otherwise a growing message history could cause false-positive trips.

Sync nodes

guarded_node supports sync and async node functions. Sync nodes are called directly; async nodes are awaited. The guard call itself is always async, so if you use a sync node you must call it from a sync context (no running event loop). For anything async-first, make the node async def and everything works.

Handling trips without raising

By default, a breaker trip raises the SDK exception (e.g. LoopDetected) and propagates out of the node. If you'd rather handle trips via state — for example, to route to a human-review node — pass:

guarded_node(..., raise_on_trip=False)

The node becomes a no-op on a trip, and the graph continues.

Full example

See examples/langgraph_demo.py for a runnable two-node graph that visibly trips the breaker.

Compatibility

  • Python 3.11+
  • httpx 0.27.x
  • LangGraph 1.2.x (optional)
  • Works against any AgentTrafficCop server 1.0.0+

License

MIT

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 4

Native requirements
4 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
httpx
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
httpx<0.28.0,>=0.27.0runtime
langgraph
Environment
{
  "extras": "",
  "marker": "extra == \"langgraph\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
langgraph<2.0.0,>=1.2.0; extra == "langgraph"runtime
pytest
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
pytest>=8.0; extra == "dev"runtime
pytest-asyncio
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.11",
  "evaluation": "NOT_EVALUATED"
}
pytest-asyncio>=0.23; extra == "dev"runtime

Distribution files

2 collected
agenttrafficcop-0.1.0-py3-none-any.whl

bdist_wheel · 12.61 KB · Python py3

Source file
agenttrafficcop-0.1.0.tar.gz

sdist · 14.27 KB · Python source

Source file

Repository

PENDING
belalshafeq/agent_cop

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 23:35 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:06c3cdaa80dd44c0dd9484dceebc0a7a4fdbfc8fb5a669d021bda17f5614843d

Other collected versions

View all collected versions →