diff --git a/static/i18n.js b/static/i18n.js index f7d6eeb430..efd0464321 100644 --- a/static/i18n.js +++ b/static/i18n.js @@ -172,8 +172,8 @@ const LOCALES = { session_jump_end_label: 'Jump to end of session', session_new_message: 'New message', session_new_message_label: 'New message available, jump to end', - jump_to_question: 'to question', - jump_to_question_label: 'Jump to the question for this response', + jump_to_question: 'to response', + jump_to_question_label: 'Jump to the start of this response', queued_label: 'Sends after response', queued_count: (n) => n === 1 ? '1 queued' : `${n} queued`, queued_cancel: 'Cancel queued message', @@ -1576,8 +1576,8 @@ const LOCALES = { session_jump_end_label: 'Vai alla fine della sessione', session_new_message: 'Nuovo messaggio', session_new_message_label: 'Nuovo messaggio disponibile, vai alla fine', - jump_to_question: 'alla domanda', - jump_to_question_label: 'Vai alla domanda di questa risposta', + jump_to_question: 'alla risposta', + jump_to_question_label: 'Vai all\'inizio di questa risposta', queued_label: 'Inviato dopo la risposta', queued_count: (n) => n === 1 ? '1 in coda' : `${n} in coda`, queued_cancel: 'Annulla messaggio in coda', @@ -2972,8 +2972,8 @@ const LOCALES = { session_jump_end_label: 'セッションの末尾へ移動', session_new_message: '新着メッセージ', session_new_message_label: '新着メッセージがあります。末尾へ移動', - jump_to_question: '質問へ', - jump_to_question_label: 'この回答の質問へ移動', + jump_to_question: '回答へ', + jump_to_question_label: 'この回答の先頭へ移動', queued_label: '応答後に送信', queued_count: (n) => `${n} 件キュー中`, queued_cancel: 'キューに入れたメッセージをキャンセル', @@ -4345,8 +4345,8 @@ const LOCALES = { session_jump_end_label: 'Перейти к концу сессии', session_new_message: 'Новое сообщение', session_new_message_label: 'Новое сообщение доступно, перейти к концу', - jump_to_question: 'к вопросу', - jump_to_question_label: 'Перейти к вопросу для этого ответа', + jump_to_question: 'к ответу', + jump_to_question_label: 'Перейти к началу этого ответа', queued_label: 'Отправить после ответа', queued_count: (n) => n === 1 ? '1 в очереди' : `${n} в очереди`, queued_cancel: 'Отменить сообщение', @@ -5686,8 +5686,8 @@ const LOCALES = { session_jump_end_label: 'Saltar al final de la sesión', session_new_message: 'Mensaje nuevo', session_new_message_label: 'Mensaje nuevo disponible, saltar al final', - jump_to_question: 'a la pregunta', - jump_to_question_label: 'Saltar a la pregunta de esta respuesta', + jump_to_question: 'a la respuesta', + jump_to_question_label: 'Saltar al inicio de esta respuesta', queued_label: 'Enviar después de la respuesta', queued_count: (n) => n === 1 ? '1 en cola' : `${n} en cola`, queued_cancel: 'Cancelar mensaje en cola', @@ -7018,8 +7018,8 @@ const LOCALES = { session_jump_end_label: 'Zum Ende der Sitzung springen', session_new_message: 'Neue Nachricht', session_new_message_label: 'Neue Nachricht verfügbar, zum Ende springen', - jump_to_question: 'zur Frage', - jump_to_question_label: 'Zur Frage dieser Antwort springen', + jump_to_question: 'zur Antwort', + jump_to_question_label: 'Zum Anfang dieser Antwort springen', queued_label: 'Wird nach Antwort gesendet', queued_count: (n) => n === 1 ? '1 in Warteschlange' : `${n} in Warteschlange`, queued_cancel: 'Nachricht abbrechen', @@ -8354,8 +8354,8 @@ const LOCALES = { session_jump_end_label: '跳转到会话结尾', session_new_message: '新消息', session_new_message_label: '有新消息,跳转到结尾', - jump_to_question: '回到问题', - jump_to_question_label: '跳转到这条回答对应的问题', + jump_to_question: '回到回答', + jump_to_question_label: '跳转到这条回答的开头', queued_label: '响应后发送', queued_count: (n) => n === 1 ? '1 条排队' : `${n} 条排队`, queued_cancel: '取消排队消息', @@ -9709,8 +9709,8 @@ const LOCALES = { session_jump_end_label: '跳至對話結尾', session_new_message: '新訊息', session_new_message_label: '有新訊息,跳至結尾', - jump_to_question: '回到問題', - jump_to_question_label: '跳至這則回答對應的問題', + jump_to_question: '回到回答', + jump_to_question_label: '跳至這則回答的開頭', queued_label: '回應後傳送', queued_count: (n) => n === 1 ? '1 已排隊' : `${n} 已排隊`, queued_cancel: '取消排隊訊息', @@ -11015,8 +11015,8 @@ const LOCALES = { session_jump_end_label: 'Ir para o fim da sessão', session_new_message: 'Nova mensagem', session_new_message_label: 'Nova mensagem disponível, ir para o fim', - jump_to_question: 'para a pergunta', - jump_to_question_label: 'Ir para a pergunta desta resposta', + jump_to_question: 'para a resposta', + jump_to_question_label: 'Ir para o início desta resposta', queued_label: 'Envia após a resposta', queued_count: (n) => n === 1 ? '1 na fila' : `${n} na fila`, queued_cancel: 'Cancelar mensagem na fila', @@ -12293,8 +12293,8 @@ const LOCALES = { session_jump_end_label: '세션 끝으로 이동', session_new_message: '새 메시지', session_new_message_label: '새 메시지가 있습니다, 끝으로 이동', - jump_to_question: '질문으로', - jump_to_question_label: '이 응답의 질문으로 이동', + jump_to_question: '응답으로', + jump_to_question_label: '이 응답의 시작으로 이동', queued_label: 'Sends after response', queued_count: (n) => n === 1 ? '1 queued' : `${n} queued`, queued_cancel: 'Cancel queued message', @@ -13695,8 +13695,8 @@ const LOCALES = { session_jump_end_label: 'Aller à la fin de la session', session_new_message: 'Nouveau message', session_new_message_label: 'Nouveau message disponible, aller à la fin', - jump_to_question: 'à la question', - jump_to_question_label: 'Aller à la question de cette réponse', + jump_to_question: 'à la réponse', + jump_to_question_label: 'Aller au début de cette réponse', queued_label: 'Envoie après réponse', queued_cancel: 'Annuler le message en file d\'attente', model_unavailable: '(indisponible)', @@ -15024,8 +15024,8 @@ const LOCALES = { session_jump_end_label: 'Oturumun sonuna atla', session_new_message: 'Yeni mesaj', session_new_message_label: 'Yeni mesaj mevcut, sona atla', - jump_to_question: 'sorgulamak', - jump_to_question_label: 'Bu yanıt için soruya geçin', + jump_to_question: 'yanıta', + jump_to_question_label: 'Bu yanıtın başına git', queued_label: 'Yanıttan sonra gönderilir', queued_count: (n) => n === 1 ? '1 queued' : `${n} queued`, queued_cancel: 'Sıraya alınmış mesajı iptal et', @@ -16421,8 +16421,8 @@ const LOCALES = { session_jump_end_label: 'Przejdź do końca sesji', session_new_message: 'Nowa wiadomość', session_new_message_label: 'Dostępna nowa wiadomość, przejdź do końca', - jump_to_question: 'do pytania', - jump_to_question_label: 'Przejdź do pytania dotyczącego tej odpowiedzi', + jump_to_question: 'do odpowiedzi', + jump_to_question_label: 'Przejdź do początku tej odpowiedzi', queued_label: 'Zostanie wysłane po odpowiedzi', queued_count: (n) => n === 1 ? '1 w kolejce' : `${n} w kolejce`, queued_cancel: 'Anuluj wiadomości w kolejce', diff --git a/static/ui.js b/static/ui.js index 378e2016b8..b2827bb9b9 100644 --- a/static/ui.js +++ b/static/ui.js @@ -484,11 +484,12 @@ function _userMessageDomId(rawIdx){ return `msg-user-${rawIdx}`; } -function _questionJumpButtonHtml(questionRawIdx){ +function _questionJumpButtonHtml(questionRawIdx, assistantRawIdx){ if(typeof questionRawIdx!=='number'||questionRawIdx<0) return ''; - const label=t('jump_to_question')||'Question'; - const title=t('jump_to_question_label')||'Jump to the question for this response'; - return ``; + const label=t('jump_to_question')||'Response'; + const title=t('jump_to_question_label')||'Jump to the start of this response'; + const aIdx=(typeof assistantRawIdx==='number'&&assistantRawIdx>=0)?assistantRawIdx:-1; + return ``; } function _highlightQuestionRow(row){ @@ -499,10 +500,13 @@ function _highlightQuestionRow(row){ window.setTimeout(()=>row.classList.remove('msg-question-highlight'),1800); } -async function jumpToTurnQuestion(questionRawIdx){ +async function jumpToTurnQuestion(questionRawIdx, assistantRawIdx){ const container=$('messages'); if(!container||typeof questionRawIdx!=='number'||questionRawIdx<0) return; const scrollToTarget=()=>{ + const hasAssistant=typeof assistantRawIdx==='number'&&assistantRawIdx>=0; + const seg=hasAssistant?container.querySelector('[data-msg-idx="'+assistantRawIdx+'"]'):null; + if(seg){seg.scrollIntoView({block:'start',behavior:'smooth'});return true;} const row=document.getElementById(_userMessageDomId(questionRawIdx)); if(!row) return false; row.scrollIntoView({block:'center',behavior:'smooth'}); @@ -8162,6 +8166,10 @@ function renderMessages(options){ if(role==='user') lastQuestionRawIdx=entry.rawIdx; else if(role==='assistant') questionRawIdxByAssistantRawIdx.set(entry.rawIdx,lastQuestionRawIdx); } + const assistantRawIdxByQuestionRawIdx=new Map(); + for(const [aIdx,qIdx] of questionRawIdxByAssistantRawIdx){ + if(!assistantRawIdxByQuestionRawIdx.has(qIdx)) assistantRawIdxByQuestionRawIdx.set(qIdx,aIdx); + } // #3709 (defect B): build a per-turn combined visible-answer text so the // thinking echo-strip can de-dupe a thinking-only message (whose own visible // body is empty) against the answer prose carried by a SIBLING message in the @@ -8316,7 +8324,7 @@ function renderMessages(options){ // user loses the navigation affordance. const _qJumpTarget=(!isUser&&!m._live)?questionRawIdxByAssistantRawIdx.get(rawIdx):undefined; const questionJumpBtn = (_qJumpTarget!==undefined&&_qJumpTarget!==null) - ? _questionJumpButtonHtml(_qJumpTarget) + ? _questionJumpButtonHtml(_qJumpTarget, assistantRawIdxByQuestionRawIdx.get(_qJumpTarget)??rawIdx) : ''; const footHtml = `