Local models
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import type { ModelOption } from 'state/useModels';
|
||||
import { getProviderDisplayName } from 'state/useModels';
|
||||
import type { ChatMessage } from '../types';
|
||||
|
||||
const PROVIDER_DISPLAY: Record<string, string> = {
|
||||
@@ -41,6 +42,12 @@ export function ModelSelector({
|
||||
hasStarted,
|
||||
}: ModelSelectorProps) {
|
||||
const providers = [...new Set(availableModels.map((m) => m.provider).filter(Boolean))] as string[];
|
||||
|
||||
console.log('[ModelSelector]', {
|
||||
availableModelsCount: availableModels.length,
|
||||
providers,
|
||||
models: availableModels.map(m => ({ id: m.id, provider: m.provider, name: m.name }))
|
||||
});
|
||||
|
||||
// Determine which model to display: selectedModel takes precedence, then model (from server), then fallback
|
||||
const displayModel = selectedModel || model;
|
||||
@@ -58,7 +65,15 @@ export function ModelSelector({
|
||||
if (firstModel) onModelChange(firstModel.id);
|
||||
};
|
||||
|
||||
const displayName = (provider: string) => PROVIDER_DISPLAY[provider] ?? provider;
|
||||
const displayName = (provider: string) => {
|
||||
// Handle local providers (officer-local-{uuid})
|
||||
if (provider.startsWith('officer-local-')) {
|
||||
const name = getProviderDisplayName(provider);
|
||||
console.log('[displayName] Local provider:', provider, '→', name);
|
||||
return name;
|
||||
}
|
||||
return PROVIDER_DISPLAY[provider] ?? provider;
|
||||
};
|
||||
|
||||
// Get display text for the model
|
||||
const getModelDisplayText = () => {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Plus, MessageSquare, Folder, ChevronRight, FolderPlus } from 'lucide-re
|
||||
import { usePanelChannel } from 'hooks/usePanelChannel';
|
||||
import { useChatSessions } from 'state/useChatSessions';
|
||||
import { useChatGroups } from 'state/useChatGroups';
|
||||
import { getProviderDisplayName } from 'state/useModels';
|
||||
import type { SelectedSession } from './ChatDetailPanel';
|
||||
import { CreateGroupDialog } from './CreateGroupDialog';
|
||||
import { GroupContextMenu } from './GroupContextMenu';
|
||||
@@ -91,7 +92,20 @@ export const SessionList = () => {
|
||||
</div>
|
||||
{session.model && (
|
||||
<div className="text-xs text-duck-teal/70 dark:text-duck-teal/60 truncate">
|
||||
{session.model.includes('/') ? session.model.replace('/', ' - ') : session.model}
|
||||
{(() => {
|
||||
if (!session.model.includes('/')) return session.model;
|
||||
|
||||
const [provider, modelId] = session.model.split('/');
|
||||
|
||||
// Handle local providers - show friendly name
|
||||
if (provider.startsWith('officer-local-')) {
|
||||
const friendlyName = getProviderDisplayName(provider);
|
||||
return `${friendlyName} - ${modelId}`;
|
||||
}
|
||||
|
||||
// Regular providers - just replace / with -
|
||||
return session.model.replace('/', ' - ');
|
||||
})()}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,13 @@ export function modelKey(m: ModelOption): string {
|
||||
return `${m.provider}:${m.id}`;
|
||||
}
|
||||
|
||||
// Store provider names globally for display
|
||||
let globalProviderNames: Record<string, string> = {};
|
||||
|
||||
export function getProviderDisplayName(providerId: string): string {
|
||||
return globalProviderNames[providerId] || providerId;
|
||||
}
|
||||
|
||||
export function usePiModels() {
|
||||
const client = useClient();
|
||||
const { isAuthenticated } = useAuth();
|
||||
@@ -18,7 +25,20 @@ export function usePiModels() {
|
||||
queryKey: ['PI_MODELS'],
|
||||
enabled: isAuthenticated,
|
||||
queryFn: async () => {
|
||||
const data = await client.get<{ models: ModelOption[] }>('/pi/models');
|
||||
const data = await client.get<{ models: ModelOption[]; providerNames?: Record<string, string> }>('/pi/models');
|
||||
|
||||
console.log('[usePiModels] Fetched models:', {
|
||||
modelCount: data.models.length,
|
||||
providerNames: data.providerNames,
|
||||
providers: [...new Set(data.models.map(m => m.provider))]
|
||||
});
|
||||
|
||||
// Store provider names for later use
|
||||
if (data.providerNames) {
|
||||
globalProviderNames = data.providerNames;
|
||||
console.log('[usePiModels] Stored provider names:', globalProviderNames);
|
||||
}
|
||||
|
||||
return data.models;
|
||||
},
|
||||
staleTime: 5 * 60 * 1000,
|
||||
@@ -32,8 +52,33 @@ export function useVisiblePiModels() {
|
||||
const { settings } = useSettings();
|
||||
const enabled = settings.ai?.enabledModels ?? [];
|
||||
|
||||
const filtered = models.filter((m) => enabled.includes(modelKey(m)));
|
||||
// If no models match the visibility filter, show all
|
||||
// The provider list changes dynamically based on API keys so the filter may be stale
|
||||
return filtered.length > 0 ? filtered : models;
|
||||
// If no enabled models list exists, show all models
|
||||
if (enabled.length === 0) {
|
||||
console.log('[useVisiblePiModels] No enabled models list, showing all');
|
||||
return models;
|
||||
}
|
||||
|
||||
// Get all providers from enabled models
|
||||
const enabledProviders = new Set(
|
||||
enabled.map(key => key.split(':')[0])
|
||||
);
|
||||
|
||||
// Filter to include:
|
||||
// 1. Models that are explicitly enabled
|
||||
// 2. Models from providers that aren't in the enabled list at all (new providers)
|
||||
const filtered = models.filter((m) => {
|
||||
const isExplicitlyEnabled = enabled.includes(modelKey(m));
|
||||
const isFromNewProvider = !enabledProviders.has(m.provider);
|
||||
return isExplicitlyEnabled || isFromNewProvider;
|
||||
});
|
||||
|
||||
console.log('[useVisiblePiModels]', {
|
||||
allModels: models.length,
|
||||
enabledModels: enabled,
|
||||
enabledProviders: Array.from(enabledProviders),
|
||||
filtered: filtered.length,
|
||||
finalCount: filtered.length
|
||||
});
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user