@@ -1284,6 +1359,85 @@ defineExpose({ scrollToEnd, isAtBottom, chatWrapper });
border-bottom: none;
}
+.max-mode-thinking {
+ color: var(--text-secondary);
+ font-size: 0.95rem;
+ padding: 12px 0;
+ min-height: 24px;
+}
+
+.max-mode-experts-area {
+ margin-top: 12px;
+ border-top: 1px solid var(--border);
+ padding-top: 12px;
+}
+
+.max-mode-experts-details {
+ font-size: 0.9rem;
+ color: var(--text-secondary);
+}
+
+.max-mode-experts-details summary {
+ cursor: pointer;
+ font-weight: 600;
+ color: var(--text-primary);
+}
+
+.max-mode-expert-block {
+ margin-top: 10px;
+ padding: 8px 0;
+ border-bottom: 1px solid var(--border);
+}
+
+.max-mode-expert-block:last-child {
+ border-bottom: none;
+}
+
+.max-mode-expert-label {
+ font-weight: 600;
+ color: var(--text-primary);
+ margin-bottom: 4px;
+}
+
+.max-mode-expert-content {
+ font-size: 0.85rem;
+ color: var(--text-secondary);
+ line-height: 1.5;
+}
+
+.max-mode-expert-content :deep(p) {
+ margin: 0.25em 0;
+}
+
+.max-mode-round-label {
+ font-weight: 700;
+ color: var(--text-primary);
+ margin-top: 12px;
+ margin-bottom: 4px;
+}
+
+.max-mode-round-label:first-child {
+ margin-top: 0;
+}
+
+.max-mode-votes {
+ margin-top: 12px;
+ padding-top: 8px;
+ border-top: 1px solid var(--border);
+}
+
+.max-mode-vote-line {
+ font-size: 0.85rem;
+ color: var(--text-secondary);
+ margin: 2px 0;
+}
+
+.max-mode-winner {
+ font-weight: 600;
+ color: var(--primary);
+ margin-top: 6px;
+}
+
.part-content {
margin-top: 12px;
min-height: 20px;
diff --git a/app/components/MessageForm.vue b/app/components/MessageForm.vue
index 93425c0..11ca769 100644
--- a/app/components/MessageForm.vue
+++ b/app/components/MessageForm.vue
@@ -17,7 +17,8 @@ import {
showReasoningEffortSelector,
getDefaultReasoningEffort,
isReasoningEnabled as checkReasoningEnabled,
- normalizeReasoningConfig
+ normalizeReasoningConfig,
+ isMaxModeSupported
} from "~/composables/availableModels";
// Define component properties and emitted events
@@ -122,6 +123,31 @@ const isReasoningEnabled = computed(() => {
return checkReasoningEnabled(selectedModel.value, reasoningEffort.value);
});
+const paramConfig = computed(() => props.settingsManager?.settings?.parameter_config || {});
+const maxMode = computed({
+ get: () => paramConfig.value.maxMode === true,
+ set: (v) => {
+ if (!props.settingsManager) return;
+ if (!props.settingsManager.settings.parameter_config) {
+ props.settingsManager.settings.parameter_config = { maxMode: false, maxModeModels: [] };
+ }
+ props.settingsManager.settings.parameter_config.maxMode = v;
+ if (v && (!props.settingsManager.settings.parameter_config.maxModeModels || props.settingsManager.settings.parameter_config.maxModeModels.length !== 4)) {
+ props.settingsManager.settings.parameter_config.maxModeModels = ['', '', '', ''];
+ }
+ props.settingsManager.saveSettings();
+ }
+});
+const maxModeModels = computed(() => {
+ const arr = paramConfig.value.maxModeModels;
+ if (!Array.isArray(arr)) return ['', '', '', ''];
+ return [arr[0] ?? '', arr[1] ?? '', arr[2] ?? '', arr[3] ?? ''];
+});
+const maxModeValid = computed(() => {
+ const ids = maxModeModels.value.filter(Boolean);
+ return ids.length === 4 && new Set(ids).size === 4 && ids.every(id => isMaxModeSupported(props.availableModels || [], id));
+});
+const canSendWithMaxMode = computed(() => maxModeValid.value);
// Watch the selected model and load the appropriate reasoning effort setting
watch(
@@ -167,12 +193,16 @@ function closeBottomSheet() {
isBottomSheetOpen.value = false;
}
+function handleSheetModelSelected(modelId, modelName) {
+ handleModelSelect(modelId, modelName);
+ closeBottomSheet();
+}
+
function handleModelSelect(modelId, modelName) {
if (props.settingsManager) {
props.settingsManager.settings.selected_model_id = modelId;
props.settingsManager.saveSettings();
}
- closeBottomSheet();
}
// --- Event Handlers ---
@@ -223,12 +253,10 @@ function handleEnterKey(event) {
* Emits the message to the parent, then clears the input.
*/
async function submitMessage() {
- // Emit the message to parent component
+ if (maxMode.value && !canSendWithMaxMode.value) return;
emit("send-message", inputMessage.value, inputMessage.value, toRaw(attachments.value));
inputMessage.value = "";
- // Clear attachments after sending
clearAttachments();
- // Force textarea resize after clearing
await nextTick();
if (textareaRef.value) {
textareaRef.value.style.height = "auto";
@@ -493,7 +521,6 @@ defineExpose({ setMessage, toggleReasoning, setReasoningEffort, $el: messageForm
-
Processing...
@@ -539,6 +566,18 @@ defineExpose({ setMessage, toggleReasoning, setReasoningEffort, $el: messageForm
+
+
-
+
+
+
+
Daily usage
+
Limits reset at midnight (local time)
+
+
+
+
Messages
+
+
{{ usageStats.general.used }} / {{ usageStats.general.limit }}
+
+
+
Images
+
+
{{ usageStats.image.used }} / {{ usageStats.image.limit }}
+
+
{{ formatResetTime() }}
+
+