Skip to main content

A purely functional agent framework with immutable state and composable tools - Python implementation

Project description

JAF (Juspay Agent Framework) - Python Implementation

Version Python Docs

A purely functional agent framework with immutable state and composable tools, professionally converted from TypeScript to Python. JAF enables building production-ready AI agent systems with built-in security, observability, and error handling.

๐ŸŽฏ Production Ready: Complete feature parity with TypeScript version, comprehensive test suite, and production deployment support.

๐Ÿ“š Read the Full Documentation

๐Ÿš€ Get Started โ†’ | ๐Ÿ“– API Reference โ†’ | ๐ŸŽฎ Examples โ†’

โœจ Key Features

๐Ÿ—๏ธ Complete TypeScript Conversion

  • โœ… Full Feature Parity: All TypeScript functionality converted to Python
  • โœ… Type Safety: Pydantic models with runtime validation
  • โœ… Immutable State: Functional programming principles preserved
  • โœ… Tool Integration: Complete tool calling and execution system

๐Ÿš€ Production Ready Server

  • โœ… FastAPI Server: High-performance async HTTP API
  • โœ… Auto Documentation: Interactive API docs at /docs
  • โœ… Health Monitoring: Built-in health checks and metrics
  • โœ… CORS Support: Ready for browser integration

๐Ÿ”Œ Model Context Protocol (MCP)

  • โœ… MCP Client: Full MCP specification support
  • โœ… Stdio & SSE: Multiple transport protocols
  • โœ… Tool Integration: Seamless MCP tool integration
  • โœ… Auto Discovery: Dynamic tool loading from MCP servers

๐Ÿ›ก๏ธ Enterprise Security

  • โœ… Input Guardrails: Content filtering and validation
  • โœ… Output Guardrails: Response sanitization
  • โœ… Permission System: Role-based access control
  • โœ… Audit Logging: Complete interaction tracing

๐Ÿ“Š Observability & Monitoring

  • โœ… Real-time Tracing: Event-driven observability
  • โœ… Structured Logging: JSON-formatted logs
  • โœ… Error Handling: Comprehensive error types and recovery
  • โœ… Performance Metrics: Built-in timing and counters

๐Ÿ”ง Developer Experience

  • โœ… CLI Tools: Project initialization and management
  • โœ… Hot Reload: Development server with auto-reload
  • โœ… Type Hints: Full mypy compatibility
  • โœ… Rich Examples: RAG, multi-agent, and server demos
  • โœ… Visual Architecture: Graphviz-powered agent and tool diagrams

๐ŸŽฏ Core Philosophy

  • Immutability: All core data structures are deeply immutable
  • Pure Functions: Core logic expressed as pure, predictable functions
  • Effects at the Edge: Side effects isolated in Provider modules
  • Composition over Configuration: Build complex behavior by composing simple functions
  • Type-Safe by Design: Leverages Python's type system with Pydantic for runtime safety

๐Ÿš€ Quick Start

Installation

# Install from GitHub (development version)
pip install git+https://github.com/xynehq/jaf-py.git

# Or install with all optional dependencies
pip install "jaf-py[all] @ git+https://github.com/xynehq/jaf-py.git"

# Install specific feature sets
pip install "jaf-py[server] @ git+https://github.com/xynehq/jaf-py.git"        # FastAPI server support
pip install "jaf-py[memory] @ git+https://github.com/xynehq/jaf-py.git"        # Redis/PostgreSQL memory providers
pip install "jaf-py[visualization] @ git+https://github.com/xynehq/jaf-py.git" # Graphviz visualization tools
pip install "jaf-py[dev] @ git+https://github.com/xynehq/jaf-py.git"           # Development tools

CLI Usage

JAF includes a powerful CLI for project management:

# Initialize a new JAF project
jaf init my-agent-project

# Run the development server
jaf server --host 0.0.0.0 --port 8000

# Show version and help
jaf version
jaf --help

