Skip to content

Comments

healthcare agent example#4606

Open
tinalenguyen wants to merge 28 commits intomainfrom
tina/healthcare-agent-example
Open

healthcare agent example#4606
tinalenguyen wants to merge 28 commits intomainfrom
tina/healthcare-agent-example

Conversation

@tinalenguyen
Copy link
Member

@tinalenguyen tinalenguyen commented Jan 23, 2026

Summary by CodeRabbit

  • New Features
    • Added a healthcare agent example with voice-based interaction capabilities
    • Supports insurance information collection from patients
    • Enables appointment scheduling with doctor selection and confirmation
    • Includes patient information gathering workflow (name, date of birth, email, insurance)

✏️ Tip: You can customize this high-level summary in your review settings.


Open with Devin

@chenghao-mou chenghao-mou requested a review from a team January 23, 2026 22:42
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 23, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review
📝 Walkthrough

Walkthrough

A new healthcare agent workflow module is introduced featuring data structures for insurance and appointment results, task implementations for collecting insurance and scheduling appointments, and a core HealthcareAgent with information gathering, appointment scheduling, and server integration capabilities.

Changes

Cohort / File(s) Summary
Data Structures
examples/healthcare/healthcare_agent.py
Introduces GetInsuranceResult with insurance field and ScheduleAppointmentResult with doctor_name, appointment_time, and visit_reason fields
Task Implementations
examples/healthcare/healthcare_agent.py
Implements GetInsuranceTask with insurance collection via record_health_insurance tool; implements ScheduleAppointmentTask with doctor confirmation, visit reason validation, and appointment scheduling with error handling for required fields
Agent and Server Setup
examples/healthcare/healthcare_agent.py
Adds HealthcareAgent class with information gathering factory, appointment scheduling, and records update methods; creates AgentServer instance and RTC-wrapped entrypoint for real-time session management with STT/LLM/TTS/VAD backends

Sequence Diagram

