- Answer product questions, return policies, shipping info, and warranty questions in real time using a knowledge base
- Collect customer details and create an Amazon Connect task for cases that need specialist follow-up
- Transfer the caller back to a live Connect agent queue for sensitive escalations (complaints, legal, “I want to speak to a human”)
How It Works
Prerequisites
- Python 3.10 or later
- A Guava account with an API key and a phone number — sign up at app.goguava.ai
- An AWS account with an Amazon Connect instance
Step 1: Install Guava
Choose whichever package manager you prefer:boto3 for the Amazon Connect task API:
Step 2: Set Up Amazon Connect
2a. Create or locate your Connect instance
- Open the Amazon Connect console.
- Create an instance if you don’t have one, or select an existing one.
- Note the Instance ID — it’s the UUID at the end of the instance ARN:
2b. Create a task contact flow
Riley creates Amazon Connect tasks for cases requiring follow-up. Tasks need a dedicated contact flow — the default queue flow doesn’t support them.- In your Connect instance, go to Routing → Contact flows → Create contact flow.
- Name it
Guava Task Flow(or similar). - Add a Set working queue block and point it to your support queue.
- Connect it to a Transfer to queue block, then a Disconnect block.
- Save and publish the flow.
- Open the flow, click Show additional flow information, and copy the Contact flow ID (UUID at the end of the ARN).
2c. Note your support queue phone number
This is the number Riley will transfer escalations to — your live agent queue’s direct dial number in Amazon Connect.- Go to Routing → Phone numbers in your Connect instance.
- Use any number claimed to your instance that routes to your support queue, or claim a new one.
- Copy the number in E.164 format (e.g.,
+15551234567).
2d. Create the contact flow that routes to Riley
This is the contact flow your customers actually call into. It transfers them to Riley’s Guava number.- Go to Routing → Contact flows → Create contact flow (type: Inbound contact flow).
- Name it
AI Customer Service. - Build the flow:
- Add a Play prompt block: set the text to a brief hold message (or skip it).
- Add a Transfer to phone number block:
- Set Phone number to your Guava agent number (the value of
GUAVA_AGENT_NUMBER). - Set Transfer type to
Softphone transferorPSTN.
- Set Phone number to your Guava agent number (the value of
- Add a Disconnect block on the error branch.
- Save and publish the flow.
- Assign this flow to an inbound phone number: go to Channels → Phone numbers, select a number, and set its contact flow to
AI Customer Service.
Adding routing logic: If you want Connect to handle an IVR before routing to Riley, add a Get customer input block before the transfer. You can route product questions to Guava and billing escalations to a human queue based on the customer’s menu selection.
Step 3: Configure AWS Credentials
Step 4: Set Environment Variables
Step 5: Run Riley
AI Customer Service flow to in Step 2d) — Connect will transfer the call to Riley automatically.
How the Code Works
Defining the agent
Agent is a top-level handle for your AI persona. You attach behavior to it with decorators (@agent.on_call_start, @agent.on_question, @agent.on_task_complete(...)) — each decorator registers a handler that runs when the corresponding event fires on a live call.
Accepting inbound calls
listen_phone opens a persistent WebSocket to the Guava server and waits for calls. Each time a call arrives on Riley’s number — whether from a customer dialing directly or transferred from Amazon Connect — the agent’s registered handlers run on a fresh Call object that represents that conversation.
Kicking off the conversation
on_call_start runs as soon as the call connects. We use it to set the first task — a named intake step the agent works through, greeting the caller and collecting the fields we need before deciding what to do next.
Answering questions with a knowledge base
on_question with the question in natural language. DocumentQA retrieves the most relevant chunks from SUPPORT_DOCS and generates an accurate answer. Riley speaks the answer back and continues the conversation without any perceivable delay.
DocumentQA() with no store argument runs in server mode — your documents are uploaded to the Guava server and searched there. The namespace parameter scopes the uploaded documents to this agent so they don’t collide with documents from other DocumentQA instances in the same account.
Routing after the conversation
intake task finishes collecting details, the registered @agent.on_task_complete("intake") handler classifies the outcome using IntentRecognizer and routes accordingly. Using an LLM-based classifier handles natural phrasing correctly — “the zipper broke on the first use” maps to follow_up_task even without explicitly matching “broken”. The recognizer is instantiated once at module level and reused across calls.
Transferring back to Amazon Connect
call.transfer gives Riley natural language guidance on what to say before transferring — she’ll let the customer know what’s happening and transfer when it feels right in the conversation. The customer lands in the Connect support queue as a normal inbound call, which agents handle in the Contact Control Panel (CCP).
Creating a Connect task for follow-up
follow_up). The @agent.on_task_complete("follow_up") handler then creates a task in Amazon Connect via StartTaskContact. Agents see it in the CCP like any other contact — with the customer’s name, issue summary, and email for follow-up.
Customization Ideas
Use your own knowledge base ReplaceSUPPORT_DOCS with your actual product documentation, policy pages, or FAQs. DocumentQA handles chunking and retrieval automatically — paste in as much text as you need.
Add IVR routing in Connect before transferring
Instead of routing all calls to Riley, add a Get customer input block in your Connect flow. Route product questions to Riley’s number and billing escalations to a human queue. Riley only handles the calls she’s best suited for.
Pass context from Connect to Riley via SIP
For more advanced setups, Amazon Connect can transfer calls over a SIP trunk to a Guava SIP endpoint. This lets Connect pass the original Contact ID and other attributes as SIP headers, which the agent can read from the call info. You can then link Riley’s Connect task back to the original call using PreviousContactId for full call chain reporting.
Route different inquiry types to different agents
Run multiple Guava agents on different agent numbers — one for product support, one for returns, one for technical help. Have Connect’s IVR route to the right one based on the customer’s menu selection.
Use call info to customize behavior per call
The @agent.on_call_received decorator lets you inspect the inbound CallInfo (caller number, SIP headers, etc.) before the call is accepted. Use this to accept or decline calls, or to set per-call variables in on_call_start that change Riley’s behavior — for example, routing region-specific callers to region-specific transfer numbers.