# Duty Schedule — Voice Agent Tools

This reference covers the three duty schedule tools available to voice agents. All tools are enabled per campaign in the campaign's Tools tab and are available for both voice and other agent modalities (`allowedModalities: ['all']`).

---

## duty-check

Look up who is currently on duty. Use this when you need to tell the caller who to expect a call from, or to decide whether to escalate.

### When to use

- Caller asks "who is on call right now?"
- Agent needs to personalize the call (e.g. "I'll connect you with Jane who's on duty today")
- Agent needs to decide whether to escalate based on whether anyone is available

### Parameters

None required. The tool takes no input.

```json
{}
```

### Response

```json
{
  "success": true,
  "onDuty": [
    {
      "name": "Jane Doe",
      "email": "jane@example.com",
      "phone": "+15551234567"
    }
  ],
  "schedules": [ /* full schedule objects */ ],
  "primary": { /* first/highest-priority schedule object */ },
  "usingDefault": false
}
```

| Field | Description |
|-------|-------------|
| `onDuty` | Array of all currently on-duty personnel. May contain multiple people if schedules overlap. Ordered by priority (lowest number first). |
| `primary` | The highest-priority schedule record. Use this when you only need one contact. |
| `usingDefault` | `true` if no one is scheduled and the response is falling back to the configured default contact. |
| `onDuty[]` (when `usingDefault: true`) | Contains the default contact's name, email, and phone from settings. |

**Empty case:** When no one is on duty and no default is configured, `onDuty` is an empty array. Handle this gracefully — tell the caller no one is available and offer to leave a message or try again later.

### Example LLM prompt guidance

```
When the caller asks who is on call, use duty-check to get the current on-duty person.
If onDuty is empty, tell the caller no one is currently available and offer to take a message.
If usingDefault is true, let the caller know they'll be reached by the backup contact.
```

---

## duty-notify

Send an urgent notification to the person currently on duty. This is fire-and-forget — the agent does not track whether the notification was acknowledged.

### When to use

- Caller needs to reach on-call staff but confirmation is not required
- Simpler workflows where tracking delivery is sufficient
- When `confirmation` is disabled in Duty Schedule settings

### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `subject` | string | Yes | Short subject line for the notification (used as email subject) |
| `message` | string | Yes | Full notification body. Be clear and concise. |
| `priority` | string | No | `low`, `normal`, `high`, or `urgent`. Defaults to `normal`. |

```json
{
  "subject": "Urgent: HVAC system alarm at Building A",
  "message": "The caller reports that the HVAC system in Building A is showing a fault alarm and the temperature is rising. Please investigate immediately.",
  "priority": "high"
}
```

### Response

```json
{
  "success": true,
  "message": "Notification sent to 2 on-duty personnel",
  "notifications": [
    {
      "name": "Jane Doe",
      "email": "jane@example.com",
      "method": "email",
      "sent": true
    }
  ]
}
```

**Note:** The notification is sent via email and SMS (if the on-duty person has a phone number). The agent should tell the caller the notification has been sent and that someone will follow up, without making promises about response time.

---

## duty-notify-confirm

Send a notification and require the on-duty person to confirm via SMS before the request is considered handled. The system escalates automatically to the next available person if no confirmation is received within the configured timeout.

**This is an asynchronous background process.** The agent fires the notification and immediately continues or ends the call. Confirmation tracking, escalation, and fail behavior all happen in the background via the tick processor.

### When to use

- Situations that require a guaranteed response (e.g. emergency maintenance, critical system failures)
- When your organization needs an audit trail of who acknowledged an alert
- When you have multiple on-call staff and want the system to escalate automatically

### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `subject` | string | Yes | Short subject line (used in the SMS and email) |
| `message` | string | Yes | Full description of what needs attention |
| `priority` | string | No | `low`, `normal`, `high`, or `urgent`. Defaults to `normal`. |
| `specialty` | string | No | Requested skill/role (e.g. `"HVAC"`, `"Electrical"`, `"Network Security"`). When provided and the selection rule is `specialty_then_priority`, personnel with this specialty are contacted first. |

```json
{
  "subject": "Urgent: Boiler failure at Main Campus",
  "message": "A caller reports a complete boiler failure at the main campus. No heat in the building. Needs immediate attention.",
  "priority": "urgent",
  "specialty": "HVAC"
}
```

### Response

