UNPKG

@xynehq/jaf

Version:

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

380 lines (378 loc) 15.1 kB
/** * JAF ADK Layer - Advanced Features Example * * Demonstrates schema validation, guardrails, streaming, and other advanced features */ import { createAgent, createFunctionTool, createInMemorySessionProvider, createRunnerConfig, runAgent, runAgentStream, createUserMessage, createObjectValidator, stringSchema, numberSchema, booleanSchema, weatherQueryValidator, weatherResponseValidator, createAgentEvent, createLiveRequestQueue, monitorStream, metricsMonitor, Model, ToolParameterType } from '../index'; const bookingRequestValidator = createObjectValidator({ customerName: stringSchema({ description: 'Customer full name' }), serviceType: stringSchema({ description: 'Type of service requested', enum: ['consultation', 'maintenance', 'repair'] }), preferredDate: stringSchema({ description: 'Preferred appointment date (YYYY-MM-DD)' }), duration: numberSchema({ description: 'Expected duration in hours' }), urgent: booleanSchema({ description: 'Whether this is an urgent request' }), contactInfo: { type: 'object', properties: { email: stringSchema({ description: 'Customer email address' }), phone: stringSchema({ description: 'Customer phone number' }) }, required: ['email', 'phone'] } }, ['customerName', 'serviceType', 'preferredDate', 'duration', 'urgent', 'contactInfo']); // ========== Guardrails Example ========== const contentModerationGuardrail = async (message) => { const messageText = message.parts .filter(p => p.type === 'text') .map(p => p.text) .join(' ') .toLowerCase(); // Check for inappropriate content const blockedWords = ['spam', 'scam', 'inappropriate']; const containsBlockedContent = blockedWords.some(word => messageText.includes(word)); if (containsBlockedContent) { return { allowed: false, reason: 'Content contains inappropriate language', action: 'block' }; } // Check for excessive length if (messageText.length > 1000) { return { allowed: true, modifiedMessage: { ...message, parts: [{ type: 'text', text: messageText.substring(0, 1000) + '... [truncated]' }] }, reason: 'Message truncated due to length', action: 'modify' }; } return { allowed: true }; }; const rateLimitGuardrail = async (_message, context) => { // Simple rate limiting based on session message count const messageCount = context.session.messages.length; if (messageCount > 10) { return { allowed: false, reason: 'Rate limit exceeded - too many messages in this session', action: 'block' }; } return { allowed: true }; }; // ========== Advanced Agent with Schema Validation ========== export const createBookingAgent = () => { const processBookingTool = createFunctionTool({ name: 'process_booking', description: 'Process a service booking request with validation', execute: (params) => { // Validate input using schema const validation = bookingRequestValidator.validate(params); if (!validation.success) { throw new Error(`Invalid booking request: ${validation.errors?.join(', ')}`); } const booking = validation.data; // Process the booking const bookingId = `BK${Date.now()}`; const estimatedCost = { consultation: 100, maintenance: 150, repair: 200 }[booking.serviceType] * booking.duration; return { bookingId, status: 'confirmed', customer: booking.customerName, service: booking.serviceType, scheduledDate: booking.preferredDate, duration: booking.duration, estimatedCost, priority: booking.urgent ? 'high' : 'normal', contactMethod: 'email' }; }, parameters: [ { name: 'customerName', type: ToolParameterType.STRING, description: 'Customer full name', required: true }, { name: 'serviceType', type: ToolParameterType.STRING, description: 'Type of service (consultation, maintenance, repair)', required: true }, { name: 'preferredDate', type: ToolParameterType.STRING, description: 'Preferred date in YYYY-MM-DD format', required: true }, { name: 'duration', type: ToolParameterType.NUMBER, description: 'Duration in hours', required: true }, { name: 'urgent', type: ToolParameterType.BOOLEAN, description: 'Whether this is urgent', required: true }, { name: 'contactInfo', type: ToolParameterType.OBJECT, description: 'Customer contact information', required: true } ] }); const agent = createAgent({ name: 'booking_agent', model: Model.GEMINI_2_0_FLASH, instruction: `You are a professional booking assistant. Help customers schedule services. When processing bookings: 1. Collect all required information 2. Validate the booking details 3. Use the process_booking tool to create the booking 4. Confirm details with the customer Required information: - Customer name - Service type (consultation, maintenance, or repair) - Preferred date - Duration in hours - Urgency level - Contact information (email and phone)`, tools: [processBookingTool], inputSchema: weatherQueryValidator, // Example of input validation outputSchema: weatherResponseValidator, // Example of output validation guardrails: [contentModerationGuardrail, rateLimitGuardrail] }); const sessionProvider = createInMemorySessionProvider(); const runnerConfig = createRunnerConfig(agent, sessionProvider, { guardrails: [contentModerationGuardrail, rateLimitGuardrail], maxLLMCalls: 5, timeout: 30000 }); return { agent, sessionProvider, runnerConfig }; }; // ========== Streaming with Monitoring Example ========== export const createStreamingAgent = () => { const storyTool = createFunctionTool({ name: 'generate_story_part', description: 'Generate part of a story', execute: (params) => { const { theme, character, setting } = params; const storyParts = [ `In the ${setting}, ${character} discovered something extraordinary about ${theme}.`, `The ${theme} seemed to pulse with an otherworldly energy as ${character} approached.`, `${character} realized that ${theme} held the key to understanding the mysteries of ${setting}.`, `As the sun set over ${setting}, ${character} made a decision that would change everything about ${theme}.`, `The adventure continued as ${character} ventured deeper into the secrets of ${theme} within ${setting}.` ]; return { part: storyParts[Math.floor(Math.random() * storyParts.length)], theme, character, setting, timestamp: new Date().toISOString() }; }, parameters: [ { name: 'theme', type: ToolParameterType.STRING, description: 'Story theme or topic', required: true }, { name: 'character', type: ToolParameterType.STRING, description: 'Main character name', required: true }, { name: 'setting', type: ToolParameterType.STRING, description: 'Story setting or location', required: true } ] }); const agent = createAgent({ name: 'streaming_storyteller', model: Model.GEMINI_2_0_FLASH, instruction: `You are an interactive storyteller. Create engaging stories using the generate_story_part tool. Build stories progressively, creating suspense and engaging narratives.`, tools: [storyTool] }); const sessionProvider = createInMemorySessionProvider(); const runnerConfig = createRunnerConfig(agent, sessionProvider); return { agent, sessionProvider, runnerConfig }; }; // ========== Example Usage Functions ========== export async function runSchemaValidationExample() { console.log('=== JAF ADK Layer - Schema Validation Example ===\n'); const { runnerConfig } = createBookingAgent(); // Test valid booking request console.log('1. Valid Booking Request:'); const validBookingMessage = createUserMessage(` I need to book a repair service for next week. My name is John Smith, I need a 3-hour repair on 2024-02-15. It's urgent. My email is john@example.com and phone is 555-0123. `); try { const response = await runAgent(runnerConfig, { userId: 'user_123', sessionId: 'booking_session_1' }, validBookingMessage); console.log('User:', validBookingMessage.parts[0].text); console.log('Agent:', response.content.parts[0].text); } catch (error) { console.log('Error:', error.message); } // Test invalid booking request (blocked by guardrail) console.log('\n2. Blocked Request (Guardrail):'); const blockedMessage = createUserMessage('This is spam content that should be blocked'); try { const response = await runAgent(runnerConfig, { userId: 'user_123', sessionId: 'booking_session_2' }, blockedMessage); console.log('User:', blockedMessage.parts[0].text); console.log('Agent:', response.content.parts[0].text); } catch (error) { console.log('Blocked by guardrail:', error.message); } } export async function runStreamingWithMonitoringExample() { console.log('\n=== JAF ADK Layer - Streaming with Monitoring Example ===\n'); const { runnerConfig } = createStreamingAgent(); const message = createUserMessage('Tell me a story about a brave knight named Arthur in a mystical forest'); console.log('User:', message.parts[0].text); console.log('Agent (streaming with monitoring):'); // Create monitoring const metrics = metricsMonitor(); const events = runAgentStream(runnerConfig, { userId: 'user_123', sessionId: 'streaming_session' }, message); // Add monitoring to the stream const monitoredStream = monitorStream(events, (event) => { metrics.monitor(event); // Log important events if (event.type === 'function_call_start') { console.log(`\n[FUNCTION CALL] ${event.functionCall?.name}`); } else if (event.type === 'function_call_complete') { console.log(`[FUNCTION COMPLETE] ${event.functionResponse?.name}`); } }); let messageContent = ''; for await (const event of monitoredStream) { if (event.type === 'message_delta' && event.content) { const text = event.content.parts[0].text || ''; messageContent += text; process.stdout.write(text); } else if (event.type === 'message_complete') { console.log('\n[Stream complete]'); break; } else if (event.type === 'error') { console.log('\n[Error]:', event.error); break; } } // Show metrics console.log('\nStream Metrics:', metrics.getMetrics()); } export async function runAdvancedStreamingExample() { console.log('\n=== JAF ADK Layer - Advanced Streaming Features ===\n'); // Create a live request queue const queue = createLiveRequestQueue(); // Simulate incoming messages setTimeout(async () => { await queue.enqueue(createUserMessage('Start the story')); await queue.enqueue(createUserMessage('Continue with action')); await queue.enqueue(createUserMessage('Add a plot twist')); queue.close(); }, 100); console.log('Processing queued messages:'); // Process messages from queue let isQueueActive = true; while (isQueueActive) { const message = await queue.dequeue(); if (!message) { await new Promise(resolve => setTimeout(resolve, 50)); continue; } console.log('Processing:', message.parts[0].text); if (queue.isEmpty()) { isQueueActive = false; break; } } console.log('Queue processing complete'); } export async function runLiveStreamingExample() { console.log('\n=== JAF ADK Layer - Live Streaming Simulation ===\n'); // Simulate a live streaming scenario async function* mockAgentStream() { const responses = [ 'Hello! I\'m ready to help you.', 'What would you like to know?', 'I can assist with various tasks.', 'Feel free to ask me anything!' ]; for (const response of responses) { // Simulate typing delay await new Promise(resolve => setTimeout(resolve, 500)); yield createAgentEvent('message_delta', { content: createUserMessage(response) }); } yield createAgentEvent('message_complete'); } console.log('Live streaming simulation:'); const stream = mockAgentStream(); for await (const event of stream) { if (event.type === 'message_delta' && event.content) { console.log('→', event.content.parts[0].text); } else if (event.type === 'message_complete') { console.log('[Stream ended]'); } } } // ========== Main Example Runner ========== export async function runAllAdvancedExamples() { try { await runSchemaValidationExample(); await runStreamingWithMonitoringExample(); await runAdvancedStreamingExample(); await runLiveStreamingExample(); console.log('\n=== All advanced examples completed successfully! ==='); } catch (error) { console.error('Advanced example failed:', error); } } // Run examples if this file is executed directly if (require.main === module) { runAllAdvancedExamples(); } //# sourceMappingURL=advanced-features.js.map