Skip to content

Route generation through the AI Client; migrate all tools to the Abilities API - #347

Merged
mmtr merged 13 commits into
trunkfrom
deskmod-9-route-generation-through-the-wp-ai-client-migrate-all-tools
Jul 14, 2026
Merged

Route generation through the AI Client; migrate all tools to the Abilities API#347
mmtr merged 13 commits into
trunkfrom
deskmod-9-route-generation-through-the-wp-ai-client-migrate-all-tools

Conversation

@mmtr

@mmtr mmtr commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

What & why

The Copilot's built-in tools are now WordPress Abilities, and the agent loop dispatches them through Core (wp_get_ability()->execute()) instead of a hand-rolled registry. Permission checks and input/output validation now live in the ability, not our code. Because the assistant offers the model every registered read-only ability, it's now a general agent — it answers site questions (version, environment, current user) via Core's own abilities, and picks up any read-only ability a plugin registers, with no opt-in.

Changes

  • New includes/ai-copilot/abilities.php — a desktop-mode ability category plus one ability per built-in tool (search-posts/pages/comments, search-comments-by-post, list-admin-pages, search-wporg-plugins, get-php-error-log) and analyze-comment. Each has input/output JSON Schema, a permission_callback, and meta (annotations, show_in_rest, mcp on the safe read-only ones). They appear in GET /wp-abilities/v1/abilities.
  • Loop rewired (search.php) — the assistant offers the model every registered read-only ability (its own, Core's, or another plugin's) and runs each call via execute(). A permission denial or bad input becomes a clean tool error (never a fatal) and fires desktop_mode_ai_search_error. The system prompt tells the model its tool list is authoritative, so it uses whatever fits.
  • Removed desktop_mode_register_ai_tool() + the whole tool registry.
  • Generation (client.php) — provider + model fully delegated to the Core AI Client; desktop_mode_ai_search_completed now carries usage (tokens) + model. wp_ai_client_prevent_prompt is honored via Core.

Testing

Requires WordPress 7.0 with an AI provider in Settings → Connectors and the AI assistant enabled in OS Settings → Features.

  1. Open desktop mode and press Cmd/Ctrl+K.
  2. Content search — ask "Which post did I write about paella?" → returns the matching post.
  3. Navigation — ask "Where do I manage categories?" → returns wp-admin links.
  4. Plugin search — ask "Is there a plugin for SEO?" → returns wp.org plugins.
  5. Multi-step — ask "Was there a comment about the recipe on my paella post?" → searches posts, then comments on that post.
  6. Core abilities (site questions) — ask "What PHP version is this site running?" → answers via Core's get_environment_info; "What's my WordPress version?"get_site_info. No plugin code needed — the assistant offers every read-only ability. (Confirm the call in the debug log: desktop_mode_ai_tool_called with tool_name=get_environment_info.)
  7. Permission (clean error) — as a non-admin, ask "Are there any PHP errors?" → a normal "no permission" reply, not a crash.
  8. Abilities RESTGET /wp-abilities/v1/abilities lists the desktop-mode/* abilities with schemas.
  9. Comment scoring — post a new comment → it gets an AI spam/harm verdict.

Automated: build, lint, typecheck, JS + PHP suites green.

🤖 Generated with Claude Code

Open WordPress Playground Preview

mmtr and others added 4 commits July 13, 2026 13:40
Add includes/ai-copilot/abilities.php: a `desktop-mode` ability category plus
one ability per built-in Copilot tool (search-posts/pages/comments,
search-comments-by-post, list-admin-pages, search-wporg-plugins,
get-php-error-log) and a comment-spam analyze-comment ability. Each carries a
model-facing description, input/output JSON Schema, a permission_callback
mirroring the old gates (read for search/nav; manage_options for the error log;
moderate_comments for analysis), and meta annotations/show_in_rest/mcp. Execute
callbacks delegate to the existing query handlers so there is one implementation.

The agentic loop still uses the legacy tool path; wiring it to using_abilities()
+ the ability resolver (and removing the old registry) follows in later commits.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ol registry

- search.php: advertise the built-in tools from their WordPress Abilities
  (description + input schema) and dispatch each call through
  wp_get_ability()->execute(), which runs the permission_callback and validates
  input/output. A denial or bad input surfaces as a clean tool error + fires
  desktop_mode_ai_search_error; never a fatal. Tool names are derived from the
  ability names and match the historical names, so progress labels, the system
  prompt, and the answer schema are unchanged.
- Hard-remove desktop_mode_register_ai_tool() and the whole tools-registry.php
  (+ its test) and the dead desktop_mode_ai_search_tool_definitions().
- client.php: add the desktop_mode_ai_model filter -> using_model_preference()
  (soft, with fallback); return per-turn token usage + resolved model metadata,
  accumulated into the desktop_mode_ai_search_completed observability payload.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cover category + ability registration with populated schemas, the permission
gates (reader vs manage_options vs moderate_comments), execute() round-trips
with output validation, the tool-name mapping the loop relies on, limited MCP
exposure, and the desktop_mode_ai_model preference filter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- abilities.php: make the Copilot's advertised ability list filterable via
  desktop_mode_ai_abilities — the replacement extension point for the removed
  desktop_mode_register_ai_tool(). Register an ability + append its name; the
  loop advertises + dispatches it through execute(). Dedupes.
- tests: cover the filter.
- docs: hooks-reference (remove register_ai_tool/tool_registered; add
  desktop_mode_ai_abilities + desktop_mode_ai_model; document usage/model on
  search_completed + tool_execute stage on search_error; built-ins are
  abilities), examples/ai-ask.md (ability recipe replaces the tool recipe),
  migration-ai-connectors.md, javascript-reference.md. Provider-neutral wording.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mmtr mmtr self-assigned this Jul 14, 2026
@mmtr
mmtr requested a review from Copilot July 14, 2026 08:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the Desktop Mode AI Copilot’s server-dispatched tools from a plugin-owned registry to WordPress 7.0’s Abilities API, routing tool execution through wp_get_ability()->execute() so that permission checks and JSON-Schema input/output validation are enforced by Core.

Changes:

  • Introduces desktop-mode/* Abilities (category + one ability per built-in tool, plus analyze-comment) and wires them into the /ai/search agent loop.
  • Reworks generation to run through the Core AI Client, adding soft model preference (desktop_mode_ai_model) and propagating token usage + resolved model metadata.
  • Removes the old PHP tool registry (desktop_mode_register_ai_tool()), replaces extensibility with desktop_mode_ai_abilities, and updates docs/examples accordingly.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/phpunit/tests/aiToolsRegistry.php Removes tests for the deleted PHP tool registry API.
tests/phpunit/tests/aiAbilities.php Adds PHPUnit coverage for ability registration, permission gates, execute(), tool-name mapping, and model-preference normalization.
includes/ai-copilot/tools-registry.php Deletes the old desktop_mode_register_ai_tool() registry implementation.
includes/ai-copilot/search.php Switches tool assembly/dispatch to Abilities (execute()), adds usage/model accrual, and updates observability payloads.
includes/ai-copilot/client.php Adds AI Client model preference support plus helpers to extract token usage and model metadata from results.
includes/ai-copilot/bootstrap.php Loads the new abilities module instead of the removed tools registry.
includes/ai-copilot/abilities.php Registers the desktop-mode ability category and all built-in Copilot abilities with schemas + permission callbacks.
docs/migration-ai-connectors.md Documents the Tools → Abilities migration and the new extensibility surface.
docs/javascript-reference.md Updates server-side tool guidance to Abilities + desktop_mode_ai_abilities.
docs/hooks-reference.md Removes registry docs, adds desktop_mode_ai_model + desktop_mode_ai_abilities, and updates hook semantics.
docs/examples/ai-ask.md Updates the example to register server tools via Abilities and to reflect provider-neutral wording.
Comments suppressed due to low confidence (1)

includes/ai-copilot/search.php:1124

  • This docblock still says the hook fires for “built-in and registered” tools, but this PR removes the PHP tool registry. The hook now effectively applies to ability-dispatched tools (and will also run for ability error envelopes) before the FunctionResponse is sent back to the model, so the comment should be updated to avoid pointing developers at a removed surface.
			/**
			 * Transform a tool result before it goes back to the
			 * model. Fires for every tool, built-in and registered.
			 *

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread includes/ai-copilot/search.php Outdated
Comment thread includes/ai-copilot/abilities.php
mmtr and others added 4 commits July 14, 2026 10:29
- search.php: guard the $ability_by_tool lookup with isset() so a name in
  $valid_tools without a mapping returns a clean tool error instead of a
  notice / wp_get_ability(null). Fix stale tool_result docblock.
- abilities.php: normalize the derived tool name to [a-z0-9_] (lowercase,
  collapse other chars) so third-party ability names with extra slashes or
  mixed case can't produce a function name providers reject.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0.9.4 is the current unreleased dev version (latest tag is v0.9.3), so this
work ships in 0.9.4. Fix every @SInCE / doc "0.9.5" → "0.9.4", clarify that the
`desktop_mode_ai_model` filter name is reused (old provider-selection filter
gone, now a soft model preference), and add a 0.9.4 changelog line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pre-1.0 APIs are unstable; deleted APIs don't need documenting outside the
changelog. Drop the desktop_mode_register_ai_tool() removal framing from
hooks-reference and the ai-ask example — describe the current ability +
desktop_mode_ai_abilities/desktop_mode_ai_model surface positively instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Drop the desktop_mode_ai_model filter: provider and model are delegated
  entirely to the Core AI Client (there was no prior filter to preserve).
- Drop the desktop_mode_ai_abilities opt-in filter. The assistant now offers
  every registered read-only ability (its own, Core's, or another plugin's) —
  register a read-only ability and it's picked up automatically; permission is
  still enforced by the ability's permission_callback. Only read-only abilities
  are offered, since a search turn can be steered by attacker-controlled content.
- Link "WordPress Abilities" to the Abilities API docs; drop Linear issue refs
  from code/docs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mmtr mmtr changed the title DESKMOD-9: route generation through the AI Client; migrate all tools to the Abilities API Route generation through the AI Client; migrate all tools to the Abilities API Jul 14, 2026
mmtr and others added 4 commits July 14, 2026 13:24
…acks

The system prompt hard-scoped the assistant to five tracks and only listed the
built-in tools, so it declined questions the auto-included read-only abilities
(Core's site/user/environment info, third-party tools) could answer. Broaden
the prompt: the tool list is authoritative; call any tool that fits and
summarise the result as a chat answer.

Also fix ability dispatch for tools with no input schema (e.g. Core's
get-*-info): execute() rejects a non-null input when no schema is defined, so
pass null in that case instead of the (empty) args array.

Verified: "what PHP version…" -> get_environment_info, "what WP version…" ->
get_site_info, and content search still resolves via search_posts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The assistant now answers with any read-only ability (site/environment info,
plugin tools), not just content search + wp-admin navigation, so widen the
footer hint accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Match the assistant's wider scope (site questions via any read-only ability),
not just content search + wp-admin navigation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@AllTerrainDeveloper AllTerrainDeveloper left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing, thanks for the awesome work!

Image Image

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mmtr
mmtr merged commit d44e5a2 into trunk Jul 14, 2026
5 checks passed
@mmtr
mmtr deleted the deskmod-9-route-generation-through-the-wp-ai-client-migrate-all-tools branch July 14, 2026 13:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants