PR 310 review, round two

rancher-ai-ui PR 310 (torchiaf, “Stop message”, fixes issue 246), re-reviewed on 2026-10-26 at head 320d519 (round one was 5a6dc90 on 2026-10-15). Since then: the backend (rancher-ai-agent PR 419) merged, the stop reason became message-manual-stop, colours moved from --active-nav to --active, and the description was filled in. Nothing posted to GitHub yet.

Preview: https://rancheraipr310stopr.mf-created-dashboard.ui.rancher.space/dashboard/, built from 320d519, backend 13.62 (Rancher v2.15.1 with the merged stop agent, Gemini)

What's missing: two should-fixes from round one, plus two questions

Test it yourself

The PR preview talks to 13.62, which runs the merged agent. Log in as admin with the 13.62 password. Its Gemini is out of quota (429 after ~35 s), so answers never arrive, but Stop works during that wait.

  1. Open Ask Liz, send any long question, and click Stop within 30 s: Send comes back and “You stopped the previous response.” appears.
  2. Send a question, then a second one while the first runs: the first closes without a notice (card 3).
  3. ☰ → New chat, then reopen the stopped chat from history: compare the notice with the live one (card 4).
  4. For the Send-only console before this PR, open the shared main preview (its backend is the mf Rancher's older agent).
Round-one findings on 320d519
Round oneWhat changedChecked now
1. Stop during <think> leaks the stop JSON, no noticeUnchanged (stop check still at :684, after the thinking branch at :620)Still there. Unit test fails on 320d519; replayed in the preview, the thinking ends with {“reason”: “message-manual-stop”} (card 1)
2. icon-stop blank on Rancher 2.13–2.15UnchangedStill there. Missing in every 2.13–2.15 dashboard build, pinned (v2.13.0 … v2.15.1) and floating (release-2.13/14/15). 13.62 shows it only because it loads dashboard/latest (card 2)
3a. e2e needs the agent with stop supportrancher-ai-agent PR 419 merged 2026-10-16Done. CI on 320d519 green with agent chart v1.2.0-alpha.2; all 3 stop specs pass
3b. “Stop when a new message is sent” passes without any stop; ~1.3 s windowUnchangedStill applies: it passed in the earlier run against an agent that ignores stop (card 5)
4. Hard-coded English history notice, looks different from the live oneUnchangedStill applies. The design also gives the notice a timestamp, which the live one lacks (card 4)
5. No aria-label on Stop; no unit testsUnchanged (no new unit tests)Still applies (card 6)
6. Turn stopped during thinking reloads with the thinking as the answerUnchanged (agent still stores the raw partial text)Still open (card 7)
7. Nits: inverted comment, 34 px Stop next to 32 px SendButtons now share one 32 px ruleWidth fixed; comment still inverted (card 8)
8. Empty description, shell bump not explainedDescription now links issue 246, explains the bump, has two videosDone
Live checks on 320d519 (preview → 13.62, merged agent)
CaseResult
Stop while the agent is working (13.62, merged agent)One stop frame, agent answers message-manual-stop + </message>, Send comes back, notice “You stopped the previous response.”
Reload that chat from historyUser message + notice come back (notice without the period, with a timestamp)
Send a new message while one runsAgent answers new-request, old turn closed without a notice, new turn starts (here it hit Gemini’s 429)
Stop when nothing runsAgent ignores it
Stop mid-textNot testable on 13.62: Gemini returns 429 (quota), so no text streams. Verified in round 1 on the PR 419 code with llm-mock
Colour rename --active-nav → --active--active is defined on 2.13.0, 2.14.0, 2.15.0, 2.15.1 (light + dark) and 2.16 head, so it is safe on every supported Rancher
Console while the agent works: Stop buttonSecond message sent while the first runs
1

Stopping while Liz is still thinking leaks the stop JSON and skips the notice (from round 1, still there)

useChatMessageComposable.ts:684 (stop check) vs :620 (thinking branch)
Should fix

When the run is cancelled inside <think>, the agent never sends </think>, so the stop frame goes to the thinking branch and is appended to the thinking text. stopType stays unset, so no “You stopped” notice. Moving the stop check above the thinking branch fixes it: my unit test fails on 320d519 and passes with the move; all 78 composable tests pass, lint clean.

Screenshot: the 320d519 preview, with the agent's frames for this case replayed in the browser (13.62's Gemini doesn't emit <think>; reasoning models such as llm-mock's or Ollama's do).

Thinking text ends with the stop JSON, no notice
2

The Stop button is an empty square on Rancher 2.13–2.15 (from round 1, still there)

Console.vue:334 · pkg/rancher-ai-ui/package.json (rancher-version >= 2.13.0)
Should fix

icon-stop only exists in @rancher/icons 2.0.65, and an installed extension uses the host's icon font. I loaded every 2.13–2.15 dashboard build: v2.13.0, v2.14.0, v2.15.0, v2.15.1 and the floating release-2.13, release-2.14, release-2.15. None has the glyph; only dashboard/latest does. 13.62 shows the icon only because its dashboard is served from releases.rancher.com/dashboard/latest/, so it isn't a fair check.

v2.15.1 dashboard: icon-stop emptylatest dashboard: icon-stop present

A small CSS square or an inline SVG would work everywhere.

3

The design says “type, but you can’t send until you press Stop”; the PR sends and cuts the answer off

Console.vue:135 (Enter sends while a response runs) · issue 246 design comment
Question

From the design comment on issue 246 (oboc-sts, 2026-10-09): “Whilst Liz is responding, we change the send button into a Stop button. You can still use the prompt area to write something new, but you can't send it yet, you need to press the stop button first.”

The PR does the opposite on purpose (its description lists “the user sends a new message” as a stop trigger): Enter during a response sends the message, the agent replies new-request and drops the old answer without a notice. Checked live on 13.62. Which one do UX and the author want? If it's the design, Enter should do nothing while Stop is shown, and the “stop when a new message is sent” spec goes away.

4

The stop notice doesn’t match the design, live or after a reload

format.ts:454 (hard-coded history string) · useChatMessageComposable.ts notifyManualStopMessage
Suggestion

The design shows “You stopped the previous response.” in a regular Liz bubble with a timestamp. Live, the PR's notice has the period but no timestamp. After a reload it's the hard-coded English 'You stopped the previous response' (not translatable, no period) with a timestamp. Reusing ai.message.system.manualStopMessage.info in buildMessageFromHistoryMessage, and giving both the same look, would line all three up.

Design: notice with period and timestampPR live on 13.62: period, no timestampPR after history reload: no period, timestamp
5

The “stop when a new message is sent” spec can’t fail

cypress/e2e/tests/features/console/console-actions.spec.ts:178
Suggestion

should('not.contain.text', 'long response') passes straight away while the text is still streaming, then isCompleted() waits for the full answer. Proof: it passed in the 2026-10-15 run against agent v1.2.0-alpha.1, which can't stop. Waiting for message 3 to complete first would make it fail when nothing stops. The mock streams 100 ms per chunk, so the stop specs have ~1.3 s to reach the Stop click; more chunks would give CI slack. (If card 3 goes the design's way, this spec goes anyway.)

