Skip to content
/ jaf Public

A purely functional agent framework built on immutable state, type safety, and composable policies. JAF enables building production-ready AI agent systems with built-in security, observability, and error handling.

License

Notifications You must be signed in to change notification settings

xynehq/jaf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Juspay Agent Framework (JAF)

CI Documentation npm version npm downloads License: MIT

Juspay Agent Framework

A purely functional agent framework built on immutable state, type safety, and composable policies. JAF enables building production-ready AI agent systems with built-in security, observability, and error handling.

๐Ÿ“š Read the Documentation

๐ŸŽฏ Core Philosophy

  • Immutability: All core data structures are deeply readonly
  • 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 TypeScript's advanced features for compile-time safety
  • Functional Composition: Complex behaviors built through function composition, not inheritance or mutation

๐Ÿš€ Quick Start

Installation

# Install from npm
npm install @xynehq/jaf

# Or using yarn
yarn add @xynehq/jaf

# Or using pnpm
pnpm add @xynehq/jaf

Development Setup

# Clone the repository
git clone https://github.com/xynehq/jaf.git
cd jaf

# Install dependencies
npm install

# Build the project
npm run build

# Run tests
npm test

๐Ÿ“ Project Structure

src/
โ”œโ”€โ”€ core/           # Core framework types and engine
โ”‚   โ”œโ”€โ”€ engine.ts   # Main execution engine
โ”‚   โ”œโ”€โ”€ errors.ts   # Error handling and types
โ”‚   โ”œโ”€โ”€ tool-results.ts # Tool execution results
โ”‚   โ”œโ”€โ”€ tracing.ts  # Event tracing system
โ”‚   โ””โ”€โ”€ types.ts    # Core type definitions
โ”œโ”€โ”€ memory/         # Memory providers for conversation persistence
โ”‚   โ”œโ”€โ”€ factory.ts  # Memory provider factory
โ”‚   โ”œโ”€โ”€ types.ts    # Memory system types
โ”‚   โ””โ”€โ”€ providers/
โ”‚       โ”œโ”€โ”€ in-memory.ts  # In-memory provider
โ”‚       โ”œโ”€โ”€ postgres.ts   # PostgreSQL provider
โ”‚       โ””โ”€โ”€ redis.ts      # Redis provider
โ”œโ”€โ”€ providers/      # External integrations
โ”‚   โ”œโ”€โ”€ mcp.ts      # Model Context Protocol integration
โ”‚   โ””โ”€โ”€ model.ts    # LLM provider integrations
โ”œโ”€โ”€ policies/       # Validation and security policies
โ”‚   โ”œโ”€โ”€ handoff.ts  # Agent handoff policies
โ”‚   โ””โ”€โ”€ validation.ts # Input/output validation
โ”œโ”€โ”€ server/         # HTTP server implementation
โ”‚   โ”œโ”€โ”€ index.ts    # Server entry point
โ”‚   โ”œโ”€โ”€ server.ts   # Express server setup
โ”‚   โ””โ”€โ”€ types.ts    # Server-specific types
โ”œโ”€โ”€ __tests__/      # Test suite
โ”‚   โ”œโ”€โ”€ engine.test.ts     # Engine tests
โ”‚   โ””โ”€โ”€ validation.test.ts # Validation tests
โ””โ”€โ”€ index.ts        # Main framework exports
examples/
โ”œโ”€โ”€ rag-demo/       # Vertex AI RAG integration demo
โ”‚   โ”œโ”€โ”€ index.ts    # Demo entry point
โ”‚   โ”œโ”€โ”€ rag-agent.ts # RAG agent implementation
โ”‚   โ””โ”€โ”€ rag-tool.ts  # RAG tool implementation
โ””โ”€โ”€ server-demo/    # Development server demo
    โ””โ”€โ”€ index.ts    # Server demo entry point
docs/               # Documentation
โ”œโ”€โ”€ getting-started.md
โ”œโ”€โ”€ core-concepts.md
โ”œโ”€โ”€ api-reference.md
โ”œโ”€โ”€ tools.md
โ”œโ”€โ”€ memory-system.md
โ”œโ”€โ”€ model-providers.md
โ”œโ”€โ”€ server-api.md
โ”œโ”€โ”€ examples.md
โ”œโ”€โ”€ deployment.md
โ””โ”€โ”€ troubleshooting.md

