Skip to main content

Declarative agent creation framework for LangGraph (Stigmer local copy)

Project description

Graphton

CI Python 3.11+ License: Apache-2.0

Declarative agent creation framework for LangGraph

Graphton eliminates boilerplate when creating LangGraph agents with MCP tools. Create production-ready agents in 3-10 lines instead of 100+.

Features

  • Declarative Agent Creation: Minimal boilerplate - just specify model and behavior
  • Automatic Prompt Enhancement: Agents automatically understand available capabilities (planning, file system, MCP tools)
  • Universal MCP Authentication: Support for any MCP server configuration with both static and dynamic authentication modes
  • Intelligent Loop Detection: Automatically detects and prevents infinite loops in autonomous agents
  • Production Ready: Works in both local and remote LangGraph deployments
  • Type-Safe Configuration: Pydantic validation with helpful error messages
  • IDE Support: Full autocomplete and type hints for better developer experience

Quick Start

Installation

pip install graphton

Simple Agent

Create a basic agent in just 3 lines:

from graphton import create_deep_agent

SYSTEM_PROMPT = """You are a helpful assistant that answers questions concisely.
When answering questions:
- Be direct and to the point
- Provide accurate information
- If you're not sure, say so
"""

# Create agent with just model and prompt
agent = create_deep_agent(
    model="claude-sonnet-4.5",
    system_prompt=SYSTEM_PROMPT,
)

# Invoke the agent
result = agent.invoke({
    "messages": [{"role": "user", "content": "What is the capital of France?"}]
})

Agent with MCP Tools

Integrate MCP tools with dynamic per-user authentication:

from graphton import create_deep_agent
import os

# Agent with dynamic MCP authentication
agent = create_deep_agent(
    model="claude-sonnet-4.5",
    system_prompt="You are a Planton assistant helping users manage cloud resources.",
    
    # MCP integration with template variables
    mcp_servers={
        "planton": {
            "transport": "streamable_http",
            "url": "https://mcp.planton.ai/",
            "headers": {
                "Authorization": "Bearer {{USER_TOKEN}}"  # Substituted at runtime
            }
        }
    },
    mcp_tools={
        "planton": [
            "list_organizations",
            "search_cloud_resources",
            "create_cloud_resource",
        ]
    },
    
    # Optional parameters
    recursion_limit=150,
    temperature=0.3,
)

# Invoke with user-specific token
result = agent.invoke(
    {"messages": [{"role": "user", "content": "List my organizations"}]},
    config={
        "configurable": {
            "USER_TOKEN": os.getenv("PLANTON_API_KEY")
        }
    }
)

Static MCP Configuration

For shared credentials, use static configuration (tools loaded once at creation time):

agent = create_deep_agent(
    model="claude-sonnet-4.5",
    system_prompt="You are an API assistant.",
    
    mcp_servers={
        "public-api": {
            "transport": "http",
            "url": "https://api.example.com/mcp",
            "headers": {
                "X-API-Key": "hardcoded-key-123"  # No templates = static
            }
        }
    },
    mcp_tools={
        "public-api": ["search", "fetch"]
    }
)

# Invoke without auth config - credentials already in config
result = agent.invoke(
    {"messages": [{"role": "user", "content": "Search for Python"}]}
)

Agent with Sub-agents

Delegate complex tasks to specialized sub-agents with isolated context:

from graphton import create_deep_agent

agent = create_deep_agent(
    model="claude-sonnet-4.5",
    system_prompt="You are a research coordinator that delegates specialized tasks.",
    
    # Define specialized sub-agents
    subagents=[
        {
            "name": "deep-researcher",
            "description": "Conducts thorough research on complex topics with comprehensive analysis",
            "system_prompt": "You are a research specialist. Conduct thorough research, cite sources, and provide comprehensive analysis.",
        },
        {
            "name": "code-reviewer",
            "description": "Reviews code for quality, security, and best practices",
            "system_prompt": "You are a code review expert. Analyze code for bugs, security issues, and improvement opportunities.",
        }
    ],
    
    # Include general-purpose sub-agent for other tasks
    general_purpose_agent=True,
)

# The agent can now delegate tasks to sub-agents
result = agent.invoke({
    "messages": [{"role": "user", "content": "Research quantum computing and review the attached code"}]
})

When to use sub-agents:

  • Complex multi-step tasks that can be delegated
  • Independent parallel tasks
  • Tasks requiring focused reasoning without context bloat
  • Specialized domains (research, code review, data analysis)

Benefits:

  • Context isolation: Each sub-agent has its own context window
  • Token efficiency: Main agent gets concise summaries, not full task history
  • Parallel execution: Launch multiple sub-agents simultaneously
  • Specialization: Different sub-agents with domain-specific tools

Automatic Prompt Enhancement

Graphton automatically enhances your instructions with awareness of Deep Agents capabilities. This ensures agents understand what tools they have and when to use them.

What Gets Enhanced

When you provide simple instructions like:

agent = create_deep_agent(
    model="claude-sonnet-4.5",
    system_prompt="You are a helpful research assistant.",
)

Graphton automatically adds context about:

  • Planning System: For breaking down complex multi-step tasks
  • File System: For storing and managing information across operations
  • MCP Tools: When configured, awareness of domain-specific capabilities

Why This Matters

Deep Agents come with powerful built-in tools (planning, file system, subagents), but agents won't use them effectively unless they know they exist. Graphton bridges this gap by automatically informing agents about available capabilities.

Control and Flexibility

  • Automatic by default: Enhancement happens automatically for all agents
  • Redundancy is fine: If your instructions already mention planning or file system, some overlap will occur. This is intentional - LLMs handle redundancy gracefully, and reinforcement is better than missing critical context
  • Can be disabled: Use auto_enhance_prompt=False to pass instructions as-is
