@@ -81,6 +81,13 @@ const DEFAULT_PROMPT_STACK: PromptBlock[] = [
8181 { id : "default-6" , kind : "scene" , enabled : true , order : 6 , content : "" } ,
8282 { id : "default-7" , kind : "history" , enabled : true , order : 7 , content : "" }
8383] ;
84+ const DEFAULT_SCENE_FIELD_VISIBILITY = {
85+ dialogueStyle : true ,
86+ initiative : true ,
87+ descriptiveness : true ,
88+ unpredictability : true ,
89+ emotionalDepth : true
90+ } ;
8491
8592function normalizePromptStack ( raw : PromptBlock [ ] | null | undefined ) : PromptBlock [ ] {
8693 if ( ! Array . isArray ( raw ) || raw . length === 0 ) return [ ...DEFAULT_PROMPT_STACK ] ;
@@ -98,8 +105,6 @@ function resolveChatMode(state: Partial<RpSceneState> | null | undefined): ChatM
98105}
99106const DEFAULT_SCENE_STATE : Omit < RpSceneState , "chatId" > = {
100107 variables : {
101- location : "Private room" ,
102- time : "Night" ,
103108 dialogueStyle : "teasing" ,
104109 initiative : "65" ,
105110 descriptiveness : "70" ,
@@ -113,6 +118,13 @@ const DEFAULT_SCENE_STATE: Omit<RpSceneState, "chatId"> = {
113118 pureChatMode : false
114119} ;
115120
121+ function sanitizeSceneVariables ( variables : Record < string , string > | null | undefined ) : Record < string , string > {
122+ const next = { ...( variables || { } ) } ;
123+ delete next . location ;
124+ delete next . time ;
125+ return next ;
126+ }
127+
116128function readSceneVarPercent ( variables : Record < string , string > , key : string , fallback : number ) : number {
117129 const raw = Number ( variables [ key ] ) ;
118130 if ( ! Number . isFinite ( raw ) ) return fallback ;
@@ -182,6 +194,7 @@ export function ChatScreen() {
182194 chatId : "" ,
183195 ...DEFAULT_SCENE_STATE
184196 } ) ;
197+ const [ sceneFieldVisibility , setSceneFieldVisibility ] = useState ( { ...DEFAULT_SCENE_FIELD_VISIBILITY } ) ;
185198 const [ promptStack , setPromptStack ] = useState < PromptBlock [ ] > ( [ ...DEFAULT_PROMPT_STACK ] ) ;
186199 const [ contextSummary , setContextSummary ] = useState ( "" ) ;
187200 const [ editingId , setEditingId ] = useState < string | null > ( null ) ;
@@ -501,6 +514,10 @@ export function ChatScreen() {
501514 setPromptStack ( normalizePromptStack ( settings . promptStack ) ) ;
502515 setAlternateSimpleMode ( settings . alternateSimpleMode === true ) ;
503516 setSimpleSidebarOpen ( settings . alternateSimpleMode !== true ) ;
517+ setSceneFieldVisibility ( {
518+ ...DEFAULT_SCENE_FIELD_VISIBILITY ,
519+ ...( settings . sceneFieldVisibility || { } )
520+ } ) ;
504521 if ( Number . isFinite ( Number ( settings . ragTopK ) ) ) {
505522 setChatRagTopK ( Math . max ( 1 , Math . min ( 12 , Math . floor ( Number ( settings . ragTopK ) ) ) ) ) ;
506523 }
@@ -606,7 +623,7 @@ export function ChatScreen() {
606623 mood : state . mood || DEFAULT_SCENE_STATE . mood ,
607624 pacing : state . pacing || DEFAULT_SCENE_STATE . pacing ,
608625 intensity : typeof state . intensity === "number" ? state . intensity : DEFAULT_SCENE_STATE . intensity ,
609- variables : state . variables || { } ,
626+ variables : sanitizeSceneVariables ( state . variables ) ,
610627 chatMode : nextMode ,
611628 pureChatMode : nextMode === "pure_chat"
612629 } ) ;
@@ -946,11 +963,6 @@ export function ChatScreen() {
946963 setErrorText ( "" ) ;
947964 try {
948965 startStreamingUi ( null ) ;
949- setMessages ( ( prev ) => {
950- const lastAssistant = [ ...prev ] . reverse ( ) . find ( ( msg ) => msg . role === "assistant" ) ;
951- if ( ! lastAssistant ) return prev ;
952- return prev . filter ( ( msg ) => msg . id !== lastAssistant . id && msg . parentId !== lastAssistant . id ) ;
953- } ) ;
954966 const updated = await api . chatRegenerate ( activeChat . id , activeBranchId || undefined , {
955967 onDelta : appendStreamDelta ,
956968 onToolEvent : handleStreamingToolEvent ,
@@ -1118,7 +1130,7 @@ export function ChatScreen() {
11181130 mood : result . sceneState . mood || DEFAULT_SCENE_STATE . mood ,
11191131 pacing : result . sceneState . pacing || DEFAULT_SCENE_STATE . pacing ,
11201132 intensity : typeof result . sceneState . intensity === "number" ? result . sceneState . intensity : DEFAULT_SCENE_STATE . intensity ,
1121- variables : result . sceneState . variables || { } ,
1133+ variables : sanitizeSceneVariables ( result . sceneState . variables ) ,
11221134 chatMode : nextMode ,
11231135 pureChatMode : nextMode === "pure_chat"
11241136 } ) ;
@@ -1554,24 +1566,6 @@ export function ChatScreen() {
15541566 </ div >
15551567 < div className = "chat-simple-scene-modal-body" >
15561568 < fieldset disabled = { pureChatMode } className = "space-y-2 disabled:opacity-50" >
1557- < div className = "grid gap-2 sm:grid-cols-2" >
1558- < div >
1559- < label className = "mb-1 block text-[10px] text-text-tertiary" > { t ( "inspector.location" ) } </ label >
1560- < input
1561- value = { sceneState . variables . location || "" }
1562- onChange = { ( e ) => setSceneVariable ( "location" , e . target . value ) }
1563- className = "chat-simple-scene-input"
1564- />
1565- </ div >
1566- < div >
1567- < label className = "mb-1 block text-[10px] text-text-tertiary" > { t ( "inspector.time" ) } </ label >
1568- < input
1569- value = { sceneState . variables . time || "" }
1570- onChange = { ( e ) => setSceneVariable ( "time" , e . target . value ) }
1571- className = "chat-simple-scene-input"
1572- />
1573- </ div >
1574- </ div >
15751569 < div className = "grid gap-2 sm:grid-cols-2" >
15761570 < div >
15771571 < label className = "mb-1 block text-[10px] text-text-tertiary" > { t ( "inspector.mood" ) } </ label >
@@ -1609,27 +1603,29 @@ export function ChatScreen() {
16091603 className = "w-full"
16101604 />
16111605 </ div >
1612- < div >
1613- < label className = "mb-1 block text-[10px] text-text-tertiary" > { t ( "inspector.dialogueStyle" ) } </ label >
1614- < select
1615- value = { sceneState . variables . dialogueStyle || "teasing" }
1616- onChange = { ( e ) => setSceneVariable ( "dialogueStyle" , e . target . value ) }
1617- className = "chat-simple-scene-select"
1618- >
1619- < option value = "teasing" > { t ( "inspector.dialogueStyleTeasing" ) } </ option >
1620- < option value = "playful" > { t ( "inspector.dialogueStylePlayful" ) } </ option >
1621- < option value = "dominant" > { t ( "inspector.dialogueStyleDominant" ) } </ option >
1622- < option value = "tender" > { t ( "inspector.dialogueStyleTender" ) } </ option >
1623- < option value = "formal" > { t ( "inspector.dialogueStyleFormal" ) } </ option >
1624- < option value = "chaotic" > { t ( "inspector.dialogueStyleChaotic" ) } </ option >
1625- </ select >
1626- </ div >
1606+ { sceneFieldVisibility . dialogueStyle && (
1607+ < div >
1608+ < label className = "mb-1 block text-[10px] text-text-tertiary" > { t ( "inspector.dialogueStyle" ) } </ label >
1609+ < select
1610+ value = { sceneState . variables . dialogueStyle || "teasing" }
1611+ onChange = { ( e ) => setSceneVariable ( "dialogueStyle" , e . target . value ) }
1612+ className = "chat-simple-scene-select"
1613+ >
1614+ < option value = "teasing" > { t ( "inspector.dialogueStyleTeasing" ) } </ option >
1615+ < option value = "playful" > { t ( "inspector.dialogueStylePlayful" ) } </ option >
1616+ < option value = "dominant" > { t ( "inspector.dialogueStyleDominant" ) } </ option >
1617+ < option value = "tender" > { t ( "inspector.dialogueStyleTender" ) } </ option >
1618+ < option value = "formal" > { t ( "inspector.dialogueStyleFormal" ) } </ option >
1619+ < option value = "chaotic" > { t ( "inspector.dialogueStyleChaotic" ) } </ option >
1620+ </ select >
1621+ </ div >
1622+ ) }
16271623 { [
16281624 { key : "initiative" , label : t ( "inspector.initiative" ) } ,
16291625 { key : "descriptiveness" , label : t ( "inspector.descriptiveness" ) } ,
16301626 { key : "unpredictability" , label : t ( "inspector.unpredictability" ) } ,
16311627 { key : "emotionalDepth" , label : t ( "inspector.emotionalDepth" ) }
1632- ] . map ( ( item ) => {
1628+ ] . filter ( ( item ) => sceneFieldVisibility [ item . key as keyof typeof sceneFieldVisibility ] ) . map ( ( item ) => {
16331629 const value = readSceneVarPercent ( sceneState . variables , item . key , 60 ) ;
16341630 return (
16351631 < div key = { item . key } >
@@ -3018,27 +3014,29 @@ export function ChatScreen() {
30183014 onChange = { ( e ) => setSceneState ( ( prev ) => ( { ...prev , intensity : Number ( e . target . value ) } ) ) }
30193015 className = "w-full" />
30203016 </ div >
3021- < div >
3022- < label className = "mb-1 block text-[10px] text-text-tertiary" > { t ( "inspector.dialogueStyle" ) } </ label >
3023- < select
3024- value = { sceneState . variables . dialogueStyle || "teasing" }
3025- onChange = { ( e ) => setSceneVariable ( "dialogueStyle" , e . target . value ) }
3026- className = "w-full rounded-md border border-border bg-bg-primary px-2.5 py-1.5 text-xs text-text-primary"
3027- >
3028- < option value = "teasing" > { t ( "inspector.dialogueStyleTeasing" ) } </ option >
3029- < option value = "playful" > { t ( "inspector.dialogueStylePlayful" ) } </ option >
3030- < option value = "dominant" > { t ( "inspector.dialogueStyleDominant" ) } </ option >
3031- < option value = "tender" > { t ( "inspector.dialogueStyleTender" ) } </ option >
3032- < option value = "formal" > { t ( "inspector.dialogueStyleFormal" ) } </ option >
3033- < option value = "chaotic" > { t ( "inspector.dialogueStyleChaotic" ) } </ option >
3034- </ select >
3035- </ div >
3017+ { sceneFieldVisibility . dialogueStyle && (
3018+ < div >
3019+ < label className = "mb-1 block text-[10px] text-text-tertiary" > { t ( "inspector.dialogueStyle" ) } </ label >
3020+ < select
3021+ value = { sceneState . variables . dialogueStyle || "teasing" }
3022+ onChange = { ( e ) => setSceneVariable ( "dialogueStyle" , e . target . value ) }
3023+ className = "w-full rounded-md border border-border bg-bg-primary px-2.5 py-1.5 text-xs text-text-primary"
3024+ >
3025+ < option value = "teasing" > { t ( "inspector.dialogueStyleTeasing" ) } </ option >
3026+ < option value = "playful" > { t ( "inspector.dialogueStylePlayful" ) } </ option >
3027+ < option value = "dominant" > { t ( "inspector.dialogueStyleDominant" ) } </ option >
3028+ < option value = "tender" > { t ( "inspector.dialogueStyleTender" ) } </ option >
3029+ < option value = "formal" > { t ( "inspector.dialogueStyleFormal" ) } </ option >
3030+ < option value = "chaotic" > { t ( "inspector.dialogueStyleChaotic" ) } </ option >
3031+ </ select >
3032+ </ div >
3033+ ) }
30363034 { [
30373035 { key : "initiative" , label : t ( "inspector.initiative" ) } ,
30383036 { key : "descriptiveness" , label : t ( "inspector.descriptiveness" ) } ,
30393037 { key : "unpredictability" , label : t ( "inspector.unpredictability" ) } ,
30403038 { key : "emotionalDepth" , label : t ( "inspector.emotionalDepth" ) }
3041- ] . map ( ( item ) => {
3039+ ] . filter ( ( item ) => sceneFieldVisibility [ item . key as keyof typeof sceneFieldVisibility ] ) . map ( ( item ) => {
30423040 const value = readSceneVarPercent ( sceneState . variables , item . key , 60 ) ;
30433041 return (
30443042 < div key = { item . key } >
0 commit comments