Skip to content

Commit f12654c

Browse files
author
Chris Scott
committed
Fix session model detection to use actual session model instead of default preference
1 parent c7d01b1 commit f12654c

5 files changed

Lines changed: 43 additions & 78 deletions

File tree

frontend/src/components/message/PromptInput.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ChevronDown } from 'lucide-react'
1111
import { CommandSuggestions } from '@/components/command/CommandSuggestions'
1212
import { FileSuggestions } from './FileSuggestions'
1313
import { detectMentionTrigger, parsePromptToParts, getFilename } from '@/lib/promptParser'
14+
import { getSessionModel } from '@/lib/model'
1415
import { getModel, formatModelName } from '@/api/providers'
1516
import type { components } from '@/api/opencode-types'
1617
import type { MessageWithParts, FileInfo } from '@/api/types'
@@ -365,11 +366,7 @@ export function PromptInput({
365366
const modeColor = currentMode === 'plan' ? 'text-yellow-600 dark:text-yellow-500' : 'text-green-600 dark:text-green-500'
366367
const modeBg = currentMode === 'plan' ? 'bg-yellow-500/10 border-yellow-500/30' : 'bg-green-500/10 border-green-500/30'
367368

368-
const lastAssistantMessage = messages?.filter(msg => msg.info.role === 'assistant').pop()
369-
const sessionModel = lastAssistantMessage?.info.role === 'assistant'
370-
? `${lastAssistantMessage.info.providerID}/${lastAssistantMessage.info.modelID}`
371-
: null
372-
const currentModel = sessionModel || config?.model || ''
369+
const currentModel = getSessionModel(messages, config?.model) || ''
373370

374371
useEffect(() => {
375372
const loadModelName = async () => {

frontend/src/components/model/ModelSelectDialog.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ interface ModelSelectDialogProps {
2525
open: boolean;
2626
onOpenChange: (open: boolean) => void;
2727
opcodeUrl?: string | null;
28+
currentSessionModel?: string | null;
2829
}
2930

3031
export function ModelSelectDialog({
3132
open,
3233
onOpenChange,
3334
opcodeUrl,
35+
currentSessionModel,
3436
}: ModelSelectDialogProps) {
3537
const [searchQuery, setSearchQuery] = useState("");
3638
const [selectedProvider, setSelectedProvider] = useState<string>("");
@@ -39,7 +41,7 @@ export function ModelSelectDialog({
3941
const client = useOpenCodeClient(opcodeUrl);
4042
const { sessionID } = useParams<{ sessionID: string }>();
4143

42-
const currentModel = preferences?.defaultModel || "";
44+
const currentModel = currentSessionModel || preferences?.defaultModel || "";
4345

4446
const { data: providers = [], isLoading: loading } = useQuery({
4547
queryKey: ["providers-with-models"],
@@ -51,6 +53,7 @@ export function ModelSelectDialog({
5153
if (currentModel && providers.length > 0) {
5254
const [providerId] = currentModel.split("/");
5355
setSelectedProvider(providerId);
56+
setViewMode('models');
5457
}
5558
}, [currentModel, providers]);
5659

frontend/src/components/session/ContextUsageIndicator.tsx

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { useContextUsage } from '@/hooks/useContextUsage'
22
import { getModel, formatModelName } from '@/api/providers'
3-
import { useSettings } from '@/hooks/useSettings'
43
import { useState, useEffect } from 'react'
54

65
interface ContextUsageIndicatorProps {
@@ -11,36 +10,33 @@ interface ContextUsageIndicatorProps {
1110

1211
export function ContextUsageIndicator({ opcodeUrl, sessionID, directory }: ContextUsageIndicatorProps) {
1312
const { totalTokens, contextLimit, usagePercentage, currentModel, isLoading } = useContextUsage(opcodeUrl, sessionID, directory)
14-
const { preferences } = useSettings()
1513
const [modelName, setModelName] = useState<string>('')
1614

17-
const displayModel = preferences?.defaultModel || currentModel || ''
18-
1915
useEffect(() => {
2016
const loadModelName = async () => {
21-
if (displayModel) {
17+
if (currentModel) {
2218
try {
23-
const [providerId, modelId] = displayModel.split('/')
19+
const [providerId, modelId] = currentModel.split('/')
2420
if (providerId && modelId) {
2521
const model = await getModel(providerId, modelId)
2622
if (model) {
2723
setModelName(formatModelName(model))
2824
} else {
29-
setModelName(displayModel)
25+
setModelName(currentModel)
3026
}
3127
} else {
32-
setModelName(displayModel)
28+
setModelName(currentModel)
3329
}
3430
} catch {
35-
setModelName(displayModel)
31+
setModelName(currentModel)
3632
}
3733
} else {
3834
setModelName('')
3935
}
4036
}
4137

4238
loadModelName()
43-
}, [displayModel, opcodeUrl])
39+
}, [currentModel])
4440

4541
if (isLoading) {
4642
return (

frontend/src/hooks/useContextUsage.ts

Lines changed: 24 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,7 @@ import { useMemo } from 'react'
22
import { useMessages } from './useOpenCode'
33
import { useSettings } from './useSettings'
44
import { useQuery } from '@tanstack/react-query'
5-
import type { components } from '@/api/opencode-types'
6-
7-
type AssistantMessage = components['schemas']['AssistantMessage']
8-
9-
type MessageListItem = {
10-
info: components['schemas']['Message']
11-
parts: components['schemas']['Part'][]
12-
}
5+
import { getSessionModel } from '@/lib/model'
136

147
interface ContextUsage {
158
totalTokens: number
@@ -40,10 +33,6 @@ interface ProvidersResponse {
4033
providers: Provider[]
4134
}
4235

43-
const isAssistantMessage = (message: MessageListItem): message is MessageListItem & { info: AssistantMessage } => {
44-
return message.info.role === 'assistant'
45-
}
46-
4736
async function fetchProviders(opcodeUrl: string): Promise<ProvidersResponse> {
4837
const response = await fetch(`${opcodeUrl}/config/providers`)
4938
if (!response.ok) {
@@ -64,70 +53,45 @@ export const useContextUsage = (opcodeUrl: string | null | undefined, sessionID:
6453
})
6554

6655
return useMemo(() => {
67-
// Get current model from preferences immediately
68-
let currentModel = preferences?.defaultModel || null
56+
const currentModel = getSessionModel(messages, preferences?.defaultModel)
6957

70-
if (!messages || messages.length === 0) {
71-
// Still try to get context limit from preferences model even without messages
72-
let contextLimit: number | null = null
73-
74-
if (currentModel && providersData) {
75-
const [providerId, modelId] = currentModel.split('/')
76-
const provider = providersData.providers.find(p => p.id === providerId)
77-
if (provider && provider.models) {
78-
const model = provider.models[modelId]
79-
if (model && model.limit) {
80-
contextLimit = model.limit.context
81-
}
82-
}
83-
}
84-
85-
return {
86-
totalTokens: 0,
87-
contextLimit,
88-
usagePercentage: contextLimit ? 0 : null,
89-
currentModel,
90-
isLoading: messagesLoading
91-
}
92-
}
93-
94-
// Get the latest assistant message for current context usage
95-
const assistantMessages = messages.filter(isAssistantMessage)
58+
const assistantMessages = messages?.filter(msg => msg.info.role === 'assistant') || []
9659
let latestAssistantMessage = assistantMessages[assistantMessages.length - 1]
9760

98-
// If the latest message has 0 tokens (still being created), use the previous one
99-
if (latestAssistantMessage) {
100-
const latestTokens = latestAssistantMessage.info.tokens.input + latestAssistantMessage.info.tokens.output + latestAssistantMessage.info.tokens.reasoning
101-
if (latestTokens === 0 && assistantMessages.length > 1) {
61+
if (latestAssistantMessage?.info.role === 'assistant') {
62+
const tokens = latestAssistantMessage.info.tokens.input + latestAssistantMessage.info.tokens.output + latestAssistantMessage.info.tokens.reasoning
63+
if (tokens === 0 && assistantMessages.length > 1) {
10264
latestAssistantMessage = assistantMessages[assistantMessages.length - 2]
10365
}
10466
}
105-
106-
let totalTokens = 0
107-
if (latestAssistantMessage) {
108-
// The latest message contains the total context usage
109-
totalTokens = latestAssistantMessage.info.tokens.input + latestAssistantMessage.info.tokens.output + latestAssistantMessage.info.tokens.reasoning
110-
111-
// If no model in preferences, use the model from the message
112-
if (!currentModel && 'modelID' in latestAssistantMessage.info && 'providerID' in latestAssistantMessage.info) {
113-
currentModel = `${latestAssistantMessage.info.providerID}/${latestAssistantMessage.info.modelID}`
114-
}
115-
}
11667

117-
// Find the model configuration from providers data
11868
let contextLimit: number | null = null
119-
12069
if (currentModel && providersData) {
12170
const [providerId, modelId] = currentModel.split('/')
12271
const provider = providersData.providers.find(p => p.id === providerId)
123-
if (provider && provider.models) {
72+
if (provider?.models) {
12473
const model = provider.models[modelId]
125-
if (model && model.limit) {
74+
if (model?.limit) {
12675
contextLimit = model.limit.context
12776
}
12877
}
12978
}
13079

80+
if (!messages || messages.length === 0) {
81+
return {
82+
totalTokens: 0,
83+
contextLimit,
84+
usagePercentage: contextLimit ? 0 : null,
85+
currentModel,
86+
isLoading: messagesLoading
87+
}
88+
}
89+
90+
let totalTokens = 0
91+
if (latestAssistantMessage?.info.role === 'assistant') {
92+
totalTokens = latestAssistantMessage.info.tokens.input + latestAssistantMessage.info.tokens.output + latestAssistantMessage.info.tokens.reasoning
93+
}
94+
13195
const usagePercentage = contextLimit ? (totalTokens / contextLimit) * 100 : null
13296

13397
return {
@@ -138,4 +102,4 @@ export const useContextUsage = (opcodeUrl: string | null | undefined, sessionID:
138102
isLoading: false
139103
}
140104
}, [messages, messagesLoading, preferences?.defaultModel, providersData])
141-
}
105+
}

frontend/src/pages/SessionDetail.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from "react";
1+
import { useState, useMemo } from "react";
22
import { useParams, useNavigate } from "react-router-dom";
33
import { useQuery } from "@tanstack/react-query";
44
import { getRepo } from "@/api/repos";
@@ -10,8 +10,9 @@ import { SessionList } from "@/components/session/SessionList";
1010
import { PermissionRequestDialog } from "@/components/session/PermissionRequestDialog";
1111
import { FileBrowserSheet } from "@/components/file-browser/FileBrowserSheet";
1212
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
13-
import { useSession, useAbortSession, useUpdateSession, useOpenCodeClient, useMessages } from "@/hooks/useOpenCode";
13+
import { useSession, useAbortSession, useUpdateSession, useOpenCodeClient, useMessages, useConfig } from "@/hooks/useOpenCode";
1414
import { OPENCODE_API_ENDPOINT } from "@/config";
15+
import { getSessionModel } from "@/lib/model";
1516
import { useSSE } from "@/hooks/useSSE";
1617
import { useSettings } from "@/hooks/useSettings";
1718
import { useKeyboardShortcuts } from "@/hooks/useKeyboardShortcuts";
@@ -48,6 +49,9 @@ export function SessionDetail() {
4849
const repoDirectory = repo?.fullPath;
4950

5051
const { data: messages, isLoading: messagesLoading } = useMessages(opcodeUrl, sessionId, repoDirectory);
52+
const { data: config } = useConfig(opcodeUrl);
53+
54+
const currentSessionModel = useMemo(() => getSessionModel(messages, config?.model), [messages, config?.model]);
5155

5256
const { scrollToBottom } = useAutoScroll({
5357
containerRef: messageContainerRef,
@@ -205,6 +209,7 @@ export function SessionDetail() {
205209
open={modelDialogOpen}
206210
onOpenChange={setModelDialogOpen}
207211
opcodeUrl={opcodeUrl}
212+
currentSessionModel={currentSessionModel}
208213
/>
209214

210215
{/* Sessions Dialog */}

0 commit comments

Comments
 (0)