1- import { setLocale as applyLocale , useT } from '@open-codesign/i18n' ;
1+ import { setLocale as applyLocale , getCurrentLocale , useT } from '@open-codesign/i18n' ;
22import type { OnboardingState , ReasoningLevel , WireApi } from '@open-codesign/shared' ;
33import {
44 PROVIDER_SHORTLIST as SHORTLIST ,
@@ -323,7 +323,7 @@ function ProviderCard({
323323 code : 'CONNECTION_TEST_FAILED' ,
324324 scope : 'settings' ,
325325 title : t ( 'settings.providers.toast.connectionFailed' ) ,
326- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
326+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
327327 ...( err instanceof Error && err . stack !== undefined ? { stack : err . stack } : { } ) ,
328328 context : { provider : row . provider } ,
329329 } ) ;
@@ -384,8 +384,8 @@ function ProviderCard({
384384 </ div >
385385 </ div >
386386
387- { row . isActive && ! hasError && config !== null && (
388- < ActiveModelSelector config = { config } provider = { row . provider } />
387+ { ! hasError && row . hasKey !== false && config !== null && (
388+ < RowModelSelector config = { config } row = { row } onRowChanged = { onRowChanged } />
389389 ) }
390390 { ! hasError && row . hasKey !== false && (
391391 < ReasoningDepthSelector
@@ -398,24 +398,34 @@ function ProviderCard({
398398 ) ;
399399}
400400
401- function ActiveModelSelector ( {
401+ function RowModelSelector ( {
402402 config,
403- provider,
403+ row,
404+ onRowChanged,
404405} : {
405406 config : OnboardingState ;
406- provider : string ;
407+ row : ProviderRow ;
408+ onRowChanged : ( row : ProviderRow ) => void ;
407409} ) {
408410 const t = useT ( ) ;
409411 const setConfig = useCodesignStore ( ( s ) => s . completeOnboarding ) ;
410412 const reportableErrorToast = useCodesignStore ( ( s ) => s . reportableErrorToast ) ;
411413
412- const [ primary , setPrimary ] = useState ( config . modelPrimary ?? '' ) ;
414+ const provider = row . provider ;
415+ const isActive = row . isActive ;
416+
417+ const initial = isActive
418+ ? ( config . modelPrimary ?? row . defaultModel ?? '' )
419+ : ( row . defaultModel ?? '' ) ;
420+ const [ primary , setPrimary ] = useState ( initial ) ;
413421 const [ models , setModels ] = useState < string [ ] | null > ( null ) ;
414422 const [ loadingModels , setLoadingModels ] = useState ( false ) ;
415423
416424 useEffect ( ( ) => {
417- setPrimary ( config . modelPrimary ?? '' ) ;
418- } , [ config . modelPrimary ] ) ;
425+ setPrimary (
426+ isActive ? ( config . modelPrimary ?? row . defaultModel ?? '' ) : ( row . defaultModel ?? '' ) ,
427+ ) ;
428+ } , [ isActive , config . modelPrimary , row . defaultModel ] ) ;
419429
420430 // Fetch models immediately on mount
421431 useEffect ( ( ) => {
@@ -437,19 +447,26 @@ function ActiveModelSelector({
437447 async function save ( next : string ) : Promise < boolean > {
438448 if ( ! window . codesign ) return false ;
439449 try {
440- const updated = await window . codesign . settings . setActiveProvider ( {
441- provider,
442- modelPrimary : next ,
443- } ) ;
444- recordAction ( { type : 'provider.switch' , data : { provider, modelId : next } } ) ;
445- setConfig ( updated ) ;
450+ if ( isActive ) {
451+ const updated = await window . codesign . settings . setActiveProvider ( {
452+ provider,
453+ modelPrimary : next ,
454+ } ) ;
455+ recordAction ( { type : 'provider.switch' , data : { provider, modelId : next } } ) ;
456+ setConfig ( updated ) ;
457+ } else {
458+ // Inactive row: persist the per-provider default so that clicking
459+ // "Set as current" later picks it up (see handleActivate → currentRow.defaultModel).
460+ await window . codesign . config . updateProvider ( { id : provider , defaultModel : next } ) ;
461+ onRowChanged ( { ...row , defaultModel : next } ) ;
462+ }
446463 return true ;
447464 } catch ( err ) {
448465 reportableErrorToast ( {
449466 code : 'PROVIDER_MODEL_SAVE_FAILED' ,
450467 scope : 'settings' ,
451468 title : t ( 'settings.providers.toast.modelSaveFailed' ) ,
452- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
469+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
453470 ...( err instanceof Error && err . stack !== undefined ? { stack : err . stack } : { } ) ,
454471 context : { provider } ,
455472 } ) ;
@@ -537,7 +554,7 @@ function ReasoningDepthSelector({
537554 code : 'PROVIDER_REASONING_SAVE_FAILED' ,
538555 scope : 'settings' ,
539556 title : t ( 'settings.providers.toast.reasoningSaveFailed' ) ,
540- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
557+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
541558 ...( err instanceof Error && err . stack !== undefined ? { stack : err . stack } : { } ) ,
542559 context : { provider } ,
543560 } ) ;
@@ -579,6 +596,24 @@ const PARSE_REASON_NOT_JSON_OBJECT = '__parse_reason_not_json_object__';
579596
580597const DISMISSED_BANNER_PREFIX = 'open-codesign:settings:dismissed-import-banner:' ;
581598
599+ /**
600+ * Electron IPC wraps thrown errors as
601+ * `Error invoking remote method '<channel>': <ErrorName>: <message>`.
602+ * Strip the wrapper and, for bilingual messages formatted as `en / zh`,
603+ * pick the side matching the active locale so toast descriptions read
604+ * like natural sentences instead of framework tracebacks.
605+ */
606+ function cleanIpcError ( err : unknown ) : string {
607+ if ( ! ( err instanceof Error ) ) return String ( err ?? '' ) ;
608+ const raw = err . message ;
609+ const stripped = raw . replace ( / ^ E r r o r i n v o k i n g r e m o t e m e t h o d ' [ ^ ' ] * ' : \s * [ A - Z a - z ] * E r r o r : \s * / , '' ) ;
610+ const parts = stripped . split ( ' / ' ) ;
611+ if ( parts . length >= 2 ) {
612+ return getCurrentLocale ( ) === 'zh-CN' ? ( parts [ 1 ] ?? stripped ) : ( parts [ 0 ] ?? stripped ) ;
613+ }
614+ return stripped ;
615+ }
616+
582617/**
583618 * Strip any user:pass@ credentials from a URL before putting it into
584619 * visible copy (banner, toast, screenshot). Preserves the full URL for
@@ -883,7 +918,7 @@ function ModelsTab() {
883918 pushToast ( {
884919 variant : 'error' ,
885920 title : t ( 'settings.providers.toast.loadFailed' ) ,
886- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
921+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
887922 } ) ;
888923 } )
889924 . finally ( ( ) => setLoading ( false ) ) ;
@@ -973,7 +1008,8 @@ function ModelsTab() {
9731008 code : 'CODEX_IMPORT_FAILED' ,
9741009 scope : 'onboarding' ,
9751010 title : t ( 'settings.providers.import.failed' ) ,
976- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1011+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
1012+ reportable : false ,
9771013 ...( err instanceof Error && err . stack !== undefined ? { stack : err . stack } : { } ) ,
9781014 } ) ;
9791015 }
@@ -1002,7 +1038,8 @@ function ModelsTab() {
10021038 code : 'GEMINI_IMPORT_FAILED' ,
10031039 scope : 'onboarding' ,
10041040 title : t ( 'settings.providers.import.failed' ) ,
1005- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1041+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
1042+ reportable : false ,
10061043 ...( err instanceof Error && err . stack !== undefined ? { stack : err . stack } : { } ) ,
10071044 } ) ;
10081045 }
@@ -1033,7 +1070,8 @@ function ModelsTab() {
10331070 code : 'OPENCODE_IMPORT_FAILED' ,
10341071 scope : 'onboarding' ,
10351072 title : t ( 'settings.providers.import.failed' ) ,
1036- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1073+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
1074+ reportable : false ,
10371075 ...( err instanceof Error && err . stack !== undefined ? { stack : err . stack } : { } ) ,
10381076 } ) ;
10391077 }
@@ -1076,7 +1114,8 @@ function ModelsTab() {
10761114 code : 'CLAUDECODE_IMPORT_FAILED' ,
10771115 scope : 'onboarding' ,
10781116 title : t ( 'settings.providers.import.failed' ) ,
1079- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1117+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
1118+ reportable : false ,
10801119 ...( err instanceof Error && err . stack !== undefined ? { stack : err . stack } : { } ) ,
10811120 } ) ;
10821121 }
@@ -1146,7 +1185,7 @@ function ModelsTab() {
11461185 code : 'PROVIDER_DELETE_FAILED' ,
11471186 scope : 'settings' ,
11481187 title : t ( 'settings.providers.toast.deleteFailed' ) ,
1149- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1188+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
11501189 ...( err instanceof Error && err . stack !== undefined ? { stack : err . stack } : { } ) ,
11511190 } ) ;
11521191 }
@@ -1188,7 +1227,7 @@ function ModelsTab() {
11881227 code : 'PROVIDER_ACTIVATE_FAILED' ,
11891228 scope : 'settings' ,
11901229 title : t ( 'settings.providers.toast.switchFailed' ) ,
1191- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1230+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
11921231 ...( err instanceof Error && err . stack !== undefined ? { stack : err . stack } : { } ) ,
11931232 } ) ;
11941233 }
@@ -1560,7 +1599,7 @@ function AppearanceTab() {
15601599 pushToast ( {
15611600 variant : 'error' ,
15621601 title : t ( 'settings.appearance.languageLoadFailed' ) ,
1563- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1602+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
15641603 } ) ;
15651604 } ) ;
15661605 } , [ pushToast , t ] ) ;
@@ -1581,7 +1620,7 @@ function AppearanceTab() {
15811620 pushToast ( {
15821621 variant : 'error' ,
15831622 title : t ( 'errors.localePersistFailed' ) ,
1584- description : err instanceof Error ? err . message : t ( 'errors.unknown' ) ,
1623+ description : cleanIpcError ( err ) || t ( 'errors.unknown' ) ,
15851624 } ) ;
15861625 }
15871626 }
@@ -1737,7 +1776,7 @@ function StorageTab() {
17371776 pushToast ( {
17381777 variant : 'error' ,
17391778 title : t ( 'settings.storage.pathsLoadFailed' ) ,
1740- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1779+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
17411780 } ) ;
17421781 } ) ;
17431782 } , [ pushToast , t ] ) ;
@@ -1749,7 +1788,7 @@ function StorageTab() {
17491788 pushToast ( {
17501789 variant : 'error' ,
17511790 title : t ( 'settings.storage.openFolderFailed' ) ,
1752- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1791+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
17531792 } ) ;
17541793 }
17551794 }
@@ -1765,7 +1804,7 @@ function StorageTab() {
17651804 pushToast ( {
17661805 variant : 'error' ,
17671806 title : t ( 'settings.storage.locationSaveFailed' ) ,
1768- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1807+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
17691808 } ) ;
17701809 } finally {
17711810 setChoosing ( null ) ;
@@ -1790,7 +1829,7 @@ function StorageTab() {
17901829 pushToast ( {
17911830 variant : 'error' ,
17921831 title : t ( 'settings.storage.openFolderFailed' ) ,
1793- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1832+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
17941833 } ) ;
17951834 }
17961835 }
@@ -1809,7 +1848,7 @@ function StorageTab() {
18091848 pushToast ( {
18101849 variant : 'error' ,
18111850 title : t ( 'settings.storage.diagnosticsExportFailed' ) ,
1812- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1851+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
18131852 } ) ;
18141853 } finally {
18151854 setExporting ( false ) ;
@@ -1944,7 +1983,7 @@ function AdvancedTab() {
19441983 pushToast ( {
19451984 variant : 'error' ,
19461985 title : t ( 'settings.advanced.prefsLoadFailed' ) ,
1947- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
1986+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
19481987 } ) ;
19491988 } ) ;
19501989 } , [ pushToast , t ] ) ;
@@ -1958,7 +1997,7 @@ function AdvancedTab() {
19581997 pushToast ( {
19591998 variant : 'error' ,
19601999 title : t ( 'settings.advanced.prefsSaveFailed' ) ,
1961- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
2000+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
19622001 } ) ;
19632002 }
19642003 }
@@ -1971,7 +2010,7 @@ function AdvancedTab() {
19712010 pushToast ( {
19722011 variant : 'error' ,
19732012 title : t ( 'settings.advanced.devtoolsFailed' ) ,
1974- description : err instanceof Error ? err . message : t ( 'settings.common.unknownError' ) ,
2013+ description : cleanIpcError ( err ) || t ( 'settings.common.unknownError' ) ,
19752014 } ) ;
19762015 }
19772016 }
0 commit comments