|
| 1 | +import { RECOMMENDED_PROMPT_PREFIX } from '@openai/agents-core/extensions'; |
| 2 | +import { RealtimeAgent, tool } from '@openai/agents/realtime'; |
| 3 | +import { z } from 'zod'; |
| 4 | + |
| 5 | +export const WELCOME_MESSAGE = |
| 6 | + 'Hello, this is ABC customer service. How can I help you today?'; |
| 7 | + |
| 8 | +const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); |
| 9 | + |
| 10 | +const faqLookupSchema = z.object({ |
| 11 | + question: z.string().describe('The caller question to search for.'), |
| 12 | +}); |
| 13 | + |
| 14 | +const faqLookupTool = tool({ |
| 15 | + name: 'faq_lookup_tool', |
| 16 | + description: 'Lookup frequently asked questions for the caller.', |
| 17 | + parameters: faqLookupSchema, |
| 18 | + execute: async ({ question }: z.infer<typeof faqLookupSchema>) => { |
| 19 | + await wait(1000); |
| 20 | + |
| 21 | + const normalized = question.toLowerCase(); |
| 22 | + if (normalized.includes('wi-fi') || normalized.includes('wifi')) { |
| 23 | + return 'We provide complimentary Wi-Fi. Join the ABC-Customer network.'; |
| 24 | + } |
| 25 | + if (normalized.includes('billing') || normalized.includes('invoice')) { |
| 26 | + return 'Your latest invoice is available in the ABC portal under Billing > History.'; |
| 27 | + } |
| 28 | + if (normalized.includes('hours') || normalized.includes('support')) { |
| 29 | + return 'Human support agents are available 24/7; transfer to the specialist if needed.'; |
| 30 | + } |
| 31 | + return "I'm not sure about that. Let me transfer you back to the triage agent."; |
| 32 | + }, |
| 33 | +}); |
| 34 | + |
| 35 | +const updateCustomerRecordSchema = z.object({ |
| 36 | + customerId: z |
| 37 | + .string() |
| 38 | + .describe('Unique identifier for the customer you are updating.'), |
| 39 | + note: z |
| 40 | + .string() |
| 41 | + .describe('Brief summary of the customer request to store in records.'), |
| 42 | +}); |
| 43 | + |
| 44 | +const updateCustomerRecord = tool({ |
| 45 | + name: 'update_customer_record', |
| 46 | + description: 'Record a short note about the caller.', |
| 47 | + parameters: updateCustomerRecordSchema, |
| 48 | + execute: async ({ |
| 49 | + customerId, |
| 50 | + note, |
| 51 | + }: z.infer<typeof updateCustomerRecordSchema>) => { |
| 52 | + await wait(1000); |
| 53 | + return `Recorded note for ${customerId}: ${note}`; |
| 54 | + }, |
| 55 | +}); |
| 56 | + |
| 57 | +const faqAgent = new RealtimeAgent({ |
| 58 | + name: 'FAQ Agent', |
| 59 | + handoffDescription: |
| 60 | + 'Handles frequently asked questions and general account inquiries.', |
| 61 | + instructions: `${RECOMMENDED_PROMPT_PREFIX} |
| 62 | +You are an FAQ specialist. Always rely on the faq_lookup_tool for answers and keep replies concise. If the caller needs hands-on help, transfer back to the triage agent.`, |
| 63 | + tools: [faqLookupTool], |
| 64 | +}); |
| 65 | + |
| 66 | +const recordsAgent = new RealtimeAgent({ |
| 67 | + name: 'Records Agent', |
| 68 | + handoffDescription: |
| 69 | + 'Updates customer records with brief notes and confirmation numbers.', |
| 70 | + instructions: `${RECOMMENDED_PROMPT_PREFIX} |
| 71 | +You handle structured updates. Confirm the customer's ID, capture their request in a short note, and use the update_customer_record tool. For anything outside data updates, return to the triage agent.`, |
| 72 | + tools: [updateCustomerRecord], |
| 73 | +}); |
| 74 | + |
| 75 | +const triageAgent = new RealtimeAgent({ |
| 76 | + name: 'Triage Agent', |
| 77 | + handoffDescription: |
| 78 | + 'Greets callers and routes them to the most appropriate specialist.', |
| 79 | + instructions: `${RECOMMENDED_PROMPT_PREFIX} |
| 80 | +Always begin the call by saying exactly '${WELCOME_MESSAGE}' before collecting details. Once the greeting is complete, gather context and hand off to the FAQ or Records agents when appropriate.`, |
| 81 | + handoffs: [faqAgent, recordsAgent], |
| 82 | +}); |
| 83 | + |
| 84 | +faqAgent.handoffs = [triageAgent, recordsAgent]; |
| 85 | +recordsAgent.handoffs = [triageAgent, faqAgent]; |
| 86 | + |
| 87 | +export function getStartingAgent(): RealtimeAgent { |
| 88 | + return triageAgent; |
| 89 | +} |
0 commit comments