@@ -591,16 +591,57 @@ export function modelPickerItems(
591591 * caller maps it back to the {@link ModelChoice}. The description carries the
592592 * owning connection so identical model ids on different providers are readable.
593593 */
594+ export function modelChoiceConnectionLabels ( choices : readonly ModelChoice [ ] ) : Map < string , string > {
595+ const connectionBySlug = new Map <
596+ string ,
597+ Pick < ModelChoice , 'connectionId' | 'connectionName' | 'connectionSlug' >
598+ > ( ) ;
599+ for ( const choice of choices ) {
600+ if ( ! connectionBySlug . has ( choice . connectionSlug ) ) {
601+ connectionBySlug . set ( choice . connectionSlug , choice ) ;
602+ }
603+ }
604+ const connections = [ ...connectionBySlug . values ( ) ]
605+ . map ( ( choice ) => ( {
606+ ...choice ,
607+ base : choice . connectionName . trim ( )
608+ ? `${ choice . connectionName . trim ( ) } · ${ choice . connectionSlug } `
609+ : choice . connectionSlug ,
610+ } ) )
611+ . sort (
612+ ( left , right ) =>
613+ left . base . localeCompare ( right . base ) ||
614+ left . connectionSlug . localeCompare ( right . connectionSlug ) ,
615+ ) ;
616+ const used = new Set < string > ( ) ;
617+ const labels = new Map < string , string > ( ) ;
618+ for ( const connection of connections ) {
619+ let label = connection . base ;
620+ if ( used . has ( label ) && connection . connectionId ) {
621+ label = `${ connection . base } · ${ connection . connectionId } ` ;
622+ }
623+ let suffix = 2 ;
624+ while ( used . has ( label ) ) {
625+ label = `${ connection . base } · ${ connection . connectionId ?? connection . connectionSlug } · ${ suffix } ` ;
626+ suffix += 1 ;
627+ }
628+ used . add ( label ) ;
629+ labels . set ( connection . connectionSlug , label ) ;
630+ }
631+ return labels ;
632+ }
633+
594634function modelChoicePickerItems (
595635 choices : readonly ModelChoice [ ] ,
596636 current : { model : string ; connectionId ?: string ; connectionSlug : string } ,
597637) : SelectItem [ ] {
638+ const connectionLabels = modelChoiceConnectionLabels ( choices ) ;
598639 return choices . map ( ( choice , index ) => {
599640 const isCurrent =
600641 choice . model === current . model &&
601642 choice . connectionId === current . connectionId &&
602643 choice . connectionSlug === current . connectionSlug ;
603- const tags = [ choice . connectionName || choice . connectionSlug ] ;
644+ const tags = [ connectionLabels . get ( choice . connectionSlug ) ?? choice . connectionSlug ] ;
604645 if ( isCurrent ) tags . push ( 'current' ) ;
605646 else if ( choice . isDefaultConnection ) tags . push ( 'default' ) ;
606647 return {
@@ -797,14 +838,21 @@ export function onboardingProviderPickerItems(
797838 providers : readonly OnboardingProviderEntry [ ] ,
798839) : SelectItem [ ] {
799840 return providers . map ( ( provider ) => ( {
800- value : provider . providerType ,
841+ value : onboardingProviderKey ( provider ) ,
801842 label : provider . label ,
802- description : provider . hasConnection
803- ? `${ provider . providerType } · 已设置`
804- : provider . providerType ,
843+ description :
844+ 'connectionSlug' in provider
845+ ? `${ provider . providerType } · ${ provider . connectionSlug } · 已设置`
846+ : `${ provider . providerType } · 添加账号` ,
805847 } ) ) ;
806848}
807849
850+ function onboardingProviderKey ( provider : OnboardingProviderEntry ) : string {
851+ return provider . target . kind === 'existing'
852+ ? provider . target . connectionId
853+ : `create:${ provider . target . providerType } ` ;
854+ }
855+
808856const THINKING_LEVEL_LABELS : Record < ThinkingLevel , string > = {
809857 off : '关' ,
810858 minimal : '最小' ,
@@ -857,7 +905,7 @@ export interface OnboardingWizardInput {
857905 /** search→key: the user picked a provider. The runner records it — and the
858906 * existing connection's identity, when the catalog resolved one — for
859907 * verify/save, so saving edits that connection in place. */
860- onPickProvider : ( providerType : ProviderType , existingConnectionId : string | undefined ) => void ;
908+ onPickProvider : ( provider : OnboardingProviderEntry ) => void ;
861909 /** baseUrl submit (only for `requiresBaseUrl` providers). Empty means "reuse
862910 * the existing connection's persisted endpoint"; the wizard has already
863911 * rejected an empty value for a provider with no connection. */
@@ -905,6 +953,7 @@ export class OnboardingWizard implements Component {
905953 private modelHighlight = 0 ;
906954 private modelScroll = 0 ;
907955 private successCount = 0 ;
956+ private successWarning : string | undefined ;
908957
909958 constructor (
910959 private readonly tui : TUI ,
@@ -943,7 +992,9 @@ export class OnboardingWizard implements Component {
943992 { minPrimaryColumnWidth : 16 , maxPrimaryColumnWidth : 32 } ,
944993 ) ;
945994 list . onSelect = ( item ) => {
946- const provider = this . filtered . find ( ( p ) => p . providerType === item . value ) ;
995+ const provider = this . filtered . find (
996+ ( candidate ) => onboardingProviderKey ( candidate ) === item . value ,
997+ ) ;
947998 if ( ! provider ) return ;
948999 this . enterKeyPhase ( provider ) ;
9491000 } ;
@@ -968,7 +1019,7 @@ export class OnboardingWizard implements Component {
9681019 this . modelHighlight = 0 ;
9691020 this . modelScroll = 0 ;
9701021 this . modelsSearchEditor . setText ( '' ) ;
971- this . input . onPickProvider ( provider . providerType , provider . connectionId ) ;
1022+ this . input . onPickProvider ( provider ) ;
9721023 }
9731024
9741025 private submitBaseUrl ( value : string ) : void {
@@ -991,7 +1042,7 @@ export class OnboardingWizard implements Component {
9911042 */
9921043 private validateBaseUrl ( trimmed : string ) : string | null {
9931044 if ( ! trimmed ) {
994- return this . picked ?. hasConnection ? null : '需要填写 Base URL' ;
1045+ return this . picked ?. target . kind === 'existing' ? null : '需要填写 Base URL' ;
9951046 }
9961047 let parsed : URL ;
9971048 try {
@@ -1086,9 +1137,10 @@ export class OnboardingWizard implements Component {
10861137 }
10871138
10881139 /** Runner hook: save succeeded — show the enabled-model count in-frame. */
1089- setSuccess ( enabledCount : number ) : void {
1140+ setSuccess ( enabledCount : number , warning ?: string ) : void {
10901141 this . phase = 'success' ;
10911142 this . successCount = enabledCount ;
1143+ this . successWarning = warning ;
10921144 this . status = { kind : 'prompt' } ;
10931145 }
10941146
@@ -1286,9 +1338,10 @@ export class OnboardingWizard implements Component {
12861338 this . keyEditor . focused = false ;
12871339 this . modelsSearchEditor . focused = false ;
12881340 const label = this . picked ?. label ?? '' ;
1289- const hint = this . picked ?. hasConnection
1290- ? '留空复用已保存的 Base URL,或输入新地址替换 · Esc 返回选择服务商'
1291- : '输入中转站的 Base URL(http/https)· Esc 返回选择服务商' ;
1341+ const hint =
1342+ this . picked ?. target . kind === 'existing'
1343+ ? '留空复用已保存的 Base URL,或输入新地址替换 · Esc 返回选择服务商'
1344+ : '输入中转站的 Base URL(http/https)· Esc 返回选择服务商' ;
12921345 return [
12931346 padLine ( `Set Up Provider ${ ansi . dim ( `· ${ this . step ( 2 ) } ` ) } ${ ansi . accent ( label ) } ` , width ) ,
12941347 padLine ( ansi . dim ( hint ) , width ) ,
@@ -1331,9 +1384,10 @@ export class OnboardingWizard implements Component {
13311384 this . modelsSearchEditor . focused = false ;
13321385 const label = this . picked ?. label ?? '' ;
13331386 const backTarget = this . picked ?. requiresBaseUrl ? 'Esc 返回 Base URL' : 'Esc 返回选择服务商' ;
1334- const hint = this . picked ?. hasConnection
1335- ? `留空复用已保存的 key,或输入新 key 轮换 · ${ backTarget } `
1336- : `输入 API key · 仅本机存储 · ${ backTarget } ` ;
1387+ const hint =
1388+ this . picked ?. target . kind === 'existing'
1389+ ? `留空复用已保存的 key,或输入新 key 轮换 · ${ backTarget } `
1390+ : `输入 API key · 仅本机存储 · ${ backTarget } ` ;
13371391 return [
13381392 padLine (
13391393 `Set Up Provider ${ ansi . dim ( `· ${ this . step ( this . picked ?. requiresBaseUrl ? 3 : 2 ) } ` ) } ${ ansi . accent ( label ) } ` ,
@@ -1420,6 +1474,7 @@ export class OnboardingWizard implements Component {
14201474 return [
14211475 padLine ( `Set Up Provider ${ ansi . dim ( '· 完成' ) } ${ ansi . accent ( label ) } ` , width ) ,
14221476 padLine ( ansi . green ( `✓ 已启用 ${ this . successCount } 个模型` ) , width ) ,
1477+ ...( this . successWarning ? [ padLine ( ansi . yellow ( this . successWarning ) , width ) ] : [ ] ) ,
14231478 padLine ( '' , width ) ,
14241479 padLine ( ansi . dim ( 'Enter 关闭' ) , width ) ,
14251480 padLine ( ansi . accent ( '-' . repeat ( width ) ) , width ) ,
0 commit comments