6

Stop has no accessible name, and the new logic has no unit tests

Console.vue:326–335 · composables/__tests__
Suggestion
  • Icon-only button with no aria-label or tooltip, so a screen reader says only “button”. (Send has the same gap on main; only Stop is new here.)
  • Nothing covers formatStopMessage, the stop-frame handling, isResponsePending or the history patch. The test from card 1 fits the existing “WebSocket message handling” section.
7

planning-manual-stop isn’t handled, and issue 246 asks to stop “the related plan”

useChatMessageComposable.ts:546 · format.ts:452 · agent websocket.py (planning stop)
Question

The merged agent sends planning-manual-stop when you stop a run that has a plan in progress, and also when a stop arrives while a plan waits for approval or for an answer. The PR only knows message-manual-stop, so a plan stop shows no notice and leaves nothing in history (the empty marker row is filtered out). Planning is enabled on 13.62. The plan UI itself is in PR 292: is the plan stop meant to land there, or here?

Related, from round 1: a turn stopped during thinking reloads with the thinking text shown as the answer, because the agent stores <think>… without the closing tag. That needs either the agent to close it or the UI to accept an unclosed <think>.

8

Inverted comment

Console.vue:101
Nit

“Return true if there is no incomplete assistant message…”: it returns true when there is one.

What else was checked
CheckResult
CI on 320d519All green: lint, unit-test, i18n, e2e (stop specs 3/3 on agent chart v1.2.0-alpha.2)
BackendAgent PR 419 merged; read its stop paths on main (a3e6334): message-manual-stop, planning-manual-stop, new-request
Unit testThinking case fails on 320d519, passes with the card 1 move; 78/78 composable tests, lint clean
DesignCompared with the issue 246 design comment and its two mock-ups
ScopeOnly what the PR adds or changes vs current main. The toggle-history shortcut change (Shift S → Shift H) is already on main, so it is out of scope
Suggested review (Comment): short body, the points inline
Preview: https://rancheraipr310stopr.mf-created-dashboard.ui.rancher.space/dashboard/, built from 320d519, backend Rancher v2.15.1 with the merged stop agent

Thanks for the updates, the stop flow works well against the merged agent: Stop, sending while it runs and the history reload all behave as described. A few things inline, two of them still from my first pass.

Inline comments

  • useChatMessageComposable.ts:684: [screenshot] If you stop while the response is still in <think>, the agent never sends </think>, so the stop frame lands in the thinking branch above: the thinking ends with {"reason": "message-manual-stop"} and the notice doesn't show. Moving this check above the thinking branch fixes it; I tried it with a unit test.
  • Console.vue:334: [screenshot] icon-stop only exists in the latest icons release, and an installed extension uses the host's icon font. Every 2.13–2.15 dashboard build I loaded (pinned and release-2.x) renders an empty square here, and the extension supports 2.13+. A CSS square or an inline SVG would work everywhere.
  • Console.vue:135: The design on the issue says you can type while Liz responds but can't send until you press Stop. Here Enter sends and cuts the answer off. Which one do we want? cc oboc-sts
  • useChatMessageComposable.ts:546: The agent also sends planning-manual-stop (stopping a running or waiting plan), and the issue asks to stop the related plan too. Right now that shows no notice. Is it planned for the planning PR?
  • format.ts:454: [screenshot] Could this reuse ai.message.system.manualStopMessage.info and the same look as the live notice? After a reload it's untranslated, loses the period and looks different. The design also gives the notice a timestamp.
  • console-actions.spec.ts:178: This assertion passes straight away while the text is still streaming, so the spec passed even against an agent that can't stop. Waiting for message 3 to complete before it would catch a missing stop.
  • Console.vue:326: Could Stop get an aria-label/tooltip (e.g. “Stop response”)? It's icon-only.