```json
{
  "success": true,
  "notificationId": "64f3a2b1c9e0d1234567890a",
  "status": "pending_confirmation",
  "notifiedPerson": "Mike Torres",
  "message": "Duty notification sent to Mike Torres. Awaiting confirmation."
}
```

| Field | Description |
|-------|-------------|
| `notificationId` | ID of the created DutyNotification record. Visible in the Notifications tab. |
| `status` | `pending_confirmation` (normal start), `failed` (no one on duty — fail behavior already applied) |
| `notifiedPerson` | Name of the first person contacted |
| `message` | Human-readable summary of what happened |

**What the agent should say to the caller:**

> "I've sent an urgent notification to our on-call technician. They'll receive an SMS shortly and are expected to respond within [timeout] minutes. If they're unavailable, our system will automatically reach the next available person."

Do not promise that someone has already responded. Do not say you will monitor progress. The confirmation happens entirely in the background after the call.

### Confirmation SMS flow

The on-duty person receives an SMS formatted as:

```
[DUTY ALERT - URGENT]
Subject: Boiler failure at Main Campus
A caller reports a complete boiler failure at the main campus...
Reply YES to confirm you're handling this, or NO to pass.
```

The system accepts natural confirmation language: YES, Y, CONFIRM, OK, ON IT, ACK, and variants are treated as confirmed. NO, N, PASS, DECLINE are treated as declined. Ambiguous replies are evaluated by the AI to determine intent.

### Escalation behavior

When someone declines or doesn't reply within the timeout:

1. Their attempt is recorded with outcome `timed_out` or `declined`
2. The next person in the queue receives the same SMS
3. This continues until someone confirms or the queue is exhausted
4. Queue ordering follows the configured selection rule:
   - `priority` — all on-duty personnel sorted by priority (lowest number first)
   - `specialty_then_priority` — personnel matching the requested specialty are placed first, then everyone else by priority

### Fail behavior

When the queue is exhausted without a confirmation, the configured fail behavior runs:

| Setting | What happens |
|---------|-------------|
| `log_only` | The notification is marked `resolved` with `failBehaviorTriggered: true`. No further action. |
| `notify_default` | The default contact from settings receives an escalation SMS |
| `notify_fallback` | A custom fallback contact receives an escalation SMS |

---

## Configuration Required for duty-notify-confirm

Before using `duty-notify-confirm`, configure the following in Duty Schedule → Settings (Confirmation Settings card):

| Setting | Description |
|---------|-------------|
| Enable confirmation | Must be turned on for the confirmation flow to run |
| Twilio From Number | The phone number confirmation SMS are sent from. Staff replies to this number are intercepted and routed to the confirmation handler automatically. |
| Timeout (minutes) | How long each person has to reply before escalation. Default: 20 minutes. |
| Selection rule | How to order the queue when multiple people are on duty |
| Fail behavior | What happens when no one confirms |

---

## Enabling Tools on a Campaign

1. Go to your campaign in Voice Agents → (select campaign) → Tools tab
2. Enable the duty tools you want the agent to use:
   - `duty-check` — query who is on duty
   - `duty-notify` — send a basic notification
   - `duty-notify-confirm` — send with confirmation tracking
3. Save the campaign

The agent will have access to the enabled tools on every call for that campaign.

---

## Notification Log

All `duty-notify-confirm` dispatches are logged in Duty Schedule → Notifications. Each record shows:

- When the notification was created
- Subject, message, priority, and requested specialty
- Current status (pending, confirmed, escalating, failed, resolved)
- Who confirmed (if anyone)
- How many attempts were made vs. how many people were in the queue

---

## Prompt Engineering Tips

### Deciding between duty-notify and duty-notify-confirm

```
Use duty-notify for standard alerts where you just need to reach someone.
Use duty-notify-confirm when the situation is critical and you need to guarantee a response is tracked.
```

### Passing specialty context

The agent should extract the relevant skill from the caller's description and pass it as the `specialty` parameter. For example:

- "The HVAC unit is down" → `specialty: "HVAC"`
- "We have a network outage" → `specialty: "Network Security"` or `"IT Support"`
- "There's an electrical fault" → `specialty: "Electrical"`

The specialty name should match one of the names configured in Duty Schedule → Specialties. Partial matches are not supported — the name must match exactly (case-insensitive).

### Checking before notifying

For critical situations, consider calling `duty-check` first to confirm someone is actually available before using `duty-notify-confirm`. If `onDuty` is empty, you can tell the caller upfront that no one is scheduled and the notification will go to the default contact instead of creating a false expectation.
