Skip to main content

Detect infinite loops in LLM agentic workflows and interrupt them

Project description

TokenCircuit

PyPI Python CI License

The Agentic Pre-Frontal Cortex.

Current agent frameworks rely on blunt "Circuit Breakers" (like recursion_limit) that throw raw Python exceptions, destroying execution state and crashing the run when an agent loops. TokenCircuit is a zero-bloat, local-first SDK that intercepts the agent before the next LLM call, actively coaching it out of infinite loops and semantic stagnation.

Instead of failing the run, TokenCircuit forces a strategy pivot, turning bounded degradation into successful task completion.

TokenCircuit Demo

Supported frameworks: LangGraph, CrewAI, OpenAI function calling.

The Progressive Intervention Protocol

TokenCircuit operates silently in the background, intervening progressively:

Stage What Happens
PASS No intervention — agent proceeds normally
NUDGE Ephemeral system message injected: "You have tried this 3 times. Change strategy."
OVERRIDE Compacts failed transactions + injects forceful directive. Protects against OpenAI API validation errors.
HARD_STOP Graceful fallback termination, preserving state dictionary for debugging.

Quick Start

TokenCircuit requires exactly one line of code to secure your graph.

from tokencircuit import instrument_langgraph, InterventionConfig

# Secure your graph with auto-recovery and a budget
config = InterventionConfig(
    max_budget_usd=0.50, 
    auto_recovery=True
)
safe_graph = instrument_langgraph(builder, config=config).compile()

Fleet Dashboard (Coming Soon)

A single pane of glass to monitor agentic reliability across your entire fleet.

[Placeholder for Fleet Dashboard Screenshot]

from tokencircuit import InterventionConfig, LangGraphPreModelAdapter

adapter = LangGraphPreModelAdapter(
    config=InterventionConfig(
        nudge_threshold=3,
        override_threshold=5,
        hard_stop_threshold=8,
    )
)

# LangGraph pre_model_hook integration
graph.add_node("agent", call_model, pre_model_hook=adapter.hook)

Installation

pip install tokencircuit                    # Core
pip install "tokencircuit[langgraph]"       # + LangGraph support
pip install "tokencircuit[crewai]"          # + CrewAI support
pip install "tokencircuit[otel]"            # + OpenTelemetry tracing

Requires Python ≥ 3.11.

Quick Start — LangGraph

from typing import Annotated
from langgraph.graph import StateGraph, MessagesState
from tokencircuit import (
    InterventionConfig,
    LangGraphPreModelAdapter,
    InterventionStateSchema,
    tc_state_reducer,
)

# 1. Create the adapter
adapter = LangGraphPreModelAdapter(
    config=InterventionConfig(
        nudge_threshold=3,
        override_threshold=5,
        hard_stop_threshold=8,
        audit_mode=False,          # Set True to monitor without intervening
        max_tokens_per_turn=4000,  # Runaway generation detection
    )
)

# 2. Define state with TokenCircuit channel
class AgentState(MessagesState):
    _tc_intervention: Annotated[InterventionStateSchema, tc_state_reducer]

# 3. Build graph with pre_model_hook
builder = StateGraph(AgentState)
builder.add_node("agent", call_model, pre_model_hook=adapter.hook)
graph = builder.compile()

# 4. Run — TokenCircuit handles the rest
async for step in graph.astream({"messages": [...]}, config):
    print(step)

Quick Start — CrewAI

from tokencircuit import instrument_crewai, InterventionConfig

config = InterventionConfig(
    nudge_threshold=3,
    override_threshold=5,
    hard_stop_threshold=8,
)
safe_crew = instrument_crewai(crew, config=config)
safe_crew.kickoff()  # Raises TokenCircuitError if loop detected

Detection Signals

Six signal types evaluate the agent's behavior:

Signal Description
STATE_STAGNATION Identical content hash across the sliding window
FUTILE_ACTION Same tool signature repeats with no progress
SEMANTIC_STAGNATION Paraphrased repetition detected via token n-gram Jaccard similarity
TRANSCRIPT_CORRUPTION Malformed tool calls or excessive orphaned results
TOOL_TRANSACTION_ORPHAN Tool results without matching calls
RUNAWAY_GENERATION Single AI turn exceeds token velocity limit