sequenceDiagram
    participant Client as RTCClient
    participant Agent as HealthcareAgent
    participant InfoTG as TaskGroup<br/>(Information)
    participant GetInsTask as GetInsuranceTask
    participant SchAppTask as ScheduleAppointmentTask
    
    Client->>Agent: Start Session
    Agent->>Agent: on_enter() - gather reason for call
    Client->>Agent: schedule_appointment()
    Agent->>InfoTG: build information TaskGroup
    InfoTG->>GetInsTask: collect insurance info
    GetInsTask->>Client: prompt for insurance
    Client->>GetInsTask: record_health_insurance()
    GetInsTask->>InfoTG: complete with GetInsuranceResult
    InfoTG->>SchAppTask: begin appointment scheduling
    SchAppTask->>Client: confirm doctor selection
    Client->>SchAppTask: confirm_doctor_selection()
    SchAppTask->>Client: confirm visit reason
    Client->>SchAppTask: confirm_visit_reason()
    SchAppTask->>Client: schedule appointment
    Client->>SchAppTask: schedule_appointment(time)
    SchAppTask->>SchAppTask: validate required fields
    SchAppTask->>InfoTG: complete with ScheduleAppointmentResult
    InfoTG->>Agent: information gathering complete
    Agent->>Client: return completion message
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A hopping healthcare workflow hops into place,
Insurance and doctors in time-saving grace,
Task by task we gather the care,
Scheduling appointments with rabbit-like flair! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: introducing a new healthcare agent example module with multiple task implementations and data structures.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tina/healthcare-agent-example

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@tinalenguyen tinalenguyen marked this pull request as draft January 23, 2026 22:43
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@examples/healthcare/healthcare_agent.py`:
- Around line 145-146: The variable results assigned from awaiting task_group is
unused and triggers ruff F841; either remove the binding or use the
value—replace "results = await task_group" with just "await task_group" to avoid
the unused variable, or if you intend to persist task outputs, iterate the
returned results and load them into the DB (e.g., process/insert each item) so
the results from task_group are consumed; apply the same change for the other
occurrence where results is assigned.
- Around line 72-76: The tool handler stubs never store the user's choices, so
implement the handlers (e.g., the `@function_tool` methods
confirm_doctor_selection and the corresponding confirm_visit_reason handler) to
set the agent's state fields _selected_doctor and _visit_reason respectively
from their arguments, persist any needed normalized values, and return a short
confirmation string; update any downstream call in on_enter or schedule flow to
read these fields so scheduling can proceed.
- Around line 78-88: schedule_appointment currently passes the appointment_time
string into ScheduleAppointmentResult which expects a datetime; parse and
validate the incoming appointment_time string into a datetime before calling
self.complete. In schedule_appointment, use a safe parser (e.g.,
datetime.fromisoformat or a robust parser) to convert appointment_time to a
datetime, catch parsing exceptions and call self.session.generate_reply with a
clear error message if parsing fails, and only construct
ScheduleAppointmentResult with the parsed datetime
(doctor_name=self._selected_doctor, appointment_time=<parsed_datetime>,
visit_reason=self._visit_reason) when validation succeeds.
- Around line 96-101: The instructions string in HealthcareAgent tells the model
to call EndCallTool but EndCallTool is not imported or registered; either remove
the "call EndCallTool" phrase from the instructions or register the tool by
importing EndCallTool and passing it in the Agent's tools parameter (uncomment
and wire the existing tools=[EndCallTool(...)] line), ensuring the tools list
includes the EndCallTool instance and any required end_instructions so the model
can actually invoke it; update HealthcareAgent.__init__ accordingly and keep the
"schedule_appointment" instruction if that tool is handled separately.
- Around line 69-70: Replace the Python 3.10-only union annotations with
typing.Optional for compatibility: import Optional from typing at the top of the
module, and change the attributes self._selected_doctor: str | None and
self._visit_reason: str | None to use Optional[str] (i.e.,
self._selected_doctor: Optional[str] and self._visit_reason: Optional[str]);
ensure the import is added only if not already present.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7fe642d and e1f6935.

📒 Files selected for processing (1)
  • examples/healthcare/healthcare_agent.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Format code with ruff
Run ruff linter and auto-fix issues
Run mypy type checker in strict mode
Maintain line length of 100 characters maximum
Ensure Python 3.9+ compatibility
Use Google-style docstrings

Files:

  • examples/healthcare/healthcare_agent.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: livekit/agents PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-16T07:44:49.987Z
Learning: Follow the guidelines and standards defined in AGENTS.md
🧬 Code graph analysis (1)
examples/healthcare/healthcare_agent.py (3)
livekit-agents/livekit/agents/voice/agent.py (4)
  • Agent (34-642)
  • AgentTask (648-813)
  • instructions (99-104)
  • complete (687-706)
livekit-agents/livekit/agents/beta/workflows/email_address.py (1)
  • GetEmailTask (27-130)
livekit-agents/livekit/agents/beta/workflows/task_group.py (1)
  • TaskGroup (39-155)
🪛 GitHub Check: ruff
examples/healthcare/healthcare_agent.py

[failure] 159-159: Ruff (F841)
examples/healthcare/healthcare_agent.py:159:9: F841 Local variable results is assigned to but never used


[failure] 145-145: Ruff (F841)
examples/healthcare/healthcare_agent.py:145:9: F841 Local variable results is assigned to but never used

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: type-check (3.13)
  • GitHub Check: type-check (3.9)
  • GitHub Check: livekit-plugins-cartesia
  • GitHub Check: livekit-plugins-deepgram
  • GitHub Check: unit-tests

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@tinalenguyen tinalenguyen marked this pull request as ready for review February 2, 2026 07:08
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 4 potential issues.

View issues and 5 additional flags in Devin Review.

Open in Devin Review

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 4 new potential issues.

View issues and 8 additional flags in Devin Review.

Open in Devin Review

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 new potential issues.

View 7 additional findings in Devin Review.

Open in Devin Review

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 7 additional findings in Devin Review.

Open in Devin Review

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

View 8 additional findings in Devin Review.

Open in Devin Review

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 new potential issues.

View 13 additional findings in Devin Review.

Open in Devin Review

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 18 additional findings in Devin Review.

Open in Devin Review

@tinalenguyen tinalenguyen changed the title [draft] healthcare agent example healthcare agent example Feb 12, 2026
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 new potential issues.

View 17 additional findings in Devin Review.

Open in Devin Review

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

View 19 additional findings in Devin Review.

Open in Devin Review

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

View 21 additional findings in Devin Review.

Open in Devin Review

Comment on lines +127 to +131
if len(str(card_number)) < 13 or len(str(card_number)) > 19:
self.session.generate_reply(
instructions="The length of the card number is invalid, ask the user to repeat their card number."
)
return None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Negative card number passes length check and crashes Luhn validation

In GetCardNumberTask.update_card_number, the length validation at line 127 uses len(str(card_number)). For a negative integer (e.g., -1234567890123), str() includes the minus sign in the length ("-1234567890123" has length 14), so the check < 13 or > 19 can pass. The negative number is then stored and passed to validate_card_number, where str(card_number)[::-1] reverses to "3210987654321-". When iterating and calling int(digit) on the '-' character at credit_card.py:198, an unhandled ValueError is raised.

Root Cause

The length check len(str(card_number)) at line 127 counts the minus sign as part of the length, so a negative integer with 13+ digits (plus sign) passes validation. The Luhn algorithm at credit_card.py:185-200 then crashes because int('-') raises ValueError.

Impact: An unhandled ValueError exception propagates from the tool function, causing a tool execution failure rather than a graceful error message to the user.

Suggested change
if len(str(card_number)) < 13 or len(str(card_number)) > 19:
self.session.generate_reply(
instructions="The length of the card number is invalid, ask the user to repeat their card number."
)
return None
if card_number < 0 or len(str(card_number)) < 13 or len(str(card_number)) > 19:
self.session.generate_reply(
instructions="The length of the card number is invalid, ask the user to repeat their card number."
)
return None
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@theomonnom theomonnom self-requested a review February 12, 2026 23:39
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 21 additional findings in Devin Review.

Open in Devin Review

Comment on lines +491 to +493
if self._found_profile:
self._database.update_patient_record(patient_name, **profile)
self.session.userdata.profile = self._database.get_patient_by_name(patient_name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 NOT_GIVEN sentinel is truthy, causing if self._found_profile: to always take the update path for new patients

At line 491, the code uses if self._found_profile: to decide whether to update an existing patient record or add a new one. However, self._found_profile is initialized as NOT_GIVEN (a NotGiven instance) at healthcare_agent.py:400, and is only ever set to True (at line 418) when an existing record is found. It is never set to False.

For new patients (no existing record), _found_profile remains NOT_GIVEN. Since NotGiven is a plain class without a __bool__ override, Python treats all its instances as truthy by default. This means if self._found_profile: evaluates to True even for new patients.

Root Cause and Impact

When a new patient goes through profile_authenticator, the code incorrectly enters the update branch:

if self._found_profile:  # NOT_GIVEN is truthy → True!
    self._database.update_patient_record(patient_name, **profile)  # returns False, patient doesn't exist
    self.session.userdata.profile = self._database.get_patient_by_name(patient_name)  # returns None

update_patient_record silently fails (returns False, not checked), and get_patient_by_name returns None for the non-existent patient. This sets self.session.userdata.profile = None, causing subsequent operations (e.g., self.session.userdata.profile["name"]) to crash with a TypeError.

Notably, the rest of the code correctly uses is_given(self._found_profile) for the same variable (at lines 463 and 470), making this inconsistency a clear oversight.

Impact: New patients can never be registered. The profile is set to None, and all downstream operations that access profile fields will crash.

Suggested change
if self._found_profile:
self._database.update_patient_record(patient_name, **profile)
self.session.userdata.profile = self._database.get_patient_by_name(patient_name)
if is_given(self._found_profile) and self._found_profile:
self._database.update_patient_record(patient_name, **profile)
self.session.userdata.profile = self._database.get_patient_by_name(patient_name)
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@theomonnom
Copy link
Member

Can we use a different TTS? Deepgram doesn’t sound very good

@theomonnom
Copy link
Member

theomonnom commented Feb 19, 2026

nit: small prompt tweaks:

Human: Yeah. Can I schedule an appointment?

Agent: Of course! Before we proceed, may I have your full name, please? Please say your first and last name (for example: "Sarah Johnson"). If you need to spell it or use special characters, go ahead and say it however you prefer.

I don't think the agent should be that verbose

EDIT:

Same for phone numbers

Agent: Thank you. May I have your phone number, please? You can say it however you like, for example: "five five five, one two three, four five six seven," or any other way that’s comfortable for you.

@theomonnom
Copy link
Member

Human: It's still
Agent: I understand; just to clarify, is your first name "Still"? If that's correct, could you please provide your last name as well? If not, please repeat your first and last name clearly.
Theo: No. It's t o mono.
Agent: Thank you. I have "Tomo" as your first name. Could you please provide your last name? If you need to spell it, please say each letter one by one.
Agent:  It's Theo Mono.
Theo: Thank you. Just to confirm, I have your name as Tomo Mono. Is that correct?

Can we improve the prompt engineering there?
I think sometimes it's too obvious the agent got the name wrong

@theomonnom
Copy link
Member

The way the agent is saying available time slots is very unnatural IMO

Great, you’ve selected Dr. Edward Hyde.

Dr. Hyde has the following available time slots:
- February 19, 2026 at 10:00 AM
- February 21, 2026 at 2:30 PM
- February 23, 2026 at 3:45 PM

Which time works best for you?

Comment on lines +244 to +246
await self.session.generate_reply(
instructions=f"The selected doctor has availabilities at {available_times}. Ask the user which time slot they prefer."
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a more reliable way to communicate critical information like the available times.

If the user interrupts or if the agent gets interrupted by background noise—the agent can lose context and may no longer be able to retrieve the available times.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about injecting the context with the available times before generating speech?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants