From 84f005fb25cd3c3b906bcb42e0763196a29314de Mon Sep 17 00:00:00 2001 From: Shine1i Date: Mon, 9 Mar 2026 02:06:12 +0100 Subject: [PATCH] feat(recipe-studio, studio): dataset logic, refine run settings, and improve validation UI --- .../recipe-studio/components/block-sheet.tsx | 35 ++++- .../recipe-studio/dialogs/preview-dialog.tsx | 135 ++++++++++++++---- .../recipe-studio/stores/recipe-executions.ts | 21 ++- .../studio/sections/dataset-section.tsx | 31 ++-- 4 files changed, 171 insertions(+), 51 deletions(-) diff --git a/studio/frontend/src/features/recipe-studio/components/block-sheet.tsx b/studio/frontend/src/features/recipe-studio/components/block-sheet.tsx index bf4785943e..ffe11076ad 100644 --- a/studio/frontend/src/features/recipe-studio/components/block-sheet.tsx +++ b/studio/frontend/src/features/recipe-studio/components/block-sheet.tsx @@ -1,4 +1,5 @@ import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Sheet, @@ -152,6 +153,8 @@ function BlockSheetButton({ draggable = false, onDragStart, trailing = "chevron", + disabled = false, + badge, }: { icon: typeof Database02Icon; title: string; @@ -161,24 +164,38 @@ function BlockSheetButton({ draggable?: boolean; onDragStart?: (event: ReactDragEvent) => void; trailing?: "chevron" | "drag" | "none"; + disabled?: boolean; + badge?: string; }): ReactElement { return ( -
+
-
+
+
+

Keep running through failures

+

+ Recommended for longer runs when you want maximum output. +

+
@@ -545,17 +614,19 @@ export function RunDialog({ }) } /> - Disable early shutdown
{errors.length > 0 && ( -
-

- Run checks -

+
+
+ + + Run checks + +
{errors.map((error) => (

{error} @@ -572,6 +643,7 @@ export function RunDialog({ variant="outline" onClick={() => onOpenChange(false)} disabled={loading} + className="corner-squircle border-border/70 bg-card/70" > Cancel @@ -580,11 +652,12 @@ export function RunDialog({ variant="outline" onClick={onValidate} disabled={loading || validateLoading} + className="corner-squircle border-border/70 bg-card/70" > {validateLoading ? "Validating..." : "Validate recipe"} - diff --git a/studio/frontend/src/features/recipe-studio/stores/recipe-executions.ts b/studio/frontend/src/features/recipe-studio/stores/recipe-executions.ts index 9ed37e1415..c776536ca9 100644 --- a/studio/frontend/src/features/recipe-studio/stores/recipe-executions.ts +++ b/studio/frontend/src/features/recipe-studio/stores/recipe-executions.ts @@ -18,13 +18,13 @@ export type RecipeRunSettings = { const DEFAULT_RUN_SETTINGS: RecipeRunSettings = { batchSize: 1000, - batchEnabled: true, + batchEnabled: false, mergeBatches: false, llmParallelRequests: null, nonInferenceWorkers: 4, maxConversationRestarts: 5, maxConversationCorrectionSteps: 0, - disableEarlyShutdown: false, + disableEarlyShutdown: true, shutdownErrorRate: 0.5, shutdownErrorWindow: 10, }; @@ -60,7 +60,7 @@ const INITIAL_STATE = { runDialogOpen: false, runDialogKind: "preview", previewRows: 5, - fullRows: 1000, + fullRows: 100, fullRunName: "", runErrors: [], runSettings: DEFAULT_RUN_SETTINGS, @@ -86,7 +86,20 @@ const INITIAL_STATE = { export const useRecipeExecutionsStore = create((set) => ({ ...INITIAL_STATE, setRunDialogOpen: (open) => set({ runDialogOpen: open }), - setRunDialogKind: (kind) => set({ runDialogKind: kind }), + setRunDialogKind: (kind) => + set((state) => { + if (state.runDialogKind === "preview" && kind === "full") { + return { + runDialogKind: kind, + fullRows: 100, + runSettings: { + ...state.runSettings, + batchEnabled: false, + }, + }; + } + return { runDialogKind: kind }; + }), setPreviewRows: (rows) => set({ previewRows: Number.isFinite(rows) && rows > 0 ? Math.floor(rows) : 1 }), setFullRows: (rows) => diff --git a/studio/frontend/src/features/studio/sections/dataset-section.tsx b/studio/frontend/src/features/studio/sections/dataset-section.tsx index 69698af3a8..cc4f26cd2b 100644 --- a/studio/frontend/src/features/studio/sections/dataset-section.tsx +++ b/studio/frontend/src/features/studio/sections/dataset-section.tsx @@ -135,6 +135,7 @@ export function DatasetSection() { datasetSource === "upload" ? "local" : "huggingface", ); const [localDatasets, setLocalDatasets] = useState([]); + const [hasLoadedLocalDatasets, setHasLoadedLocalDatasets] = useState(false); const [localLoading, setLocalLoading] = useState(false); const [localError, setLocalError] = useState(null); const openPreview = useDatasetPreviewDialogStore((s) => s.openPreview); @@ -157,6 +158,7 @@ export function DatasetSection() { error instanceof Error ? error.message : "Failed to load local datasets.", ); } finally { + setHasLoadedLocalDatasets(true); setLocalLoading(false); } }, []); @@ -247,19 +249,34 @@ export function DatasetSection() { return new Map(localDatasets.map((item) => [item.id, item.label])); }, [localDatasets]); - const selectedLocalId = useMemo(() => { + const selectedLocalDataset = useMemo(() => { if (!uploadedFile) return null; - const item = localDatasets.find((entry) => entry.path === uploadedFile); - return item?.id ?? deriveLocalDatasetName(uploadedFile); + return localDatasets.find((item) => item.path === uploadedFile) ?? null; }, [localDatasets, uploadedFile]); + const selectedLocalId = selectedLocalDataset?.id ?? null; + const localResultIds = useMemo(() => { const ids = localFilteredDatasets.map((item) => item.id); - if (selectedLocalId && !ids.includes(selectedLocalId)) { + if (selectedLocalDataset && selectedLocalId && !ids.includes(selectedLocalId)) { ids.push(selectedLocalId); } return ids; - }, [localFilteredDatasets, selectedLocalId]); + }, [localFilteredDatasets, selectedLocalDataset, selectedLocalId]); + + useEffect(() => { + if (!hasLoadedLocalDatasets) return; + if (datasetSource !== "upload") return; + if (!uploadedFile) return; + if (selectedLocalDataset) return; + selectLocalDataset(null); + }, [ + datasetSource, + hasLoadedLocalDatasets, + uploadedFile, + selectedLocalDataset, + selectLocalDataset, + ]); const activeSourceTab = datasetSource === "upload" ? "local" : "huggingface"; const comboboxItems = pickerTab === "huggingface" ? hfResultIds : localResultIds; @@ -277,10 +294,6 @@ export function DatasetSection() { !isLikelyLocalDatasetRef(dataset); const selectedDatasetName = datasetSource === "upload" ? uploadedFile : dataset; - const selectedLocalDataset = useMemo(() => { - if (!uploadedFile) return null; - return localDatasets.find((item) => item.path === uploadedFile) ?? null; - }, [localDatasets, uploadedFile]); const selectedLocalMetadata = selectedLocalDataset?.metadata ?? null; const selectedLocalColumns = selectedLocalMetadata?.columns ?? []; const selectedLocalRows =