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 = `
${timeHtml}${editBtn}${ttsBtn}${forkBtn}${copyBtn}${retryBtn}${questionJumpBtn}
`; 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