1414 WsGetVariablesMessage ,
1515 WsInterruptMessage ,
1616 WsResetMessage ,
17+ WsSetUiValueMessage ,
1718 WsStatusMessage ,
1819)
1920from ..kernel .uiEventFlow import resetKernelUiCallbacks
@@ -89,6 +90,8 @@ async def handleKernelWsMessage(websocket: WebSocket, session: Any, message: Any
8990 logger .debug ("kernel-variables %s" , formatLogFields (transport = "ws" , sessionId = session .sessionId ))
9091 elif isinstance (message , WsExecuteReactiveMessage ):
9192 await handleReactiveMessage (websocket , session , message , logger )
93+ elif isinstance (message , WsSetUiValueMessage ):
94+ await handleSetUiValueMessage (websocket , session , message , logger )
9295 elif isinstance (message , WsResetMessage ):
9396 session .reset ()
9497 resetKernelUiCallbacks ()
@@ -106,6 +109,8 @@ def validateKernelWsMessage(message: dict[str, Any]) -> Any:
106109 return WsGetVariablesMessage .model_validate (message )
107110 if messageType == "executeReactive" :
108111 return WsExecuteReactiveMessage .model_validate (message )
112+ if messageType == "setUiValue" :
113+ return WsSetUiValueMessage .model_validate (message )
109114 if messageType == "reset" :
110115 return WsResetMessage .model_validate (message )
111116 raise ValueError (f"Unsupported websocket message type: { messageType or 'unknown' } ." )
@@ -152,28 +157,55 @@ async def handleReactiveMessage(
152157 message : WsExecuteReactiveMessage ,
153158 logger : Any ,
154159) -> None :
155- requestId = message .requestId
156- changedBlockId = message .blockId
157160 blocks = [block .model_dump () for block in message .blocks ]
161+ await _runReactiveAndSend (
162+ websocket , session , message .requestId , message .blockId , blocks , logger ,
163+ includeSource = True , kind = "reactive" ,
164+ )
165+
166+
167+ async def handleSetUiValueMessage (
168+ websocket : WebSocket ,
169+ session : Any ,
170+ message : WsSetUiValueMessage ,
171+ logger : Any ,
172+ ) -> None :
173+ # 위젯 값 store 갱신 → 그 변수를 쓰는 다운스트림만 재실행(위젯 셀 자신은 제외).
174+ session .setUiValue (message .elementId , message .value )
175+ blocks = [block .model_dump () for block in message .blocks ]
176+ await _runReactiveAndSend (
177+ websocket , session , message .requestId , message .blockId , blocks , logger ,
178+ includeSource = False , kind = "setUiValue" ,
179+ )
180+
158181
182+ async def _runReactiveAndSend (
183+ websocket : WebSocket ,
184+ session : Any ,
185+ requestId : str ,
186+ changedBlockId : str ,
187+ blocks : list [dict [str , Any ]],
188+ logger : Any ,
189+ * ,
190+ includeSource : bool ,
191+ kind : str ,
192+ ) -> None :
159193 if not await _safeSendJson (websocket , WsStatusMessage (type = "status" , engineStatus = "busy" ).model_dump ()):
160194 return
161195 reactiveEvents : list [dict [str , Any ]] = []
162196
163197 async def eventHandler (event : Any ) -> None :
164- reactiveEvents .append (
165- {
166- "blockId" : event .blockId ,
167- "eventType" : event .eventType ,
168- }
169- )
198+ reactiveEvents .append ({"blockId" : event .blockId , "eventType" : event .eventType })
170199 await sendExecutionEvent (websocket , requestId , event )
171200
172- payload = await executeKernelReactive (session , blocks , changedBlockId , eventHandler = eventHandler )
201+ payload = await executeKernelReactive (
202+ session , blocks , changedBlockId , eventHandler = eventHandler , includeSource = includeSource
203+ )
173204 logger .debug (
174205 "kernel-reactive %s" ,
175206 formatLogFields (
176207 transport = "ws" ,
208+ kind = kind ,
177209 sessionId = session .sessionId ,
178210 requestId = requestId ,
179211 changedBlockId = changedBlockId ,
0 commit comments