/** * @license * Copyright 2025 Vybestack LLC * SPDX-License-Identifier: Apache-2.0 */ import type React from 'react'; import { useState, useCallback } from 'react'; import { Box, Text } from 'ink'; import { SemanticColors } from '../colors.js'; import { useResponsive } from '../hooks/useResponsive.js'; import { useKeypress } from '../hooks/useKeypress.js'; import type { Profile } from '@vybestack/llxprt-code-settings'; import { getBorderStyle } from '../contexts/UnicodeRenderingContext.js'; interface ProfileDetailDialogProps { profileName: string; profile: Profile | null; onClose: () => void; onLoad: (profileName: string) => void; onDelete: (profileName: string) => void; onSetDefault: (profileName: string) => void; onEdit: (profileName: string) => void; isLoading?: boolean; isDefault?: boolean; isActive?: boolean; error?: string; } interface LoadBalancerMemberDetail { name: string; provider?: string; model?: string; contextLimit?: number; reasoningEnabled?: boolean; temperature?: unknown; maxTokens?: unknown; loadError?: boolean; } type LoadBalancerDisplayProfile = Profile & { type: 'loadbalancer'; profiles: string[]; policy: string; contextLimit?: number; loadBalancerProfileDetails?: LoadBalancerMemberDetail[]; }; /** * Allowlist of ephemeralSettings keys that are safe to display. * Any key NOT in this set will be hidden to prevent accidental secret leakage. */ const SAFE_EPHEMERAL_KEYS = new Set([ 'baseurl', 'endpoint', 'url', 'timeout', 'maxretries', 'retries', 'region', 'debug', 'loglevel', 'version', 'apiversion', 'organization', 'orgid', 'project', 'projectid', 'maxtokens', 'temperature', 'topp', 'topk', 'stream', 'safetysettings', ]); // Type guard for load balancer profile function isLoadBalancerProfile(profile: Profile): profile is Profile & { type: 'loadbalancer'; profiles: string[]; policy: string; } { const record = asRenderableRecord(profile); return ( profile.type === 'loadbalancer' && Array.isArray(record?.profiles) && typeof record.policy === 'string' ); } function asRenderableRecord( value: unknown, ): Record | undefined { if (typeof value !== 'object' || value === null || Array.isArray(value)) { return undefined; } return value as Record; } function getBooleanValue( record: Record | undefined, key: string, ): boolean | undefined { const value = record?.[key]; return typeof value === 'boolean' ? value : undefined; } function getLoadBalancerContextLimit( profile: LoadBalancerDisplayProfile, ): number | undefined { return profile.contextLimit; } function getLoadBalancerEffectiveMinimum( profile: LoadBalancerDisplayProfile, ): number | undefined { const limits = profile.loadBalancerProfileDetails ?.map((detail) => detail.contextLimit) .filter( (value): value is number => typeof value === 'number' && Number.isInteger(value) && value > 0, ); return limits === undefined || limits.length === 0 ? undefined : Math.min(...limits); } function formatDetailValue(value: unknown): string { if (typeof value === 'string') return value; return JSON.stringify(value); } function handleDetailKeypress( key: { name?: string; sequence?: string }, confirmDelete: boolean, profileName: string, error: string | undefined, profile: Profile | null, setConfirmDelete: React.Dispatch>, onClose: () => void, onDelete: (name: string) => void, onLoad: (name: string) => void, onEdit: (name: string) => void, onSetDefault: (name: string) => void, ): void { if (key.name === 'escape') { if (confirmDelete) { setConfirmDelete(false); } else { onClose(); } return; } if (error || !profile) { return; } if (confirmDelete) { if (key.sequence === 'y' || key.sequence === 'Y') { onDelete(profileName); } else if (key.sequence === 'n' || key.sequence === 'N') { setConfirmDelete(false); } return; } if (key.sequence === 'l') { onLoad(profileName); return; } if (key.sequence === 'e') { onEdit(profileName); return; } if (key.sequence === 'd') { setConfirmDelete(true); } if (key.sequence === 's') { onSetDefault(profileName); } } const LoadBalancerMemberItem: React.FC<{ memberName: string; detail: LoadBalancerMemberDetail | undefined; }> = ({ memberName, detail }) => ( {' '}- {memberName} {detail?.loadError === true && ( {' '}details unavailable )} {detail?.provider !== undefined && ( {' '}Provider: {detail.provider} )} {detail?.model !== undefined && ( {' '}Model: {detail.model} )} {detail?.contextLimit !== undefined && ( {' '}Context Limit: {detail.contextLimit} )} {detail?.reasoningEnabled !== undefined && ( {' '}Reasoning: {detail.reasoningEnabled ? 'enabled' : 'disabled'} )} {detail?.temperature !== undefined && ( {' '}temperature: {formatDetailValue(detail.temperature)} )} {detail?.maxTokens !== undefined && ( {' '}maxTokens: {formatDetailValue(detail.maxTokens)} )} ); const LoadBalancerConfig: React.FC<{ profile: LoadBalancerDisplayProfile; }> = ({ profile }) => { const ephemeralSettings = asRenderableRecord(profile.ephemeralSettings); const modelParams = asRenderableRecord(profile.modelParams); const contextLimit = getLoadBalancerContextLimit(profile); const effectiveMinimum = getLoadBalancerEffectiveMinimum(profile); const reasoningEnabled = getBooleanValue( ephemeralSettings, 'reasoning.enabled', ); return ( Type: Load Balancer Policy: {profile.policy} {contextLimit !== undefined && ( Context Limit: {contextLimit} )} {effectiveMinimum !== undefined && ( Effective Minimum Context:{' '} {effectiveMinimum} )} {reasoningEnabled !== undefined && ( Reasoning: {reasoningEnabled ? 'enabled' : 'disabled'} )} {modelParams !== undefined && ( )} Member Profiles: {profile.profiles.map((memberName: string) => { const detail = profile.loadBalancerProfileDetails?.find( (candidate) => candidate.name === memberName, ); return ( ); })} ); }; const ModelParamsSection: React.FC<{ modelParams: Record; }> = ({ modelParams }) => { if (Object.keys(modelParams).length === 0) return null; return ( Model Parameters: {Object.entries(modelParams).map(([key, value]) => ( {' '} {key}: {JSON.stringify(value)} ))} ); }; const EphemeralSettingsSection: React.FC<{ ephemeralSettings: Record; }> = ({ ephemeralSettings }) => ( Settings: {Object.entries(ephemeralSettings) .filter(([key]) => SAFE_EPHEMERAL_KEYS.has(key.toLowerCase())) .filter(([, value]) => value !== undefined && value !== null) .slice(0, 10) .map(([key, value]) => ( {' '} {key}: {JSON.stringify(value)} ))} ); const AuthConfigSection: React.FC<{ profile: Profile & { auth?: { type: string; buckets?: string[] } }; }> = ({ profile }) => { if (!profile.auth) return null; return ( Authentication: {' '}Type: {profile.auth.type} {profile.auth.buckets != null && profile.auth.buckets.length > 0 && ( {' '}Buckets: {profile.auth.buckets.join(', ')} )} ); }; const StandardProfileConfig: React.FC<{ profile: Profile }> = ({ profile }) => { const modelParams = asRenderableRecord( (profile as { modelParams?: unknown }).modelParams, ); const ephemeralSettings = asRenderableRecord( (profile as { ephemeralSettings?: unknown }).ephemeralSettings, ); return ( Type: Standard Provider: {profile.provider} Model: {profile.model} {modelParams !== undefined && ( )} {ephemeralSettings !== undefined && ( )} ); }; const ProfileConfigDisplay: React.FC<{ profile: Profile }> = ({ profile }) => { if (isLoadBalancerProfile(profile)) { return ; } return ; }; const DeleteConfirmation: React.FC<{ profileName: string; width: number; }> = ({ profileName, width }) => ( Delete Profile? Are you sure you want to delete "{profileName}"? This action cannot be undone. Press y to confirm, n or Esc to cancel ); const ActionsBar: React.FC = () => ( Actions: l=load{' '} e=edit{' '} d=delete{' '} s=set-default{' '} Esc=back ); const LoadingState: React.FC = () => ( Loading profile... ); const ErrorState: React.FC<{ error: string }> = ({ error }) => ( Error Loading Profile {error} Press Esc to go back ); const NotFoundState: React.FC<{ profileName: string }> = ({ profileName }) => ( Profile not found: {profileName} Press Esc to go back ); const ProfileHeader: React.FC<{ profileName: string; isActive: boolean; isDefault: boolean; }> = ({ profileName, isActive, isDefault }) => ( {profileName} {isActive && (Active)} {isDefault && (Default)} ); export const ProfileDetailDialog: React.FC = ({ profileName, profile, onClose, onLoad, onDelete, onSetDefault, onEdit, isLoading = false, isDefault = false, isActive = false, error, }) => { const { isNarrow, width } = useResponsive(); const [confirmDelete, setConfirmDelete] = useState(false); const handleKeypress = useCallback( (key: Parameters[0]>[0]) => { handleDetailKeypress( key, confirmDelete, profileName, error, profile, setConfirmDelete, onClose, onDelete, onLoad, onEdit, onSetDefault, ); }, [ confirmDelete, profileName, error, profile, setConfirmDelete, onClose, onDelete, onLoad, onEdit, onSetDefault, ], ); useKeypress(handleKeypress, { isActive: !isLoading }); if (isLoading) return ; if (error) return ; if (!profile) return ; if (confirmDelete) { return ; } const dialogWidth = isNarrow ? undefined : Math.min(width, 80); return ( ); };