๐Ÿ—๏ธ Key Components

Core Types

import { z } from 'zod';
import { Agent, Tool, RunState, run } from '@xynehq/jaf';

// Define your context type
type MyContext = {
  userId: string;
  permissions: string[];
};

// Create a tool
const calculatorTool: Tool<{ expression: string }, MyContext> = {
  schema: {
    name: "calculate",
    description: "Perform mathematical calculations",
    parameters: z.object({
      expression: z.string().describe("Math expression to evaluate")
    }),
  },
  execute: async (args) => {
    const result = eval(args.expression); // Don't do this in production!
    return `${args.expression} = ${result}`;
  },
};

// Define an agent
const mathAgent: Agent<MyContext, string> = {
  name: 'MathTutor',
  instructions: () => 'You are a helpful math tutor',
  tools: [calculatorTool],
};

Running the Framework

import { run, makeLiteLLMProvider } from '@xynehq/jaf';

const modelProvider = makeLiteLLMProvider('http://localhost:4000');
const agentRegistry = new Map([['MathTutor', mathAgent]]);

const config = {
  agentRegistry,
  modelProvider,
  maxTurns: 10,
  onEvent: (event) => console.log(event), // Real-time tracing
};

const initialState = {
  runId: generateRunId(),
  traceId: generateTraceId(),
  messages: [{ role: 'user', content: 'What is 2 + 2?' }],
  currentAgentName: 'MathTutor',
  context: { userId: 'user123', permissions: ['user'] },
  turnCount: 0,
};

const result = await run(initialState, config);

๐Ÿ”„ Function Composition

JAF emphasizes function composition to build complex behaviors from simple, reusable functions:

Composing Tools

import { createFunctionTool, composeTool, withRetry, withCache } from '@xynehq/jaf';

// Simple base tools
const fetchWeatherTool = createFunctionTool({
  name: 'fetch_weather',
  description: 'Fetch weather data',
  execute: async ({ location }) => {
    const response = await fetch(`/api/weather?location=${location}`);
    return response.json();
  },
  parameters: [{ name: 'location', type: 'string', required: true }]
});

const formatTemperatureTool = createFunctionTool({
  name: 'format_temp',
  description: 'Format temperature reading',
  execute: ({ temp, unit }) => `${temp}ยฐ${unit.toUpperCase()}`,
  parameters: [
    { name: 'temp', type: 'number', required: true },
    { name: 'unit', type: 'string', required: true }
  ]
});

// Compose tools with higher-order functions
const cachedWeatherTool = withCache(fetchWeatherTool, { ttl: 300000 }); // 5 min cache
const reliableWeatherTool = withRetry(cachedWeatherTool, { maxRetries: 3 });

// Chain tools together
const weatherReportTool = composeTool([
  reliableWeatherTool,
  formatTemperatureTool
], 'weather_report', 'Get formatted weather report');

Composing Validators

import { compose, createValidator } from '@xynehq/jaf';

// Base validators
const isPositive = createValidator<number>(
  n => n > 0,
  'Value must be positive'
);

const isInteger = createValidator<number>(
  n => Number.isInteger(n),
  'Value must be an integer'
);

const isInRange = (min: number, max: number) => createValidator<number>(
  n => n >= min && n <= max,
  `Value must be between ${min} and ${max}`
);

// Compose validators
const validateAge = compose(
  isPositive,
  isInteger,
  isInRange(0, 150)
);

// Use in tool parameters
const ageTool = createFunctionTool({
  name: 'process_age',
  description: 'Process age data',
  execute: ({ age }) => `Age ${age} is valid`,
  parameters: [{
    name: 'age',
    type: 'number',
    required: true,
    validate: validateAge
  }]
});

Composing Agent Behaviors

import { createAgent, withMiddleware, withFallback } from '@xynehq/jaf';

// Base agents
const primaryAgent = createAgent({
  name: 'primary',
  model: 'gpt-4',
  instruction: 'Primary processing agent',
  tools: [calculatorTool]
});

const fallbackAgent = createAgent({
  name: 'fallback',
  model: 'gpt-3.5-turbo',
  instruction: 'Fallback processing agent',
  tools: [simpleMathTool]
});

