| ... | @@ -304,7 +304,8 @@ type ComposerCommandItem = | ... | @@ -304,7 +304,8 @@ type ComposerCommandItem = |
| 304 | | { | 304 | | { |
| 305 | id: string; | 305 | id: string; |
| 306 | type: "model"; | 306 | type: "model"; |
| 307 | model: string; | 307 | provider: ProviderKind; |
| | 308 | model: ModelSlug; |
| 308 | label: string; | 309 | label: string; |
| 309 | description: string; | 310 | description: string; |
| 310 | }; | 311 | }; |
| ... | @@ -658,27 +659,21 @@ export default function ChatView({ threadId }: ChatViewProps) { | ... | @@ -658,27 +659,21 @@ export default function ChatView({ threadId }: ChatViewProps) { |
| 658 | ); | 659 | ); |
| 659 | const selectedModel = resolveModelSlugForProvider(selectedProvider, composerDraft.model ?? baseThreadModel); | 660 | const selectedModel = resolveModelSlugForProvider(selectedProvider, composerDraft.model ?? baseThreadModel); |
| 660 | const selectedEffort = composerDraft.effort ?? DEFAULT_REASONING; | 661 | const selectedEffort = composerDraft.effort ?? DEFAULT_REASONING; |
| 661 | const modelOptions = useMemo( | 662 | const searchableModelOptions = useMemo( |
| 662 | () => | 663 | () => |
| 663 | selectedProvider === "codex" | 664 | PROVIDER_OPTIONS.filter((option) => option.available).flatMap((option) => |
| 664 | ? getAppModelOptions(settings.customCodexModels, selectedModel) | 665 | getModelOptions(option.value).map(({ slug, name }) => ({ |
| 665 | : getModelOptions(selectedProvider), | 666 | provider: option.value, |
| 666 | [selectedModel, selectedProvider, settings.customCodexModels], | 667 | providerLabel: option.label, |
| | 668 | slug, |
| | 669 | name, |
| | 670 | searchSlug: slug.toLowerCase(), |
| | 671 | searchName: name.toLowerCase(), |
| | 672 | searchProvider: option.label.toLowerCase(), |
| | 673 | })), |
| | 674 | ), |
| | 675 | [], |
| 667 | ); | 676 | ); |
| 668 | const slashModelOptions = useMemo(() => { | | |
| 669 | if (selectedProvider === "codex") { | | |
| 670 | return getSlashModelOptions(settings.customCodexModels, composerTrigger?.query ?? "", selectedModel); | | |
| 671 | } | | |
| 672 | const query = (composerTrigger?.query ?? "").trim().toLowerCase(); | | |
| 673 | if (!query) { | | |
| 674 | return modelOptions; | | |
| 675 | } | | |
| 676 | return modelOptions.filter(({ slug, name }) => { | | |
| 677 | const searchSlug = slug.toLowerCase(); | | |
| 678 | const searchName = name.toLowerCase(); | | |
| 679 | return searchSlug.includes(query) || searchName.includes(query); | | |
| 680 | }); | | |
| 681 | }, [composerTrigger?.query, modelOptions, selectedModel, selectedProvider, settings.customCodexModels]); | | |
| 682 | useEffect(() => { | 677 | useEffect(() => { |
| 683 | if (!activeThread?.id || !sessionProvider) return; | 678 | if (!activeThread?.id || !sessionProvider) return; |
| 684 | setSelectedProviderByThread((existing) => { | 679 | setSelectedProviderByThread((existing) => { |
| ... | @@ -961,14 +956,19 @@ export default function ChatView({ threadId }: ChatViewProps) { | ... | @@ -961,14 +956,19 @@ export default function ChatView({ threadId }: ChatViewProps) { |
| 961 | ]; | 956 | ]; |
| 962 | } | 957 | } |
| 963 | | 958 | |
| 964 | return slashModelOptions.map(({ slug, name }) => ({ | 959 | return searchableModelOptions.filter(({ searchSlug, searchName, searchProvider }) => { |
| 965 | id: `model:${slug}`, | 960 | const query = composerTrigger.query.trim().toLowerCase(); |
| 966 | type: "model" as const, | 961 | if (!query) return true; |
| | 962 | return searchSlug.includes(query) || searchName.includes(query) || searchProvider.includes(query); |
| | 963 | }).map(({ provider, providerLabel, slug, name }) => ({ |
| | 964 | id: `model:${provider}:${slug}`, |
| | 965 | type: "model", |
| | 966 | provider, |
| 967 | model: slug, | 967 | model: slug, |
| 968 | label: name, | 968 | label: name, |
| 969 | description: slug, | 969 | description: `${providerLabel} · ${slug}`, |
| 970 | })); | 970 | })); |
| 971 | }, [composerTrigger, slashModelOptions, workspaceEntries]); | 971 | }, [composerTrigger, searchableModelOptions, workspaceEntries]); |
| 972 | const composerMenuOpen = Boolean(composerTrigger); | 972 | const composerMenuOpen = Boolean(composerTrigger); |
| 973 | const activeComposerMenuItem = useMemo( | 973 | const activeComposerMenuItem = useMemo( |
| 974 | () => | 974 | () => |
| ... | @@ -2255,24 +2255,6 @@ export default function ChatView({ threadId }: ChatViewProps) { | ... | @@ -2255,24 +2255,6 @@ export default function ChatView({ threadId }: ChatViewProps) { |
| 2255 | [activeThreadId, setStoreThreadError], | 2255 | [activeThreadId, setStoreThreadError], |
| 2256 | ); | 2256 | ); |
| 2257 | | 2257 | |
| 2258 | const onModelSelect = useCallback( | | |
| 2259 | (model: string) => { | | |
| 2260 | const normalizedModel = normalizeModelSlug(model); | | |
| 2261 | const resolvedModel = normalizedModel ?? baseThreadModel; | | |
| 2262 | setComposerDraftModel(threadId, resolvedModel === baseThreadModel ? null : resolvedModel); | | |
| 2263 | const api = readNativeApi(); | | |
| 2264 | if (api && isServerThread && activeThread) { | | |
| 2265 | void api.orchestration.dispatchCommand({ | | |
| 2266 | type: "thread.meta.update", | | |
| 2267 | commandId: newCommandId(), | | |
| 2268 | threadId: activeThread.id, | | |
| 2269 | model: resolveModelSlugForProvider(selectedProvider, model), | | |
| 2270 | }); | | |
| 2271 | } | | |
| 2272 | scheduleComposerFocus(); | | |
| 2273 | }, | | |
| 2274 | [activeThread, scheduleComposerFocus, selectedProvider], | | |
| 2275 | ); | | |
| 2276 | const onProviderModelSelect = useCallback( | 2258 | const onProviderModelSelect = useCallback( |
| 2277 | (provider: ProviderKind, model: ModelSlug) => { | 2259 | (provider: ProviderKind, model: ModelSlug) => { |
| 2278 | const api = readNativeApi(); | 2260 | const api = readNativeApi(); |
| ... | @@ -2390,7 +2372,7 @@ export default function ChatView({ threadId }: ChatViewProps) { | ... | @@ -2390,7 +2372,7 @@ export default function ChatView({ threadId }: ChatViewProps) { |
| 2390 | } | 2372 | } |
| 2391 | return; | 2373 | return; |
| 2392 | } | 2374 | } |
| 2393 | onModelSelect(item.model); | 2375 | onProviderModelSelect(item.provider, item.model); |
| 2394 | const applied = applyPromptReplacement(trigger.rangeStart, trigger.rangeEnd, "", { | 2376 | const applied = applyPromptReplacement(trigger.rangeStart, trigger.rangeEnd, "", { |
| 2395 | expectedText: expectedToken, | 2377 | expectedText: expectedToken, |
| 2396 | }); | 2378 | }); |
| ... | @@ -2398,7 +2380,7 @@ export default function ChatView({ threadId }: ChatViewProps) { | ... | @@ -2398,7 +2380,7 @@ export default function ChatView({ threadId }: ChatViewProps) { |
| 2398 | setComposerHighlightedItemId(null); | 2380 | setComposerHighlightedItemId(null); |
| 2399 | } | 2381 | } |
| 2400 | }, | 2382 | }, |
| 2401 | [applyPromptReplacement, onModelSelect, resolveActiveComposerTrigger], | 2383 | [applyPromptReplacement, onProviderModelSelect, resolveActiveComposerTrigger], |
| 2402 | ); | 2384 | ); |
| 2403 | const onComposerMenuItemHighlighted = useCallback((itemId: string | null) => { | 2385 | const onComposerMenuItemHighlighted = useCallback((itemId: string | null) => { |
| 2404 | setComposerHighlightedItemId(itemId); | 2386 | setComposerHighlightedItemId(itemId); |