Hooks

Agent

36 hooks fired by Agent: 30 filters and 6 actions across 36 call sites.

36 hooks fired by Agent: 30 filters and 6 actions across 36 call sites. 36 of the 36 call sites are described by a docblock, at the call or on the constant that names the hook; the rest are listed with their signature and call sites only. Paths are relative to the plugin directory.

http_request_host_is_external

Filter · 3 arguments · 1 call site

Filters whether a host whose address is private or reserved may be read all the same.

WordPress's own filter, applied with its own arguments, so a host a site lets wp_safe_remote_get() reach is one the agent's pinned requests reach too.

apply_filters( 'http_request_host_is_external', false, $host, $url )
  • $external (bool) — Whether the host counts as outside this network. Default false.
  • $host (string) — The host.
  • $url (string) — The address.

Fired from:

  • packages/Agent/Site/WebPage.php:266

xpac_agent_activity_logged

Action · 2 arguments · 1 call site

Fires once a tool call the agent ran is in the activity log for good.

For a site that keeps its own audit trail, or sends one elsewhere: the entry is what the log keeps, with what the call was asked summarised and its secrets and visitor data left out, never the call's own arguments or answer.

do_action( 'xpac_agent_activity_logged', $id, $entry )
  • $id (int) — The row's id.
  • $entry (array<string, mixed>) — The row, as Activity\Log::find() reads it.

Fired from:

  • packages/Agent/Activity/Log.php:171

xpac_agent_activity_pruned

Action · 2 arguments · 1 call site

Fires once the daily prune of the activity log has run.

Whether or not it removed anything, and only when the site keeps a limited number of days. The rows are gone by now; a site that wants to archive them reads them before, on xpac_agent_activity_logged as each is written.

do_action( 'xpac_agent_activity_pruned', $deleted, $days )
  • $deleted (int) — Rows removed.
  • $days (int) — Days the site keeps.

Fired from:

  • packages/Agent/Activity/Retention.php:103

xpac_agent_activity_record

Filter · 3 arguments · 1 call site

Filters whether the activity log records calls to a tool.

By default every tool that can change the site is recorded, and one its catalog entry or its ability's annotations call read-only is not. Answering true for a read-only tool records its calls too, such as a tool that reads form submissions on a site that wants to know who looked; false leaves a tool out.

apply_filters( 'xpac_agent_activity_record', $record, $name, $channel )
  • $record (bool) — Whether calls to it are recorded.
  • $name (string) — The full ability name.
  • $channel (string) — chat for the admin chat, mcp for an AI app on the MCP server.

Fired from:

  • packages/Agent/Activity/Recorder.php:141

xpac_agent_activity_retention_days

Filter · 1 argument · 1 call site

Filters how many days of AI activity the log keeps.

Read by the daily prune and shown on the Activity screen. Zero or less keeps everything.

apply_filters( 'xpac_agent_activity_retention_days', self::DEFAULT_DAYS )
  • $days (int) — Days to keep. Default 90.

Fired from:

  • packages/Agent/Activity/Retention.php:72

xpac_agent_activity_summary

Filter · 3 arguments · 1 call site

Filters what the activity log keeps of a tool call's input.

The default is built by rules that know nothing about the tool, see Activity\Summary. A plugin that knows which of its tool's arguments are safe to show, or which short ones are personal data, answers for its own tool and passes the others through. Whatever it answers is kept only up to 2 KB of JSON, past which only its keys are.

apply_filters( 'xpac_agent_activity_summary', $summary, $tool, $args )
  • $summary (array<string, mixed>) — What the rules kept.
  • $tool (string) — The full ability name, such as xpac-forms/connect-form.
  • $args (mixed) — The input the tool got, with nulls taken out. Never stored as it is.

Fired from:

  • packages/Agent/Activity/Summary.php:130

xpac_agent_call_finished

Action · 3 arguments · 1 call site

Fires once a tool call the agent ran has ended.

