Page builders don’t cost the whole page per edit. An agent reads an index of the blocks, fetches the one it needs, and sends back only what changed. The server merges that into the stored page by id, so the other blocks keep their content, including changes someone made in the Control Panel in the meantime.
How an edit works#
Step through it. The arguments and responses were recorded from the real server, on a page with 16 blocks.
- hero0001 1
- text0002 2
- text0003 3
- text0004 4
- text0005 5
- text0006 6
- text0007 7
- text0008 8
- text0009 9
- text0010 10
- text0011 11
- text0012 12
- text0013 13
- text0014 14
- text0015 15
- text0016 16
A large Replicator field comes back as an index: each set's id, type, and a short preview. The agent sees the page without holding it.
{
"collection": "landing",
"slug": "tours"
}{
"id": "cd6fb094-92a7-4293-a2b0-1e46ac56a597",
"collection": "landing",
"blueprint": "landing_page",
"slug": "tours",
"site": "en",
"status": "published",
"published": true,
"url": "/landing/tours",
"format": "raw",
"data": {
"title": "Tours",
"page_builder": {
"__preview": "16 sets",
"truncated": true,
"sets": [
{
"id": "hero0001",
"type": "section_hero",
"preview": "Bike tours along the Silver Coast"
},
{
"id": "text0002",
"type": "section_text_block",
"preview": "Block 2 describes one part of the tour in detail, with pract..."
},
"… 14 more sets"
],
"note": "NOT writable — fetch one set with entries_get fields: [\"page_builder.<id>\"], or the whole field with fields: [\"page_builder\"]. The update tool merges into one set with {\"page_builder\": {\"<id>\": {...}}}, and adds, removes, or reorders sets with the list of ids in their new order, a new set where it goes: [{\"id\": \"<id>\"}, {\"type\": \"...\", ...}]"
},
"body": {
"__preview": "The coastal route runs north from the harbour, past the lighthouse and along the dunes. Ev…",
"truncated": true,
"note": "NOT writable — fetch raw field before editing: entries_get with fields: [\"body\"]"
}
},
"cp_edit_url": "https://example.com/cp/collections/landing/entries/cd6fb094-92a7-4293-a2b0-1e46ac56a597"
}The token counts are the package’s own measurements of a page with 16 blocks. Changing one title this way cost 1,968 tokens in total, counting the 100-token result of entries_update, against 14,050 for reading and resending the whole page builder.
What large values come back as#
entries_get and terms_get shorten large values unless the agent asks for them with fields.
| Value | Comes back as |
|---|---|
| Bard or Markdown over 500 bytes | A preview |
Any other value over 4 KB, such as a synced array field | A preview |
| A large Replicator field | An index of its sets, each with its id, type, and a short preview |
| A Grid | Inline, whatever its size |
Each shortened value says what to do next, so the agent isn’t left guessing.
{
"__preview": "16 sets",
"truncated": true,
"sets": [
{ "id": "hero0001", "type": "section_hero", "preview": "Bike tours along the Silver Coast" }
],
"note": "NOT writable — fetch one set with entries_get fields: ["page_builder.<id>"], or the whole field with fields: ["page_builder"]. …"
} fields: ["page_builder"] returns the whole field. fields: ["page_builder.<id>"] returns one set of a Replicator or Grid field, as an object keyed by its id, which is the shape entries_update merges by id.
The merge rules#
entries_update does a shallow top-level merge of raw data, so nested structures are replaced whole. Replicator and Grid fields are the exception, because their sets are addressed by id.
An object keyed by set id#
Merges into just those sets.
{ "page_builder": { "wKJQXf2s": { "variant": "centered" } } } - Send only the fields you change, and
nullto remove a set. - Inside a set the merge is shallow as well. Each named field is replaced whole, a Group included, and
nullclears it. - A Replicator or Grid nested in the set merges by id the same way.
A list#
Sets the order.
{ "page_builder": [{ "id": "wKJQXf2s" }, { "type": "faq", "question": "…" }, { "id": "3kPq9xYz" }] } - An item with a stored id merges into that set, so
{"id": "wKJQXf2s"}keeps it as it is. - An item in another type replaces its set.
- An item without an id is a new set, and the result lists its id under
added. - Sets you leave out are removed.
- A new set sent with a blank id,
0, or an id another new set also has gets a fresh id. This also applies through the create tools,terms_update, andglobals_update. - A bare id the field doesn’t store is refused, so a block someone removed in the meantime never comes back empty.
Clearing a field#
null clears the field. An empty list or object is refused, because PHP can’t tell {} from [], and {} would wipe the page.
Find and replace#
A Bard, Markdown, text, or textarea field also takes a find and replace, so fixing a sentence never costs the whole article.
{ "article": { "find": "…", "replace": "…" } } find must match the stored text exactly once. For Bard it must match inside one formatting run, because bold, a link, or a line break ends a run. It works inside a set addressed by id too, and in terms_update and globals_update.
A miss or several matches is an error that says what went wrong, and multiple matches quote the nearby text.
find matches nothing in title — it must match the stored text exactly once; read the field to copy it find matches 12 times in page_builder.text0002.text — add words around it so it matches once: …es one part of the tour in detail, with practical notes for riders. Block 2 describes one part … | … Validation#
The whole field is validated and saved as the Control Panel saves it.
- Whatever a set already stores passes, including keys its blueprint no longer defines and sets of removed types.
- A block that no longer passes its blueprint’s rules blocks the write, and the error names it by id, as in
page_builder.wKJQXf2s.heading. - An update that changes nothing saves nothing and creates no revision.
- Every unknown key is reported in one error.
unknown field no_such_field — valid handles: body, facts, hero, page_builder, seo, starts, title What it saves#
Write results also carry no copy of what was just written, so an agent doesn’t pay to read back its own edit.
- Read an entry with a large synced field 32× less24.4k758
- Add a block to a page 7.3× less11.1k1.5k
- Edit one field of one block 7.1× less10.7k1.5k
- Add a link to a menu 1.5× less4.7k3.1k
- List 25 images 1.6× less2.3k1.5k
- Change one global setting 1.2× less1.7k1.4k
Published by the package. Counted with the cl100k tokenizer over HTTP, for the tool calls and results of each task, on pages with 8 to 16 blocks. On 0.7, each page edit is counted at a single whole-page write.