// Compose with middleware
const loggingMiddleware = (agent) => ({
  ...agent,
  execute: async (input) => {
    console.log(`[${agent.name}] Processing:`, input);
    const result = await agent.execute(input);
    console.log(`[${agent.name}] Result:`, result);
    return result;
  }
});

const rateLimitMiddleware = (limit: number) => (agent) => {
  let count = 0;
  const resetTime = Date.now() + 60000;
  
  return {
    ...agent,
    execute: async (input) => {
      if (Date.now() > resetTime) {
        count = 0;
      }
      if (count >= limit) {
        throw new Error('Rate limit exceeded');
      }
      count++;
      return agent.execute(input);
    }
  };
};

// Compose everything
const productionAgent = compose(
  withFallback(fallbackAgent),
  withMiddleware(loggingMiddleware),
  withMiddleware(rateLimitMiddleware(100))
)(primaryAgent);

Composing Memory Providers

import { composeMemoryProviders, createCacheLayer } from '@xynehq/jaf';

// Layer memory providers for performance and reliability
const memoryProvider = composeMemoryProviders([
  createCacheLayer({ maxSize: 100 }),      // L1: In-memory cache
  createRedisProvider({ ttl: 3600 }),      // L2: Redis cache
  createPostgresProvider({ table: 'chat' }) // L3: Persistent storage
]);

// The composed provider automatically:
// - Reads from the fastest available layer
// - Writes to all layers
// - Falls back on layer failure

๐Ÿ›ก๏ธ Security & Validation

Composable Validation Policies

import { createPathValidator, createPermissionValidator, composeValidations } from '@xynehq/jaf';

// Create individual validators
const pathValidator = createPathValidator(['/shared', '/public']);
const permissionValidator = createPermissionValidator('admin', ctx => ctx);

// Compose them
const combinedValidator = composeValidations(pathValidator, permissionValidator);

// Apply to tools
const secureFileTool = withValidation(baseFileTool, combinedValidator);

Guardrails

import { createContentFilter, createRateLimiter } from '@xynehq/jaf';

const config = {
  // ... other config
  initialInputGuardrails: [
    createContentFilter(),
    createRateLimiter(10, 60000, input => 'global')
  ],
  finalOutputGuardrails: [
    createContentFilter()
  ],
};

๐Ÿ”— Agent Handoffs

import { handoffTool } from '@xynehq/jaf';

const triageAgent: Agent<Context, { agentName: string }> = {
  name: 'TriageAgent',
  instructions: () => 'Route requests to specialized agents',
  tools: [handoffTool],
  handoffs: ['MathTutor', 'FileManager'], // Allowed handoff targets
  outputCodec: z.object({
    agentName: z.enum(['MathTutor', 'FileManager'])
  }),
};

๐Ÿ“Š Observability

Real-time Tracing

import { ConsoleTraceCollector, FileTraceCollector } from '@xynehq/jaf';

// Console logging
const consoleTracer = new ConsoleTraceCollector();

// File logging
const fileTracer = new FileTraceCollector('./traces.log');

// Composite tracing
const tracer = createCompositeTraceCollector(consoleTracer, fileTracer);

const config = {
  // ... other config
  onEvent: tracer.collect.bind(tracer),
};

Error Handling

import { JAFErrorHandler } from '@xynehq/jaf';

if (result.outcome.status === 'error') {
  const formattedError = JAFErrorHandler.format(result.outcome.error);
  const isRetryable = JAFErrorHandler.isRetryable(result.outcome.error);
  const severity = JAFErrorHandler.getSeverity(result.outcome.error);
  
  console.error(`[${severity}] ${formattedError} (retryable: ${isRetryable})`);
}

๐Ÿ”Œ Provider Integrations

LiteLLM Provider

import { makeLiteLLMProvider } from '@xynehq/jaf';

// Connect to LiteLLM proxy for 100+ model support
const modelProvider = makeLiteLLMProvider(
  'http://localhost:4000', // LiteLLM proxy URL
  'your-api-key'           // Optional API key
);

MCP (Model Context Protocol) Tools

import { makeMCPClient, mcpToolToJAFTool } from '@xynehq/jaf';

