Skip to content

Assistant: place images, diagrams, references and child notes by paragraph - #202

Merged
davior merged 1 commit into
mainfrom
claude/peaceful-hopper-wynn08
Oct 5, 2026
Merged

davior merged 1 commit into
mainfrom
claude/peaceful-hopper-wynn08

Conversation

@davior

@davior davior commented Oct 5, 2026

Copy link
Copy Markdown
Owner

Problem

A request like "In the second chapter, add an image above every paragraph that describes the paragraph" put every image at the start of the chapter. generate_image could only take a heading (section) and always inserted at heading + 1, so N images stacked under the chapter title (in reverse order). The model had no way to express "next to this paragraph". create_diagram was worse: it always appended to the end of the note.

Fix

The four actions that insert a single block (generate_image, create_diagram, add_reference, create_child_note) now accept three optional placement fields:

field meaning
anchorText opening words of an existing paragraph / list item / quote; the block goes directly next to it
position with an anchor: before / after (default). Section only: after (under heading, default — old behaviour), before (above heading), end (after the section's last block). above/below/under/beneath fold onto these
section narrows the anchor search to that section; on its own places relative to the heading

Executor (executor.py): new resolve_placement / find_anchor_index. Anchors match through the Markdown the model copies (emphasis, [link](url), escapes, bullets, trailing …), and link text inside link nodes is now included (the old block_text skipped it). Tightest match wins: whole block → starts-with → contains → nested child (resolved to its top-level ancestor so the block isn't indented under a list item). If a target can't be found it falls back to the section, then the end of the note, and the run summary says so instead of failing a paid image generation. section_end was pulled out of edit_section and shared.

Prompt (aiPlan.ts): new "Placing blocks" rule with the per-paragraph example spelled out, updated action signatures, and the Images rule now points at paragraph anchoring.

Parsers: TS validateAction and Python validate_action both carry the new fields; add_reference also accepts section (folded onto insertAfterSection) so every block action uses the same vocabulary. Labels in the review modal say where a block will land ("Generate image above “Storm clouds…” in …").

Testing

  • Reproduced the bug against the original executor: two anchored images → ['Chapter 2', 'image', 'image', 'Storm clouds…', 'The crew…']. With this change they land above their paragraphs.
  • Backend: 1178 passed (new tests cover the reported scenario, section scoping, wrong-section rescue, fallbacks, section before/end, diagrams/references/child notes, Markdown-tolerant matching, nested anchors).
  • Frontend: tsc --noEmit clean, vitest 204 passed (new placement parse/label tests).
  • tools/plan_parse_diff: added 3 corpus samples; 57/57 agree between TS and Python on plan, labels and prompts.

Notes

  • Changing PLAN_INSTRUCTIONS invalidates the Anthropic prompt-cache prefix once after deploy.
  • Inserting text next to a paragraph still goes through edit_section (rewrite of the whole section); not changed here.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Fym1mUkgMQ1jAexC6D6zmK


Generated by Claude Code

…graph

A block-inserting action could only be placed against a heading, so "in the
second chapter, add an image above every paragraph" put every image directly
beneath the chapter title. The model had no way to say "next to this paragraph".

generate_image, create_diagram, add_reference and create_child_note now take
three optional placement fields:

- anchorText: the opening words of an existing paragraph, list item, quote or
  other block; the new block goes directly before or after it
- position: "before" / "after" (default) relative to the anchor; with only a
  section, "after" (beneath the heading), "before" (above it) or "end" (after
  the section's last block). Synonyms like above/below are folded in.
- section: narrows the anchor search to that section, or places relative to
  the heading on its own (the previous behaviour)

Anchors are matched through the Markdown the model copies (emphasis, link
syntax, escapes, bullets, trailing ellipsis), preferring a whole-block match,
then a block that starts with the snippet, then one that contains it. A
target that cannot be found degrades to the section, then the end of the
note, and the run summary says so. create_diagram previously always appended
to the end; it now honours placement too.

The planner prompt gains a "Placing blocks" rule with the per-paragraph
example, and both parsers (TS and Python) validate and label the new fields
identically — checked with tools/plan_parse_diff (57/57 agree).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fym1mUkgMQ1jAexC6D6zmK
@davior
davior marked this pull request as ready for review October 5, 2026 23:38
@davior
davior merged commit 89d6511 into main Oct 5, 2026
2 checks passed
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.

2 participants