Enterprise Features

Audit Mode

Monitor interventions without mutating the agent's behavior:

config = InterventionConfig(audit_mode=True)
# Engine computes all signals and logs them, but always returns PASS

Runaway Generation Detection

Catch agents that dump massive garbage output:

config = InterventionConfig(max_tokens_per_turn=4000)
# Triggers immediate HARD_STOP if a single AI turn exceeds 4000 tokens

OpenTelemetry Observability

pip install "tokencircuit[otel]"

TokenCircuit emits spans and events via opentelemetry-api:

TokenCircuit.Intervention
  ├── thread_id: "thread_abc"
  ├── node_name: "agent"
  ├── audit_mode: false
  ├── intervention.stage: "NUDGE"
  └── SignalDetected: "SEMANTIC_STAGNATION"

Visualize in Datadog, Grafana, or any OTel-compatible backend.

Configuration

from tokencircuit import InterventionConfig

config = InterventionConfig(
    # Escalation thresholds (consecutive stagnation turns)
    nudge_threshold=3,        # Turns before first coaching nudge
    override_threshold=5,     # Turns before forceful directive
    hard_stop_threshold=8,    # Turns before termination

    # Cooldown
    cooldown_turns=2,         # Turns to wait after de-escalation

    # Semantic detection
    window_size=5,            # Sliding window for fingerprint comparison
    similarity_threshold=0.92, # Jaccard similarity threshold
    enable_semantic_detection=True,

    # Transaction validation
    enable_transcript_validation=True,
    max_orphan_tolerance=2,
    auto_recovery=True,

    # Enterprise
    audit_mode=False,
    max_tokens_per_turn=4000,
)

Error Handling

from tokencircuit import TokenCircuitError, StateStagnationError, FutileActionError

try:
    async for step in graph.astream(input, config):
        ...
except TokenCircuitError as e:
    print(f"Loop detected: {e}")
    print(f"Signal: {e.signal_type}")
    print(f"Node: {e.node_name}")
    print(f"Iteration: {e.iteration}")

Architecture

LangGraph pre_model_hook → LangGraphPreModelAdapter
  └── InterventionEngine.process()
        ├── MessageCanonicalizer (normalize messages)
        ├── TranscriptValidator (enforce 10 invariants)
        ├── SemanticStagnationDetector (n-gram Jaccard)
        ├── Runaway Generation Check (token velocity)
        ├── Signal Aggregation
        └── decide() → PASS | NUDGE | OVERRIDE | HARD_STOP
  • Stateless: Validators rebuild state from the transcript every turn
  • O(N): Intelligent caching avoids O(N²) transcript reprocessing
  • < 4ms P99: Full pipeline latency under 4ms for 50-turn transcripts
  • Thread-safe: Independent state per thread_id + node_name

Development

pip install -e ".[dev,langgraph,openai,otel]"
make check

See CONTRIBUTING.md.

License

MIT

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

tokencircuit-0.2.1.tar.gz (34.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tokencircuit-0.2.1-py3-none-any.whl (36.1 kB view details)

Uploaded Python 3

File details

Details for the file tokencircuit-0.2.1.tar.gz.

File metadata

  • Download URL: tokencircuit-0.2.1.tar.gz
  • Upload date:
  • Size: 34.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for tokencircuit-0.2.1.tar.gz
Algorithm Hash digest
SHA256 203bd39b75db6f4e189c8d839deda260f2dbbdbd0b6ec06416f14500851ac59e
MD5 79ec17b3ac846892136410d82f028101
BLAKE2b-256 814fb7cb321fd37708a3899dd66a64d2f8caa893b6a120ee3dcd1fb99ecbb8fe

See more details on using hashes here.

File details

Details for the file tokencircuit-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: tokencircuit-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 36.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for tokencircuit-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e4c9c4f51d04903d8d5601369f367219d51a9a7e5046ba363915b211816fda8c
MD5 7e427b728862969d280541bf8e3feb86
BLAKE2b-256 26100156f94dd2535760c09625caaf2880a72e7e039b9473499416aa0b4659ee

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page