Metadata-Version: 2.4
Name: graphton
Version: 0.3.0
Summary: Declarative agent creation framework for LangGraph (Stigmer local copy)
License: Apache-2.0
License-File: LICENSE
Keywords: langgraph,langchain,agents,mcp,ai
Author: Stigmer
Author-email: engineering@stigmer.ai
Requires-Python: >=3.11,<4.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: deepagents (>=0.4.0,!=0.4.1,<0.5.0)
Requires-Dist: httpx (>=0.28.0,<1.0.0)
Requires-Dist: langchain (>=1.0.0,<2.0.0)
Requires-Dist: langchain-anthropic (>=1.0.0,<2.0.0)
Requires-Dist: langchain-mcp-adapters (>=0.2.0,<0.3.0)
Requires-Dist: langchain-ollama (>=1.0.0,<2.0.0)
Requires-Dist: langchain-openai (>=1.0.0,<2.0.0)
Requires-Dist: langgraph (>=1.0.0,<2.0.0)
Requires-Dist: langmem (>=0.0.30,<1.0.0)
Requires-Dist: nest-asyncio (>=1.6.0,<2.0.0)
Requires-Dist: pathspec (>=0.12.0,<1.0.0)
Requires-Dist: pydantic (>=2.0.0,<3.0.0)
Requires-Dist: tiktoken (>=0.7.0,<1.0.0)
Description-Content-Type: text/markdown

# Graphton

[![CI](https://github.com/plantoncloud/graphton/actions/workflows/ci.yml/badge.svg)](https://github.com/plantoncloud/graphton/actions/workflows/ci.yml)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/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

```bash
pip install graphton
```

### Simple Agent

Create a basic agent in just 3 lines:

```python
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:

```python
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):

```python
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:

```python
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:

```python
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

```python
# 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](docs/CONFIGURATION.md)** - Complete reference for all configuration options
- **[API Documentation](docs/API.md)** - Full API reference
- **[Examples](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:

```python
@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:

```python
@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](LICENSE) for details

## Contributing

We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.

## Links

- **Repository**: https://github.com/plantoncloud/graphton
- **Documentation**: https://github.com/plantoncloud/graphton#readme
- **Issues**: https://github.com/plantoncloud/graphton/issues

