import { useState, useCallback, useMemo } from 'react';
import { useAppStore } from '@/store/app-store';
import type { ModelId, PhaseModelKey, PhaseModelEntry } from '@automaker/types';
import { DEFAULT_PHASE_MODELS } from '@automaker/types';
export interface UseModelOverrideOptions {
/** Which phase this override is for */
phase: PhaseModelKey;
/** Initial override value (optional) */
initialOverride?: PhaseModelEntry | null;
}
export interface UseModelOverrideResult {
/** The effective model entry (override or global default) */
effectiveModelEntry: PhaseModelEntry;
/** The effective model string (for backward compatibility with APIs that only accept strings) */
effectiveModel: ModelId;
/** Whether the model is currently overridden */
isOverridden: boolean;
/** Set a model override */
setOverride: (entry: PhaseModelEntry | null) => void;
/** Clear the override and use global default */
clearOverride: () => void;
/** The global default for this phase */
globalDefault: PhaseModelEntry;
/** The current override value (null if not overridden) */
override: PhaseModelEntry | null;
}
/**
* Normalize PhaseModelEntry or string to PhaseModelEntry
*/
function normalizeEntry(entry: PhaseModelEntry | string): PhaseModelEntry {
if (typeof entry === 'string') {
return { model: entry as ModelId };
}
return entry;
}
/**
* Hook for managing model overrides per phase
*
* Provides a simple way to allow users to override the global phase model
* for a specific run or context. Now supports PhaseModelEntry with thinking levels.
*
* @example
* ```tsx
* function EnhanceDialog() {
* const { effectiveModelEntry, isOverridden, setOverride, clearOverride } = useModelOverride({
* phase: 'enhancementModel',
* });
*
* return (
*
* );
* }
* ```
*/
export function useModelOverride({
phase,
initialOverride = null,
}: UseModelOverrideOptions): UseModelOverrideResult {
const { phaseModels } = useAppStore();
const [override, setOverrideState] = useState(
initialOverride ? normalizeEntry(initialOverride) : null
);
// Normalize global default to PhaseModelEntry, with fallback to DEFAULT_PHASE_MODELS
// This handles cases where settings haven't been migrated to include new phase models
const globalDefault = normalizeEntry(phaseModels[phase] ?? DEFAULT_PHASE_MODELS[phase]);
const effectiveModelEntry = useMemo(() => {
return override ?? globalDefault;
}, [override, globalDefault]);
const effectiveModel = useMemo(() => {
return effectiveModelEntry.model;
}, [effectiveModelEntry]);
const isOverridden = override !== null;
const setOverride = useCallback((entry: PhaseModelEntry | null) => {
setOverrideState(entry ? normalizeEntry(entry) : null);
}, []);
const clearOverride = useCallback(() => {
setOverrideState(null);
}, []);
return {
effectiveModelEntry,
effectiveModel,
isOverridden,
setOverride,
clearOverride,
globalDefault,
override,
};
}