Build Your OmniagentTools

Creating Tools

Define a tool — its fields, execution flow, and the prompt that controls when it fires

Tools extend what your agent can do during a session. You define what each tool does, what parameters it accepts, and whether the tool call is delivered to your client (implicit) or to your server (explicit).

Tools are reusable. Create a tool once, then attach it to as many agents as you need.

Creating a custom tool

Create a tool via POST /public/functions:

curl -X POST https://companion-api.napster.com/public/functions \
  -H "X-Api-Key: $NAPSTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "name": "get_order_status",
      "description": "Look up the current status of a customer order by order ID",
      "parameters": {
        "type": "object",
        "properties": {
          "order_id": {
            "type": "string",
            "description": "The unique order identifier"
          }
        },
        "required": ["order_id"]
      }
    },
    "flow": "explicit",
    "url": "https://your-api.example.com/tools/get-order-status",
    "headers": {
      "x-api-key": "your-internal-api-key"
    },
    "receiveMessages": false,
    "prompt": "Use this tool when the user asks about the status of their order."
  }'

The response returns the created tool with its ID, which you use to attach it to agents. For the full request and response schema, see the API reference:

Field reference

FieldRequiredDescription
data.nameYesThe function name the model calls. Use snake_case.
data.descriptionYesWhat the tool does. The model reads this to decide relevance.
data.parametersYesJSON Schema for the arguments (type, properties, required).
flowYes"implicit" (delivered to your client) or "explicit" (delivered to your server). See execution flows.
urlExplicit onlyThe HTTP or WebSocket endpoint that receives the call. A wss:// URL keeps a connection open for the whole session — see Executing Tools.
headersNoCustom headers sent with explicit calls — authentication, routing.
receiveMessagesNoWebSocket tools only. Stream the live conversation to your endpoint. Default false.
connectionBehaviorNoWebSocket tools only. Whether the session waits for your server's socket at start (waitBeforeStart) and whether it survives a failed connection (abortOnFailure). Both default false — see Connection behavior.
promptNo (but important)Controls when and how the agent calls the tool. See below.

Writing effective tool prompts

The prompt field on a tool definition is the most important lever you have for controlling when and how the agent calls a tool. At runtime, the contents of prompt are injected into the system instruction alongside the tool's function declaration:

## tool_name(param1, param2)
[contents of the prompt field]

The tool name and parameters are generated automatically from your tool definition. The prompt field is your space to control everything else — when the tool fires, when it doesn't, and what the agent says (or doesn't say) to the user.

Structure of a good prompt

Every prompt should cover three things:

  1. When to use the tool — what user intent or conversation state should trigger it.
  2. When NOT to use the tool — what situations look similar but should not trigger it.
  3. How to behave when calling it — should the agent announce it, ask for confirmation, or call it silently?

A well-written prompt:

Use when the user asks to book, reserve, or schedule a table.
Do NOT use when the user is asking about menu items, hours, or general restaurant info.
Before calling, confirm the reservation details (name, date, time, party size) with the user and wait for explicit confirmation.

A poorly-written prompt:

Books a restaurant reservation.

The second version gives the agent no guidance on invocation timing, edge cases, or user interaction. It will misfire.

Invocation conditions

Write explicit positive and negative conditions using "Use when" and "Do NOT use when" to control when the agent reaches for a tool.

Positive conditions describe the user intent that should trigger the tool. Be specific — use concrete language the user might say:

  • Good: Use when the user asks to book, reserve, or schedule a table.
  • Bad: Use when relevant.

Negative conditions describe situations that look similar but should not trigger the tool. These matter more than most developers expect — models often call tools when the intent is close but not quite right:

  • Good: Do NOT use when the user is asking about menu items, restaurant hours, or general info.
  • Bad: (omitted entirely)

Sequencing conditions control the order in which tools fire. Use "only after" to require a prerequisite and "only if" to add conditional logic:

  • Only call after the user has provided their name, date, and time.
  • Only call if check_availability was called first and returned available slots.
  • After calling this tool, you can call confirm_booking or cancel_booking.

This prevents the agent from calling tools out of order or with missing information. If a tool requires parameters the user hasn't provided yet, instruct the agent to ask for them first.

"prompt": "Use when the user wants to book an appointment. Before calling, make sure the user has provided a preferred date, time, and service type — ask for any missing details. Only call after all three are confirmed. Do NOT use for cancellations."

