Prevent IME Enter from submitting Duo Agentic Chat prompt

What does this MR do and why?

On macOS, in both Chrome and Safari, I saw a bug with a Japanese IME. Pressing Enter to confirm a kanji conversion in the web UI Duo Agentic Chat sent the unfinished message.

Root cause

This is the event order I saw in Chrome DevTools:

  1. The Enter keydown that confirms the conversion fires before the keyup of the last typed character.
  2. The keyup of the last character arrives.
  3. The Enter keyup fires. By now isComposing is already false.

The old code sent the message on Enter keyup. It set a flag (compositionJustEnded) on compositionend to skip the next Enter. But every keyup cleared that flag. The keyup of the last character (step 2) cleared it. So the Enter keyup (step 3) sent the message.

Fix

In prompt_textarea.vue, I now send on keydown instead. At keydown, isComposing is still true for the confirming Enter. The component skips sending when:

  • the key is not Enter
  • e.isComposing is true, or e.keyCode === 229. Key code 229 means the IME is handling the key. It is a fallback for browsers where isComposing can already be false. One example is Safari, when compositionend fires before keydown.
  • e.repeat is true (Enter is held down)
  • a modifier key is pressed (Shift+Enter still inserts a new line)

I also made these changes:

  • I removed the compositionJustEnded flag, the compositionend handler, and the resetComposition() method.
  • In prompt_composer.vue, I removed the resetComposition() call after a slash command is selected. It is no longer needed.
  • The slash commands menu still catches Enter on keydown in the capture phase and stops it. So picking a command with Enter does not send. Tests cover this.
  • In slash_commands_menu.vue, I updated the comment on swallowKeyup. It no longer stops a keyup-based send, but it still keeps the keyup from reaching evaluate(). Without it, the menu would reopen right after Escape closes it.
  • I updated the specs. In prompt_textarea_spec.js, I use keydown instead of keyup. I added cases for key code 229 and repeat, and a check that a later Enter still submits after an IME Enter is ignored. I removed the compositionend tests. In prompt_composer_spec.js, I changed keyup to keydown. The composition-flag test now checks that a later Enter can send after picking a slash command. In slash_commands_menu_spec.js, I added a check that the menu stays closed after the Escape keyup.

Scope

This changes only the web UI Duo Agentic Chat. The issue was first reported in the VS Code extension. I did not verify the fix there. The classic Duo Chat (ee/app/assets/javascripts/ai/tanuki_bot/components/duo_chat_view.vue) still uses the old keyup approach. I did not change it.

References

Screenshots or screen recordings

Before After

I tested this locally in GDK on macOS Chrome and macOS Safari with a Japanese IME. Before the fix, both sent the message on the confirming Enter. After the fix, neither does.

How to set up and validate locally

  1. Open Duo Agentic Chat in the web UI in GDK.
  2. Turn on a Japanese IME.
  3. Type hiragana and press Enter to confirm the kanji conversion. The message is not sent.
  4. Press Enter again. The message is sent once.
  5. Press Shift+Enter. A new line is inserted.
  6. Type /co and press Enter on a slash command. The command is inserted and nothing is sent.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

🤖 Generated with Claude Code

Edited by Toshihide Omori

Merge request reports

Loading
Loading