Development Setup

git clone https://github.com/xynehq/jaf-py
cd jaf-py
pip install -e ".[dev]"

# Run tests
pytest

# Type checking and linting
mypy jaf/
ruff check jaf/
black jaf/

# Documentation
pip install -r requirements-docs.txt
./docs.sh serve  # Start documentation server
./docs.sh deploy # Deploy to GitHub Pages

๐Ÿ“– Documentation

๐ŸŒ Official Documentation Website

The complete, searchable documentation is available at xynehq.github.io/jaf-py with:

  • โœ… Interactive navigation with search and filtering
  • โœ… Dark/light mode with automatic system preference detection
  • โœ… Mobile-responsive design for documentation on any device
  • โœ… Live code examples with syntax highlighting
  • โœ… API reference with auto-generated documentation
  • โœ… Always up-to-date with automatic deployments

๐Ÿ“ Local Documentation

For offline access, documentation is also available in the docs/ directory:

๐Ÿ“ Project Structure

jaf-py/
โ”œโ”€โ”€ docs/                    # Complete documentation
โ”œโ”€โ”€ jaf/                     # Core framework package
โ”‚   โ”œโ”€โ”€ core/               # Core types and engine
โ”‚   โ”œโ”€โ”€ memory/             # Conversation persistence
โ”‚   โ”œโ”€โ”€ providers/          # External integrations (LiteLLM, MCP)
โ”‚   โ”œโ”€โ”€ policies/           # Validation and security
โ”‚   โ”œโ”€โ”€ server/             # FastAPI server
โ”‚   โ””โ”€โ”€ cli.py              # Command-line interface
โ”œโ”€โ”€ examples/               # Example applications
โ””โ”€โ”€ tests/                  # Test suite

๐ŸŽจ Architectural Visualization

JAF includes powerful visualization capabilities to help you understand and document your agent systems.

Prerequisites

First, install the system Graphviz dependency:

# macOS
brew install graphviz

# Ubuntu/Debian  
sudo apt-get install graphviz

# Windows (via Chocolatey)
choco install graphviz

Then install JAF with visualization support:

pip install "jaf-py[visualization]"

Quick Start

import asyncio
from jaf import Agent, Tool, generate_agent_graph, GraphOptions

# Create your agents
agent = Agent(
    name='MyAgent',
    instructions=lambda state: "I am a helpful assistant.",
    tools=[my_tool],
    handoffs=['OtherAgent']
)

# Generate visualization
async def main():
    result = await generate_agent_graph(
        [agent],
        GraphOptions(
            title="My Agent System",
            output_path="./my-agents.png",
            color_scheme="modern",
            show_tool_details=True
        )
    )
    
    if result.success:
        print(f"โœ… Visualization saved to: {result.output_path}")
    else:
        print(f"โŒ Error: {result.error}")

asyncio.run(main())

Features

  • ๐ŸŽจ Multiple Color Schemes: Choose from default, modern, or minimal themes
  • ๐Ÿ“Š Agent Architecture: Visualize agents, tools, and handoff relationships
  • ๐Ÿ”ง Tool Ecosystems: Generate dedicated tool interaction diagrams
  • ๐Ÿƒ Runner Architecture: Show complete system architecture with session layers
  • ๐Ÿ“„ Multiple Formats: Export as PNG, SVG, or PDF
  • โš™๏ธ Customizable Layouts: Support for various Graphviz layouts (dot, circo, neato, etc.)

Example Output

The visualization system generates clear, professional diagrams showing:

  • Agent Nodes: Rounded rectangles with agent names and model information
  • Tool Nodes: Ellipses showing tool names and descriptions
  • Handoff Edges: Dashed lines indicating agent handoff relationships
  • Tool Connections: Colored edges connecting agents to their tools
  • Cluster Organization: Grouped components in runner architecture views

Advanced Usage

from jaf.visualization import run_visualization_examples