Behavior patterns

You control what the agent says to the user around a tool call through the prompt field. There are three patterns, and you can mix them across tools in the same session.

Proactive (silent)

The agent calls the tool without announcing it or asking permission.

Best for read-only or low-stakes operations: looking up context, logging events, enriching data, tagging conversations. As a rule of thumb, if the tool only reads data and has no side effects, proactive is a safe default.

{
  "data": {
    "name": "log_mood",
    "description": "Logs the user's current mood for session analytics"
  },
  "prompt": "Call automatically whenever the user expresses a clear emotion (happy, frustrated, anxious, etc.). Do not announce it to the user. Do NOT call when the user is asking a factual question without emotional content.",
  "flow": "explicit",
  "url": "https://your-api.example.com/tools/log-mood"
}

Preamble (brief acknowledgment)

The agent says a short bridging phrase before or during the tool call so the user doesn't hear silence. This is the recommended default for most tools.

{
  "data": {
    "name": "check_order_status",
    "description": "Looks up the status of a customer order by order ID"
  },
  "prompt": "Use when the user asks about their order, delivery, or shipment status. Before calling, briefly let the user know you're looking it up (e.g., 'Let me check that for you'). Do NOT use when the user is asking about products, pricing, or returns.",
  "flow": "explicit",
  "url": "https://your-api.example.com/tools/order-status"
}

If you want a specific phrase instead of letting the agent generate one:

"prompt": "Use when the user asks about their order status. Before calling, say: 'One moment while I pull up your order.' Do NOT use for returns or cancellations."

Keep bridging phrases neutral — they should not imply success or failure before the tool has returned. Good examples: "Let me check that," "One moment," "Let me look into that." Bad examples: "Great news, let me confirm that," "I found your order, one second."

You can also guide what the agent says after the tool returns. This helps the agent transition naturally back into the conversation:

"prompt": "Use when the user asks about their order. Before calling, say 'Let me check on that.' After receiving the result, start with a brief opener like 'Here's what I found' and then share the details."

Confirmation (ask first)

The agent describes what it's about to do and waits for the user to say yes before calling the tool.

Best for write operations and high-stakes actions: anything that costs money, sends a message, makes a booking, changes account settings, or can't be easily undone. As a rule of thumb, if the tool changes state or has side effects, require confirmation.

{
  "data": {
    "name": "book_appointment",
    "description": "Books an appointment for the user"
  },
  "prompt": "Use when the user wants to schedule an appointment. Before calling, describe the appointment details (date, time) to the user and wait for explicit confirmation before proceeding. Do NOT call without confirmation. Do NOT use for cancellations or rescheduling.",
  "flow": "explicit",
  "url": "https://your-api.example.com/tools/book-appointment"
}

Mixing patterns across tools

A single session can include tools with different behavior patterns. Control the behavior per tool through each tool's prompt field:

get_weather (proactive)
→ "Call automatically when the user mentions weather, outdoor plans, or travel. Do not announce it."

search_products (preamble)
→ "Use when the user asks about products or wants recommendations. Before calling, say something like 'Let me find that for you.' Do NOT use for order status or returns."

process_payment (confirmation)
→ "Use when the user is ready to pay. Before calling, confirm the total amount and payment method with the user. Do NOT call without explicit confirmation. Do NOT use for refunds."

Voice-specific considerations

Tool calls in voice conversations behave differently than in text chat. Keep these in mind when writing prompts:

  • Silence is bad. In text, the user sees a loading indicator. In voice, they hear nothing — and assume the agent froze. If a tool takes more than a moment, use the preamble pattern so the user knows something is happening.
  • Fewer tools is better. Each tool adds tokens to the system instruction. More tools also increases the chance the agent calls the wrong one. Keep the set focused.
  • Keep prompts short. Every token in prompt counts against the instruction budget. Use short, direct sentences. Avoid paragraphs.
  • Don't duplicate the description. The description field already tells the agent what the tool does. Use prompt for when, when not, and how — not to repeat the description.

If prompt is left empty, the agent relies entirely on the tool's description to decide when to call it. This works for simple tools but gives you no control over invocation timing, negative conditions, or call behavior.

Managing custom tools

You can list, update, and delete your custom tools through the API:

Next steps

On this page