mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-08-05 02:45:28 +00:00
Merge 1c2ebc064e into 20e7fc0164
This commit is contained in:
commit
c3133ea74d
3 changed files with 28 additions and 82 deletions
|
|
@ -3908,85 +3908,10 @@ function startOdysseusApp() {
|
||||||
const messageInput = el('message');
|
const messageInput = el('message');
|
||||||
const modelPickerWrap = document.getElementById('model-picker-wrap');
|
const modelPickerWrap = document.getElementById('model-picker-wrap');
|
||||||
|
|
||||||
function _readComposerPromptHistory() {
|
// ArrowUp/ArrowDown prompt recall on #message lives in
|
||||||
const chatBox = document.getElementById('chat-history');
|
// static/js/composerArrowUpRecall.js (wired from chat.js). Do not re-add a
|
||||||
if (!chatBox) return [];
|
// copy here: two capture-phase listeners on the same textarea meant the one
|
||||||
return Array.from(chatBox.querySelectorAll('.msg-user'))
|
// without the draft guard won and ate unsent multi-line prompts (#5862).
|
||||||
.reverse()
|
|
||||||
.map(msg => {
|
|
||||||
const body = msg.querySelector('.body');
|
|
||||||
return msg.dataset?.raw || (body ? body.textContent : '') || '';
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (messageInput && !messageInput._odysseusPromptRecallCapture) {
|
|
||||||
messageInput._odysseusPromptRecallCapture = true;
|
|
||||||
let recallHistory = [];
|
|
||||||
let recallIndex = -1;
|
|
||||||
let lastRecalled = '';
|
|
||||||
const norm = (v) => String(v || '').replace(/\r\n/g, '\n').trimEnd();
|
|
||||||
messageInput.addEventListener('input', () => {
|
|
||||||
if (norm(messageInput.value) === norm(lastRecalled)) return;
|
|
||||||
recallHistory = [];
|
|
||||||
recallIndex = -1;
|
|
||||||
lastRecalled = '';
|
|
||||||
try { delete messageInput.dataset.odysseusRecallIndex; } catch {}
|
|
||||||
}, true);
|
|
||||||
messageInput.addEventListener('keydown', (e) => {
|
|
||||||
if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') return;
|
|
||||||
if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.isComposing) return;
|
|
||||||
if (window._ghostAutocomplete?.isActive?.()) return;
|
|
||||||
const fresh = _readComposerPromptHistory();
|
|
||||||
const history = fresh.length ? fresh : recallHistory;
|
|
||||||
if (!history.length) return;
|
|
||||||
const current = norm(messageInput.value);
|
|
||||||
let currentIndex = current ? history.findIndex(item => norm(item) === current) : -1;
|
|
||||||
if (current && currentIndex < 0 && current === norm(lastRecalled)) currentIndex = recallIndex;
|
|
||||||
if (current && currentIndex < 0) {
|
|
||||||
const markedIndex = Number(messageInput.dataset.odysseusRecallIndex);
|
|
||||||
if (Number.isInteger(markedIndex) && markedIndex >= 0 && markedIndex < history.length) {
|
|
||||||
currentIndex = markedIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
if (e.key === 'ArrowDown') {
|
|
||||||
if (currentIndex < 0) return;
|
|
||||||
const nextIndex = currentIndex - 1;
|
|
||||||
if (nextIndex < 0) {
|
|
||||||
recallHistory = history;
|
|
||||||
recallIndex = -1;
|
|
||||||
lastRecalled = '';
|
|
||||||
try { delete messageInput.dataset.odysseusRecallIndex; } catch {}
|
|
||||||
messageInput.value = '';
|
|
||||||
try { messageInput.selectionStart = messageInput.selectionEnd = 0; } catch {}
|
|
||||||
try { uiModule.autoResize(messageInput); } catch {}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const recalled = history[nextIndex];
|
|
||||||
recallHistory = history;
|
|
||||||
recallIndex = nextIndex;
|
|
||||||
lastRecalled = recalled;
|
|
||||||
try { messageInput.dataset.odysseusRecallIndex = String(nextIndex); } catch {}
|
|
||||||
messageInput.value = recalled;
|
|
||||||
try { messageInput.selectionStart = messageInput.selectionEnd = recalled.length; } catch {}
|
|
||||||
try { uiModule.autoResize(messageInput); } catch {}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const nextIndex = currentIndex >= 0 ? Math.min(currentIndex + 1, history.length - 1) : 0;
|
|
||||||
const recalled = history[nextIndex];
|
|
||||||
if (!recalled) return;
|
|
||||||
recallHistory = history;
|
|
||||||
recallIndex = nextIndex;
|
|
||||||
lastRecalled = recalled;
|
|
||||||
try { messageInput.dataset.odysseusRecallIndex = String(nextIndex); } catch {}
|
|
||||||
messageInput.value = recalled;
|
|
||||||
try { messageInput.selectionStart = messageInput.selectionEnd = recalled.length; } catch {}
|
|
||||||
try { uiModule.autoResize(messageInput); } catch {}
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const _sendIcon = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19V5M5 12l7-7 7 7"/></svg>';
|
const _sendIcon = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19V5M5 12l7-7 7 7"/></svg>';
|
||||||
const _micIcon = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg>';
|
const _micIcon = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg>';
|
||||||
|
|
|
||||||
|
|
@ -143,9 +143,9 @@ export function wireArrowUpRecall(composer, getUserMessages, options = {}) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArrowUp owns prompt history in the chat composer. If the current text
|
// ArrowUp walks older prompts. An unmatched draft already returned above,
|
||||||
// is not already a recalled prompt, start from newest instead of letting
|
// so reaching here means the composer is empty or holds a recalled prompt
|
||||||
// the browser move the caret inside the textarea.
|
// — the caret-navigation case is never hijacked.
|
||||||
const nextIndex = currentIndex >= 0 ? Math.min(currentIndex + 1, history.length - 1) : 0;
|
const nextIndex = currentIndex >= 0 ? Math.min(currentIndex + 1, history.length - 1) : 0;
|
||||||
const recalled = history[nextIndex];
|
const recalled = history[nextIndex];
|
||||||
if (!recalled) {
|
if (!recalled) {
|
||||||
|
|
|
||||||
|
|
@ -306,3 +306,24 @@ def test_integration_recalls_from_chat_history_dom():
|
||||||
)
|
)
|
||||||
assert proc.returncode == 0, proc.stderr
|
assert proc.returncode == 0, proc.stderr
|
||||||
assert json.loads(proc.stdout.strip()) == {"value": "stored prompt", "prevented": True}
|
assert json.loads(proc.stdout.strip()) == {"value": "stored prompt", "prevented": True}
|
||||||
|
|
||||||
|
|
||||||
|
def test_prompt_recall_is_not_duplicated_in_app_js():
|
||||||
|
"""Only composerArrowUpRecall.js may own ArrowUp on #message (issue #5862).
|
||||||
|
|
||||||
|
static/app.js once carried a near-verbatim copy of this recall logic, wired
|
||||||
|
as a second capture-phase listener on the same textarea. That copy lacked
|
||||||
|
the draft guard here, and because it called stopImmediatePropagation it won
|
||||||
|
regardless of registration order — so a typed multi-line prompt was replaced
|
||||||
|
by the last sent one instead of the caret moving up a line.
|
||||||
|
"""
|
||||||
|
app_js = (_REPO / "static" / "app.js").read_text(encoding="utf-8")
|
||||||
|
for marker in (
|
||||||
|
"_odysseusPromptRecallCapture",
|
||||||
|
"_readComposerPromptHistory",
|
||||||
|
"odysseusRecallIndex",
|
||||||
|
):
|
||||||
|
assert marker not in app_js, (
|
||||||
|
f"static/app.js reintroduces prompt recall ({marker!r}); "
|
||||||
|
"it belongs to static/js/composerArrowUpRecall.js alone"
|
||||||
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue