## 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

```python
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,
)
```

| Parameter           | Type                             | Default | Description                                                                                                     |
|---------------------|----------------------------------|---------|-----------------------------------------------------------------------------------------------------------------|
| contact_full_name   | str                              | —       | The full name of the person you're trying to reach.                                                          |
| greeting            | str \| None                     | None    | Custom greeting message. Overrides the default introduction.                                                   |
| voicemail_message    | str \| None                     | None    | Message to leave if voicemail is reached. Mutually exclusive with voicemail_hangup and with set_voicemail_action(). |
| voicemail_hangup    | bool                             | False   | Immediately hang up if voicemail is reached. Mutually exclusive with voicemail_message and with set_voicemail_action(). |
| outcomes            | list[ReachPersonOutcome] \| None | None    | Custom outcome routing. Defaults to five outcomes: available, unavailable, voicemail, wrong_number, and do_not_contact. Use this to define additional or different outcomes. |

### Example

```python
@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`.

```python
# 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."),\
            ...\
        ])
```