# Run comprehensive examples
await run_visualization_examples()

# This generates multiple example files:
# - ./examples/agent-graph.png (agent system overview)
# - ./examples/tool-graph.png (tool ecosystem)  
# - ./examples/runner-architecture.png (complete system)
# - ./examples/agent-modern.png (modern color scheme)

๐Ÿ—๏ธ Key Components

Core Types

from dataclasses import dataclass
from pydantic import BaseModel, Field
from jaf import Agent, Tool, RunState, run

# Define your context type
@dataclass
class MyContext:
    user_id: str
    permissions: list[str]

# Define tool schema
class CalculateArgs(BaseModel):
    expression: str = Field(description="Math expression to evaluate")

# Create a tool
class CalculatorTool:
    @property
    def schema(self):
        return type('ToolSchema', (), {
            'name': 'calculate',
            'description': 'Perform mathematical calculations',
            'parameters': CalculateArgs
        })()
    
    async def execute(self, args: CalculateArgs, context: MyContext) -> str:
        result = eval(args.expression)  # Don't do this in production!
        return f"{args.expression} = {result}"

# Define an agent
def create_math_agent():
    def instructions(state):
        return 'You are a helpful math tutor'
    
    return Agent(
        name='MathTutor',
        instructions=instructions,
        tools=[CalculatorTool()]
    )

Running the Framework

import asyncio
from jaf import run, make_litellm_provider, generate_run_id, generate_trace_id
from jaf.core.types import RunState, RunConfig, Message

async def main():
    model_provider = make_litellm_provider('http://localhost:4000')
    math_agent = create_math_agent()
    
    config = RunConfig(
        agent_registry={'MathTutor': math_agent},
        model_provider=model_provider,
        max_turns=10,
        on_event=lambda event: print(event),  # Real-time tracing
    )
    
    initial_state = RunState(
        run_id=generate_run_id(),
        trace_id=generate_trace_id(),
        messages=[Message(role='user', content='What is 2 + 2?')],
        current_agent_name='MathTutor',
        context=MyContext(user_id='user123', permissions=['user']),
        turn_count=0,
    )
    
    result = await run(initial_state, config)
    print(result.outcome.output if result.outcome.status == 'completed' else result.outcome.error)

asyncio.run(main())

๐Ÿ›ก๏ธ Security & Validation

Composable Validation Policies

from jaf.policies.validation import create_path_validator, create_permission_validator, compose_validations

# Create individual validators
path_validator = create_path_validator(['/shared', '/public'])
permission_validator = create_permission_validator('admin', lambda ctx: ctx)

# Compose them
combined_validator = compose_validations(path_validator, permission_validator)

# Apply to tools
secure_file_tool = with_validation(base_file_tool, combined_validator)

Guardrails

from jaf.policies.validation import create_content_filter, create_length_guardrail

config = RunConfig(
    # ... other config
    initial_input_guardrails=[
        create_content_filter(['spam', 'inappropriate']),  # Requires blocked patterns
        create_length_guardrail(max_length=1000, min_length=1)
    ],
    final_output_guardrails=[
        create_content_filter(['harmful', 'unsafe'])
    ],
)

๐Ÿ”— Agent Handoffs

from jaf.policies.handoff import create_handoff_guardrail, HandoffPolicy
from pydantic import BaseModel
from enum import Enum

class AgentName(str, Enum):
    MATH_TUTOR = 'MathTutor'
    FILE_MANAGER = 'FileManager'

class HandoffOutput(BaseModel):
    agent_name: AgentName

def create_triage_agent():
    def instructions(state):
        return 'Route requests to specialized agents'
    
    return Agent(
        name='TriageAgent',
        instructions=instructions,
        tools=[],  # Regular tools would go here
        handoffs=['MathTutor', 'FileManager'],  # Allowed handoff targets
        output_schema=HandoffOutput,
    )

๐Ÿ“Š Observability

Real-time Tracing

