UNPKG

@xynehq/jaf

Version:

Juspay Agent Framework - A purely functional agent framework with immutable state and composable tools

622 lines (492 loc) โ€ข 18.2 kB
# Juspay Agent Framework (JAF) [![CI](https://github.com/xynehq/jaf/workflows/CI/badge.svg)](https://github.com/xynehq/jaf/actions) [![Documentation](https://img.shields.io/badge/docs-mkdocs-blue)](https://xynehq.github.io/jaf/) [![npm version](https://img.shields.io/npm/v/@xynehq/jaf.svg)](https://www.npmjs.com/package/@xynehq/jaf) [![npm downloads](https://img.shields.io/npm/dm/@xynehq/jaf.svg)](https://www.npmjs.com/package/@xynehq/jaf) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ![Juspay Agent Framework](/docs/cover.png?raw=true "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](https://xynehq.github.io/jaf/)** ## ๐ŸŽฏ 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 ```bash # Install from npm npm install @xynehq/jaf # Or using yarn yarn add @xynehq/jaf # Or using pnpm pnpm add @xynehq/jaf ``` ### Development Setup ```bash # 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript import { createContentFilter, createRateLimiter } from '@xynehq/jaf'; const config = { // ... other config initialInputGuardrails: [ createContentFilter(), createRateLimiter(10, 60000, input => 'global') ], finalOutputGuardrails: [ createContentFilter() ], }; ``` ## ๐Ÿ”— Agent Handoffs ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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: ```typescript 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`](./docs) folder: - **[Getting Started](./docs/getting-started.md)** - Installation, basic concepts, and first agent - **[Core Concepts](./docs/core-concepts.md)** - JAF's functional architecture and principles - **[API Reference](./docs/api-reference.md)** - Complete TypeScript API documentation - **[ADK Layer](./docs/adk-layer.md)** - Agent Development Kit for simplified agent creation - **[A2A Protocol](./docs/a2a-protocol.md)** - Agent-to-Agent communication and task management - **[Tools](./docs/tools.md)** - Building robust tools with validation and error handling - **[Memory System](./docs/memory-system.md)** - Conversation persistence (in-memory, Redis, PostgreSQL) - **[Model Providers](./docs/model-providers.md)** - LLM integration and configuration - **[Server & API](./docs/server-api.md)** - HTTP server setup and REST API - **[Visualization](./docs/visualization.md)** - Generate Graphviz diagrams of agents and tools - **[Examples](./docs/examples.md)** - Tutorials and integration patterns - **[Deployment](./docs/deployment.md)** - Production deployment guide - **[Troubleshooting](./docs/troubleshooting.md)** - Common issues and debugging - **[New Features](./docs/new-features.md)** - Recent enhancements and capabilities ### ๐Ÿ“– Documentation Website Browse the full documentation online at **[https://xynehq.github.io/jaf/](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 ```bash # 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 ```bash 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 ```bash 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 ```bash 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 ๐Ÿš€