diff --git a/studio/backend/core/data_recipe/oxc-validator/validate.mjs b/studio/backend/core/data_recipe/oxc-validator/validate.mjs index 28f9f242e3..a3ec29bf3c 100644 --- a/studio/backend/core/data_recipe/oxc-validator/validate.mjs +++ b/studio/backend/core/data_recipe/oxc-validator/validate.mjs @@ -100,36 +100,37 @@ function normalizeLintDiagnostic(diagnostic) { if (!diagnostic || typeof diagnostic !== "object") { return null; } + + const readString = (value) => + typeof value === "string" ? value : null; + const readInt = (value) => + Number.isInteger(value) ? value : null; + const asObject = (value) => + value && typeof value === "object" ? value : null; + const message = String(diagnostic.message || "").trim(); if (!message) { return null; } + const severityRaw = String(diagnostic.severity || "").trim().toLowerCase(); const severity = severityRaw === "error" ? "error" : "warning"; - const labels = Array.isArray(diagnostic.labels) - ? diagnostic.labels.map((label) => { - const span = label && typeof label === "object" ? label.span : null; - const start = - span && typeof span === "object" && Number.isInteger(span.offset) - ? span.offset - : null; - const length = - span && typeof span === "object" && Number.isInteger(span.length) - ? span.length - : null; - return { - message: - label && typeof label === "object" && typeof label.label === "string" - ? label.label - : null, - start, - end: - start !== null && length !== null - ? start + length - : null, - }; - }) - : []; + + const labels = []; + if (Array.isArray(diagnostic.labels)) { + for (const label of diagnostic.labels) { + const labelObj = asObject(label); + const span = asObject(labelObj?.span); + const start = readInt(span?.offset); + const length = readInt(span?.length); + labels.push({ + message: readString(labelObj?.label), + start, + end: start !== null && length !== null ? start + length : null, + }); + } + } + const code = typeof diagnostic.code === "string" ? diagnostic.code : null; return { message: code ? `${code}: ${message}` : message, diff --git a/studio/frontend/src/features/recipe-studio/dialogs/models/model-config-dialog.tsx b/studio/frontend/src/features/recipe-studio/dialogs/models/model-config-dialog.tsx index 0d2b01fd30..28251bd6f2 100644 --- a/studio/frontend/src/features/recipe-studio/dialogs/models/model-config-dialog.tsx +++ b/studio/frontend/src/features/recipe-studio/dialogs/models/model-config-dialog.tsx @@ -1,3 +1,8 @@ +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible"; import { Checkbox } from "@/components/ui/checkbox"; import { Combobox, @@ -8,7 +13,8 @@ import { ComboboxList, } from "@/components/ui/combobox"; import { Input } from "@/components/ui/input"; -import { type ReactElement, useRef } from "react"; +import { Textarea } from "@/components/ui/textarea"; +import { type ReactElement, useRef, useState } from "react"; import type { ModelConfig } from "../../types"; import { FieldLabel } from "../shared/field-label"; import { NameField } from "../shared/name-field"; @@ -24,11 +30,13 @@ export function ModelConfigDialog({ providerOptions, onUpdate, }: ModelConfigDialogProps): ReactElement { + const [optionalOpen, setOptionalOpen] = useState(false); const modelId = `${config.id}-model`; const providerId = `${config.id}-provider`; const tempId = `${config.id}-temperature`; const topPId = `${config.id}-top-p`; const maxTokensId = `${config.id}-max-tokens`; + const extraBodyId = `${config.id}-inference-extra-body`; const providerAnchorRef = useRef(null); const providerInputRef = useRef(config.provider); const lastProviderRef = useRef(config.provider); @@ -145,15 +153,44 @@ export function ModelConfigDialog({ /> - + + + + + +
+ +