Custom AI tools and function calling
Registering your own functions for the Aimogen Pro chatbot and agents to call, with a complete worked example.
Beyond the built-in extensions, you can register your own tools. The AI then decides when to call them and supplies the arguments.
The plugin ships a working example at examples/function_call.php.
The two hooks#
aiomatic_ai_functions registers the tool, so the model knows it exists.
aiomatic_ai_reply_raw receives the raw provider response, where you detect a call to your tool and
execute it.
A complete example#
Registering a tool that emails the site administrator:
add_filter( 'aiomatic_ai_functions', function ( $query, $god_extensions = false ) {
$functions = is_array( $query ) ? $query : array();
$functions['functions'][] = array(
'type' => 'function',
'function' => new Aiomatic_Query_Function(
'send_email',
'Send an email to the administrator of this website',
array(
new Aiomatic_Query_Parameter( 'subject', 'The subject of the email', 'string', true ),
new Aiomatic_Query_Parameter( 'message', 'The message of the email', 'string', true ),
),
false
),
);
// Optional: the text shown while the tool runs.
$functions['message'] = 'Sure, I just sent an email to admin, they will respond soon.';
return $functions;
}, 999, 2 );Then handle the call:
add_filter( 'aiomatic_ai_reply_raw', function ( $reply, $query ) {
if ( empty( $reply->tool_calls ) ) {
return $reply;
}
foreach ( $reply->tool_calls as $tool_call ) {
if ( ! isset( $tool_call->type ) || $tool_call->type !== 'function' ) {
continue;
}
if ( isset( $tool_call->function->arguments ) && is_string( $tool_call->function->arguments ) ) {
$tool_call->function->arguments = json_decode( $tool_call->function->arguments );
}
if ( $tool_call->function->name !== 'send_email' ) {
continue;
}
$subject = sanitize_text_field( $tool_call->function->arguments->subject );
$message = wp_kses_post( $tool_call->function->arguments->message );
wp_mail( get_option( 'admin_email' ), $subject, $message );
// Optionally set the text the AI appears to reply with.
if ( ! isset( $reply->choices ) ) {
$reply->choices = array();
$reply->choices[0] = new stdClass();
}
$reply->choices[0]->text = 'Email sent.';
$reply->choices[0]->message->content = 'Email sent.';
}
return $reply;
}, 10, 2 );The classes#
Aiomatic_Query_Function( $name, $description, $parameters, $required ) and
Aiomatic_Query_Parameter( $name, $description, $type, $required ).
The description is not documentation — it is the instruction to the model. It is how the model decides whether to call your tool. Be specific about when it should and should not be used:
new Aiomatic_Query_Function(
'check_order_status',
'Look up the current status of a customer order by its order number. ' .
'Use this only when the visitor gives an order number. ' .
'Do not use it to look up products, and do not guess an order number.',
array( new Aiomatic_Query_Parameter( 'order_number', 'The order number, digits only', 'string', true ) ),
false
);Requirements#
A function-calling model. See Selecting models.
Tool calling enabled for the placement. The preview, global and per-shortcode switches are separate. See Chatbot Extensions.
Responses API toggles off, if tools do not fire. Several beta implementations do not support them.
Related filters#
| Filter | Purpose |
|---|---|
aiomatic_ai_functions | Register tools |
aiomatic_post_ai_functions | The tool list after built-ins are added |
aiomatic_ai_reply_raw | The raw response, for handling calls |
aiomatic_ai_responses_reply_raw | The same, for the Responses API path |
aiomatic_google_tools_ai_reply_raw | The same, for the Google path |
aiomatic_function_result | The tool result before it goes back to the model |
Actions: aiomatic_tool_result and aiomatic_tool_direct_message.
Security#
A defensive tool:
$order_number = preg_replace( '/[^0-9]/', '', (string) $args->order_number );
if ( $order_number === '' || strlen( $order_number ) > 12 ) {
return 'Invalid order number.';
}
$order = my_get_order( (int) $order_number );
if ( ! $order ) {
return 'No order found with that number.';
}
// Return only what the visitor is entitled to see.
return sprintf( 'Order %d is currently %s.', $order->id, $order->status );Note the last line: return the minimum. Everything a tool returns goes into the model context and may be repeated to the visitor.
MCP as an alternative#
If your tool would be useful to more than this plugin, consider exposing it as an MCP server instead. Aimogen Pro can connect to it, and so can any other MCP-capable client.
Related#
Still stuck? Open a support ticket and include the diagnostics from Aimogen Pro › System & Logs › System Info.