openpencil/apps
Fini f7e776de4f fix(ai): image search pipeline picks up role:image-placeholder frames
The `add_image_placeholder_v0` / `_v1` element tools and JSONL payloads
that mimic them emit a `frame` carrying `role: 'image-placeholder'` (a
gray slate-100 box + centered icon_font child + optional label) — NOT
an `image` node. The auto-search pipeline only filtered on
`type === 'image'`, so every placeholder produced via element tools
silently bypassed the search hook. Latest GPT-5.5 food-app run shipped
8 placeholder frames; zero got auto-filled and the design landed with
all dashed-border icons instead of real photos.

Pipeline now:
- `isImagePlaceholderFrame` predicate identifies placeholder frames.
- `collectImageSearchTargets` returns mixed `{node, kind}` pairs
  ('image' for `type==='image'` with placeholder src, 'placeholder-frame'
  for the role-keyed frames). Skips descending into placeholder
  children (icon_font + label get wiped on fill anyway).
- `enqueueImageForSearch` accepts both shapes; queue items track `kind`.
- `processQueue` re-checks the right invariant per kind, and on success
  uses `updateNode(id, { fill: [{type:'image',url,mode:'crop'}], children: [] })`
  for placeholder frames (vs `updateNode(id, { src })` for image nodes).
  Clearing children prevents the icon/label from rendering on top of
  the searched photo.
- Streaming path (insertStreamingNode line 382) intentionally still
  gates on `type === 'image'` — placeholder frames stream their
  children separately, so enqueueing mid-stream would race with the
  late-arriving icon. Placeholder frames are only enqueued via the
  post-tree `scanAndFillImages` scan (orchestrator-tail + dispatcher
  per-subtask), where the full tree is already in the doc.

`extractQueryForNode` looks for `imageSearchQuery` first, falls back
to a non-default `name`, then mines the optional
`role: 'image-placeholder-label'` text child for a hint. Generic
default still works ("placeholder") if nothing useful is on the frame.

7 new tests cover `isImagePlaceholderFrame` and
`collectImageSearchTargets` (placeholder + image mix, no descent into
placeholder children, missing root id).
2026-05-05 03:57:30 +08:00
..
cli Merge origin/v0.8.0 into feat/rust-ification 2026-05-03 21:00:00 +08:00
desktop Merge origin/v0.8.0 into feat/rust-ification 2026-05-03 21:00:00 +08:00
web fix(ai): image search pipeline picks up role:image-placeholder frames 2026-05-05 03:57:30 +08:00