diff --git a/static/ui.js b/static/ui.js
index d209e151..66004f9b 100644
--- a/static/ui.js
+++ b/static/ui.js
@@ -6494,8 +6494,14 @@ function renderMessages(options){
const tsTitle=tsVal?(_fmtSv?_fmtSv(new Date(tsVal*1000),{}):new Date(tsVal*1000).toLocaleString()):'';
const tsTime=_formatMessageFooterTimestamp(tsVal);
const timeHtml = tsTime ? `${tsTime}` : '';
- const questionJumpBtn = (!isUser&&!m._live&&isTurnFinalAssistant)
- ? _questionJumpButtonHtml(questionRawIdxByAssistantRawIdx.get(rawIdx))
+ // #3114: show jump-to-question on every assistant message that has a
+ // resolvable question target, not just the turn-final one. Multi-step
+ // turns (tool_call -> assistant -> tool_call -> assistant) otherwise
+ // strip the button from every intermediate assistant bubble and the
+ // user loses the navigation affordance.
+ const _qJumpTarget=(!isUser&&!m._live)?questionRawIdxByAssistantRawIdx.get(rawIdx):undefined;
+ const questionJumpBtn = (_qJumpTarget!==undefined&&_qJumpTarget!==null)
+ ? _questionJumpButtonHtml(_qJumpTarget)
: '';
const footHtml = `
`;
diff --git a/tests/test_issue2246_question_jump.py b/tests/test_issue2246_question_jump.py
index e06ce874..c4f81460 100644
--- a/tests/test_issue2246_question_jump.py
+++ b/tests/test_issue2246_question_jump.py
@@ -15,8 +15,14 @@ def test_assistant_footer_gets_completed_turn_question_jump_button():
assert "questionRawIdxByAssistantRawIdx.set(entry.rawIdx,lastQuestionRawIdx)" in UI_JS
assert "row.id=_userMessageDomId(rawIdx)" in UI_JS
assert "const isTurnFinalAssistant=!isUser&&(!nextRendered||!nextRendered.m||nextRendered.m.role!=='assistant')" in UI_JS
- assert "(!isUser&&!m._live&&isTurnFinalAssistant)" in UI_JS
- assert "_questionJumpButtonHtml(questionRawIdxByAssistantRawIdx.get(rawIdx))" in UI_JS
+ # #3114 superseded the turn-final-only gate: the jump-to-question button now
+ # renders on every assistant message that has a resolvable question target,
+ # not just the turn-final one (multi-step turns otherwise lost the affordance
+ # on intermediate assistant bubbles). The button is gated on a non-null
+ # resolved target instead of isTurnFinalAssistant.
+ assert "const _qJumpTarget=(!isUser&&!m._live)?questionRawIdxByAssistantRawIdx.get(rawIdx):undefined;" in UI_JS
+ assert "const questionJumpBtn = (_qJumpTarget!==undefined&&_qJumpTarget!==null)" in UI_JS
+ assert "_questionJumpButtonHtml(_qJumpTarget)" in UI_JS
assert "msg-question-jump-btn" in UI_JS