Please choose one option, or type your own response below.
`;
host.appendChild(card);
const submit = $("clarifySubmit");
if (submit) submit.onclick = () => respondClarify();
if (typeof applyLocaleToDOM === "function") applyLocaleToDOM();
return card;
}
function _clearClarifyHideTimer() {
if (_clarifyHideTimer) {
clearTimeout(_clarifyHideTimer);
_clarifyHideTimer = null;
}
}
function _resetClarifyCardState() {
_clearClarifyHideTimer();
_clarifyVisibleSince = 0;
_clarifySignature = '';
}
function hideClarifyCard(force=false) {
const card = $("clarifyCard");
if (!card) {
_clarifySessionId = null;
_resetClarifyCardState();
if (typeof unlockComposerForClarify === "function") unlockComposerForClarify();
return;
}
if (!force && _clarifyVisibleSince) {
const remaining = CLARIFY_MIN_VISIBLE_MS - (Date.now() - _clarifyVisibleSince);
if (remaining > 0) {
const scheduledSignature = _clarifySignature;
_clearClarifyHideTimer();
_clarifyHideTimer = setTimeout(() => {
_clarifyHideTimer = null;
if (_clarifySignature !== scheduledSignature) return;
hideClarifyCard(true);
}, remaining);
return;
}
}
_clarifySessionId = null;
_resetClarifyCardState();
card.classList.remove("visible");
if (typeof unlockComposerForClarify === "function") unlockComposerForClarify();
$("clarifyQuestion").textContent = "";
$("clarifyChoices").innerHTML = "";
$("clarifyInput").value = "";
$("clarifyInput").disabled = false;
$("clarifyInput").onkeydown = null;
const submit = $("clarifySubmit");
if (submit) { submit.disabled = false; submit.classList.remove("loading"); }
}
function _clarifySetControlsDisabled(disabled, loading=false) {
const input = $("clarifyInput");
const submit = $("clarifySubmit");
if (input) input.disabled = disabled;
if (submit) {
submit.disabled = disabled;
submit.classList.toggle("loading", !!loading);
}
const choices = $("clarifyChoices");
if (choices) {
choices.querySelectorAll("button").forEach(btn => {
btn.disabled = disabled;
if (loading && btn.dataset && btn.dataset.choice === "other") {
btn.classList.toggle("loading", false);
}
});
}
}
function showClarifyCard(pending) {
const question = pending.question || pending.description || '';
const choices = Array.isArray(pending.choices_offered)
? pending.choices_offered
: (Array.isArray(pending.choices) ? pending.choices : []);
const sig = JSON.stringify({
question,
choices,
sid: pending._session_id || (S.session && S.session.session_id) || null,
});
const card = _ensureClarifyCardDom();
if (!card) return;
const questionEl = $("clarifyQuestion");
const choicesEl = $("clarifyChoices");
const input = $("clarifyInput");
const sameClarify = card.classList.contains("visible") && _clarifySignature === sig;
_clarifySessionId = pending._session_id || (S.session && S.session.session_id) || null;
_clarifySignature = sig;
if (!sameClarify) {
_clarifyVisibleSince = Date.now();
_clearClarifyHideTimer();
}
if (questionEl) questionEl.textContent = question;
if (choicesEl) {
choicesEl.innerHTML = '';
choicesEl.style.display = choices.length ? '' : 'none';
if (choices.length) {
choices.forEach((choice, idx) => {
const btn = document.createElement('button');
btn.type = 'button';
btn.className = 'clarify-choice';
btn.dataset.choice = choice;
btn.onclick = () => respondClarify(choice);
const badge = document.createElement('span');
badge.className = 'clarify-choice-badge';
badge.textContent = String(idx + 1);
const text = document.createElement('span');
text.className = 'clarify-choice-text';
text.textContent = choice;
btn.appendChild(badge);
btn.appendChild(text);
choicesEl.appendChild(btn);
});
const other = document.createElement('button');
other.type = 'button';
other.className = 'clarify-choice other';
other.dataset.choice = 'other';
other.setAttribute('data-i18n', 'clarify_other');
const otherBadge = document.createElement('span');
otherBadge.className = 'clarify-choice-badge other';
otherBadge.textContent = '•';
const otherText = document.createElement('span');
otherText.className = 'clarify-choice-text';
otherText.textContent = t('clarify_other') || 'Other';
other.appendChild(otherBadge);
other.appendChild(otherText);
other.onclick = () => {
const el = $("clarifyInput");
if (el) {
el.focus();
if (typeof el.select === 'function') el.select();
}
};
choicesEl.appendChild(other);
}
}
if (input) {
if (!sameClarify) input.value = '';
input.disabled = false;
input.onkeydown = (e) => {
if (e.key === 'Enter') {
e.preventDefault();
respondClarify();
}
};
}
if (typeof lockComposerForClarify === "function") {
lockComposerForClarify(question ? `Clarification needed: ${question}` : "Clarification needed");
}
_clarifySetControlsDisabled(false, false);
card.classList.add("visible");
if (typeof applyLocaleToDOM === "function") applyLocaleToDOM();
if (input && !sameClarify) setTimeout(() => input.focus({preventScroll: true}), 50);
}
async function respondClarify(response) {
const sid = _clarifySessionId || (S.session && S.session.session_id);
if (!sid) return;
const input = $("clarifyInput");
let value = typeof response === 'string' ? response : (input ? input.value : '');
value = String(value || '').trim();
if (!value) {
if (input) input.focus();
return;
}
_clarifySessionId = null;
_clarifySetControlsDisabled(true, true);
hideClarifyCard(true);
try {
await api("/api/clarify/respond", {
method: "POST",
body: JSON.stringify({ session_id: sid, response: value })
});
} catch(e) { setStatus(t("clarify_responding") + " " + e.message); }
}
function startClarifyPolling(sid) {
stopClarifyPolling();
_clarifyMissingEndpointWarned = false;
_clarifyPollTimer = setInterval(async () => {
if (!S.session || S.session.session_id !== sid) {
stopClarifyPolling(); hideClarifyCard(true); return;
}
try {
const data = await api("/api/clarify/pending?session_id=" + encodeURIComponent(sid));
if (data.pending) { data.pending._session_id=sid; showClarifyCard(data.pending); }
else { hideClarifyCard(); }
} catch(e) {
const msg = String((e && e.message) || "");
if (!_clarifyMissingEndpointWarned && /(^|\b)(404|not found)(\b|$)/i.test(msg)) {
_clarifyMissingEndpointWarned = true;
setComposerStatus("Clarify unavailable on current server build. Restart server.");
if (typeof showToast === "function") {
showToast("Clarify endpoint unavailable. Please restart server.", 5000);
}
stopClarifyPolling();
}
// Ignore transient poll errors; SSE clarify event still provides a fast path.
}
}, 1500);
}
function stopClarifyPolling() {
if (_clarifyPollTimer) { clearInterval(_clarifyPollTimer); _clarifyPollTimer = null; }
}
// ── Notifications and Sound ──────────────────────────────────────────────────
function playNotificationSound(){
if(!window._soundEnabled) return;
try{
const ctx=new (window.AudioContext||window.webkitAudioContext)();
const osc=ctx.createOscillator();
const gain=ctx.createGain();
osc.connect(gain);gain.connect(ctx.destination);
osc.type='sine';osc.frequency.setValueAtTime(660,ctx.currentTime);
osc.frequency.setValueAtTime(880,ctx.currentTime+0.1);
gain.gain.setValueAtTime(0.3,ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01,ctx.currentTime+0.3);
osc.start(ctx.currentTime);osc.stop(ctx.currentTime+0.3);
osc.onended=()=>ctx.close();
}catch(e){console.warn('Notification sound failed:',e);}
}
function sendBrowserNotification(title,body){
if(!window._notificationsEnabled||!document.hidden) return;
if(!('Notification' in window)) return;
const botName=window._botName||'Hermes';
if(Notification.permission==='granted'){
new Notification(title||botName,{body:body});
}else if(Notification.permission!=='denied'){
Notification.requestPermission().then(p=>{
if(p==='granted') new Notification(title||botName,{body:body});
});
}
}
// ── Panel navigation (Chat / Tasks / Skills / Memory) ──