({
open, updateMode = false, onClose, onRunningChange,
})
| 290 | type DistillStatus = 'idle' | 'running' | 'failed'; |
| 291 | |
| 292 | export const SessionDistillDialog: React.FC<SessionDistillDialogProps> = ({ |
| 293 | open, updateMode = false, onClose, onRunningChange, |
| 294 | }) => { |
| 295 | const { t } = useTranslation(); |
| 296 | const dispatch = useDispatch<AppDispatch>(); |
| 297 | |
| 298 | const tables = useSelector((s: DataFormulatorState) => s.tables); |
| 299 | const charts = useSelector((s: DataFormulatorState) => s.charts); |
| 300 | const conceptShelfItems = useSelector((s: DataFormulatorState) => s.conceptShelfItems); |
| 301 | const activeWorkspace = useSelector((s: DataFormulatorState) => s.activeWorkspace); |
| 302 | const selectedModelId = useSelector((s: DataFormulatorState) => s.selectedModelId); |
| 303 | const allModels = useSelector( |
| 304 | (s: DataFormulatorState) => [...s.globalModels, ...s.models], |
| 305 | ); |
| 306 | const selectedModel = allModels.find(m => m.id === selectedModelId); |
| 307 | |
| 308 | const built = useMemo(() => { |
| 309 | if (!open || !activeWorkspace) return null; |
| 310 | const threads = collectSessionThreads(tables, charts, conceptShelfItems); |
| 311 | return buildSessionExperienceContext(activeWorkspace, threads); |
| 312 | }, [open, activeWorkspace, tables, charts, conceptShelfItems]); |
| 313 | |
| 314 | const [userInstruction, setUserInstruction] = useState(''); |
| 315 | const [status, setStatus] = useState<DistillStatus>('idle'); |
| 316 | const runningRef = useRef(false); |
| 317 | |
| 318 | const handleClose = useCallback(() => { |
| 319 | onClose(); |
| 320 | if (!runningRef.current) { |
| 321 | setUserInstruction(''); |
| 322 | setStatus('idle'); |
| 323 | } |
| 324 | }, [onClose]); |
| 325 | |
| 326 | const handleDistill = useCallback(async () => { |
| 327 | if (runningRef.current) return; |
| 328 | if (!built || !selectedModel) return; |
| 329 | runningRef.current = true; |
| 330 | setStatus('running'); |
| 331 | onRunningChange?.(true); |
| 332 | const instruction = userInstruction.trim() || undefined; |
| 333 | |
| 334 | try { |
| 335 | const modelConfig = buildDistillModelConfig(selectedModel as ModelConfig); |
| 336 | const timeoutSeconds = (store.getState() as DataFormulatorState).config.formulateTimeoutSeconds; |
| 337 | const controller = new AbortController(); |
| 338 | const timeoutId = setTimeout(() => controller.abort(), timeoutSeconds * 1000); |
| 339 | let result; |
| 340 | try { |
| 341 | result = await distillSessionExperience( |
| 342 | built.payload, modelConfig, instruction, timeoutSeconds, controller.signal, |
| 343 | ); |
| 344 | } finally { |
| 345 | clearTimeout(timeoutId); |
| 346 | } |
| 347 | dispatch(dfActions.addMessages({ |
| 348 | timestamp: Date.now(), |
| 349 | type: 'success', |
nothing calls this directly
no test coverage detected