${escapeHtml(reminder.title)}
${escapeHtml(reminder.status)}
${escapeHtml(reminder.note)}
` : ""}
${reminder.completed ? "" : ``}
${reminder.completed ? "" : ``}
const state = { sessionId: null, sessions: [], messages: [], reminders: [], editingReminderId: null, }; const DEFAULT_API_BASE = "http://127.0.0.1:8000"; let apiBase = window.location.protocol === "file:" ? DEFAULT_API_BASE : ""; const WELCOME_HTML = `
$1");
html = html.replace(/^- (.*)$/gm, "${escapeHtml(content)}`;
if (sideHelperContent) {
sideHelperContent.textContent = `${title}\n\n${content}`;
}
setActiveTab("focus");
}
function placePrompt(prompt, autoSend = false) {
messageInput.value = prompt;
autoResize();
messageInput.focus();
messageInput.setSelectionRange(prompt.length, prompt.length);
if (autoSend && prompt.trim()) chatForm.requestSubmit();
}
function ensureWelcomeState() {
const existing = document.getElementById("welcomeState");
if (existing) return existing;
const node = document.createElement("div");
node.id = "welcomeState";
node.className = "welcome-state";
node.innerHTML = WELCOME_HTML;
chatMessages.appendChild(node);
bindPromptButtons();
return node;
}
function addMessage(message, saveable = true) {
const currentWelcome = document.getElementById("welcomeState");
if (currentWelcome) currentWelcome.style.display = "none";
const node = messageTemplate.content.firstElementChild.cloneNode(true);
node.classList.add(message.role);
const avatar = node.querySelector(".msg-avatar");
avatar.classList.add(message.role === "user" ? "user" : "ai");
avatar.textContent = message.role === "user" ? "U" : "AI";
const bubble = node.querySelector(".bubble");
bubble.innerHTML = renderMarkdown(message.content);
const actions = node.querySelector(".message-actions");
if (message.role === "assistant") {
const copyBtn = document.createElement("button");
copyBtn.className = "msg-action-btn";
copyBtn.innerHTML = ` Copy`;
copyBtn.addEventListener("click", async () => {
await navigator.clipboard.writeText(message.content);
copyBtn.textContent = "Saved";
setTimeout(() => {
copyBtn.innerHTML = ` Copy`;
}, 1500);
});
actions.appendChild(copyBtn);
}
if (saveable && Number.isInteger(message.id) && state.sessionId) {
const saveBtn = document.createElement("button");
saveBtn.className = "msg-action-btn";
saveBtn.innerHTML = ` Save`;
saveBtn.addEventListener("click", async () => {
await api(`/api/history/sessions/${state.sessionId}/messages/${message.id}/save`, { method: "POST" });
saveBtn.textContent = "Saved";
});
actions.appendChild(saveBtn);
}
chatMessages.appendChild(node);
scrollToBottom();
}
function renderMessages(messages) {
chatMessages.innerHTML = "";
if (!messages.length) {
ensureWelcomeState().style.display = "flex";
return;
}
messages.forEach(message => addMessage(message));
}
function typingBubble() {
const currentWelcome = document.getElementById("welcomeState");
if (currentWelcome) currentWelcome.style.display = "none";
const node = messageTemplate.content.firstElementChild.cloneNode(true);
node.classList.add("assistant", "typing");
const avatar = node.querySelector(".msg-avatar");
avatar.classList.add("ai");
avatar.textContent = "AI";
const bubble = node.querySelector(".bubble");
bubble.innerHTML = `