improve reasoning toggle tests and refactor model capability checks
This commit is contained in:
@@ -196,7 +196,12 @@
|
||||
<div class="input-meta">
|
||||
<p class="composer-hint">Enter to send · Shift+Enter for new line</p>
|
||||
</div>
|
||||
<div id="uploadPreviews" class="upload-previews" aria-live="polite" hidden></div>
|
||||
<div class="input-container">
|
||||
<input id="imagePicker" type="file" accept="image/png,image/jpeg,image/webp" multiple hidden>
|
||||
<button id="attachImage" class="icon-button" type="button" aria-label="Attach image" title="Attach image">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="3"/><circle cx="8" cy="8" r="1.5"/><path d="m3 17 5-5 4 4 4-6 5 7"/></svg>
|
||||
</button>
|
||||
<button id="webSearch" class="icon-button" type="button" aria-label="Search the web" title="Search the web" aria-pressed="false">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="9"/><ellipse cx="12" cy="12" rx="4" ry="9"/><path d="M3 12h18"/></svg>
|
||||
</button>
|
||||
|
||||
+15
-6
@@ -1,5 +1,6 @@
|
||||
import {del, get, post, put, stream} from "./app/api.js?v=20260909-account-controls";
|
||||
import {appendSources, createWebSearchToggle} from "./app/webSearch.js";
|
||||
import {appendAttachments, createAttachmentComposer} from "./app/attachments.js";
|
||||
import {createReasoningToggle, finishReasoning, updateReasoning} from "./app/reasoning.js?v=20260921-reasoning-capability";
|
||||
import {closeChatDrawer, openChatDrawer} from "./app/chatDrawer.js?v=20260909-account-controls";
|
||||
import {onboardingPrompts, requestedChatId} from "./app/constants.js?v=20260909-account-controls";
|
||||
@@ -109,6 +110,7 @@ const webSearchToggle = createWebSearchToggle(webSearchButton);
|
||||
const reasoningToggle = createReasoningToggle(document.getElementById("reasoning"));
|
||||
|
||||
let isProcessing = false, activeChatId = null, editingPersonaId = null, editingPersonaType = "assistant", currentUsername = "";
|
||||
const attachmentComposer = createAttachmentComposer({onChange: updateSendState, onError: message => setNotice(message, "error")});
|
||||
let chatSessions = [], currentMessages = [], assistantPersonas = [], userPersonas = [];
|
||||
let activeUserPersonaId = null, currentSummary = null, publishedPersonaIds = new Set();
|
||||
let popupResolver = null, popupMode = null, popupLastFocus = null;
|
||||
@@ -329,7 +331,7 @@ function updateComposerPlaceholder() {
|
||||
|
||||
function updateSendState() {
|
||||
const hasText = Boolean(msgInput.value.trim());
|
||||
sendBtn.disabled = isProcessing ? false : !hasText;
|
||||
sendBtn.disabled = isProcessing ? false : attachmentComposer.pending || (!hasText && !attachmentComposer.attachments.length);
|
||||
sendBtn.setAttribute("aria-label", isProcessing ? "Stop generation" : "Send message");
|
||||
}
|
||||
|
||||
@@ -742,7 +744,9 @@ function addMessage(contentOrMessage, isUser = false, isLoading = false, options
|
||||
actions.append(prevBtn, indexBadge, nextBtn);
|
||||
}
|
||||
|
||||
msgDiv.append(header, body);
|
||||
msgDiv.append(header);
|
||||
appendAttachments(msgDiv, message.attachments);
|
||||
msgDiv.append(body);
|
||||
if (!isMessageUser) updateReasoning(msgDiv, message.thinking);
|
||||
if (!isMessageUser) appendSources(msgDiv, message.sources);
|
||||
if (message.deliveryStatus === "failed" && message.errorMessage) {
|
||||
@@ -1364,6 +1368,7 @@ function setLoadingState(loading, overlayOptions = null) {
|
||||
msgInput.disabled = loading;
|
||||
webSearchButton.disabled = loading;
|
||||
reasoningToggle.setBusy(loading);
|
||||
attachmentComposer.setBusy(loading);
|
||||
sendBtn.classList.toggle("loading", loading);
|
||||
messagesDiv.querySelectorAll('[data-message-action="regenerate"]').forEach((button) => {
|
||||
button.disabled = loading || button.dataset.retryLimitReached === "true";
|
||||
@@ -1811,7 +1816,9 @@ async function checkSession() {
|
||||
|
||||
async function sendMessage() {
|
||||
if (isProcessing) return;
|
||||
const message = msgInput.value.trim();
|
||||
if (attachmentComposer.pending) return;
|
||||
const attachments = attachmentComposer.attachments;
|
||||
const message = msgInput.value.trim() || (attachments.length ? "Describe the attached images." : "");
|
||||
if (!message) return;
|
||||
const webSearch = webSearchToggle.enabled;
|
||||
const reasoning = reasoningToggle.enabled;
|
||||
@@ -1821,7 +1828,8 @@ async function sendMessage() {
|
||||
const autoTitle = message.length > 40 ? `${message.slice(0, 40)}...` : message;
|
||||
currentChat.title = autoTitle; updateWorkspaceCopy(); renderChatList(); await put(`/chats/${activeChatId}`, {title: autoTitle});
|
||||
}
|
||||
currentMessages.push({role: "user", content: message}); addMessage(message, true); updateChatActionState();
|
||||
const userMessage = {role: "user", content: message, attachments};
|
||||
currentMessages.push(userMessage); addMessage(userMessage, true); updateChatActionState();
|
||||
msgInput.value = "";
|
||||
resizeComposerInput();
|
||||
setLoadingState(true, false); setNotice("Generating reply...");
|
||||
@@ -1832,14 +1840,15 @@ async function sendMessage() {
|
||||
loadingLabel.textContent = "Preparing response...";
|
||||
try {
|
||||
let streamError = null;
|
||||
await stream("/chat/stream", {message, model: modelSelect.value, chatId: activeChatId, webSearch, reasoning}, {
|
||||
await stream("/chat/stream", {message, attachments: attachments.map(item => item.id), model: modelSelect.value, chatId: activeChatId, webSearch, reasoning}, {
|
||||
onStatus: ({status, sourceCount, searchState}) => {
|
||||
if (status === "accepted") {
|
||||
attachmentComposer.clear();
|
||||
webSearchToggle.reset();
|
||||
reasoningToggle.reset();
|
||||
return;
|
||||
}
|
||||
loadingLabel.textContent = status === "searching" ? "Searching the web..."
|
||||
loadingLabel.textContent = status === "analyzing" ? "Analyzing images..." : status === "searching" ? "Searching the web..."
|
||||
: searchState === "no_relevant_results" ? "No sufficiently relevant results. Generating response..."
|
||||
: sourceCount === 0 ? "No web results found. Generating response..." : "Generating response...";
|
||||
},
|
||||
|
||||
+12
-1
@@ -456,7 +456,18 @@ input:focus, textarea:focus, select:focus { border-color: var(--brand); }
|
||||
.input-meta, .input-container { width: min(940px, 100%); margin-inline: auto; }
|
||||
.input-meta { margin-bottom: 5px; padding-left: 10px; }
|
||||
.composer-hint { margin: 0; color: var(--text-muted); font-size: .72rem; }
|
||||
.input-container { padding: 7px; display: grid; grid-template-columns: 44px 44px minmax(0, 1fr) 44px; grid-template-areas: "search reasoning message send"; gap: 7px; align-items: end; background: var(--input-bg); border: 1px solid var(--border-strong); border-radius: 24px; box-shadow: var(--shadow-sm); }
|
||||
.input-container { padding: 7px; display: grid; grid-template-columns: 44px 44px 44px minmax(0, 1fr) 44px; grid-template-areas: "attach search reasoning message send"; gap: 7px; align-items: end; background: var(--input-bg); border: 1px solid var(--border-strong); border-radius: 24px; box-shadow: var(--shadow-sm); }
|
||||
#attachImage { grid-area: attach; }
|
||||
.upload-previews { width: min(940px, 100%); margin: 0 auto 8px; display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.upload-previews[hidden] { display: none; }
|
||||
.upload-preview { display: flex; align-items: center; gap: 8px; padding: 6px; border: 1px solid var(--border-strong); border-radius: 12px; max-width: 100%; }
|
||||
.upload-preview span { overflow-wrap: anywhere; font-size: 12px; }
|
||||
.upload-preview img { width: 48px; height: 48px; object-fit: contain; border-radius: 6px; }
|
||||
.message-images { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
|
||||
.message-images img { max-width: min(360px, 100%); max-height: 300px; object-fit: contain; border-radius: 12px; }
|
||||
.message-images a { max-width: 100%; }
|
||||
.image-drag-target { outline: 2px solid currentColor; }
|
||||
@media (max-width: 480px) { .input-container { grid-template-columns: 36px 36px 36px minmax(0, 1fr) 36px; gap: 3px; } }
|
||||
#webSearch, #reasoning { width: 44px; height: 44px; display: grid; place-items: center; border-radius: 17px; }
|
||||
#webSearch { grid-area: search; }
|
||||
#reasoning { grid-area: reasoning; }
|
||||
|
||||
Reference in New Issue
Block a user