from jaf.core.tracing import ConsoleTraceCollector, FileTraceCollector, create_composite_trace_collector

# Console logging
console_tracer = ConsoleTraceCollector()

# File logging
file_tracer = FileTraceCollector('./traces.log')

# Composite tracing
tracer = create_composite_trace_collector(console_tracer, file_tracer)

config = RunConfig(
    # ... other config
    on_event=tracer.collect,
)

Error Handling

from jaf.core.errors import JAFErrorHandler

if result.outcome.status == 'error':
    formatted_error = JAFErrorHandler.format_error(result.outcome.error)
    is_retryable = JAFErrorHandler.is_retryable(result.outcome.error)
    severity = JAFErrorHandler.get_severity(result.outcome.error)
    
    print(f"[{severity}] {formatted_error} (retryable: {is_retryable})")

๐Ÿ”Œ Provider Integrations

A2A (Agent-to-Agent) Communication

JAF provides a robust A2A communication layer that allows agents to interact with each other. This is useful for building multi-agent systems where different agents have specialized skills.

from jaf.a2a import create_a2a_agent, create_a2a_client, create_a2a_server

# Create agents
echo_agent = create_a2a_agent("EchoBot", "Echoes messages", "You are an echo bot.", [])
ping_agent = create_a2a_agent("PingBot", "Responds to pings", "You are a ping bot.", [])

# Create a server
server_config = {
    "agents": {"EchoBot": echo_agent, "PingBot": ping_agent},
    "agentCard": {"name": "Test Server"},
    "port": 8080,
}
server = create_a2a_server(server_config)

# Create a client
client = create_a2a_client("http://localhost:8080")

LiteLLM Provider

from jaf.providers.model import make_litellm_provider

# Connect to LiteLLM proxy for 100+ model support
model_provider = make_litellm_provider(
    'http://localhost:4000',  # LiteLLM proxy URL
    'your-api-key'           # Optional API key
)

MCP (Model Context Protocol) Integration

JAF includes full Model Context Protocol support for seamless tool integration:

from jaf.providers.mcp import create_mcp_stdio_client, create_mcp_tools_from_client

# Connect to MCP server via stdio
mcp_client = create_mcp_stdio_client(['python', '-m', 'my_mcp_server'])

# Initialize and get all available tools
await mcp_client.initialize()
mcp_tools = await create_mcp_tools_from_client(mcp_client)

# Use MCP tools in your agent
def create_mcp_agent():
    def instructions(state):
        return "You have access to powerful MCP tools for various tasks."
    
    return Agent(
        name='MCPAgent',
        instructions=instructions,
        tools=mcp_tools  # Automatically converted JAF tools
    )

# SSE client is also supported
from jaf.providers.mcp import create_mcp_sse_client
sse_client = create_mcp_sse_client('http://localhost:8080/sse')

๐Ÿš€ Development Server

JAF includes a built-in development server for testing agents locally via HTTP endpoints:

from jaf.server import run_server
from jaf.providers.model import make_litellm_provider

def create_my_agent():
    def instructions(state):
        return 'You are a helpful assistant'
    
    return Agent(
        name='MyAgent',
        instructions=instructions,
        tools=[calculator_tool, greeting_tool]
    )

model_provider = make_litellm_provider('http://localhost:4000')

# Start server on port 3000
await run_server(
    [create_my_agent()], 
    {'model_provider': model_provider},
    {'port': 3000}
)

Server provides RESTful endpoints:

  • GET /health - Health check
  • GET /agents - List available agents
  • POST /chat - General chat endpoint
  • POST /agents/{name}/chat - Agent-specific endpoint

๐Ÿ”ง Function Composition

JAF supports functional composition patterns for building complex behaviors from simple, reusable functions:

from jaf import create_function_tool, ToolSource

