reach_person()

For outbound calls, reach_person() handles the critical first step: confirming you have the right person on the line before proceeding. It automatically handles answering machines, gatekeepers, wrong numbers, and refusals.

signature
def reach_person(
    contact_full_name: str,
    *,
    greeting: str | None = None,
    voicemail_message: str | None = None,
    voicemail_hangup: bool = False,
    outcomes: list[ReachPersonOutcome] | None = None,
)
ParameterTypeDefaultDescription
contact_full_namestrThe full name of the person you're trying to reach.
greetingstr | NoneNoneCustom greeting message. Overrides the default introduction.
voicemail_messagestr | NoneNoneMessage to leave if voicemail is reached. Mutually exclusive with voicemail_hangup and with set_voicemail_action().
voicemail_hangupboolFalseImmediately hang up if voicemail is reached. Mutually exclusive with voicemail_message and with set_voicemail_action().
outcomeslist[ReachPersonOutcome] | NoneNoneCustom outcome routing. Defaults to five outcomes: available, unavailable, voicemail, wrong_number, and do_not_contact. Use this to define additional or different outcomes.
example.py
@agent.on_call_start
def on_call_start(call: guava.Call):
    call.reach_person(
        contact_full_name=call.get_variable("contact_name"),
        voicemail_message="Please give us a call back at your convenience."
    )

@agent.on_reach_person
def on_reach_person(call: guava.Call, outcome: str):
    if outcome == "available":
        call.set_task(
            "main_task",
            checklist=[...],
        )
    else:
        call.hangup("Appropriately end the call.")

What happens on the call

When reach_person() is invoked, the agent automatically:

  1. Greets whoever answers and introduces itself (organization + purpose).

  2. Asks for the contact by name. If someone else answered, asks to speak with or be transferred to the contact.

  3. Determines availability and records the contact's availability in a contact_availability field.

  4. Fires agent.on_reach_person with the outcome key. The five default outcomes are:

    • "available" — the intended contact is on the line.
    • "unavailable" — someone else or an IVR answered and the contact could not be reached.
    • "voicemail" — an answering machine or voicemail system was reached.
    • "wrong_number" — the number does not belong to the contact.
    • "do_not_contact" — the contact asked not to be called again.

    If you provided custom outcomes, those are used instead.

Voicemail handling

Warning: reach_person() and set_voicemail_action() both handle voicemail and cannot be used together. If you set voicemail_message or voicemail_hangup on reach_person(), do not call set_voicemail_action() — and vice versa. Using both raises an error.

Common mistake: redundant introductions

Warning: By the time on_reach_person fires, the agent has already introduced itself and stated the purpose of the call. Do not re-introduce in the first task after reach_person.

# WRONG — redundant introduction
@agent.on_reach_person
def on_reach_person(call: guava.Call, outcome: str):
    if outcome == "available":
        call.set_task("survey", checklist=[
            guava.Say("Hi, this is Grace from Acme Corp, I'm calling about..."),  # Already said this
            ...
        ])

# RIGHT — go straight to content
@agent.on_reach_person
def on_reach_person(call: guava.Call, outcome: str):
    if outcome == "available":
        call.set_task("survey", checklist=[
            guava.Say("I just have a few quick questions for you today."),
            ...
        ])

Questions? hi@goguava.ai