Three defects in the gemini-web executor's prompt serialization and
Playwright input path:
- buildGeminiPrompt()'s single-turn fast path returned only the last
user message, silently dropping any system instruction whenever
there was no prior user/assistant turn (title generation, one-shot
completions). Now prepends the system text on that path too.
- buildGeminiToolPrompt() picked the FIRST system message
(`.find()`), but prepareToolMessages() appends the synthetic tool
contract LAST — so any request with its own client system message
lost the tool contract entirely. Now joins all system messages in
order (client instruction(s) first, tool contract last).
- The Playwright input used `page.keyboard.type(prompt, { delay: 10 })`,
a real per-character keydown/keypress/keyup sequence, so an embedded
`\n` could fire the composer's Enter-submits handler early and cost
10ms/char on long prompts. Switched to `page.keyboard.insertText()`,
an atomic DOM input event.
Regression test: tests/unit/issue-13380-gemini-web-system-dropped.test.ts
Aligned tests/unit/gemini-web-multiturn-context-8371.test.ts's
single-turn-with-system-message case, which pinned the old dropped-
system behavior as intentional; added insertText mocks/assertions to
the existing Playwright-mocking test files.