feat(ui): add model thinking selector
This commit is contained in:
@@ -15,6 +15,7 @@ const PreferencesSchema = z.object({
|
|||||||
lastUsedBinary: z.string().optional(),
|
lastUsedBinary: z.string().optional(),
|
||||||
environmentVariables: z.record(z.string()).default({}),
|
environmentVariables: z.record(z.string()).default({}),
|
||||||
modelRecents: z.array(ModelPreferenceSchema).default([]),
|
modelRecents: z.array(ModelPreferenceSchema).default([]),
|
||||||
|
modelThinkingSelections: z.record(z.string(), z.string()).default({}),
|
||||||
diffViewMode: z.enum(["split", "unified"]).default("split"),
|
diffViewMode: z.enum(["split", "unified"]).default("split"),
|
||||||
toolOutputExpansion: z.enum(["expanded", "collapsed"]).default("expanded"),
|
toolOutputExpansion: z.enum(["expanded", "collapsed"]).default("expanded"),
|
||||||
diagnosticsExpansion: z.enum(["expanded", "collapsed"]).default("expanded"),
|
diagnosticsExpansion: z.enum(["expanded", "collapsed"]).default("expanded"),
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import InfoView from "../info-view"
|
|||||||
import InstanceServiceStatus from "../instance-service-status"
|
import InstanceServiceStatus from "../instance-service-status"
|
||||||
import AgentSelector from "../agent-selector"
|
import AgentSelector from "../agent-selector"
|
||||||
import ModelSelector from "../model-selector"
|
import ModelSelector from "../model-selector"
|
||||||
|
import ThinkingSelector from "../thinking-selector"
|
||||||
import CommandPalette from "../command-palette"
|
import CommandPalette from "../command-palette"
|
||||||
import PermissionNotificationBanner from "../permission-notification-banner"
|
import PermissionNotificationBanner from "../permission-notification-banner"
|
||||||
import PermissionApprovalModal from "../permission-approval-modal"
|
import PermissionApprovalModal from "../permission-approval-modal"
|
||||||
@@ -432,6 +433,14 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const focusVariantSelectorControl = () => {
|
||||||
|
const input = leftDrawerContentEl()?.querySelector<HTMLInputElement>("[data-thinking-selector]")
|
||||||
|
if (!input) return false
|
||||||
|
input.focus()
|
||||||
|
setTimeout(() => triggerKeyboardEvent(input, { key: "ArrowDown", code: "ArrowDown", keyCode: 40 }), 10)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
const pending = pendingSidebarAction()
|
const pending = pendingSidebarAction()
|
||||||
if (!pending) return
|
if (!pending) return
|
||||||
@@ -444,7 +453,12 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
setPendingSidebarAction(null)
|
setPendingSidebarAction(null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const handled = action === "focus-agent-selector" ? focusAgentSelectorControl() : focusModelSelectorControl()
|
const handled =
|
||||||
|
action === "focus-agent-selector"
|
||||||
|
? focusAgentSelectorControl()
|
||||||
|
: action === "focus-model-selector"
|
||||||
|
? focusModelSelectorControl()
|
||||||
|
: focusVariantSelectorControl()
|
||||||
if (handled) {
|
if (handled) {
|
||||||
setPendingSidebarAction(null)
|
setPendingSidebarAction(null)
|
||||||
}
|
}
|
||||||
@@ -905,9 +919,12 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
<span class="hint sidebar-selector-hint sidebar-selector-hint--left">
|
<span class="hint sidebar-selector-hint sidebar-selector-hint--left">
|
||||||
<Kbd shortcut="cmd+shift+a" />
|
<Kbd shortcut="cmd+shift+a" />
|
||||||
</span>
|
</span>
|
||||||
<span class="hint sidebar-selector-hint sidebar-selector-hint--right">
|
<span class="hint sidebar-selector-hint sidebar-selector-hint--center">
|
||||||
<Kbd shortcut="cmd+shift+m" />
|
<Kbd shortcut="cmd+shift+m" />
|
||||||
</span>
|
</span>
|
||||||
|
<span class="hint sidebar-selector-hint sidebar-selector-hint--right">
|
||||||
|
<Kbd shortcut="cmd+shift+t" />
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ModelSelector
|
<ModelSelector
|
||||||
@@ -916,6 +933,8 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
currentModel={activeSession().model}
|
currentModel={activeSession().model}
|
||||||
onModelChange={(model) => props.handleSidebarModelChange(activeSession().id, model)}
|
onModelChange={(model) => props.handleSidebarModelChange(activeSession().id, model)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ThinkingSelector instanceId={props.instance.id} currentModel={activeSession().model} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
103
packages/ui/src/components/thinking-selector.tsx
Normal file
103
packages/ui/src/components/thinking-selector.tsx
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import { Combobox } from "@kobalte/core/combobox"
|
||||||
|
import { createEffect, createMemo } from "solid-js"
|
||||||
|
import { providers, fetchProviders } from "../stores/sessions"
|
||||||
|
import { ChevronDown } from "lucide-solid"
|
||||||
|
import { getLogger } from "../lib/logger"
|
||||||
|
import { getModelThinkingSelection, setModelThinkingSelection } from "../stores/preferences"
|
||||||
|
|
||||||
|
const log = getLogger("session")
|
||||||
|
|
||||||
|
interface ThinkingSelectorProps {
|
||||||
|
instanceId: string
|
||||||
|
currentModel: { providerId: string; modelId: string }
|
||||||
|
}
|
||||||
|
|
||||||
|
type ThinkingOption = {
|
||||||
|
key: string
|
||||||
|
label: string
|
||||||
|
value: string | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ThinkingSelector(props: ThinkingSelectorProps) {
|
||||||
|
const instanceProviders = () => providers().get(props.instanceId) || []
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (instanceProviders().length === 0) {
|
||||||
|
fetchProviders(props.instanceId).catch((error) => log.error("Failed to fetch providers", error))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const variantKeys = createMemo(() => {
|
||||||
|
const { providerId, modelId } = props.currentModel
|
||||||
|
const provider = instanceProviders().find((p) => p.id === providerId)
|
||||||
|
const model = provider?.models.find((m) => m.id === modelId)
|
||||||
|
return model?.variantKeys ?? []
|
||||||
|
})
|
||||||
|
|
||||||
|
const options = createMemo<ThinkingOption[]>(() => {
|
||||||
|
const keys = variantKeys()
|
||||||
|
return [{ key: "__default__", label: "Default", value: undefined }, ...keys.map((k) => ({ key: k, label: k, value: k }))]
|
||||||
|
})
|
||||||
|
|
||||||
|
const currentValue = createMemo(() => {
|
||||||
|
const selected = getModelThinkingSelection(props.currentModel)
|
||||||
|
const keys = variantKeys()
|
||||||
|
if (selected && keys.includes(selected)) {
|
||||||
|
return options().find((opt) => opt.value === selected)
|
||||||
|
}
|
||||||
|
return options()[0]
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleChange = (value: ThinkingOption | null) => {
|
||||||
|
if (!value) return
|
||||||
|
setModelThinkingSelection(props.currentModel, value.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const triggerPrimary = createMemo(() => {
|
||||||
|
const selected = currentValue()?.value
|
||||||
|
return selected ? `Thinking: ${selected}` : "Thinking: Default"
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="sidebar-selector">
|
||||||
|
<Combobox<ThinkingOption>
|
||||||
|
value={currentValue()}
|
||||||
|
onChange={handleChange}
|
||||||
|
options={options()}
|
||||||
|
optionValue="key"
|
||||||
|
optionLabel="label"
|
||||||
|
placeholder="Thinking: Default"
|
||||||
|
itemComponent={(itemProps) => (
|
||||||
|
<Combobox.Item item={itemProps.item} class="selector-option">
|
||||||
|
<div class="selector-option-content">
|
||||||
|
<Combobox.ItemLabel class="selector-option-label">{itemProps.item.rawValue.label}</Combobox.ItemLabel>
|
||||||
|
</div>
|
||||||
|
<Combobox.ItemIndicator class="selector-option-indicator">
|
||||||
|
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||||
|
</svg>
|
||||||
|
</Combobox.ItemIndicator>
|
||||||
|
</Combobox.Item>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Combobox.Control class="relative w-full" data-thinking-selector-control>
|
||||||
|
<Combobox.Input class="sr-only" data-thinking-selector />
|
||||||
|
<Combobox.Trigger class="selector-trigger">
|
||||||
|
<div class="selector-trigger-label selector-trigger-label--stacked">
|
||||||
|
<span class="selector-trigger-primary selector-trigger-primary--align-left">{triggerPrimary()}</span>
|
||||||
|
</div>
|
||||||
|
<Combobox.Icon class="selector-trigger-icon">
|
||||||
|
<ChevronDown class="w-3 h-3" />
|
||||||
|
</Combobox.Icon>
|
||||||
|
</Combobox.Trigger>
|
||||||
|
</Combobox.Control>
|
||||||
|
|
||||||
|
<Combobox.Portal>
|
||||||
|
<Combobox.Content class="selector-popover">
|
||||||
|
<Combobox.Listbox class="selector-listbox" />
|
||||||
|
</Combobox.Content>
|
||||||
|
</Combobox.Portal>
|
||||||
|
</Combobox>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -69,6 +69,11 @@ export function useAppLifecycle(options: UseAppLifecycleOptions) {
|
|||||||
if (!instance) return
|
if (!instance) return
|
||||||
emitSessionSidebarRequest({ instanceId: instance.id, action: "focus-agent-selector" })
|
emitSessionSidebarRequest({ instanceId: instance.id, action: "focus-agent-selector" })
|
||||||
},
|
},
|
||||||
|
() => {
|
||||||
|
const instance = options.getActiveInstance()
|
||||||
|
if (!instance) return
|
||||||
|
emitSessionSidebarRequest({ instanceId: instance.id, action: "focus-variant-selector" })
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
registerEscapeShortcut(
|
registerEscapeShortcut(
|
||||||
|
|||||||
@@ -374,6 +374,20 @@ export function useCommands(options: UseCommandsOptions) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
commandRegistry.register({
|
||||||
|
id: "open-variant-selector",
|
||||||
|
label: "Select Model Variant",
|
||||||
|
description: "Choose a thinking effort for the current model",
|
||||||
|
category: "Agent & Model",
|
||||||
|
keywords: ["variant", "thinking", "reasoning", "effort"],
|
||||||
|
shortcut: { key: "T", meta: true, shift: true },
|
||||||
|
action: () => {
|
||||||
|
const instance = activeInstance()
|
||||||
|
if (!instance) return
|
||||||
|
emitSessionSidebarRequest({ instanceId: instance.id, action: "focus-variant-selector" })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
commandRegistry.register({
|
commandRegistry.register({
|
||||||
id: "open-agent-selector",
|
id: "open-agent-selector",
|
||||||
label: "Open Agent Selector",
|
label: "Open Agent Selector",
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
export type SessionSidebarRequestAction = "focus-agent-selector" | "focus-model-selector" | "show-session-list"
|
export type SessionSidebarRequestAction =
|
||||||
|
| "focus-agent-selector"
|
||||||
|
| "focus-model-selector"
|
||||||
|
| "focus-variant-selector"
|
||||||
|
| "show-session-list"
|
||||||
|
|
||||||
export interface SessionSidebarRequestDetail {
|
export interface SessionSidebarRequestDetail {
|
||||||
instanceId: string
|
instanceId: string
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { keyboardRegistry } from "../keyboard-registry"
|
import { keyboardRegistry } from "../keyboard-registry"
|
||||||
|
|
||||||
export function registerAgentShortcuts(focusModelSelector: () => void, openAgentSelector: () => void) {
|
export function registerAgentShortcuts(
|
||||||
|
focusModelSelector: () => void,
|
||||||
|
openAgentSelector: () => void,
|
||||||
|
focusVariantSelector: () => void,
|
||||||
|
) {
|
||||||
const isMac = () => navigator.platform.toLowerCase().includes("mac")
|
const isMac = () => navigator.platform.toLowerCase().includes("mac")
|
||||||
|
|
||||||
keyboardRegistry.register({
|
keyboardRegistry.register({
|
||||||
@@ -20,4 +24,13 @@ export function registerAgentShortcuts(focusModelSelector: () => void, openAgent
|
|||||||
description: "open agent",
|
description: "open agent",
|
||||||
context: "global",
|
context: "global",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
keyboardRegistry.register({
|
||||||
|
id: "focus-variant",
|
||||||
|
key: "T",
|
||||||
|
modifiers: { ctrl: !isMac(), meta: isMac(), shift: true },
|
||||||
|
handler: focusVariantSelector,
|
||||||
|
description: "focus thinking",
|
||||||
|
context: "global",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export interface Preferences {
|
|||||||
lastUsedBinary?: string
|
lastUsedBinary?: string
|
||||||
environmentVariables: Record<string, string>
|
environmentVariables: Record<string, string>
|
||||||
modelRecents: ModelPreference[]
|
modelRecents: ModelPreference[]
|
||||||
|
modelThinkingSelections: Record<string, string>
|
||||||
diffViewMode: DiffViewMode
|
diffViewMode: DiffViewMode
|
||||||
toolOutputExpansion: ExpansionPreference
|
toolOutputExpansion: ExpansionPreference
|
||||||
diagnosticsExpansion: ExpansionPreference
|
diagnosticsExpansion: ExpansionPreference
|
||||||
@@ -71,6 +72,7 @@ const defaultPreferences: Preferences = {
|
|||||||
showTimelineTools: true,
|
showTimelineTools: true,
|
||||||
environmentVariables: {},
|
environmentVariables: {},
|
||||||
modelRecents: [],
|
modelRecents: [],
|
||||||
|
modelThinkingSelections: {},
|
||||||
diffViewMode: "split",
|
diffViewMode: "split",
|
||||||
toolOutputExpansion: "expanded",
|
toolOutputExpansion: "expanded",
|
||||||
diagnosticsExpansion: "expanded",
|
diagnosticsExpansion: "expanded",
|
||||||
@@ -102,6 +104,11 @@ function normalizePreferences(pref?: Partial<Preferences> & { agentModelSelectio
|
|||||||
const sourceModelRecents = sanitized.modelRecents ?? defaultPreferences.modelRecents
|
const sourceModelRecents = sanitized.modelRecents ?? defaultPreferences.modelRecents
|
||||||
const modelRecents = sourceModelRecents.map((item) => ({ ...item }))
|
const modelRecents = sourceModelRecents.map((item) => ({ ...item }))
|
||||||
|
|
||||||
|
const modelThinkingSelections = {
|
||||||
|
...defaultPreferences.modelThinkingSelections,
|
||||||
|
...(sanitized.modelThinkingSelections ?? {}),
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
showThinkingBlocks: sanitized.showThinkingBlocks ?? defaultPreferences.showThinkingBlocks,
|
showThinkingBlocks: sanitized.showThinkingBlocks ?? defaultPreferences.showThinkingBlocks,
|
||||||
thinkingBlocksExpansion: sanitized.thinkingBlocksExpansion ?? defaultPreferences.thinkingBlocksExpansion,
|
thinkingBlocksExpansion: sanitized.thinkingBlocksExpansion ?? defaultPreferences.thinkingBlocksExpansion,
|
||||||
@@ -109,6 +116,7 @@ function normalizePreferences(pref?: Partial<Preferences> & { agentModelSelectio
|
|||||||
lastUsedBinary: sanitized.lastUsedBinary ?? defaultPreferences.lastUsedBinary,
|
lastUsedBinary: sanitized.lastUsedBinary ?? defaultPreferences.lastUsedBinary,
|
||||||
environmentVariables,
|
environmentVariables,
|
||||||
modelRecents,
|
modelRecents,
|
||||||
|
modelThinkingSelections,
|
||||||
diffViewMode: sanitized.diffViewMode ?? defaultPreferences.diffViewMode,
|
diffViewMode: sanitized.diffViewMode ?? defaultPreferences.diffViewMode,
|
||||||
toolOutputExpansion: sanitized.toolOutputExpansion ?? defaultPreferences.toolOutputExpansion,
|
toolOutputExpansion: sanitized.toolOutputExpansion ?? defaultPreferences.toolOutputExpansion,
|
||||||
diagnosticsExpansion: sanitized.diagnosticsExpansion ?? defaultPreferences.diagnosticsExpansion,
|
diagnosticsExpansion: sanitized.diagnosticsExpansion ?? defaultPreferences.diagnosticsExpansion,
|
||||||
@@ -118,6 +126,35 @@ function normalizePreferences(pref?: Partial<Preferences> & { agentModelSelectio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getModelKey(model: { providerId: string; modelId: string }): string {
|
||||||
|
return `${model.providerId}/${model.modelId}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function getModelThinkingSelection(model: { providerId: string; modelId: string }): string | undefined {
|
||||||
|
if (!model.providerId || !model.modelId) return undefined
|
||||||
|
return preferences().modelThinkingSelections?.[getModelKey(model)]
|
||||||
|
}
|
||||||
|
|
||||||
|
function setModelThinkingSelection(model: { providerId: string; modelId: string }, value: string | undefined): void {
|
||||||
|
if (!model.providerId || !model.modelId) return
|
||||||
|
const key = getModelKey(model)
|
||||||
|
const current = preferences().modelThinkingSelections?.[key]
|
||||||
|
if (current === value) return
|
||||||
|
|
||||||
|
updateConfig((draft) => {
|
||||||
|
const selections = { ...(draft.preferences.modelThinkingSelections ?? {}) }
|
||||||
|
if (!value) {
|
||||||
|
delete selections[key]
|
||||||
|
} else {
|
||||||
|
selections[key] = value
|
||||||
|
}
|
||||||
|
draft.preferences = normalizePreferences({
|
||||||
|
...draft.preferences,
|
||||||
|
modelThinkingSelections: selections,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const [internalConfig, setInternalConfig] = createSignal<ConfigData>(buildFallbackConfig())
|
const [internalConfig, setInternalConfig] = createSignal<ConfigData>(buildFallbackConfig())
|
||||||
|
|
||||||
const config = createMemo<DeepReadonly<ConfigData>>(() => internalConfig())
|
const config = createMemo<DeepReadonly<ConfigData>>(() => internalConfig())
|
||||||
@@ -527,6 +564,8 @@ export {
|
|||||||
addEnvironmentVariable,
|
addEnvironmentVariable,
|
||||||
removeEnvironmentVariable,
|
removeEnvironmentVariable,
|
||||||
addRecentModelPreference,
|
addRecentModelPreference,
|
||||||
|
getModelThinkingSelection,
|
||||||
|
setModelThinkingSelection,
|
||||||
setAgentModelPreference,
|
setAgentModelPreference,
|
||||||
getAgentModelPreference,
|
getAgentModelPreference,
|
||||||
setDiffViewMode,
|
setDiffViewMode,
|
||||||
@@ -540,4 +579,3 @@ export {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { resolvePastedPlaceholders } from "../lib/prompt-placeholders"
|
import { resolvePastedPlaceholders } from "../lib/prompt-placeholders"
|
||||||
import { instances } from "./instances"
|
import { instances } from "./instances"
|
||||||
|
|
||||||
import { addRecentModelPreference, setAgentModelPreference } from "./preferences"
|
import { addRecentModelPreference, getModelThinkingSelection, setAgentModelPreference } from "./preferences"
|
||||||
import { sessions, withSession } from "./session-state"
|
import { providers, sessions, withSession } from "./session-state"
|
||||||
import { getDefaultModel, isModelValid } from "./session-models"
|
import { getDefaultModel, isModelValid } from "./session-models"
|
||||||
import { updateSessionInfo } from "./message-v2/session-info"
|
import { updateSessionInfo } from "./message-v2/session-info"
|
||||||
import { messageStoreBus } from "./message-v2/bus"
|
import { messageStoreBus } from "./message-v2/bus"
|
||||||
@@ -11,6 +11,22 @@ import { requestData } from "../lib/opencode-api"
|
|||||||
|
|
||||||
const log = getLogger("actions")
|
const log = getLogger("actions")
|
||||||
|
|
||||||
|
function getVariantKeysForModel(instanceId: string, model: { providerId: string; modelId: string }): string[] {
|
||||||
|
if (!model.providerId || !model.modelId) return []
|
||||||
|
const instanceProviders = providers().get(instanceId) || []
|
||||||
|
const provider = instanceProviders.find((p) => p.id === model.providerId)
|
||||||
|
const match = provider?.models.find((m) => m.id === model.modelId)
|
||||||
|
return match?.variantKeys ?? []
|
||||||
|
}
|
||||||
|
|
||||||
|
function getThinkingVariantToSend(instanceId: string, model: { providerId: string; modelId: string }): string | undefined {
|
||||||
|
const selected = getModelThinkingSelection(model)
|
||||||
|
if (!selected) return undefined
|
||||||
|
const keys = getVariantKeysForModel(instanceId, model)
|
||||||
|
if (keys.length === 0) return undefined
|
||||||
|
return keys.includes(selected) ? selected : undefined
|
||||||
|
}
|
||||||
|
|
||||||
const ID_LENGTH = 26
|
const ID_LENGTH = 26
|
||||||
const BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
const BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
@@ -170,6 +186,12 @@ async function sendMessage(
|
|||||||
modelID: session.model.modelId,
|
modelID: session.model.modelId,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
...(session.model.providerId &&
|
||||||
|
session.model.modelId &&
|
||||||
|
(() => {
|
||||||
|
const variant = getThinkingVariantToSend(instanceId, session.model)
|
||||||
|
return variant ? { variant } : {}
|
||||||
|
})()),
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("sendMessage", {
|
log.info("sendMessage", {
|
||||||
@@ -215,6 +237,7 @@ async function executeCustomCommand(
|
|||||||
messageID: string
|
messageID: string
|
||||||
agent?: string
|
agent?: string
|
||||||
model?: string
|
model?: string
|
||||||
|
variant?: string
|
||||||
} = {
|
} = {
|
||||||
command: commandName,
|
command: commandName,
|
||||||
arguments: args,
|
arguments: args,
|
||||||
@@ -227,6 +250,8 @@ async function executeCustomCommand(
|
|||||||
|
|
||||||
if (session.model.providerId && session.model.modelId) {
|
if (session.model.providerId && session.model.modelId) {
|
||||||
body.model = `${session.model.providerId}/${session.model.modelId}`
|
body.model = `${session.model.providerId}/${session.model.modelId}`
|
||||||
|
const variant = getThinkingVariantToSend(instanceId, session.model)
|
||||||
|
if (variant) body.variant = variant
|
||||||
}
|
}
|
||||||
|
|
||||||
await requestData(
|
await requestData(
|
||||||
|
|||||||
@@ -483,6 +483,7 @@ async function fetchProviders(instanceId: string): Promise<void> {
|
|||||||
providerId: provider.id,
|
providerId: provider.id,
|
||||||
limit: model.limit,
|
limit: model.limit,
|
||||||
cost: model.cost,
|
cost: model.cost,
|
||||||
|
variantKeys: Object.keys(model.variants ?? {}),
|
||||||
})),
|
})),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|||||||
@@ -121,21 +121,26 @@ session-sidebar-controls .selector-trigger-primary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-selector-hints {
|
.sidebar-selector-hints {
|
||||||
@apply flex items-center gap-2 w-full;
|
@apply grid gap-2 w-full;
|
||||||
justify-content: space-between;
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-selector-hint--left,
|
.sidebar-selector-hint--left,
|
||||||
|
.sidebar-selector-hint--center,
|
||||||
.sidebar-selector-hint--right {
|
.sidebar-selector-hint--right {
|
||||||
@apply flex-1;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-selector-hint--left {
|
@media (max-width: 520px) {
|
||||||
justify-content: flex-start;
|
.sidebar-selector-hints {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-selector-hint--right {
|
@media (max-width: 360px) {
|
||||||
justify-content: flex-end;
|
.sidebar-selector-hints {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.session-header-hints {
|
.session-header-hints {
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ export interface Model {
|
|||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
providerId: string
|
providerId: string
|
||||||
|
variantKeys?: string[]
|
||||||
limit?: {
|
limit?: {
|
||||||
context?: number
|
context?: number
|
||||||
output?: number
|
output?: number
|
||||||
|
|||||||
Reference in New Issue
Block a user