char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Aleksander Grygierui: Improve Chat Form Actions UI/UX (models selector, add panel) (#27746)cae63579b

char/aliceai-t5-moe
3.6 KiB105 linesraw
1import { REASONING_EFFORT_LEVELS, REASONING_EFFORT_TOKENS } from '$lib/constants';
2import { ReasoningEffort } from '$lib/enums';
3import { conversationsStore, modelsStore, serverStore } from '$lib/stores';
4import type { ReasoningEffortLevel } from '$lib/types';
5import type { DatabaseMessage } from '$lib/types/database';
6import { getConversationModel } from '$lib/utils';
7
8export interface UseReasoningMenuReturn {
9	readonly modelSupportsThinking: boolean;
10	readonly thinkingEnabled: boolean;
11	readonly isReasoningActive: boolean;
12	readonly isOff: boolean;
13	readonly currentEffort: ReasoningEffort;
14	readonly levels: ReasoningEffortLevel[];
15	isSelected(level: ReasoningEffortLevel): boolean;
16	tokenLabel(level: ReasoningEffortLevel): string | null;
17	select(level: ReasoningEffortLevel): void;
18}
19
20/**
21 * Shared reactive state and helpers for the reasoning effort menu.
22 *
23 * Used by both the desktop dropdown (`ChatFormActionAddReasoningSubmenu`)
24 * and the mobile sheet (`ChatFormActionAddSheet`) to avoid duplicating the
25 * thinking-support derivation and the effort selection logic.
26 */
27export function useReasoningMenu(): UseReasoningMenuReturn {
28	const conversationModel = $derived(
29		getConversationModel(conversationsStore.activeMessages as DatabaseMessage[])
30	);
31	// a router chat can carry reasoning from an earlier turn before the props
32	// cache is primed, so a model that already produced thinking still qualifies
33	const modelSupportsThinkingFromMessages = $derived.by(() => {
34		const modelId = serverStore.isRouterMode
35			? modelsStore.selectedModelName || conversationModel
36			: null;
37
38		if (!modelId) return false;
39
40		return conversationsStore.activeMessages.some(
41			(m) => m.role === 'assistant' && m.model === modelId && !!m.reasoningContent
42		);
43	});
44	const modelSupportsThinking = $derived.by(() => {
45		void modelsStore.loadedModelIds;
46		void modelsStore.props.cacheVersion;
47
48		if (serverStore.isRouterMode) {
49			const modelId = modelsStore.selectedModelName || conversationModel;
50
51			return (
52				modelsStore.props.checkModelSupportsThinking(modelId ?? '') ||
53				modelSupportsThinkingFromMessages
54			);
55		}
56
57		return modelsStore.props.supportsThinking || modelSupportsThinkingFromMessages;
58	});
59	const currentEffort = $derived(conversationsStore.preferences.getReasoningEffort());
60	const thinkingEnabled = $derived(
61		currentEffort !== ReasoningEffort.OFF && currentEffort !== ReasoningEffort.DEFAULT
62	);
63	// Thinking is effectively on (lightbulb lit) either when an explicit effort
64	// is selected, or when the effort is left at "Default" and the model
65	// supports thinking.
66	const isReasoningActive = $derived(
67		thinkingEnabled || (currentEffort === ReasoningEffort.DEFAULT && modelSupportsThinking)
68	);
69
70	return {
71		get currentEffort() {
72			return currentEffort;
73		},
74		get isOff() {
75			return currentEffort === ReasoningEffort.OFF;
76		},
77		get isReasoningActive() {
78			return isReasoningActive;
79		},
80		isSelected(level: ReasoningEffortLevel): boolean {
81			return currentEffort === level.value;
82		},
83		get levels() {
84			return REASONING_EFFORT_LEVELS;
85		},
86		get modelSupportsThinking() {
87			return modelSupportsThinking;
88		},
89		select(level: ReasoningEffortLevel): void {
90			conversationsStore.preferences.setReasoningEffort(level.value as ReasoningEffort);
91		},
92		get thinkingEnabled() {
93			return thinkingEnabled;
94		},
95		tokenLabel(level: ReasoningEffortLevel): string | null {
96			if (level.value === ReasoningEffort.DEFAULT) return 'Model default';
97
98			const tokens = REASONING_EFFORT_TOKENS[level.value];
99
100			if (tokens === undefined) return null;
101
102			return tokens === -1 ? 'Unlimited' : `Max ${tokens.toLocaleString()} tokens`;
103		}
104	};
105}