import type { CommitMessageAiSettings, CommitMessageAiModelCapability } from './commit-message-ai-types' import { LOCAL_COMMIT_MESSAGE_HOST_KEY } from './commit-message-host-key' import type { TuiAgent } from './tui-agent' import type { RepoSourceControlAiOverrides, SourceControlAiModelChoice, SourceControlAiOperation, SourceControlAiSettings } from './source-control-ai-types' export function readSourceControlAiModelChoiceForHost( choice: SourceControlAiModelChoice | null | undefined, hostKey: string, agentId: TuiAgent ): string | undefined { return ( choice?.selectedModelByAgentByHost?.[hostKey]?.[agentId] ?? (hostKey === LOCAL_COMMIT_MESSAGE_HOST_KEY ? choice?.selectedModelByAgent?.[agentId] : undefined) ) } export function selectSourceControlAiModelChoiceForHost( choice: SourceControlAiModelChoice | undefined, hostKey: string, agentId: TuiAgent, modelId: string ): SourceControlAiModelChoice { return { ...choice, selectedModelByAgent: hostKey === LOCAL_COMMIT_MESSAGE_HOST_KEY ? { ...choice?.selectedModelByAgent, [agentId]: modelId } : choice?.selectedModelByAgent, selectedModelByAgentByHost: { ...choice?.selectedModelByAgentByHost, [hostKey]: { ...choice?.selectedModelByAgentByHost?.[hostKey], [agentId]: modelId } } } } export function clearSourceControlAiModelChoiceForHost( choice: SourceControlAiModelChoice | undefined, hostKey: string, agentId: TuiAgent ): SourceControlAiModelChoice | undefined { if (!choice) { return undefined } const selectedModelByAgent = { ...choice.selectedModelByAgent } if (hostKey === LOCAL_COMMIT_MESSAGE_HOST_KEY) { delete selectedModelByAgent[agentId] } const selectedModelByAgentByHost = { ...choice.selectedModelByAgentByHost } const hostModels = { ...selectedModelByAgentByHost[hostKey] } delete hostModels[agentId] if (Object.keys(hostModels).length > 0) { selectedModelByAgentByHost[hostKey] = hostModels } else { delete selectedModelByAgentByHost[hostKey] } const nextChoice: SourceControlAiModelChoice = {} if (Object.keys(selectedModelByAgent).length > 0) { nextChoice.selectedModelByAgent = selectedModelByAgent } if (Object.keys(selectedModelByAgentByHost).length > 0) { nextChoice.selectedModelByAgentByHost = selectedModelByAgentByHost } const hasModelSelection = nextChoice.selectedModelByAgent !== undefined || nextChoice.selectedModelByAgentByHost !== undefined if (hasModelSelection && Object.keys(choice.selectedThinkingByModel ?? {}).length > 0) { nextChoice.selectedThinkingByModel = choice.selectedThinkingByModel } return hasModelSelection ? nextChoice : undefined } export function mergeSelectedModelByAgentByHost( base: Partial>>> | undefined, override: Partial>>> | undefined ): Partial>>> { const merged = base === undefined ? {} : structuredClone(base) for (const [hostKey, hostModels] of Object.entries(override ?? {})) { merged[hostKey] = { ...merged[hostKey], ...hostModels } } return merged } export function getDiscoveredModels( source: SourceControlAiSettings, legacy: CommitMessageAiSettings | null | undefined, hostKey: string, agentId: TuiAgent ): CommitMessageAiModelCapability[] { return ( source.discoveredModelsByAgentByHost?.[hostKey]?.[agentId] ?? (hostKey === LOCAL_COMMIT_MESSAGE_HOST_KEY ? (source.discoveredModelsByAgent?.[agentId] ?? legacy?.discoveredModelsByAgentByHost?.[hostKey]?.[agentId] ?? legacy?.discoveredModelsByAgent?.[agentId] ?? []) : (legacy?.discoveredModelsByAgentByHost?.[hostKey]?.[agentId] ?? [])) ) } export function selectPersistedModelId(args: { source: SourceControlAiSettings legacy: CommitMessageAiSettings | null | undefined repoOverrides: RepoSourceControlAiOverrides | null | undefined operation: SourceControlAiOperation hostKey: string agentId: TuiAgent defaultModelId: string }): string { const { source, legacy, repoOverrides, operation, hostKey, agentId, defaultModelId } = args return ( readSourceControlAiModelChoiceForHost( repoOverrides?.modelOverridesByOperation?.[operation], hostKey, agentId ) ?? readSourceControlAiModelChoiceForHost( source.modelOverridesByOperation?.[operation], hostKey, agentId ) ?? readSourceControlAiModelChoiceForHost( { selectedModelByAgent: source.selectedModelByAgent, selectedModelByAgentByHost: source.selectedModelByAgentByHost }, hostKey, agentId ) ?? legacy?.selectedModelByAgentByHost?.[hostKey]?.[agentId] ?? (hostKey === LOCAL_COMMIT_MESSAGE_HOST_KEY ? legacy?.selectedModelByAgent?.[agentId] : undefined) ?? defaultModelId ) } export function resolveThinkingLevel(args: { model: CommitMessageAiModelCapability source: SourceControlAiSettings legacy: CommitMessageAiSettings | null | undefined repoOverrides: RepoSourceControlAiOverrides | null | undefined operation: SourceControlAiOperation }): string | undefined { if (!args.model.thinkingLevels?.length) { return undefined } const persisted = args.repoOverrides?.modelOverridesByOperation?.[args.operation]?.selectedThinkingByModel?.[ args.model.id ] ?? args.source.modelOverridesByOperation?.[args.operation]?.selectedThinkingByModel?.[ args.model.id ] ?? args.source.selectedThinkingByModel[args.model.id] ?? args.legacy?.selectedThinkingByModel?.[args.model.id] return args.model.thinkingLevels.some((level) => level.id === persisted) ? persisted : args.model.defaultThinkingLevel }