@@ -42,6 +42,11 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
4242import { useDebouncedValue } from "@tanstack/react-pacer" ;
4343import { useNavigate } from "@tanstack/react-router" ;
4444import { gitBranchesQueryOptions , gitCreateWorktreeMutationOptions } from "~/lib/gitReactQuery" ;
45+ import {
46+ getSelectableThreadProviders ,
47+ getThreadProviderLabel ,
48+ resolveThreadProviderSelection ,
49+ } from "~/lib/providerAvailability" ;
4550import { projectSearchEntriesQueryOptions } from "~/lib/projectReactQuery" ;
4651import {
4752 skillCatalogQueryOptions ,
@@ -194,7 +199,7 @@ import { useDiffViewerStore } from "~/diffViewerStore";
194199import { PreviewPanel } from "./PreviewPanel" ;
195200import { ContextWindowMeter } from "./chat/ContextWindowMeter" ;
196201import { buildExpandedImagePreview , ExpandedImagePreview } from "./chat/ExpandedImagePreview" ;
197- import { AVAILABLE_PROVIDER_OPTIONS , ProviderModelPicker } from "./chat/ProviderModelPicker" ;
202+ import { ProviderModelPicker } from "./chat/ProviderModelPicker" ;
198203import { ComposerCommandItem , ComposerCommandMenu } from "./chat/ComposerCommandMenu" ;
199204import { ComposerPendingApprovalActions } from "./chat/ComposerPendingApprovalActions" ;
200205import { CompactComposerControlsMenu } from "./chat/CompactComposerControlsMenu" ;
@@ -858,6 +863,15 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
858863
859864 const sessionProvider = activeThread ?. session ?. provider ?? null ;
860865 const selectedProviderByThreadId = composerDraft . provider ;
866+ const providerStatuses = serverConfigQuery . data ?. providers ?? EMPTY_PROVIDER_STATUSES ;
867+ const selectableProviders = useMemo (
868+ ( ) =>
869+ getSelectableThreadProviders ( {
870+ statuses : providerStatuses ,
871+ openclawGatewayUrl : settings . openclawGatewayUrl ,
872+ } ) ,
873+ [ providerStatuses , settings . openclawGatewayUrl ] ,
874+ ) ;
861875 const hasThreadStarted = Boolean (
862876 activeThread &&
863877 ( activeThread . latestTurn !== null ||
@@ -867,7 +881,12 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
867881 const lockedProvider : ProviderKind | null = hasThreadStarted
868882 ? ( sessionProvider ?? selectedProviderByThreadId ?? null )
869883 : null ;
870- const selectedProvider : ProviderKind = lockedProvider ?? selectedProviderByThreadId ?? "codex" ;
884+ const selectedProvider : ProviderKind =
885+ lockedProvider ??
886+ resolveThreadProviderSelection ( {
887+ preferredProvider : selectedProviderByThreadId ,
888+ selectableProviders,
889+ } ) ;
871890 const baseThreadModel = resolveModelSlugForProvider (
872891 selectedProvider ,
873892 activeThread ?. model ?? activeProject ?. model ?? getDefaultModel ( selectedProvider ) ,
@@ -907,20 +926,18 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
907926 } , [ modelOptionsByProvider , selectedModelForPicker , selectedProvider ] ) ;
908927 const searchableModelOptions = useMemo (
909928 ( ) =>
910- AVAILABLE_PROVIDER_OPTIONS . filter (
911- ( option ) => lockedProvider === null || option . value === lockedProvider ,
912- ) . flatMap ( ( option ) =>
913- modelOptionsByProvider [ option . value ] . map ( ( { slug, name } ) => ( {
914- provider : option . value ,
915- providerLabel : option . label ,
929+ ( lockedProvider !== null ? [ lockedProvider ] : selectableProviders ) . flatMap ( ( provider ) =>
930+ modelOptionsByProvider [ provider ] . map ( ( { slug, name } ) => ( {
931+ provider,
932+ providerLabel : getThreadProviderLabel ( provider ) ,
916933 slug,
917934 name,
918935 searchSlug : slug . toLowerCase ( ) ,
919936 searchName : name . toLowerCase ( ) ,
920- searchProvider : option . label . toLowerCase ( ) ,
937+ searchProvider : getThreadProviderLabel ( provider ) . toLowerCase ( ) ,
921938 } ) ) ,
922939 ) ,
923- [ lockedProvider , modelOptionsByProvider ] ,
940+ [ lockedProvider , modelOptionsByProvider , selectableProviders ] ,
924941 ) ;
925942 const phase = derivePhase ( activeThread ?. session ?? null ) ;
926943 const isSendBusy = sendPhase !== "idle" ;
@@ -1535,7 +1552,6 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
15351552 } ;
15361553 } , [ ] ) ;
15371554 const keybindings = serverConfigQuery . data ?. keybindings ?? EMPTY_KEYBINDINGS ;
1538- const providerStatuses = serverConfigQuery . data ?. providers ?? EMPTY_PROVIDER_STATUSES ;
15391555 const activeProviderStatus = useMemo (
15401556 ( ) => providerStatuses . find ( ( status ) => status . provider === selectedProvider ) ?? null ,
15411557 [ selectedProvider , providerStatuses ] ,
@@ -5319,6 +5335,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
53195335 provider = { selectedProvider }
53205336 model = { selectedModelForPickerWithCustomFallback }
53215337 lockedProvider = { lockedProvider }
5338+ availableProviders = { selectableProviders }
53225339 modelOptionsByProvider = { modelOptionsByProvider }
53235340 { ...( composerProviderState . modelPickerIconClassName
53245341 ? {
0 commit comments