# Disable enhancement if you've already included all context
agent = create_deep_agent(
    model="claude-sonnet-4.5",
    system_prompt="Detailed instructions with all tool context...",
    auto_enhance_prompt=False,  # Use prompt as-is
)

Documentation

  • Configuration Guide - Complete reference for all configuration options
  • API Documentation - Full API reference
  • Examples - More usage examples including:
    • simple_agent.py - Basic agent without MCP
    • mcp_agent.py - Dynamic MCP authentication
    • static_mcp_agent.py - Static MCP configuration
    • multi_auth_agent.py - Multiple servers with mixed authentication

Universal MCP Authentication

Graphton supports any MCP server configuration format and authentication method through template-based token injection:

Dynamic Mode (with {{VAR}} templates):

  • Templates substituted from config['configurable'] at invocation time
  • Tools loaded per-request with user-specific authentication
  • Use for multi-tenant systems or per-user tokens

Static Mode (no template variables):

  • Tools loaded once at agent creation time
  • Zero runtime overhead
  • Use for hardcoded credentials or public servers

Supported authentication methods:

  • Bearer tokens (OAuth, JWT)
  • API Keys
  • Basic Auth
  • Custom headers
  • Any authentication format supported by your MCP server

Durable Execution & Tool Idempotency

When running Graphton agents through Temporal workflows (as in Stigmer), agents benefit from durable execution - the ability to resume from checkpoints after crashes or failures.

How Crash Recovery Works

  1. LangGraph checkpoints state (messages, tool decisions) to MongoDB after each step
  2. Temporal heartbeats include the thread_id (checkpoint identifier)
  3. On crash/retry, the activity extracts thread_id from heartbeat and resumes from checkpoint
  4. Agent continues from the last saved state instead of restarting

Tool Idempotency Guidelines

While LangGraph checkpointing handles most crash recovery, there's a small window where a tool may execute but the checkpoint hasn't been saved yet. For critical operations, tools should be designed to be idempotent (safe to run multiple times).

Read-only tools (no special handling needed)

These tools are naturally idempotent - re-running them produces the same result:

  • read, ls, glob, grep
  • Database queries (SELECT statements)
  • API GET requests

Create operations (should check for existing resources)

Tools that create resources should check if the resource already exists:

@tool
async def create_pull_request(title: str, branch: str) -> str:
    """Create a PR - checks for existing PR first."""
    # Check if PR already exists
    existing = await github.get_prs(head=branch, state="open")
    if existing:
        return f"PR already exists: {existing[0].url}"
    
    # Create new PR
    pr = await github.create_pr(title=title, branch=branch)
    return f"Created PR: {pr.url}"

External API calls (use API-level idempotency)

Many APIs support idempotency keys to prevent duplicate operations:

@tool
async def charge_payment(amount: float, customer_id: str) -> str:
    """Charge payment with idempotency key."""
    import hashlib
    
    # Generate deterministic idempotency key from operation parameters
    key = hashlib.sha256(f"{customer_id}:{amount}:{context.execution_id}".encode()).hexdigest()
    
    result = await stripe.charges.create(
        amount=int(amount * 100),
        customer=customer_id,
        idempotency_key=key,  # Stripe prevents duplicate charges
    )
    return f"Charged ${amount}: {result.id}"

Destructive operations (usually idempotent)

Most delete operations are naturally idempotent:

  • delete_file - deleting a non-existent file is typically a no-op
  • remove_user - removing a non-existent user returns success

When idempotency is critical

For operations with significant side effects, consider:

  1. Check-before-act: Verify the operation hasn't been done
  2. Idempotency keys: Use API-provided idempotency mechanisms
  3. Transaction IDs: Include execution context in transaction identifiers

Summary

Tool Type Idempotent? Recommendation
Read operations Yes No action needed
Create operations No Check if resource exists first
API calls with idempotency Yes Use idempotency keys
Delete operations Usually Handle "not found" gracefully
Send notifications No Use API idempotency or dedup logic

Requirements

  • Python 3.11 or higher
  • Poetry (for development)

License

Apache-2.0 - See LICENSE for details

Contributing

We welcome contributions! Please see CONTRIBUTING.md for development setup and guidelines.

Links

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

graphton-0.3.1.tar.gz (151.7 kB view details)

Uploaded Source

Built Distribution

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

graphton-0.3.1-py3-none-any.whl (170.2 kB view details)

Uploaded Python 3

File details

Details for the file graphton-0.3.1.tar.gz.

File metadata

  • Download URL: graphton-0.3.1.tar.gz
  • Upload date:
  • Size: 151.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for graphton-0.3.1.tar.gz
Algorithm Hash digest
SHA256 ab08ae232dd56945a15f690ba3edf4b142d20488e61c4b9697a0a0f62908abb9
MD5 b8b2bf199c1e231790240990f064e132
BLAKE2b-256 9a97f1765dc1397e91de987bca8568f052a59199a022fb8f33573e123b62d2b2

See more details on using hashes here.

Provenance

The following attestation bundles were made for graphton-0.3.1.tar.gz:

Publisher: release.python-runner.yaml on stigmer/stigmer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file graphton-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: graphton-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 170.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for graphton-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5f166bf7f4b33de946ef733b18e47c3a838ac9e9cc2eefcf42c472d0add3e984
MD5 164266fbf0753440d8801871509c4a76
BLAKE2b-256 3704f553a570f8f7a6633e6e28eb7f079297ac12d39d87e7caaa2544f68fe371

See more details on using hashes here.

Provenance

The following attestation bundles were made for graphton-0.3.1-py3-none-any.whl:

Publisher: release.python-runner.yaml on stigmer/stigmer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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