Repository navigation
Description
Summary
On flow.google.com (migrated host), image generation with more than 3 references fails: chips 1–3
attach, the 4th never does. The model accepts up to 10 (gflow models lists nano2 with a reference
cap of 10), so the limit is not Flow's. The cause is where the caret lands when gflow clicks the
composer before typing @.
Environment
- gflow-cli 0.83.1
- Host:
flow.google.com(migrated composer) - Model: nano2 (Nano Banana 2.1), aspect 9:16
- macOS, headed Chrome (default transport)
Symptoms
- In-place refs (
GenerateImageRequest.refswithImageRef(in_project=True)):
_mention_by_tokenraisesReferenceNotFoundErrorfor the 4th ref. - Uploaded refs (4+ local
--reffiles):_mention_by_namefails with exit 32,
clearing the failed 'ref-…' query removed an already-attached reference (3 chip(s) before, 0 after).
This path uses the same composer click, so it is very likely the same cause; the fix below was
verified on the in-place path only. - Reproducible every time (3 runs, ref order shuffled): whichever image is 4th fails; 1–3 always attach.
- After the failure, the composer contains the search text as plain text right after the 3rd chip,
and no picker was opened.
Repro
- Create a project on
flow.google.comand upload 4 reference images. - Generate an image that references all 4 (in-place, or
gflow image i2iwith 4--reffiles). - Watch the composer: chips 1–3 attach; for the 4th,
@is typed but no picker opens, and the
query lands as plain text.
Root cause
Before every @, both MigratedComposer._mention_by_token and MigratedComposer._mention_by_name
(gflow_cli/api/transports/migrated_composer.py) do:
await page.locator(COMPOSER).first.click(timeout=5000)Playwright clicks the center of the ProseMirror editor. With 3 chips the first line is full and
the trailing space wraps to line 2, so a center click puts the caret directly after the 3rd chip,
with no space before it. ProseMirror's mention plugin does not open its picker for an @ typed
there, so the @ is swallowed and the query becomes plain text. With 1–2 chips the center click
happens to land after the trailing space, which is why the first three work.
Pressing End does not help: it moves to the end of the visual line, not the end of the document.
Proposed fix
After clicking the composer in _mention_by_token and _mention_by_name, move the selection to the
end of the document before typing @:
await page.locator(COMPOSER).first.click(timeout=5000)
await page.evaluate(
"""(sel) => {
const ce = document.querySelector(sel); if (!ce) return;
ce.focus();
const r = document.createRange(); r.selectNodeContents(ce); r.collapse(false);
const s = window.getSelection(); s.removeAllRanges(); s.addRange(r);
}""",
COMPOSER,
)
await page.wait_for_timeout(300)
await page.keyboard.type("@", delay=120)(A ProseMirror-native alternative would be dispatching a TextSelection.atEnd(doc) transaction, but
the editor view is not exposed on the page; the DOM Range approach works because ProseMirror syncs
its selection from the DOM on selectionchange.)
Verified
Applied as a runtime wrapper around those two methods on 0.83.1:
- 10 in-place references attached, 4/4 runs.
- 1 real generation with the fix applied succeeded.
clear_composer and send_prompt were left as-is; only the two mention paths need it.
Activity
ffroliva commentedon Oct 19, 2026
Assessment of #997: LIKELY-BUG / NEEDS-E2E (confidence 7/10)
Thanks for the precise write-up, @Ltwoz. We measured it on our side before acting on it. This was on a flow.google.com account, Windows, headed Chrome, a 1280×720 viewport, calling the production
_mention_by_tokenunchanged, with nothing submitted.What we reproduced (3/3 runs): the caret wedge is real. With 3 chips in the composer, the centre click lands on a chip and the caret stops right behind chip 2. The click is at
migrated_composer.pyin_mention_by_tokenand_mention_by_name; the same click is also in_mention_character.What we did not reproduce: on our setup the picker still opened every time (60/60 mentions), and all references attached (5/5). The 4th one went in out of order, so the chips read
1, 2, 4, 3. The chip guards count chips but don't check their order, so nothing reports the misorder. A chip right before the caret did not stop the picker opening here, so the "no picker" half of the root cause is still unexplained.Your fix works: moving the selection to the end of the composer before each
@gave the correct order (1, 2, 3, 4) in 3/3 runs. We haven't yet tested the wrapped-chip-line case you mention, where End no longer helps.Next:
Refs #997.window.innerWidth × innerHeight) and macOS version;@, the composer'sinnerHTMLandgetSelection().anchorNode/anchorOffset.fix(migrated): give the out-of-order refusal its own remediation; doc…
Merge pull request #1002 from ffroliva/bugfix/997-mention-caret-order
ffroliva commentedon Oct 19, 2026
Merged #1002 to
develop(ships next release). gflow now moves the caret to the end of the prompt before every@, at all three mention sites: in-place refs, uploaded--reffiles and@Character. A mention that lands out of order now fails with exit 32 before submit, instead of passing silently. Our e2e:developread chips[1, 2, 4, 3]; the fix reads them in order (1 passed, $0, nothing submitted).Keeping this open for the other half you reported: on macOS the picker never opens for the 4th reference. That didn't reproduce here (60/60 pickers opened at 1280×720 on Windows). When you get a chance, please try the next release and, if it still happens, share the window size and the composer
innerHTML/ selection anchor right before the 4th@. Thanks again for the diagnosis; your Range-to-end fix is what shipped.spike(ffroliva#997): pre-register the 4th-reference caret probe
spike(ffroliva#997): drive production _mention_by_token; add --send-p…
docs(spike): ffroliva#997 caret wedge is real and stable; picker fail…
fix(migrated): append every @ mention at the composer's end; refuse a…
ffroliva commentedon Oct 23, 2026
@Ltwoz a follow-up measurement on the half that was still open (no picker for the 4th+ reference). It's from 2026-10-23, on develop as released in v0.89.0: a flow.google.com account, Windows, headed Chrome.
I forced the wrap you described by narrowing the window to 900 px. The composer was 565 px wide, and chips moved onto a second line from the 5th mention.
@.So the mechanism you identified is handled here even with the wrap. If the picker still fails to open on macOS with v0.89.0 (
gflow update), please share:innerHTMLright before the failing@;merge: upstream v0.92.1 (upstream/main) into main-tun-tmp-fix