Only for a call whose ability started, so never for one whose input or permission was refused. succeeded in the frame says whether the ability came back without an error; the answer may still be an error the channel made of it, such as a result too large to keep. A throw is caught per hook, not per listener: it is logged and the listeners after it do not run, so a listener catches its own errors.

do_action( 'xpac_agent_call_finished', $frame, $result, $ms )
  • $frame (array<string, mixed>) — The call's frame, see Calls.
  • $result (mixed) — The answer as it is handed on.
  • $ms (int) — How long the call ran, in milliseconds.

Fired from:

  • packages/Agent/Tools/Calls.php:181

xpac_agent_call_result

Filter · 2 arguments · 1 call site

Filters what a tool call the agent ran answers.

Applied once per call that started, from the chat and over MCP, to the answer as that channel hands it on: in the chat after a throw was replaced by a fixed sentence and a result too large to keep was cut down, over MCP after the adapter's own filters. So what is added here reaches the model or the client as it is. A throw is caught per hook, not per listener: it is logged, the listeners after it do not run, and the answer is kept as it was before this filter, without what earlier listeners added. So a listener catches its own errors.

apply_filters( 'xpac_agent_call_result', $result, $frame )
  • $result (mixed) — The answer: an array, or a WP_Error over MCP.
  • $frame (array<string, mixed>) — The call's frame, see Calls.

Fired from:

  • packages/Agent/Tools/Calls.php:159

xpac_agent_call_started

Action · 2 arguments · 1 call site

Fires when the ability of a tool call the agent runs starts.

After its input passed the schema and the permission check, so $input is what the tool really got. A throw is caught per hook, not per listener: it is logged, the listeners after it do not run, and the call runs all the same.

do_action( 'xpac_agent_call_started', self::$frame, $input )
  • $frame (array<string, mixed>) — The call's frame, see Calls.
  • $input (mixed) — The ability's normalized input.

Fired from:

  • packages/Agent/Tools/Calls.php:246

xpac_agent_changed

Action · 4 arguments · 1 call site

Fires when an agent's tool call changed something Agent does not record by itself.

Here the site settings update-site-settings wrote: each option as it was, null for one that was not there, and the active theme's custom_logo mod beside the logo. Agent's own xpac-wp/options handler (Undo\Options) puts exactly those back.

do_action( 'xpac_agent_changed', Options::HANDLER, Options::OBJECT, $replaced, Options::label() )
  • $handler (string) — xpac-wp/options.
  • $object (string) — options:site.
  • $before (array) — {options: {name: value|null}, theme_mods: {name: value|null}}.
  • $label (string) — "Site settings".

Fired from:

  • packages/Agent/Site/Settings.php:166

xpac_agent_conversation_deleted

Action · 2 arguments · 1 call site

Fires once a conversation is deleted, still under its lock.

For whatever is kept beside a conversation and means nothing without it, such as what its tool calls changed, to go with it.

do_action( 'xpac_agent_conversation_deleted', (int) $row['id'], (int) $row['user_id'] )
  • $id (int) — The conversation that was deleted.
  • $userId (int) — The administrator it belonged to.

Fired from:

  • packages/Agent/Chat/Agent.php:215

xpac_agent_fold_results

Filter · 1 argument · 1 call site

Filters whether stale tool results are left out of what the model is sent.

apply_filters( 'xpac_agent_fold_results', true )
  • $fold (bool) — Default true.

Fired from:

  • packages/Agent/Chat/Agent.php:1397

xpac_agent_generate_image_capability

Filter · 1 argument · 1 call site

Filters the capability a user needs to make an image with generate-image.

The provider bills every image to the site, and over MCP no call waits for an administrator's Allow, so the default is the capability of the people who connect providers and use the chat. A site that trusts its editors with the bill answers with a capability they have. upload_files is needed all the same.

apply_filters( 'xpac_agent_generate_image_capability', 'manage_options' )
  • $capability (string) — Default manage_options.

Fired from:

  • packages/Agent/Site/ImageGeneration.php:78

xpac_agent_image_model

Filter · 1 argument · 1 call site

Filters the model generate-image makes images with.

Null lets the AI client pick one of the connected providers' image models, in the order xpac_agent_image_model_preference prefers. A model handed over here is used as it is, as long as it says it can make the image the way it is asked for, and it keeps the config it came with: the AI client leaves each call's config on the model, where the next call would start from it, so a square image after a landscape one would come out landscape.

apply_filters( 'xpac_agent_image_model', null )
  • $model (ModelInterface|null) — Default null.

Fired from:

  • packages/Agent/Site/ImageGeneration.php:191

xpac_agent_image_model_preference

Filter · 1 argument · 1 call site

Filters the image models generate-image prefers, in order.

Anything using_model_preference() takes: model ids, model instances, or [provider id, model id] pairs. The first one a connected provider offers for the image asked for is used, and when none is, the AI client picks as it would with no preference. An entry that is none of these is left out (Models::usable()).

apply_filters( 'xpac_agent_image_model_preference', Models::imagePreference() )
  • $preference (array<int, mixed>) — Default: the newest image model of each connected provider, as [provider id, model id] pairs, see Models::imagePreference().

Fired from:

  • packages/Agent/Site/ImageGeneration.php:211

xpac_agent_instructions

Filter · 2 arguments · 1 call site

Filters the lines plugins add to the agent's system instruction.

One line per piece of guidance about a plugin's own tools, such as which to call first or what a result means. Each line is trimmed and listed as one bullet under a heading, so each should read on its own. The same lines go to the admin chat and, when an app opens an MCP session, to that app; $audience says which, so a line that holds only in the chat, such as one about waiting for Allow, can be left out over MCP. A callback that takes one argument gets the lines alone, as before.

Add a line only while the tools it is about are on, as xpac_agent_tool_enabled answers when this runs: a chat conversation that declares only some groups of tools asks it while that filter answers false for the tools of every other group, so a plugin's lines follow its tools.

apply_filters( 'xpac_agent_instructions', [], $audience )
  • $lines (string[]) — Default none.
  • $audience (string) — 'chat' for the admin chat, 'mcp' for an app connected over MCP.

Fired from:

  • packages/Agent/Chat/Instructions.php:245

xpac_agent_keep_images

Filter · 1 argument · 1 call site

Filters how many of the latest messages with images still show the model their images.

Each image is sent again on every step, so older ones are left out of what the model is sent and replaced by a line asking it to have the administrator attach them again. The stored conversation keeps every image.

apply_filters( 'xpac_agent_keep_images', self::DEFAULT_KEEP_IMAGES )
  • $keep (int) — Default 2.

Fired from:

  • packages/Agent/Chat/Agent.php:1489

xpac_agent_keep_results

Filter · 1 argument · 1 call site

Filters how many of the latest model messages keep every tool result they follow.

A tool result older than that many model messages, and older than the administrator's latest message, may be left out of what the model is sent when it is large and stale.

apply_filters( 'xpac_agent_keep_results', self::DEFAULT_KEEP_RESULTS )
  • $keep (int) — Default 3.

Fired from:

  • packages/Agent/Chat/Agent.php:1410

xpac_agent_legacy_settings

Filter · 1 argument · 1 call site

Filters the switches a plugin had of its own before Agent held them.

Read once, the first time Agent's option is read on a site. A plugin that had a master switch sets enabled; one that had per-tool switches adds the tools that were off to disabled, by full ability name.

apply_filters( 'xpac_agent_legacy_settings', ['enabled' => null, 'disabled' => []] )
  • $legacy (array{enabled: bool|null, disabled: string[]}) — Default: nothing to import.

Fired from:

  • packages/Agent/Settings/Options.php:194

xpac_agent_max_steps

Filter · 1 argument · 1 call site

Filters how many model calls one message from the administrator may lead to.

