Complete frontend migration to unified Pi harness (Phase 7 + Phase 9)

- Delete legacy hooks: useClaude.ts, useOpenCode.ts, usePiMono.ts, App.backup.tsx
- Update all components to use usePi instead of legacy hooks
- Replace useVisiblePiMonoModels/useClaudeModels/useOpenCodeModels with useVisiblePiModels
- Migrate from LegacyChatMessage to ChatMessage type throughout
- Update SessionBar to remove provider and archive props
- Simplify ChatDetailPanel to Pi-only (remove Claude/OpenCode components)
- Fix useChatSessions calls (remove provider parameter)
- Update user-settings types: provider now only 'pi' instead of legacy values
- Update PI_HARNESS_REBUILD.md to mark phases complete
This commit is contained in:
2026-02-20 21:42:26 +00:00
parent 92f4b2be8e
commit ba51ee0320
31 changed files with 225 additions and 1176 deletions
+18 -73
View File
@@ -1,94 +1,39 @@
import { useMemo } from 'react';
import { useQuery } from '@tanstack/react-query';
import { useClient } from 'hooks/useClient';
import { useAuth } from 'hooks/useAuth';
import { useSettings } from './useSettings';
import type { ModelOption } from 'apps/Chat';
export type ModelOption = { id: string; name: string; provider?: string; providerId?: string };
export type { ModelOption };
export const modelKey = (m: ModelOption) => (m.provider ? `${m.provider}:${m.id}` : m.id);
export function modelKey(m: ModelOption): string {
return `${m.provider}:${m.id}`;
}
// Hardcoded fallback in case the API call fails
const CLAUDE_MODELS: ModelOption[] = [
{ id: 'claude-sonnet-4-5', name: 'Claude Sonnet 4.5' },
{ id: 'claude-opus-4-6', name: 'Claude Opus 4.6' },
{ id: 'claude-haiku-4-5', name: 'Claude Haiku 4.5' },
];
export const useClaudeModels = () => {
export function usePiModels() {
const client = useClient();
const { isAuthenticated } = useAuth();
const { data: models = CLAUDE_MODELS } = useQuery<ModelOption[]>({
queryKey: ['CLAUDE_MODELS'],
const { data: models = [] } = useQuery<ModelOption[]>({
queryKey: ['PI_MODELS'],
enabled: isAuthenticated,
queryFn: async () => {
const data = await client.get<ModelOption[]>('/claude/models');
return data.length > 0 ? data : CLAUDE_MODELS;
const data = await client.get<{ models: ModelOption[] }>('/api/pi/models');
return data.models;
},
staleTime: 10 * 60 * 1000,
});
return models;
};
/** @deprecated Use useClaudeModels() instead */
export const claudeModels = CLAUDE_MODELS;
export const useOpenCodeModels = () => {
const client = useClient();
const { isAuthenticated } = useAuth();
const { data: models = [] } = useQuery<ModelOption[]>({
queryKey: ['OC_MODELS'],
enabled: isAuthenticated,
queryFn: () => client.get<ModelOption[]>('/opencode/models'),
staleTime: 5 * 60 * 1000,
});
return models;
};
}
export const useVisibleClaudeModels = () => {
const models = useClaudeModels();
export function useVisiblePiModels() {
const models = usePiModels();
const { settings } = useSettings();
const enabled = settings.ai?.enabledModels ?? [];
return useMemo(() => models.filter((m) => enabled.includes(modelKey(m))), [models, enabled]);
};
export const useVisibleOpenCodeModels = () => {
const models = useOpenCodeModels();
const { settings } = useSettings();
const providers = settings.ai?.enabledProviders ?? [];
const enabled = settings.ai?.enabledModels ?? [];
return useMemo(
() => models.filter((m) => providers.includes(m.provider ?? '') && enabled.includes(modelKey(m))),
[models, providers, enabled],
);
};
export const usePiMonoModels = () => {
const client = useClient();
const { isAuthenticated } = useAuth();
const { data: models = [] } = useQuery<ModelOption[]>({
queryKey: ['PI_MONO_MODELS'],
enabled: isAuthenticated,
queryFn: () => client.get<ModelOption[]>('/pi-mono/models'),
staleTime: 5 * 60 * 1000,
});
return models;
};
export const useVisiblePiMonoModels = () => {
const models = usePiMonoModels();
const { settings } = useSettings();
const enabled = settings.ai?.enabledModels ?? [];
return useMemo(() => {
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;
}, [models, enabled]);
};
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;
}