Custom tool integration

Custom tools extend the NAF's built-in action set with your own webhook integrations. When the ConvoAgent explicitly commits to an action during a conversation, the Tool Caller detects the commitment and fires the corresponding tool — including custom ones you define. Custom tools use the same detection and execution pipeline as built-in tools.

When to use custom tools

Use custom tools when you need the ConvoAgent to trigger an action in an external system — for example:

  • Submitting a service request or quote to a CRM
  • Looking up a customer's account status or order history
  • Creating a support ticket in a helpdesk system
  • Sending lead data to a marketing platform

Custom tools are implemented as webhooks: when the tool fires, the platform sends an HTTP request to a URL you specify, with data extracted from the conversation.

How custom tools work

Custom tools follow the same pipeline as built-in tools:

  1. The ConvoAgent generates a response containing a phrase that satisfies the tool's conditions
  2. The Tool Caller evaluates the response against the tool's conditions using an LLM
  3. If all conditions are met, the platform executes the tool's action (fires the webhook)
  4. Any after_actions run on the response

The Tool Caller applies the same strict exclusion rules to custom tools as to built-in ones — the tool will not fire if the agent is making an offer ("I can send you..."), describing a future step, or if the user (not the agent) is the grammatical subject.

Defining a custom tool

Custom tools are defined in the project_attributes_settings_newo_tools project attribute as a JSON object. Each key in the tools object is a tool name; each value is the tool definition.

Tool definition schema

{
  "tools": {
    "your_tool_name": {
      "description": "Plain-text description of what this tool does.",
      "conditions": {
        "condition_name": {
          "type": "boolean",
          "description": "Natural language condition that the LLM evaluates against the conversation."
        }
      },
      "useConversationHistory": false,
      "action": {
        "type": "send_webhook",
        "options": {
          "url": "https://your-endpoint.example.com/action",
          "method": "POST",
          "headers": {
            "Content-Type": "application/json"
          },
          "body": {
            "type": "object",
            "properties": {
              "field_name": {
                "type": "string",
                "description": "Description of what to extract from the conversation for this field."
              }
            }
          }
        }
      },
      "after_actions": []
    }
  }
}

Schema fields

FieldRequiredDescription
descriptionYesPlain-text description of the tool's purpose.
conditionsYesOne or more named boolean conditions. All conditions must evaluate to true for the tool to fire.
useConversationHistoryYesWhen true, the full conversation history is analyzed. When false, only the latest agent message is analyzed. Use false for faster evaluation when conversation history isn't needed.
action.typeYesThe execution method: send_webhook, send_event, or send_urgent_message.
after_actionsNoOptional list of actions to run after the main action completes.

Action types

send_webhook

Sends an HTTP request to an external URL. The platform extracts the fields specified in body.properties (and optionally query) from the conversation using an LLM, based on each property's description.

"action": {
  "type": "send_webhook",
  "options": {
    "url": "https://api.example.com/submit",
    "method": "POST",
    "headers": {
      "Authorization": "Bearer your-static-token",
      "Content-Type": "application/json"
    },
    "body": {
      "type": "object",
      "properties": {
        "customer_name": {
          "type": "string",
          "description": "The customer's full name from the conversation"
        },
        "service_requested": {
          "type": "string",
          "description": "The specific service the customer asked about"
        }
      }
    },
    "query": {
      "type": "object",
      "properties": {
        "source": {
          "type": "string",
          "description": "Always set to 'newo-agent'"
        }
      }
    }
  }
}

The body.properties and query.properties fields are populated by extracting matching values from the conversation. Write clear descriptions so the LLM knows exactly what to extract for each field.

send_event

Fires a system event to a flow on the agent. Use this when the tool should trigger an existing flow rather than an external HTTP request.

"action": {
  "type": "send_event",
  "options": {}
}

The event IDN is the tool's key name in the tools object.

send_urgent_message

Sends an urgent message into the ConvoAgent's prompt. Typically used as an after_action rather than a primary action type.

Conditions

Conditions determine when the tool fires. Each condition is evaluated by an LLM against the conversation context. All conditions must evaluate to true for the tool to execute.