Each call is one step of the loop, and a step that runs tools asks for the next. Once the count is reached the step answers limit instead of calling the model, until the administrator writes again.

apply_filters( 'xpac_agent_max_steps', self::DEFAULT_MAX_STEPS )
  • $steps (int) — Default 12.

Fired from:

  • packages/Agent/Chat/Agent.php:478

xpac_agent_model

Filter · 1 argument · 1 call site

Filters the model the agent talks to.

Null lets the AI client pick one from the connected providers. A model handed over here is used as it is, without checking it against what the prompt needs.

apply_filters( 'xpac_agent_model', null )
  • $model (ModelInterface|null) — Default null.

Fired from:

  • packages/Agent/Chat/Agent.php:1253

xpac_agent_model_messages

Filter · 2 arguments · 1 call site

Filters the history the model is sent on this step.

A copy, made after stale tool results were folded away: what is stored never changes here, so a note added for the model, such as that the administrator took a change back, is added again on every step for as long as it applies. Anything but a list of AI client messages, or an empty one, is ignored.

apply_filters( 'xpac_agent_model_messages', $folded, $conversationId )
  • $messages (Message[]) — The history as the model gets it.
  • $conversationId (int) — The conversation.

Fired from:

  • packages/Agent/Chat/Agent.php:1161

xpac_agent_model_preference

Filter · 1 argument · 1 call site

Filters the models the agent prefers, in order.

Anything using_model_preference() takes: model ids, model instances, or [provider id, model id] pairs. The first one a connected provider offers is used, and when none is, the AI client picks as it would with no preference.

apply_filters( 'xpac_agent_model_preference', null === $chosen ? [] : [[$chosen['provider'], $chosen['model']]] )
  • $preference (array<int, mixed>) — Default: the model the administrator picked on the chat screen, as one [provider id, model id] pair, or none on Automatic.

Fired from:

  • packages/Agent/Chat/Agent.php:1273

xpac_agent_models

Filter · 1 argument · 1 call site

Filters the models an administrator can pick for the agent.

Runs on every read, after dated snapshots and deep-research models are left out. Each entry needs provider and model; key is rebuilt from them, providerName and name fall back to the ids, images falls back to true, and an entry without both ids is dropped. Removing a model someone picked sends them back to Automatic.

apply_filters( 'xpac_agent_models', $discovered )
  • $models (array<int, array<string, string|bool>>) — In the registry's order, each with key, provider, providerName, model, name and images.

Fired from:

  • packages/Agent/Chat/Models.php:156

xpac_agent_needs_approval

Filter · 4 arguments · 1 call site

Filters whether one call to a tool waits for the administrator's Allow.

Asked when the model makes the call, which decides whether it runs straight away or waits, and again for a call still waiting whenever a transcript is built, where a tool switched off since gets its catalog entry's annotations as the default. A callback decides fully for its own tools and may lower the default as well as raise it: a tool annotated destructive because some of its calls touch live content can answer false for the harmless ones. It may read the database to decide. Asked with no arguments, for the Tools screen and the chat's status, a tool that can wait for some of its calls answers true, so the screen never promises it runs without asking. A call found unanswered when a step starts waits for Allow whatever this says, since a request that died mid-step may already have run it.

The fourth argument is for a tool that fetches from the web: an address the conversation did not give the model can carry the conversation out in its query string. Only the chat asks this filter; an MCP client runs its calls, or asks first, by itself.

apply_filters( 'xpac_agent_needs_approval', $default, $name, $args, $context )
  • $needsApproval (bool) — Default true for a tool annotated destructive and not readonly, by its ability or by its catalog entry.
  • $name (string) — The full ability name, such as xpac-forms/remove-field.
  • $args (array<string, mixed>) — The call's arguments with nulls taken out, or none when no call is being judged.
  • $context (array{hosts: string[], urls: string[]}) — The hosts the administrator typed in this conversation (lowercase, no leading www.) and every address an earlier tool result carried. Both empty outside a conversation.

