Open History to see the last commit
1import {
2 type DraftId,
3 deriveEffectiveComposerModelState,
4 useComposerDraftModelState,
5} from "../../composerDraftStore";
6import {
7 type ModelSelection,
8 type ProjectId,
9 ProviderDriverKind,
10 type ScopedThreadRef,
11 type ServerProvider,
12} from "@t3tools/contracts";
13import {
14 NO_PROVIDER_MODEL_SELECTION,
15 providerInstanceEntriesFor,
16 type ProviderInstanceEntry,
17} from "../../providerInstances";
18import { type UnifiedSettings } from "@t3tools/contracts/settings";
19import { getComposerPromptInjectionState, getComposerProviderState } from "./composerProviderState";
20import { resolveComposerProviderSelection } from "../ChatView.logic";
21
22const NO_PROVIDER_MODELS: ServerProvider["models"] = [];
23
24/**
25 * The provider instances the composer offers, which one is selected, and the model and options
26 * the draft resolves to on it. The draft store is read first so every derivation follows the only
27 * hook here; in the composer body they would straddle its later hooks and lose their cache.
28 */
29export function useComposerProviderModel(
30 input: Omit<Parameters<typeof resolveComposerProviderSelection>[0], "entries"> & {
31 readonly providerStatuses: ReadonlyArray<ServerProvider>;
32 readonly settings: UnifiedSettings;
33 readonly activeProjectId: ProjectId | null;
34 readonly threadRef: ScopedThreadRef | DraftId;
35 readonly threadModelSelection: ModelSelection | null | undefined;
36 readonly projectModelSelection: ModelSelection | null | undefined;
37 readonly promptInjectionState: ReturnType<typeof getComposerPromptInjectionState>;
38 },
39) {
40 const {
41 providerStatuses,
42 settings,
43 activeProjectId,
44 threadRef,
45 threadModelSelection,
46 projectModelSelection,
47 promptInjectionState,
48 candidateInstanceIds,
49 lockedProvider,
50 lockedInstanceId,
51 } = input;
52 const draftModelState = useComposerDraftModelState(threadRef);
53 const providerInstanceEntries: ReadonlyArray<ProviderInstanceEntry> = providerInstanceEntriesFor(
54 providerStatuses,
55 settings,
56 activeProjectId,
57 );
58 const selection = resolveComposerProviderSelection({
59 entries: providerInstanceEntries,
60 candidateInstanceIds,
61 lockedProvider,
62 lockedInstanceId,
63 });
64 const selectedInstanceId =
65 selection.selectedProviderEntry?.instanceId ?? NO_PROVIDER_MODEL_SELECTION.instanceId;
66 const selectedProvider: ProviderDriverKind =
67 selection.selectedProviderEntry?.driverKind ?? selection.requestedDriverKind;
68 const modelState = deriveEffectiveComposerModelState({
69 draft: draftModelState,
70 providers: providerStatuses,
71 selectedProvider,
72 selectedInstanceId,
73 requestedInstanceId: selection.requestedInstanceId,
74 threadModelSelection,
75 projectModelSelection,
76 settings,
77 });
78 const selectedProviderModels = selection.selectedProviderEntry?.models ?? NO_PROVIDER_MODELS;
79 const composerProviderState = getComposerProviderState({
80 provider: selectedProvider,
81 model: modelState.selectedModel,
82 models: selectedProviderModels,
83 promptInjectionState,
84 modelOptions: modelState.modelOptions?.[selectedInstanceId],
85 });
86 return {
87 providerInstanceEntries,
88 ...selection,
89 selectedInstanceId,
90 selectedProvider,
91 selectedProviderModels,
92 composerModelOptions: modelState.modelOptions,
93 selectedModel: modelState.selectedModel,
94 composerProviderState,
95 };
96}