# Enhanced tool with caching and retry
def with_cache(tool_func):
    cache = {}
    async def cached_execute(args, context):
        cache_key = str(args)
        if cache_key in cache:
            return cache[cache_key]
        result = await tool_func(args, context)
        if result.status == "success":
            cache[cache_key] = result
        return result
    return cached_execute

# Create enhanced tools by composition
enhanced_tool = create_function_tool({
    'name': 'enhanced_search',
    'description': 'Search with caching',
    'execute': with_cache(base_search_function),
    'parameters': SearchArgs,
    'source': ToolSource.NATIVE
})

Key Benefits:

  • Reusability: Write once, compose everywhere
  • Testability: Each function can be tested in isolation
  • Type Safety: Full type checking support
  • Performance: Optimize individual pieces independently

๐ŸŽฎ Example Applications

Explore the example applications to see the framework in action:

1. Multi-Agent Server Demo

cd examples
python server_example.py

Features demonstrated:

  • โœ… Multiple specialized agents (math, weather, general)
  • โœ… Tool integration (calculator, weather API)
  • โœ… Agent handoffs and routing
  • โœ… RESTful API with auto-documentation
  • โœ… Real-time tracing and error handling
  • โœ… Production-ready server configuration

Available endpoints:

  • GET /health - Server health check
  • GET /agents - List all available agents
  • POST /chat - Chat with any agent
  • GET /docs - Interactive API documentation

2. MCP Integration Demo

cd examples/mcp_demo  
python main.py

Features demonstrated:

  • โœ… Model Context Protocol integration
  • โœ… Dynamic tool loading from MCP servers
  • โœ… Secure filesystem operations
  • โœ… MCP client configuration and management

๐Ÿงช Testing

pytest          # Run tests
ruff check .    # Lint code
mypy .          # Type checking
black .         # Format code

๐Ÿ›๏ธ Architecture Principles

Immutable State Machine

  • All state transformations create new state objects
  • No mutation of existing data structures
  • Predictable, testable state transitions

Type Safety

  • Runtime validation with Pydantic schemas
  • Compile-time safety with Python type hints
  • NewType for type-safe identifiers

Pure Functions

  • Core logic is side-effect free
  • Easy to test and reason about
  • Deterministic behavior

Effect Isolation

  • Side effects only in Provider modules
  • Clear boundaries between pure and impure code
  • Easier mocking and testing

๐Ÿ“œ License

MIT

๐Ÿค Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Run the test suite
  5. Submit a pull request

JAF (Juspay Agentic Framework) v2.0 - Building the future of functional AI agent systems ๐Ÿš€

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

jaf_py-2.1.0.tar.gz (273.8 kB view details)

Uploaded Source

Built Distribution

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

jaf_py-2.1.0-py3-none-any.whl (226.6 kB view details)

Uploaded Python 3

File details

Details for the file jaf_py-2.1.0.tar.gz.

File metadata

  • Download URL: jaf_py-2.1.0.tar.gz
  • Upload date:
  • Size: 273.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.17

File hashes

Hashes for jaf_py-2.1.0.tar.gz
Algorithm Hash digest
SHA256 acc98821240698efd5063085135da46b27ea840985d6b77d7e33b0c75e0e1deb
MD5 3baa4276f5f93f79c685d7003ad06a4b
BLAKE2b-256 98e63a98f10e02dfc328b0323cfb78788dfff51405c5a9fa67e8b60bf804a8e5

See more details on using hashes here.

File details

Details for the file jaf_py-2.1.0-py3-none-any.whl.

File metadata

  • Download URL: jaf_py-2.1.0-py3-none-any.whl
  • Upload date:
  • Size: 226.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.17

File hashes

Hashes for jaf_py-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a290bc32b4a3eed9ad207686fb7fb4707a0a2aace757ec08ecd9f9a7144e7e55
MD5 135696be2897ab1710d9b09b2d7cd480
BLAKE2b-256 0a9f15615d5259168b8712d57da85d8674db8be0bf793f3234eab7013da610e6

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