> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.vapi.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.vapi.ai/_mcp/server.

# Dynamic tool messages

> Configure bot_say for Function and Handoff tools so an assistant speaks a context-aware message before execution and handles multiple tool calls correctly.

`bot_say` is a reserved tool-call argument that lets the model generate a context-aware message in the same response that calls a tool. Vapi speaks the message before the tool runs, without making an additional model request.

When `bot_say` is a non-empty string, Vapi trims and speaks it before the tool runs. Vapi waits for the message to finish, the caller cannot interrupt it, and Vapi removes the property from the tool-call arguments before execution.

> **Note**
>
> Define `bot_say` inside `function.parameters`. It is not a top-level tool
> field, so it does not appear as a named field in the [Create Tool API reference](/api-reference/tools/create).

## Supported tools

| Tool     | Add `bot_say` to                 | Configuration note                                                    |
| -------- | -------------------------------- | --------------------------------------------------------------------- |
| Function | `function.parameters.properties` | Add it to the tool's existing JSON Schema.                            |
| Handoff  | `function.parameters.properties` | Preserve the generated `destination` property and its required entry. |

## Configure `bot_say`

#### Add bot\_say to the tool schema

Add a `bot_say` property with `type` set to `string` inside
`function.parameters.properties`. Include `bot_say` in
`function.parameters.required` so the schema requires the model to provide
it.

Add the property to the existing schema without removing other properties
or required entries.

#### Describe what the assistant should say

Use the property's `description` to specify the message's purpose, tone,
length, language, and script rules. Ask for a non-empty value without
trailing punctuation.

#### Suppress the static start message

For a tool that normally plays a static or default `request-start` message,
add one `request-start` entry with an empty `content` value. Replace any
existing `request-start` entries, but keep entries for other message types.

The empty entry prevents a second acknowledgment. Without it, Vapi can
select a default filler message. If you configure a non-empty static start
message, the caller can hear both the dynamic and static messages.

#### Update the assistant prompt

Tell the model to populate `bot_say` whenever it calls the tool and not to
speak a separate acknowledgment.

```text
Whenever you call lookup_order, set bot_say to one brief acknowledgment in
the caller's current language. Do not speak a separate acknowledgment.
```

## Function tool example

```json
{
  "type": "function",
  "function": {
    "name": "lookup_order",
    "description": "Look up an order by its ID",
    "parameters": {
      "type": "object",
      "properties": {
        "order_id": {
          "type": "string",
          "description": "The order ID to look up"
        },
        "bot_say": {
          "type": "string",
          "description": "One brief acknowledgment before the lookup, in the caller's current language. No trailing punctuation."
        }
      },
      "required": ["order_id", "bot_say"]
    }
  },
  "server": {
    "url": "https://example.com/vapi/tools"
  },
  "messages": [
    {
      "type": "request-start",
      "content": ""
    }
  ]
}
```

## Behavior and limits

* Vapi trims leading and trailing whitespace from a non-empty `bot_say` value before speaking it.
* An empty or whitespace-only value is neither spoken nor removed, so it remains in the tool-call arguments.
* If several tools are called in the same turn, Vapi joins their non-empty values with `. ` and speaks one combined message.
* If `bot_say` is missing, Vapi does not speak a dynamic tool message.

## Verify the behavior

Make a test call that triggers the Function tool, then inspect the request received by your server. Confirm that:

* The assistant finishes the dynamic message before the request arrives.
* The caller cannot interrupt the message.
* The caller hears no second start message.
* The received tool-call arguments contain `order_id` but not `bot_say`.

## Related

* [Function tools](/tools/custom-tools)
* [Handoff arguments](/squads/passing-data-between-assistants#approach-1-handoff-arguments)
* [Static variables and aliases](/tools/static-variables-and-aliases) for server-controlled values the model does not generate.