// Connect to MCP server
const mcpClient = await makeMCPClient('python', ['-m', 'mcp_server']);

// Get available tools
const mcpTools = await mcpClient.listTools();

// Convert to JAF tools with validation
const jafTools = mcpTools.map(tool => 
  mcpToolToJAFTool(mcpClient, tool, myValidationPolicy)
);

๐Ÿš€ Development Server

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

import { runServer, makeLiteLLMProvider, createInMemoryProvider } from '@xynehq/jaf';

const myAgent = {
  name: 'MyAgent',
  instructions: 'You are a helpful assistant',
  tools: [calculatorTool, greetingTool]
};

const modelProvider = makeLiteLLMProvider('http://localhost:4000');
const memoryProvider = createInMemoryProvider();

// Start server on port 3000
const server = await runServer(
  [myAgent], 
  { modelProvider },
  { port: 3000, defaultMemoryProvider: memoryProvider }
);

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

๐Ÿ“š Documentation

Comprehensive documentation is available in the /docs folder:

๐Ÿ“– Documentation Website

Browse the full documentation online at https://xynehq.github.io/jaf/

The documentation site features:

  • ๐Ÿ” Full-text search
  • ๐ŸŒ“ Dark/light mode toggle
  • ๐Ÿ“ฑ Mobile-friendly responsive design
  • ๐Ÿ”— Deep linking to sections
  • ๐Ÿ“‹ Code block copy buttons

Running Documentation Locally

# Install documentation dependencies
pip install -r requirements.txt

# Run local documentation server
mkdocs serve
# Visit http://127.0.0.1:8000

# Or use the convenience script
./docs/serve.sh

๐ŸŽฎ Example Applications

Explore the example applications to see the framework in action:

Development Server Demo

cd examples/server-demo
npm install
npm run dev

The server demo showcases:

  • โœ… Multiple agent types with different capabilities
  • โœ… RESTful API with type-safe validation
  • โœ… Tool integration (calculator, greeting)
  • โœ… Real-time tracing and error handling
  • โœ… CORS support and graceful shutdown

Vertex AI RAG Demo

cd examples/rag-demo
npm install
npm run dev

The RAG demo showcases:

  • โœ… Real Vertex AI RAG integration with Google GenAI SDK
  • โœ… Permission-based access control
  • โœ… Real-time streaming responses with source attribution
  • โœ… Performance metrics and comprehensive error handling
  • โœ… JAF framework orchestration with type-safe tools
  • โœ… Multi-turn conversations with observability

๐Ÿงช Testing

npm test        # Run tests
npm run lint    # Lint code
npm run typecheck # Type checking

โœจ Recent Enhancements

Multi-Agent Coordination

  • Intelligent Agent Selection: Automatic keyword-based routing for conditional delegation
  • Parallel Response Merging: Smart merging of responses from multiple agents
  • Coordination Rules: Define custom rules for sophisticated orchestration
  • Hierarchical Delegation: Multi-level agent architectures with automatic handoffs

Enhanced Schema Validation

  • Full JSON Schema Draft 7: Complete support for all validation features
  • Format Validators: Built-in email, URL, date, UUID, IPv4/IPv6 validation
  • Advanced Constraints: minLength, maxLength, pattern, multipleOf, uniqueItems
  • Deep Validation: Object property constraints, array uniqueness with deep equality

Visualization System

  • DOT Generation: Direct Graphviz DOT generation for better reliability
  • Multiple Color Schemes: Default, modern, and minimal themes
  • Architecture Diagrams: Generate agent, tool, and runner visualizations
  • Fallback Support: DOT content available even if rendering fails

Model Support

  • 300+ Models: Comprehensive enum with all major LLM providers
  • Type-Safe: Strongly typed model identifiers
  • Provider Detection: Automatic provider identification from model names

๐Ÿ›๏ธ 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 Zod schemas
  • Compile-time safety with TypeScript
  • Branded types prevent ID mixing

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

๐Ÿค 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 - Building the future of functional AI agent systems ๐Ÿš€

About

A purely functional agent framework built on immutable state, type safety, and composable policies. JAF enables building production-ready AI agent systems with built-in security, observability, and error handling.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 6

Languages