Write conditions as clear, observable statements about what the ConvoAgent has said:

"conditions": {
  "agentPromised": {
    "type": "boolean",
    "description": "The agent explicitly states they are going to submit a quote right now. Phrases like: 'I'm submitting your quote now...', 'Let me send that quote over...', 'I will submit your service request now...'"
  },
  "serviceIdentified": {
    "type": "boolean",
    "description": "The user has named a specific service they're interested in at some point during the conversation."
  }
}

Tips for writing effective conditions:

  • Match conditions to the exact phrasing of the CRITICAL STEP code-phrase in the scenario
  • For the primary trigger condition, the name agentPromised is conventional and recommended
  • Use useConversationHistory: true only when a condition requires context from earlier in the conversation (e.g., verifying the user confirmed a value several turns ago)
  • Add a second condition to prevent false positives — for example, ensuring the user has provided a required piece of information before the tool fires

After actions

after_actions run after the primary action completes. The most common use is injecting the webhook response back into the ConvoAgent's prompt.

send_urgent_message (after action)

Injects the webhook response into the conversation as an urgent message. This lets the ConvoAgent relay the result to the user (e.g., confirming a quote ID or reporting a submission status).

"after_actions": [
  {
    "type": "send_urgent_message",
    "options": {
      "prefix": "Quote submission result"
    }
  }
]

The prefix labels the injected content so the ConvoAgent understands what it's reading.

Worked example

Here is a complete custom tool that submits a service quote when the ConvoAgent commits to it:

{
  "tools": {
    "submit_quote_tool": {
      "description": "Submit a service quote request to the CRM when the agent commits to sending one.",
      "conditions": {
        "agentPromised": {
          "type": "boolean",
          "description": "The agent clearly states they are going to submit or send a quote right now. Phrases like: 'I'm submitting your quote now...', 'Let me send that quote over...', 'I will submit your service request now...'"
        }
      },
      "useConversationHistory": false,
      "action": {
        "type": "send_webhook",
        "options": {
          "url": "https://crm.example.com/api/quotes",
          "method": "POST",
          "headers": {
            "Authorization": "Bearer your-api-token",
            "Content-Type": "application/json"
          },
          "body": {
            "type": "object",
            "properties": {
              "customer_name": {
                "type": "string",
                "description": "The customer's full name"
              },
              "customer_phone": {
                "type": "string",
                "description": "The customer's phone number"
              },
              "service_type": {
                "type": "string",
                "description": "The type of service the customer requested"
              },
              "notes": {
                "type": "string",
                "description": "Any additional details mentioned during the conversation"
              }
            }
          }
        }
      },
      "after_actions": [
        {
          "type": "send_urgent_message",
          "options": {
            "prefix": "Quote submission result"
          }
        }
      ]
    }
  }
}

Corresponding scenario CRITICAL STEP:

### **Step 2.5:** **CRITICAL STEP!!!** Say the special **code-phrase**:
**"I'm submitting your quote request now and will have someone follow up with you shortly."**

When the ConvoAgent says this phrase, the Tool Caller detects agentPromised is true and fires submit_quote_tool. The platform extracts customer_name, customer_phone, service_type, and notes from the conversation and sends them to the configured URL. The webhook response is then injected back into the ConvoAgent's prompt via send_urgent_message.

Conflict policies

If your custom tool could conflict with a built-in tool (for example, a custom SMS-sending tool conflicting with send_sms_tool), you can assign a conflict tag:

"conflictPolicy": {
  "tag": "sms"
}

Tools sharing the same tag are mutually exclusive per turn. When multiple tools with the same tag are selected, the Tool Caller uses an LLM to rank them and execute only the most relevant one.

See also

  • The Supervisor and Tool Caller system — How tools are compiled, conditions are evaluated, conflicts are resolved, and actions are executed
  • Tools reference — Complete reference for all 12 built-in NAF tools, including their conditions and conflict policies

Changelog

Custom tool integration: initial publication

Published partner developer guide for extending the NAF with custom webhook integrations: tool definition schema, action types (send_webhook, send_event, send_urgent_message), conditions format, after_actions, conflict policies, and a worked end-to-end example.