Fired from:

  • packages/Agent/Tools/Toolbox.php:362

xpac_agent_recipes

Filter · 1 argument · 1 call site

Filters the recipes: ready-made requests that use the tools XPAC plugins bring.

Keyed by id, a plugin's namespace and a name, such as xpac-forms/contact-page. Each recipe has a title of one line (at most 80 characters, cut beyond), the prompt the administrator would type (at most 4000 characters with every more text and the lead, dropped beyond) and the tools it needs, a list of full ability names. It is offered only while every one of those tools is available. Optional: a description of one line (at most 160 characters, cut beyond); more, a list of {tools, prompt} whose text is added after a space only while its own tools are available too; input, {name, description, lead?}, the one thing the reader completes, with a name of lowercase letters, digits and underscores, which MCP apps ask for as a required argument; images, true for a recipe that works from an attached image; icon, one of page, form, popup, mail, image, globe, chart, inbox, lead or spark (the default); order, lower first, default 50; and audience, a list of chat and mcp, default both. Add your recipes whether or not your tools are on: Agent leaves out what cannot run. A malformed entry is dropped and reported through _doing_it_wrong(). Asked once, and again only when the abilities registry is built anew.

apply_filters( 'xpac_agent_recipes', [] )
  • $recipes (array<string, array<string, mixed>>) — Default none.

Fired from:

  • packages/Agent/Tools/Recipes.php:148

xpac_agent_scope_tools

Filter · 1 argument · 1 call site

Filters whether the chat declares only the tool groups a conversation needs.

On, a new conversation is told about the groups its plugins mark always and those whose label or keywords the administrator's messages name, and loads any other group when it needs one; a group once declared stays declared for the rest of the conversation. Off, every tool is declared on every step, which costs more on each uncached model call. A conversation stored before it was on declares every tool either way. MCP always lists every tool.

apply_filters( 'xpac_agent_scope_tools', false )
  • $scope (bool) — Default false.

Fired from:

  • packages/Agent/Chat/ToolScope.php:66

xpac_agent_strict_tool_schemas

Filter · 1 argument · 1 call site

Filters whether the agent declares its tools in strict form.

In strict form every optional property of a tool's input is declared nullable and required. OpenAI needs it; switch it off for a provider that rejects nullable types. Nulls are removed from every call before it is stored either way.

apply_filters( 'xpac_agent_strict_tool_schemas', true )
  • $strict (bool) — Default true.

Fired from:

  • packages/Agent/Chat/ToolSchema.php:128

xpac_agent_tool_catalog

Filter · 1 argument · 1 call site

Filters the tools XPAC plugins bring to the agent.

Keyed by ability category, such as xpac-forms. Each group has a label, a description and its tools, keyed by full ability name, each with a label, optionally a description of one sentence for a person, and the readonly and destructive annotations its ability registers with. A tool listed here is shown on the Tools screen whether or not it is switched on. Asked once, and again only when the abilities registry is built anew.

Two optional group keys decide when the chat declares a group's tools to the model while it declares only what a conversation needs (see ToolScope). keywords, a list of the lowercase words and short phrases an administrator types when they need the group, translated, such as contact form: a message that names one, or the group's label, has the group declared from that step on. Give them as one translatable comma-separated string, split. At most 64 are kept, of at most 40 characters each. always, true for a group declared from the first step of every conversation, which suits a small group the others lean on.

apply_filters( 'xpac_agent_tool_catalog', [] )
  • $groups (array<string, array<string, mixed>>) — Default none.

Fired from:

  • packages/Agent/Tools/Toolbox.php:111

xpac_agent_tool_enabled

Filter · 2 arguments · 1 call site

Filters whether one XPAC tool may register as an ability.

Every plugin that brings tools asks this before registering each one, with false as the default, so without Agent nothing registers. Agent's settings are bound at priority 1, so a callback at the default priority has the last word.

apply_filters( 'xpac_agent_tool_enabled', false, $name )
  • $enabled (bool) — Default false.
  • $name (string) — The full ability name, such as xpac-forms/create-form.

Fired from:

  • packages/Agent/Tools/Toolbox.php:189

xpac_agent_undo

Filter · 4 arguments · 1 call site

Filters the undo of a change a plugin reported with xpac_agent_changed.

Answer true once your handler has put the object back as $before says, or a WP_Error saying why it could not, and leave other handlers' changes alone. Check the current user's capabilities yourself. Bind it whether or not your tools are switched on, so a change stays undoable after its tool is switched off. Null means no plugin answered, and the change is refused as xpac_agent_undo_unhandled.

apply_filters( 'xpac_agent_undo', null, $row['handler'], $row['before'], $row['object_key'] )
  • $undone (true|WP_Error|null) — Default null.
  • $handler (string) — The handler the change was reported with.
  • $before (mixed) — What the plugin reported the object was.
  • $object (string) — The object key.

Fired from:

  • packages/Agent/Undo/Undo.php:440

xpac_agent_undo_capture

Filter · 2 arguments · 1 call site

Filters whether what a call to one tool changes is recorded, so it can be undone.

Asked when a call to a catalog tool that is not read-only starts, in the chat or on the xpac MCP server. Answer false for a tool whose writes should never be taken back, or that takes care of its own.

apply_filters( 'xpac_agent_undo_capture', true, $ability )
  • $capture (bool) — Default true.
  • $ability (string) — The full ability name.

Fired from:

  • packages/Agent/Undo/Recorder.php:477

xpac_agent_undo_fingerprint

Filter · 4 arguments · 1 call site

Filters the fingerprint of an object a plugin reported changed, as it is now.

Asked when a call's changes are kept, and again before they are taken back: when the two differ, the object changed after the call, and undo refuses unless the user says to go ahead. Answer a string for your own handlers, such as a hash of the state the change covers, and leave others' alone.

apply_filters( 'xpac_agent_undo_fingerprint', null, $handler, $object, $before )
  • $fingerprint (string|null) — Default null, no check.
  • $handler (string) — The handler the change was reported with.
  • $object (string) — Its object key.
  • $before (mixed) — What the plugin reported the object was.

Fired from:

  • packages/Agent/Undo/Undo.php:134

xpac_agent_undo_ignored_meta

Filter · 1 argument · 1 call site

Filters the post meta keys never recorded for undo.

WordPress keeps these for its own bookkeeping and writes them itself as posts are saved, trashed and restored, so putting them back would fight it. Add a plugin's own bookkeeping keys the same way, such as a cache it rebuilds.

apply_filters( 'xpac_agent_undo_ignored_meta', self::IGNORED_META )
  • $keys (string[]) — Default: the edit lock and last editor, old slugs and dates, the trash bookkeeping, the pingback flags, and an attachment's file and metadata.

Fired from:

  • packages/Agent/Undo/Recorder.php:496

xpac_agent_undo_max_bytes

Filter · 1 argument · 1 call site

Filters how large what one agent call replaced may be and still be kept for undo, in bytes.

Counted over every object the call changed, as stored. A call over it keeps nothing, and its result says it cannot be undone.

apply_filters( 'xpac_agent_undo_max_bytes', self::DEFAULT_MAX_BYTES )
  • $bytes (int) — Default 2097152, 2 MB.

Fired from:

  • packages/Agent/Undo/Ledger.php:438

xpac_agent_undo_ttl

Filter · 1 argument · 1 call site

Filters how long an agent's change can be undone, in seconds.

Read when a call's changes are kept, so a change keeps the time it was given. Held between an hour and 90 days.

apply_filters( 'xpac_agent_undo_ttl', self::DEFAULT_TTL )
  • $ttl (int) — Default 604800, 7 days.

Fired from:

  • packages/Agent/Undo/Ledger.php:418

On this page