import { CodeTabs } from '../views/docs/CodeTabs';
import { Callout, NextLink, PropTable } from '../views/docs/prose';
export const REACH_PERSON_SIG_PY = `def reach_person(
    contact_full_name: str,
    *,
    greeting: str | None = None,
    outcomes: list[ReachPersonOutcome] | None = None,
)`;

export const REACH_PERSON_SIG_TS = `reachPerson(
  contactFullName: string,
  options?: {
    greeting?: string;
    outcomes?: ReachPersonOutcome[];
  },
): Promise<void>`;

export const REACH_PERSON_EX_PY = `@agent.on_call_start
def on_call_start(call: guava.Call):
    call.reach_person(
        contact_full_name=call.get_variable("contact_name"),
    )

@agent.on_reach_person
def on_reach_person(call: guava.Call, outcome: str):
    if outcome == "unavailable":
        call.hangup("Leave a brief voicemail asking them to call back.")
    elif outcome == "available":
        call.set_task(
            "main_task",
            checklist=[...],
        )`;

export const REACH_PERSON_EX_TS = `agent.onCallStart(async (call: guava.Call) => {
  await call.reachPerson(await call.getVariable("contactName"));
});

agent.onReachPerson(async (call: guava.Call, outcome: string) => {
  if (outcome === "unavailable") {
    await call.hangup("Leave a brief voicemail asking them to call back.");
  } else if (outcome === "available") {
    await call.setTask({ taskId: "main_task", checklist: [...] });
  }
})`;

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

<CodeTabs
  python={{ code: REACH_PERSON_SIG_PY, filename: "signature" }}
  typescript={{ code: REACH_PERSON_SIG_TS, filename: "signature" }}
/>

<PropTable rows={[
  {
    name: "contact_full_name",
    type: "str",
    desc: "The full name of the person you're trying to reach.",
  },
  {
    name: "greeting",
    type: "str | None",
    default: "None",
    desc: "Custom greeting message. Overrides the default introduction.",
  },
  {
    name: "outcomes",
    type: "list[ReachPersonOutcome] | None",
    default: "None",
    desc: "Custom outcome routing. Defaults to a binary available/unavailable split. Use this to define additional outcomes (e.g. callback requested, wrong number, DNC).",
  },
]} />

<CodeTabs
  python={{ code: REACH_PERSON_EX_PY, filename: "example.py" }}
  typescript={{ code: REACH_PERSON_EX_TS, filename: "example.ts" }}
/>



### 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 (`"available"`, `"unavailable"`, or a custom outcome if you provided `outcomes`).

### Common mistake: redundant introductions

<Callout>
  <span className="text-primary font-semibold">Warning:</span> 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`.
</Callout>

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

<NextLink section="set-voicemail-action" label="set_voicemail_action()" />
