Repository navigation
Studio Code: State the active site's WordPress version, block types, and Site Editor copies as facts - #5301
Conversation
…urce, and Site Editor copies as facts
…or sentence it replaces
…rize Global Styles by area
📊 Performance Test ResultsComparing b5e5d7e vs trunk app-size
site-editor
site-startup
Results are median values from multiple test runs. Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff) |
## Related issues - Found in the STU-2155 header eval (#5092, #5301). An agent ran `post update 5 --post_content=<site>/tmp/header-new.html`. That saved the path itself as the template part's content, which wiped the header the site renders, and the agent reported success. ## How AI was used in this PR Claude (via the Pi coding agent in a Roadie session) wrote the change and the tests, and ran the checks below. I reviewed the diff and the tool output. ## Proposed Changes WP-CLI's `--post_content` takes the content itself; `post create <file>` and `post update <id> <file>` read it from a file. When `post create` or `post update` gets a `--post_content` value that is the path of a file in the site folder (absolute or relative to it), `wp_cli` now runs the command with that file as the positional argument, so the post gets the file's content. The result says so: > Read the post content from tmp/y.html, the file `--post_content` named. > Success: Updated post 6. - Unquoted content runs to the end of the command, so flags after the path (`--porcelain`) are split back out and kept. - Content that only looks like a path is saved as written, as before: a missing file, a folder, a file outside the site folder, a path inside text, or anything with markup. - Only `post create` and `post update` change. Every other command runs as written. - Nothing new becomes possible: the rewritten command is one the agent could already run. WP-CLI's `post update` reads the first non-numeric argument as the file, so several IDs still work. - `--post_content=$(cat file)` is still refused: shell syntax doesn't run, and that's a different mistake. ## Testing Instructions - `npx vitest run apps/cli/lib/tests/wp-cli-post-content.test.ts apps/cli/ai` passes (289). New tests cover an absolute path, a relative path with flags around it, five values that look like paths but aren't files, files outside the site folder, and other commands. - Real site. The agent wrote `tmp/x.html` and `tmp/y.html`, then ran: - `post create --post_type=page --post_title=Probe --post_status=publish --post_content=<absolute path of x.html> --porcelain`: page 6 created. - `post update 6 --post_content=tmp/y.html`: page 6 updated. - Page 6's content was then `y.html`'s block markup. Without this change, the first command saves `<path> --porcelain` as the content. - No telemetry changes: the note goes to the tool result only. ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
…at show the block (#5307) ## Related issues - Builds on #5300 (attribute check) and #5301 (Active site facts). Found while evaluating #5301. ## How AI was used in this PR Claude (via the Pi coding agent in a Roadie session) read the failing eval transcripts, wrote the change and its tests, and ran the evals below. I reviewed the code and the transcripts. ## Proposed Changes When a tool result shows block markup, Studio Code adds one line for each core block type in it, listing the settings that block type declares in the site's own `wp-includes/blocks/<block>/block.json`. For example: > `core/navigation settings, declared in …/wp-includes/blocks/navigation/block.json: ref (number), …, showSubmenuIcon (boolean, default true), submenuVisibility ("hover"|"click"|"always", default "hover"), overlayMenu (string, default "mobile"), …` - Each block type is described once per turn. Attributes read from the block's HTML (`source`) are content, so they are left out, along with internal `__unstable`/`__experimental` ones. - It applies to every Studio tool result, so `wp_cli post get`, `Read` and `Bash cat` all get it. - It reads files on disk only. Plugin blocks, remote sites and blocks without a `block.json` are skipped. **Why.** In the template-part eval ("Make the header navigation open its submenus on click instead of on hover"), the failing runs reason "there's no built-in 'open on click' toggle … this requires custom JavaScript", then write a script and CSS into the theme, at 1–1.7M tokens per run. The navigation block declares `submenuVisibility: "click"`. The model doesn't remember it and has no reason to open `block.json`. Stating the declared settings where the block appears means the model reads them while it is looking at the block. ## Testing Instructions - `npx vitest run apps/cli/ai/tests/block-settings.test.ts`: describes the core blocks in a header from their `block.json`, describes each one once, and leaves out content attributes, closing comments and blocks without a `block.json`. - **Eval:** `template-part-db-override`, 6 runs per arm, run against this branch and current trunk (`09253bcef`) at the same time: | | Pass | JS workaround | Mean tokens | Mean tool calls | Mean time | |---|---|---|---|---|---| | This branch | 6/6 | 0 | 223k | 17 | 53s | | Trunk | 4/5 | 1 | 675k | 32 | 94s | One trunk run stalled at the 420s timeout after 91k tokens without reaching an answer. It is left out above as an infrastructure stall. Counted as a failure, trunk is 4/6. - Every branch run's session shows the `core/navigation settings` line in the `post get 5` or `Read parts/header.html` result, and every branch run set `submenuVisibility` in the saved header. No branch run wrote JavaScript or read core's `navigation/view.js`. On trunk, one run wrote a script and another read `view.js` three times before finding the setting. - **Regression check:** the three other cases that start on a local site, 6 runs per arm: | Case | This branch | Trunk | |---|---|---| | `global-styles-db-override` | 6/6, 189k tokens | 5/6, 187k tokens | | `design-system-annotation` | 6/6, 260k tokens | 5/6, 289k tokens | | `active-site-reused` | 6/6, 68k tokens | 6/6, 66k tokens | Both trunk failures are unrelated to this change: one is a port collision during inspection, the other discarded the saved styles. The settings line appeared in only 1 of these 18 runs (it passed), because these tasks rarely read block markup, so this check shows no harm rather than a gain. - **Size:** replaying 263 earlier sessions that read block markup, the added lines come to a median of ~240 tokens per session (p90 ~460, max ~1.8k). - Six runs per arm can't establish a pass-rate gain, so the claim is parity or better on accuracy. The fall in tokens and tool calls is large and consistent across runs. ## Pre-merge Checklist - [x] Have you checked for TypeScript, React or other console errors?
|
I don't understand this PR to be honest. the facts about a given sites are infinite and can change over time. While I understand the WordPress version, all the rest feel like useless information in the context most of the time. |
|
It's a step towards removing skill routing from the system prompt |
|
How so? |
|
It's leading towards the goal of reducing non-deterministic behavior and simplifying our system prompts to make the agent more fluid and accurate. When running evals for #5265, I found that the agent often skipped skills, or would pick You are right that this can be useless context most of the time though. I think a better idea is to move the saved Site Editor copy notice into the tool results similarly to how #5307 handles core block context. |
|
FYI |
…all touches the theme file they replace (#5343) ## Related issues - Follows #5301, addressing the review there: the saved Site Editor copies were listed in every system prompt, though they matter only when the agent touches a theme file they replace. - Builds on #5333's shared result notes, so the notice reaches Studio Code and `studio mcp` the same way. ## How AI was used in this PR Claude (via the Pi coding agent in a Roadie session) wrote the change and the test and ran the evals below. I reviewed the diff and the results. ## Proposed Changes When someone saves a template, template part or Global Styles in the Site Editor, WordPress renders that saved copy instead of the theme file. An agent that edits `parts/header.html` then changes nothing the visitor sees. #5092 told the agent this in `edit-manage-site`; #5301 moved it into Active site facts, which listed every saved copy in every prompt. - The notice moves into tool results, stated when a call or its result names a theme file a saved copy replaces, for example: > WordPress renders the template part header from its copy saved in the Site Editor (post 12), not from wp-content/themes/twentytwentyfive/parts/header.html. - `cli/ai/saved-copies.ts` reads the copies from the site's SQLite database when a theme file is named, so copies saved earlier in the turn count. Each copy is stated once per tracker. - It is registered in `cli/ai/result-notes.ts` (#5333). The notes now see the call's arguments with its result (a Write names the file in its arguments), on both surfaces. - Active site facts keep the WordPress version; saved copies leave them. Limits: - MCP clients read and write theme files with their own tools, which never pass through Studio, so for them the notice fires only when a Studio tool names the file. - Like every result note, a notice stated early in a turn can be lost if the context is compacted later in that turn. ## Testing Instructions - `npx vitest run apps/cli/ai/tests/saved-copies.test.ts`: a real SQLite database with a saved template part and Global Styles; notices for the theme files they replace, none for other files, and each copy once; run with `wp_` tables and with another prefix, as imported sites can have. - Eval (`/tmp` override kit, 6 runs per case, Studio's default model): a site whose header part and Global Styles were saved in the Site Editor; the task edits the header, then the styles. Scored from the rendered site. | Case | #5301 (facts in prompt) | This PR | |---|---|---| | Template part saved in the Site Editor | 6/6 | 6/6 | | Global Styles saved in the Site Editor | 4/4 | 6/6 | The notice appeared in all 12 transcripts. An earlier run of this change scored 5/6 on Global Styles; the miss was broken JSON the agent wrote to a file and saved with `post update`, which the inline `--post_content` JSON check (#5310) does not cover. - Eval on site edits with no saved copies (8 cases from the routing eval: contact form, carousel, newsletter, heading font, testimonials, header search block, hero, spacing; each run stops at its first write). Before #5301, `edit-manage-site` told the agent to check for saved copies first; #5092's review asked what that costs. | | Sessions that queried saved copies | Queries | Tool calls before the first write | |---|---|---|---| | Before #5301 (Oct 22 runs) | 38/126 | 43 | 14.3 | | This PR | 0/32 | 0 | 14.1 | The queries are gone, but calls before the first write are unchanged: the agent spends them on other reading. Tokens (median 134k before, 136k now) and wall time (median 38.6s on trunk, 36.4s now) are at parity too. ## Pre-merge Checklist - [ ] Have you checked for TypeScript, React or other console errors?
Related issues
edit-manage-site(moved there fromvalidate_blocksin review). This PR states the saved copies as facts read from the site, and deletes the sentence.block.json.How AI was used in this PR
Claude (via the Pi coding agent in a Roadie session) wrote the change and the tests, and ran the evaluation below. I reviewed the diff and the eval transcripts.
Proposed Changes
The Active site section now lists facts about a local site, read from its own files and database (
site-facts.ts). For the STU-2155 header case it reads:A site with more saved copies gets one grouped line per kind, about 6 tokens per copy:
wp-includes/version.php.wp_templateandwp_template_partpost per slug for the active theme, read read-only from the site's SQLite database with Node's built-innode:sqlite. Each copy is grouped by whether it replaces a file in the theme or its parent theme (checked on disk, in the folders WordPress reads them from) or exists only in the Site Editor.wp_global_stylespost, with the areas it sets and a count of per-block styles. The details are in the post.edit-manage-sitesentence that told the agent to look for saved copies withpost listis deleted.Testing Instructions
npx vitest run apps/cli/aipasses (332). The tests use a real SQLite database and theme files:aabc42a3e, with the sentence and Studio Code: Show a core block's declared settings in tool results that show the block #5307), from the trunk-plus-Studio Code: Show a core block's declared settings in tool results that show the block #5307 arm of Studio Code: Show a core block's declared settings in tool results that show the block #5307's eval, which ran the same code. The branch is this PR merged with that trunk.template-part-db-override)global-styles-db-override)submenuVisibilitythere, and the user's tagline was kept in all six. The agent quoted the fact in its reasoning ("the description said 'Saved in the Site Editor … template part header (post 5).' So post 5 is authoritative").--post_content=<path>save. Studio Code: Show a core block's declared settings in tool results that show the block #5307 and Studio Code: Read the file a wp_cli --post_content path names #5305 fix those, and neither failure appears here.Pre-merge Checklist