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) —chatfor the admin chat,mcpfor 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 asxpac-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) — Defaultmanage_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 withkey,provider,providerName,model,nameandimages.
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 asxpac-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 leadingwww.) 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 asxpac-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