> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zavu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How agents work

> From TypeScript on your machine to an agent answering a phone call

An agent on Zavu is one object that answers on every channel. The same prompt,
model, knowledge base and skills serve a WhatsApp message and a phone call.

There are two ways to get one, and they produce the same thing:

* **In code** — declare it with `defineAgent` in a Zavu Function and deploy.
  The code is the source of truth.
* **In the dashboard or over the API** — create and configure it directly.

This page follows the code-first path end to end, because it is the one with
moving parts you cannot see.

## The pieces

```mermaid theme={null}
flowchart LR
    subgraph you["Your machine"]
        src["index.ts<br/>defineAgent + defineTool"]
    end
    subgraph cloud["Zavu Cloud"]
        bw["Build Worker<br/>bundles your code"]
        fn["Your Function<br/>an isolated runtime"]
        rec["Reconciler<br/>reads what you declared"]
        agent[("Agent<br/>prompt · model · tools")]
    end
    src -->|zavu deploy| bw
    bw -->|publishes| fn
    rec -->|asks it what it declares| fn
    rec -->|creates / updates| agent
```

Two things live in Zavu Cloud that are easy to conflate:

* **Your Function** is your TypeScript, running in its own isolated runtime. It
  holds your tool handlers — the code that talks to your systems.
* **The Agent** is the configuration a conversation runs against: the prompt,
  the model, which channels trigger it, its knowledge bases, and pointers to
  your tools.

`zavu deploy` publishes the first and derives the second from it.

## What a deploy actually does

```mermaid theme={null}
sequenceDiagram
    participant Dev as You
    participant CLI as zavu CLI
    participant BW as Build Worker
    participant Fn as Your Function
    participant Rec as Reconciler

    Dev->>CLI: zavu deploy
    CLI->>BW: source + dependencies
    BW->>BW: bundle (your runtime stays external)
    BW->>Fn: publish
    Rec->>Fn: "what do you declare?"
    Fn-->>Rec: manifest — agents + tools
    Rec->>Rec: create, update, delete to match
    Rec-->>CLI: summary + warnings
    CLI-->>Dev: ✓ Deployed
```

The step worth understanding is the **manifest**. After publishing, Zavu asks
your function what it declared, and reconciles reality to match it. That is what
makes the code the source of truth:

* A `defineAgent` you added becomes a new agent.
* A field you changed is updated.
* A `defineAgent` you **deleted** deletes the agent.

<Warning>
  Read the lines **above** the ✓. `zavu deploy` prints warnings before the success
  line, and exits non-zero when your declarations were not synced at all. They
  cover the cases where a green deploy did not do what it looks like — tools
  attached to an agent whose channels will never call them, or a second agent
  landing on a sender that already has one.
</Warning>

## A message arrives

```mermaid theme={null}
sequenceDiagram
    participant User as Customer
    participant Ch as WhatsApp / SMS / …
    participant Zavu as Zavu
    participant Agent as Your agent
    participant KB as Knowledge base

    User->>Ch: "where is order ORD-1?"
    Ch->>Zavu: inbound message
    Zavu->>Zavu: does an agent answer on this sender?
    Zavu->>KB: retrieve relevant chunks
    KB-->>Zavu: context
    Zavu->>Agent: prompt + history + context
    Agent-->>Zavu: reply
    Zavu->>Ch: send
    Ch-->>User: reply
```

## A call arrives

Voice adds speech in and out around the same agent, and one important
difference: **on a call the model is offered your tools.**

```mermaid theme={null}
sequenceDiagram
    participant Caller
    participant Tel as Telephony
    participant VP as Voice pipeline
    participant Agent as Your agent
    participant Fn as Your Function

    Caller->>Tel: dials your number
    Tel->>VP: call connected
    VP-->>Caller: greeting
    Caller->>VP: speaks
    VP->>VP: speech → text
    VP->>Agent: transcript
    Agent->>Fn: check_availability(…)
    Fn-->>Agent: { ok: true, slots: [...] }
    Agent-->>VP: reply
    VP->>VP: text → speech
    VP-->>Caller: spoken answer
```

The caller can interrupt while the agent is speaking (barge-in) and the agent
stops to listen. It can also transfer to a human, or end the call.

## Where tools run

This is the single most common surprise, so it is worth stating plainly.

| Channel                                   | Are tools offered to the model? |
| ----------------------------------------- | ------------------------------- |
| **Voice**                                 | Yes                             |
| A flow's `tool` step                      | Yes                             |
| **Text** (WhatsApp, SMS, Telegram, email) | **No**                          |

A text agent with tools attached does not refuse — it answers *"let me check
that, one moment"* and then does nothing, which is the worst outcome on a
messaging channel. Use a [flow](/guides/ai-agents/flows) with a `tool` step when
a text agent needs to reach your backend.

`zavu agents test` warns you whenever an agent has tools its channels will never
call.

## What you can verify, and when

Most of the loop is free and instant. The last step is not.

```mermaid theme={null}
flowchart TD
    A["Write index.ts"] --> B["tsc — types resolve locally"]
    B --> C["zavu fn invoke --tool<br/>runs one handler, no deploy"]
    C --> D["zavu deploy"]
    D --> E["zavu agents list<br/>confirm what landed"]
    E --> F["zavu agents test<br/>the agent's reply, nothing sent"]
    F --> G["A real message, or a real call"]
    G -.->|costs money| G
```

| Step                   | Cost   | What it proves                                           |
| ---------------------- | ------ | -------------------------------------------------------- |
| `tsc`                  | free   | Your code is valid against the runtime's types           |
| `fn invoke --tool`     | free   | A handler does what you think, in isolation              |
| `agents list`          | free   | The deploy created what you meant                        |
| `agents test`          | free   | The prompt, model and retrieval produce the right answer |
| A real message or call | billed | Everything else, including tool calling on voice         |

<Note>
  `agents test` runs the **text** path. It exercises the prompt, the model and the
  knowledge base, and it reports what it could not prove — a disabled agent, tools
  its channels will not call, flows it did not evaluate. Treat those warnings as
  part of the result.
</Note>

## Agents and senders

A **sender** is the identity a conversation happens on: a phone number, a
WhatsApp account, an email address.

```mermaid theme={null}
flowchart LR
    A["Agent"] --- S1["Sender<br/>+1 415 555 0100"]
    A --- S2["Sender<br/>support@acme.com"]
    A --- S3["Sender<br/>WhatsApp"]
```

An agent can answer on several senders. **A sender answers with at most one
agent** — connecting one that is already in use is rejected, naming the agent
that holds it.

```bash theme={null}
zavu agents list
zavu agents senders connect --agent <agentId> --sender <senderId>
```

An agent can also exist with no sender at all while you build it. It will not
receive anything until you connect one and enable it.

## Where to go next

<CardGroup cols={2}>
  <Card title="Functions quickstart" icon="rocket" href="/guides/functions/quickstart">
    Write and deploy your first agent in code.
  </Card>

  <Card title="Factory agents" icon="wand-magic-sparkles" href="/guides/functions/factory-agents">
    Start from a production agent instead of a blank file.
  </Card>

  <Card title="Voice agents" icon="phone" href="/guides/voice-agents/overview">
    Answer and place phone calls.
  </Card>

  <Card title="Agent setup" icon="sliders" href="/guides/ai-agents/setup">
    Create and configure an agent without writing code.
  </Card>
</CardGroup>
