diff --git a/web/ee/next.config.ts b/web/ee/next.config.ts index b70caf84d4..8f0e8086e1 100644 --- a/web/ee/next.config.ts +++ b/web/ee/next.config.ts @@ -32,8 +32,9 @@ const config = { "@agenta/annotation-ui", ], }, + // Type errors fail the build (tsc reached 0 on ts-chore/fix-tsc-issues; keep it there) typescript: { - ignoreBuildErrors: true, + ignoreBuildErrors: false, }, webpack: (webpackConfig: any, options: any) => { const baseConfig = diff --git a/web/ee/src/components/PostSignupForm/PostSignupHeader.tsx b/web/ee/src/components/PostSignupForm/PostSignupHeader.tsx index d85e7b02a1..96d5d2a92f 100644 --- a/web/ee/src/components/PostSignupForm/PostSignupHeader.tsx +++ b/web/ee/src/components/PostSignupForm/PostSignupHeader.tsx @@ -34,9 +34,9 @@ const PostSignupHeader = ({orgs}: PostSignupHeaderProps) => { ) diff --git a/web/ee/src/components/pages/app-management/components/ApiKeyInput.tsx b/web/ee/src/components/pages/app-management/components/ApiKeyInput.tsx index 475f83be1d..5c8fb57a2e 100644 --- a/web/ee/src/components/pages/app-management/components/ApiKeyInput.tsx +++ b/web/ee/src/components/pages/app-management/components/ApiKeyInput.tsx @@ -69,7 +69,7 @@ const ApiKeyInput: React.FC = ({apiKeyValue, onApiKeyChange}) } if (project) { - finalWorkspaceId = project.workspace_id + finalWorkspaceId = project.workspace_id ?? "" } } catch (e) { console.error("Failed to fetch projects manually", e) diff --git a/web/ee/src/components/pages/overview/deployments/HistoryConfig.tsx b/web/ee/src/components/pages/overview/deployments/HistoryConfig.tsx index 8c1caf1cc1..ff1e1282f5 100644 --- a/web/ee/src/components/pages/overview/deployments/HistoryConfig.tsx +++ b/web/ee/src/components/pages/overview/deployments/HistoryConfig.tsx @@ -1 +1,4 @@ -export {default} from "@/oss/components/pages/overview/deployments/HistoryConfig" +// Explicit OSS import (not @/oss/*, which resolves to this file itself under EE paths) +import HistoryConfig from "@agenta/oss/src/components/pages/overview/deployments/HistoryConfig" + +export default HistoryConfig diff --git a/web/ee/src/components/pages/settings/Billing/Modals/PricingModal/assets/SubscriptionPlanDetails/index.tsx b/web/ee/src/components/pages/settings/Billing/Modals/PricingModal/assets/SubscriptionPlanDetails/index.tsx index 9c932fbb07..feb30d2ada 100644 --- a/web/ee/src/components/pages/settings/Billing/Modals/PricingModal/assets/SubscriptionPlanDetails/index.tsx +++ b/web/ee/src/components/pages/settings/Billing/Modals/PricingModal/assets/SubscriptionPlanDetails/index.tsx @@ -7,7 +7,7 @@ import {SubscriptionType} from "@/oss/services/billing/types" dayjs.extend(duration) dayjs.extend(relativeTime) -const SubscriptionPlanDetails = ({subscription}: {subscription: SubscriptionType}) => { +const SubscriptionPlanDetails = ({subscription}: {subscription: SubscriptionType | undefined}) => { if (!subscription) return null const end = dayjs.unix(subscription.period_end) diff --git a/web/ee/src/components/pages/settings/Billing/Modals/PricingModal/assets/types.d.ts b/web/ee/src/components/pages/settings/Billing/Modals/PricingModal/assets/types.d.ts index 5c34b9fa15..3a09a8956b 100644 --- a/web/ee/src/components/pages/settings/Billing/Modals/PricingModal/assets/types.d.ts +++ b/web/ee/src/components/pages/settings/Billing/Modals/PricingModal/assets/types.d.ts @@ -22,7 +22,7 @@ export interface PricingPlan { export interface PricingCardProps { plan: BillingPlan - currentPlan: SubscriptionType | null + currentPlan: SubscriptionType | null | undefined onOptionClick: (plan: BillingPlan) => void isLoading: string | null } diff --git a/web/ee/src/components/pages/settings/Billing/index.tsx b/web/ee/src/components/pages/settings/Billing/index.tsx index 149b57746e..a67fe5016e 100644 --- a/web/ee/src/components/pages/settings/Billing/index.tsx +++ b/web/ee/src/components/pages/settings/Billing/index.tsx @@ -129,7 +129,10 @@ const Billing = () => { ? "Trial period will end on " : "Auto renews on "} - {dayjs.unix(subscription?.period_end).format("MMM D, YYYY")} + {/* Latent: subscription is undefined on fetch error — renders Invalid Date; typed as-is. */} + {dayjs + .unix(subscription?.period_end as number) + .format("MMM D, YYYY")} )} @@ -167,7 +170,8 @@ const Billing = () => { Limits
- {Object.entries(usage) + {/* Latent: usage is undefined when the fetch errors — entries() would throw; typed as-is. */} + {Object.entries(usage!) ?.filter(([key]) => key !== "users" && key !== "applications") ?.map(([key, info]) => { if (!info) return null @@ -197,24 +201,25 @@ const Billing = () => {
+ {/* Latent: usage.users can be absent (fetch error or plan without a users quota) — renders "undefined"; typed as-is. */} {billingEnabled && ( )}
diff --git a/web/ee/tsconfig.json b/web/ee/tsconfig.json index 3ded438dae..487e08594f 100644 --- a/web/ee/tsconfig.json +++ b/web/ee/tsconfig.json @@ -8,5 +8,5 @@ } }, "include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx"], - "exclude": ["node_modules"] + "exclude": ["node_modules", "tests", "../oss/tests"] } diff --git a/web/oss/next.config.ts b/web/oss/next.config.ts index ebfef7bb00..ed445d16c8 100644 --- a/web/oss/next.config.ts +++ b/web/oss/next.config.ts @@ -23,8 +23,9 @@ const COMMON_CONFIG: NextConfig = { eslint: { ignoreDuringBuilds: true, }, + // Type errors fail the build (tsc reached 0 on ts-chore/fix-tsc-issues; keep it there) typescript: { - ignoreBuildErrors: true, + ignoreBuildErrors: false, }, async redirects() { return [ diff --git a/web/oss/src/components/AgentChatSlice/components/clientTools/ElicitationWidget.tsx b/web/oss/src/components/AgentChatSlice/components/clientTools/ElicitationWidget.tsx index a4320ccc99..ae5bbe99a4 100644 --- a/web/oss/src/components/AgentChatSlice/components/clientTools/ElicitationWidget.tsx +++ b/web/oss/src/components/AgentChatSlice/components/clientTools/ElicitationWidget.tsx @@ -166,9 +166,15 @@ const ElicitationWidget = ({meta, settle, degradedEarlierInTurn}: ClientToolHand // storage unavailable — drafts are best-effort } } - const settleAndClear: typeof settle = (args: Parameters[0]) => { + const settleAndClear: typeof settle = ( + args: {output: Record} | {errorText: string}, + ) => { clearDraft() - settle(args as {output: Record}) + if ("errorText" in args) { + settle(args) + } else { + settle(args) + } } const restoredRef = useRef(false) useEffect(() => { diff --git a/web/oss/src/components/DeploymentsDashboard/Table/assets/deploymentColumns.tsx b/web/oss/src/components/DeploymentsDashboard/Table/assets/deploymentColumns.tsx index 10e27ab5b1..a37ae43d0c 100644 --- a/web/oss/src/components/DeploymentsDashboard/Table/assets/deploymentColumns.tsx +++ b/web/oss/src/components/DeploymentsDashboard/Table/assets/deploymentColumns.tsx @@ -92,8 +92,7 @@ export function createDeploymentColumns(actions: DeploymentColumnActions) { title: "Variant", width: 280, fixed: "left", - exportValue: (_row) => { - const record = _row as DeploymentRevisionRow + exportValue: (record) => { const name = record.variantSlug || "-" const version = record.deployedRevisionVersion return version != null ? `${name} v${version}` : name diff --git a/web/oss/src/components/DeploymentsDashboard/assets/UseApiContent.tsx b/web/oss/src/components/DeploymentsDashboard/assets/UseApiContent.tsx index 9878c7ea45..3910855a24 100644 --- a/web/oss/src/components/DeploymentsDashboard/assets/UseApiContent.tsx +++ b/web/oss/src/components/DeploymentsDashboard/assets/UseApiContent.tsx @@ -71,7 +71,12 @@ const UseApiContent = ({ ) const params = useMemo(() => { - const synthesized = variableNames.map((name) => ({name, input: name === "messages"})) + const synthesized = variableNames.map((name) => ({ + name, + type: "string", + input: name === "messages", + required: true, + })) return createParams(synthesized, envName || "none", "add_a_value", currentApp, { flags: {is_chat: isChat}, diff --git a/web/oss/src/components/DeploymentsDashboard/modals/DeploymentConfirmationModalWrapper.tsx b/web/oss/src/components/DeploymentsDashboard/modals/DeploymentConfirmationModalWrapper.tsx index 0163908a19..c6ce2aee56 100644 --- a/web/oss/src/components/DeploymentsDashboard/modals/DeploymentConfirmationModalWrapper.tsx +++ b/web/oss/src/components/DeploymentsDashboard/modals/DeploymentConfirmationModalWrapper.tsx @@ -22,7 +22,7 @@ const DeploymentConfirmationModalWrapper = () => { actionType={state.actionType} variant={state.variant} note={state.note} - setNote={(n) => setNote(n)} + setNote={(n) => setNote(typeof n === "function" ? n(state.note) : n)} okButtonProps={{loading: state.okLoading}} onOk={() => confirm()} /> diff --git a/web/oss/src/components/DrillInView/TraceSpanDrillInView.tsx b/web/oss/src/components/DrillInView/TraceSpanDrillInView.tsx index 181aa8d4fc..7a2c1bbec1 100644 --- a/web/oss/src/components/DrillInView/TraceSpanDrillInView.tsx +++ b/web/oss/src/components/DrillInView/TraceSpanDrillInView.tsx @@ -1,4 +1,5 @@ import { + type ComponentProps, memo, type ReactNode, useCallback, @@ -664,7 +665,13 @@ export const TraceSpanDrillInView = memo( return ( ["entity"] + } // Trace-specific defaults rootTitle={title} editable={editable} diff --git a/web/oss/src/components/DrillInView/viewModes.ts b/web/oss/src/components/DrillInView/viewModes.ts index 99a39798d9..e86f1fa2b1 100644 --- a/web/oss/src/components/DrillInView/viewModes.ts +++ b/web/oss/src/components/DrillInView/viewModes.ts @@ -3,8 +3,11 @@ export const getDefaultJsonViewMode = ( ): TMode => { const hasMode = (mode: string): mode is TMode => availableModes.includes(mode as TMode) - if (hasMode("pretty-json")) return "pretty-json" - if (hasMode("decoded-json")) return "decoded-json" + // Guard narrows an identifier, not a literal — bind first so the return is typed TMode. + const prettyJson = "pretty-json" + if (hasMode(prettyJson)) return prettyJson + const decodedJson = "decoded-json" + if (hasMode(decodedJson)) return decodedJson return (availableModes[0] ?? "json") as TMode } diff --git a/web/oss/src/components/EditorViews/SimpleSharedEditor/index.tsx b/web/oss/src/components/EditorViews/SimpleSharedEditor/index.tsx index 15b35d5350..ceedc3c2d6 100644 --- a/web/oss/src/components/EditorViews/SimpleSharedEditor/index.tsx +++ b/web/oss/src/components/EditorViews/SimpleSharedEditor/index.tsx @@ -6,6 +6,7 @@ import { ON_CHANGE_LANGUAGE, $isCodeBlockNode, TOGGLE_MARKDOWN_VIEW, + type CodeLanguage, } from "@agenta/ui/editor" import {SharedEditor} from "@agenta/ui/shared-editor" import {mergeRegister} from "@lexical/utils" @@ -53,7 +54,8 @@ const SimpleSharedEditorContent = ({ }: SimpleSharedEditorProps) => { const [minimized, setMinimized] = useState(() => Boolean(defaultMinimized)) const [isCopied, setIsCopied] = useState(false) - const [language, setLanguage] = useState(() => + // The code block can carry any CodeLanguage (via editorProps), beyond the dropdown's Format set. + const [language, setLanguage] = useState(() => isJSON ? "json" : isYAML ? "yaml" : "text", ) @@ -84,7 +86,8 @@ const SimpleSharedEditorContent = ({ editor.dispatchCommand(ON_CHANGE_LANGUAGE, {language: "yaml"}) } else if (isHTML) { setLanguage("html") - editor.dispatchCommand(ON_CHANGE_LANGUAGE, {language: "html"}) + // "html" has no CodeLanguage grammar — the tokenizer falls back; typed as-is. + editor.dispatchCommand(ON_CHANGE_LANGUAGE, {language: "html" as string as CodeLanguage}) } else { setLanguage("markdown") } diff --git a/web/oss/src/components/EditorViews/SimpleSharedEditor/types.ts b/web/oss/src/components/EditorViews/SimpleSharedEditor/types.ts index bb485b9e4d..cd4cf113e6 100644 --- a/web/oss/src/components/EditorViews/SimpleSharedEditor/types.ts +++ b/web/oss/src/components/EditorViews/SimpleSharedEditor/types.ts @@ -1,7 +1,7 @@ import {SharedEditorProps} from "@agenta/ui/shared-editor" import {DropdownProps} from "antd" -import {TooltipButtonProps} from "../../EnhancedUIs/Button" +import {EnhancedButtonProps} from "../../EnhancedUIs/Button/types" export interface SimpleSharedEditorProps extends SharedEditorProps { headerClassName?: string @@ -13,9 +13,15 @@ export interface SimpleSharedEditorProps extends SharedEditorProps { isFormatVisible?: boolean isCopyVisible?: boolean formatDropdownProps?: DropdownProps - copyButtonProps?: TooltipButtonProps - minimizeButtonProps?: TooltipButtonProps - disableFormatItems?: {text?: boolean; markdown?: boolean; json?: boolean; yaml?: boolean} + copyButtonProps?: EnhancedButtonProps + minimizeButtonProps?: EnhancedButtonProps + disableFormatItems?: { + text?: boolean + markdown?: boolean + json?: boolean + yaml?: boolean + html?: boolean + } minimizedHeight?: number showTextToMdOutside?: boolean defaultMinimized?: boolean diff --git a/web/oss/src/components/EditorViews/assets/helper.ts b/web/oss/src/components/EditorViews/assets/helper.ts index 8abcc9db4b..33f16f4cd5 100644 --- a/web/oss/src/components/EditorViews/assets/helper.ts +++ b/web/oss/src/components/EditorViews/assets/helper.ts @@ -1,4 +1,5 @@ import {$convertToMarkdownStringCustom, PLAYGROUND_TRANSFORMERS, $isCodeBlockNode} from "@agenta/ui" +import type {CodeLanguage} from "@agenta/ui/editor" import {$isCodeNode} from "@lexical/code" import {load as yamlLoad, dump as yamlDump, type DumpOptions} from "js-yaml" import JSON5 from "json5" @@ -150,7 +151,10 @@ export function formatYAML(input: string, opts?: DumpOptions): string { }) } -export function getDisplayedContent(editor: LexicalEditor, language: Format): string { +export function getDisplayedContent( + editor: LexicalEditor, + language: Format | CodeLanguage, +): string { return editor.getEditorState().read(() => { const root = $getRoot() diff --git a/web/oss/src/components/EnhancedUIs/Drawer/index.tsx b/web/oss/src/components/EnhancedUIs/Drawer/index.tsx index c5c568e563..c655527534 100644 --- a/web/oss/src/components/EnhancedUIs/Drawer/index.tsx +++ b/web/oss/src/components/EnhancedUIs/Drawer/index.tsx @@ -17,10 +17,13 @@ const EnhancedDrawer = ({ const drawerStyles = useMemo(() => { if (!width) return styles + // antd v6 `styles` may also be a resolver function; spreading it has always dropped the + // function form, so the width merge only ever applied to the object form (typed as-is) + const baseStyles = typeof styles === "function" ? undefined : styles return { - ...styles, + ...baseStyles, wrapper: { - ...styles?.wrapper, + ...baseStyles?.wrapper, width, }, } diff --git a/web/oss/src/components/EntityIdentity/useRenameApp.ts b/web/oss/src/components/EntityIdentity/useRenameApp.ts index c2d26e544e..2587c69880 100644 --- a/web/oss/src/components/EntityIdentity/useRenameApp.ts +++ b/web/oss/src/components/EntityIdentity/useRenameApp.ts @@ -45,7 +45,8 @@ export const useRenameApp = () => { async ({id, name, description}: RenameAppPayload): Promise => { try { const {projectId} = getProjectValues() - await updateWorkflow(projectId, { + // typed as-is: projectId can be null pre-project-scope; the call always sent it through + await updateWorkflow(projectId as string, { id, name, description, @@ -53,7 +54,7 @@ export const useRenameApp = () => { }) invalidateWorkflowsListCache() invalidateWorkflowCache(id) - await mutate() + await mutate?.() await invalidateAppManagementWorkflowQueries() return true } catch (error) { diff --git a/web/oss/src/components/EvalRunDetails/Table.tsx b/web/oss/src/components/EvalRunDetails/Table.tsx index 47d60d8578..c88a66c16d 100644 --- a/web/oss/src/components/EvalRunDetails/Table.tsx +++ b/web/oss/src/components/EvalRunDetails/Table.tsx @@ -8,6 +8,8 @@ import {useAtomValue, useSetAtom, useStore} from "jotai" import VirtualizedScenarioTableAnnotateDrawer from "@/oss/components/EvalRunDetails/components/AnnotateDrawer/VirtualizedScenarioTableAnnotateDrawer" import { InfiniteVirtualTableFeatureShell, + type ColumnVisibilityMenuRendererContext, + type ColumnVisibilityState, type TableFeaturePagination, type TableScopeConfig, useInfiniteTablePagination, @@ -1056,9 +1058,9 @@ const EvalRunDetailsTable = ({ useSettingsDropdown settingsDropdownMenuItems={rowHeightMenuItems} columnVisibilityMenuRenderer={( - controls, - close, - {scopeId, onExport, isExporting}, + controls: ColumnVisibilityState, + close: () => void, + {scopeId, onExport, isExporting}: ColumnVisibilityMenuRendererContext, ) => ( { const state: MetricProcessorState = { pending: [], @@ -689,7 +693,7 @@ export const createMetricProcessor = ({ ) const newMetricIds = runMetrics .map((metric: any) => metric?.id) - .filter((id): id is string => Boolean(id)) + .filter((id: unknown): id is string => Boolean(id)) const runReasons = new Set() const runOldMetricIds = new Set() pending @@ -700,7 +704,9 @@ export const createMetricProcessor = ({ }) const oldMetricIdsArray = Array.from(runOldMetricIds) - const reusedRunMetricIds = newMetricIds.filter((id) => runOldMetricIds.has(id)) + const reusedRunMetricIds = newMetricIds.filter((id: string) => + runOldMetricIds.has(id), + ) const staleRunMetricIds = oldMetricIdsArray.filter( (id) => !reusedRunMetricIds.includes(id), ) diff --git a/web/oss/src/components/EvalRunDetails/atoms/metrics.ts b/web/oss/src/components/EvalRunDetails/atoms/metrics.ts index cce38b7c9d..8e5f6a70d3 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/metrics.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/metrics.ts @@ -263,6 +263,16 @@ const buildGroupedMetrics = ( return grouped } +// NOTE (latent runtime bug, typed as-is per WP-4e-2a): `applyAggregatesToRaw` is +// referenced below but is not defined or imported anywhere in the codebase. At runtime +// this throws a ReferenceError whenever `buildRunLevelMetricData` is invoked. We declare +// it (emits no JS) to make the type-check faithful WITHOUT altering the runtime behavior. +// Do not "fix" by adding an implementation — that would change behavior. See QA flag. +declare const applyAggregatesToRaw: ( + raw: Record, + aggregates: ReturnType, +) => Record + const buildRunLevelMetricData = (rawMetrics: any[]): RunLevelMetricData => { const rawAccumulator: Record = {} const entries: EvaluationMetricEntry[] = [] diff --git a/web/oss/src/components/EvalRunDetails/atoms/query.ts b/web/oss/src/components/EvalRunDetails/atoms/query.ts index 5c561f46ef..167924b15b 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/query.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/query.ts @@ -246,7 +246,7 @@ const buildReferenceDescriptor = ( } const descriptorKey = (descriptor: ReferenceDescriptor) => { - const parts = [descriptor.type] + const parts: string[] = [descriptor.type] if (descriptor.id) parts.push(`id:${descriptor.id}`) if (descriptor.slug) parts.push(`slug:${descriptor.slug}`) if ("version" in descriptor && descriptor.version !== undefined) { @@ -279,7 +279,7 @@ const toVersionKey = (key: string, version: number | string | null | undefined) interface QueryRevisionBatchRequest { projectId: string - runId: string + runId: string | null reference: EvaluationQueryReference } @@ -502,7 +502,7 @@ const evaluationQueryRevisionBatchFetcher = createBatchFetcher< if (descriptor.id) { if (versionValue) { const key = toVersionKey(descriptor.id, versionValue) - matched = (key && byVariantVersionId.get(key)) ?? null + matched = (key ? byVariantVersionId.get(key) : null) ?? null } if (!matched) { matched = byVariantId.get(descriptor.id) ?? null @@ -511,7 +511,7 @@ const evaluationQueryRevisionBatchFetcher = createBatchFetcher< if (!matched && descriptor.slug) { if (versionValue) { const key = toVersionKey(descriptor.slug, versionValue) - matched = (key && byVariantVersionSlug.get(key)) ?? null + matched = (key ? byVariantVersionSlug.get(key) : null) ?? null } if (!matched) { matched = byVariantSlug.get(descriptor.slug) ?? null @@ -570,7 +570,7 @@ const buildReferenceKey = (reference: EvaluationQueryReference) => [ ] export const evaluationQueryRevisionAtomFamily = atomFamily((runId: string | null) => - atomWithQuery((get) => { + atomWithQuery((get) => { const projectId = get(effectiveProjectIdAtom) const reference = runId ? get(evaluationQueryReferenceAtomFamily(runId)) : EMPTY_REFERENCE const enabled = Boolean(projectId && runId && hasLookupValue(reference)) @@ -606,7 +606,7 @@ export const evaluationQueryRevisionAtomFamily = atomFamily((runId: string | nul export const queryReferenceLookupAtomFamily = atomFamily( (reference: EvaluationQueryReference | null | undefined) => - atomWithQuery((get) => { + atomWithQuery((get) => { const projectId = get(effectiveProjectIdAtom) const normalized = reference ?? EMPTY_REFERENCE const enabled = Boolean(projectId && hasLookupValue(normalized)) diff --git a/web/oss/src/components/EvalRunDetails/atoms/runMetrics.ts b/web/oss/src/components/EvalRunDetails/atoms/runMetrics.ts index bbc07703d1..77538f1cf9 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/runMetrics.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/runMetrics.ts @@ -10,9 +10,22 @@ import {BasicStats, canonicalizeMetricKey, getMetricValueWithAliases} from "@/os import {previewEvalTypeAtom} from "../state/evalType" -import {clearBootstrapAttempt, createMetricProcessor, type MetricScope} from "./metricProcessor" +import { + clearBootstrapAttempt, + createMetricProcessor, + type MetricProcessor, + type MetricScope, +} from "./metricProcessor" import {effectiveProjectIdAtom} from "./run" +// NOTE (latent runtime bug, typed as-is per WP-4e-2a): `metricProcessor` is referenced at +// the run-level-gap branch below but no such binding exists in that scope — the processor +// created inside `processMetrics` is named `processor` and is out of scope there. At runtime +// this throws a ReferenceError whenever `shouldMarkRunLevelGap` is true. We declare it +// (emits no JS) so the type-check is faithful WITHOUT changing the runtime behavior. Do not +// "fix" by wiring up a real processor — that would change behavior. See QA flag. +declare const metricProcessor: MetricProcessor + type RunLevelStatsMap = Record export interface TemporalMetricPoint { @@ -252,12 +265,12 @@ const mergeBasicStats = (current: BasicStats | undefined, incoming: BasicStats): result.frequency = mergedFrequency result.rank = mergedFrequency } - const mergedRank = mergeFrequencyArrays(result.rank, incoming.rank) + const mergedRank = mergeFrequencyArrays(result.rank, incoming.rank as any[] | undefined) if (mergedRank) { result.rank = mergedRank } - const mergedUnique = mergeUniqueValues(result.unique, incoming.unique) + const mergedUnique = mergeUniqueValues(result.unique, incoming.unique as any[] | undefined) if (mergedUnique) { result.unique = mergedUnique } @@ -1223,7 +1236,7 @@ export const runTemporalMetricKeysAtomFamily = atomFamily((runId: string | null if (loadable.state !== "hasData") { return cachedFlag ?? false } - const statsMap = (loadable.data as RunLevelStatsMap) ?? {} + const statsMap = (loadable.data as unknown as RunLevelStatsMap) ?? {} const inferred = Object.keys(statsMap || {}).some((key) => key.includes("temporal")) if (inferred) { temporalRunFlags.set(runId, true) @@ -1352,7 +1365,7 @@ export const latestTemporalMetricStatsSelectorFamily = atomFamily( // Fallback to run-level stats if temporal series is empty or doesn't have matching data // This is important for online evaluations where metrics might not have timestamps if (loadableResult.state === "hasData" && loadableResult.data) { - const runLevelStats = loadableResult.data as Record + const runLevelStats = loadableResult.data as unknown as Record // Run-level stats use dot separator (stepKey.metricKey), not colon const candidates = [ stepKey && metricPath ? `${stepKey}.${metricPath}` : null, diff --git a/web/oss/src/components/EvalRunDetails/atoms/runMetrics/types.ts b/web/oss/src/components/EvalRunDetails/atoms/runMetrics/types.ts index 5b47025fe7..6ec8cf4f67 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/runMetrics/types.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/runMetrics/types.ts @@ -42,6 +42,7 @@ export interface ScenarioRefreshDetailResult { oldMetricIds: string[] newMetricIds: string[] reusedMetricIds: string[] + staleMetricIds: string[] returnedCount: number attempts: string[] } @@ -51,6 +52,7 @@ export interface RunRefreshDetailResult { oldMetricIds: string[] newMetricIds: string[] reusedMetricIds: string[] + staleMetricIds: string[] returnedCount: number } diff --git a/web/oss/src/components/EvalRunDetails/atoms/scenarioColumnValues.ts b/web/oss/src/components/EvalRunDetails/atoms/scenarioColumnValues.ts index d64736b1fd..9433cdf9f6 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/scenarioColumnValues.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/scenarioColumnValues.ts @@ -4,6 +4,7 @@ import {atomFamily, selectAtom} from "jotai/utils" import type {IStepResponse} from "@/oss/lib/evaluations" import type {AnnotationDto} from "@/oss/lib/hooks/useAnnotations/types" +import type {PreviewTestCase} from "@/oss/lib/Types" import {readInvocationResponse} from "../../../lib/traces/traceUtils" import {previewEvalTypeAtom} from "../state/evalType" @@ -387,7 +388,7 @@ const resolveAnnotationValue = ( if (!annotation) return undefined const pathSegments = descriptor.pathSegments ?? column.pathSegments ?? splitPath(column.path) - const outputs = annotation?.data?.outputs ?? {} + const outputs = (annotation?.data?.outputs ?? {}) as Record const annotationDescriptor = descriptor.annotation const metricCandidates = annotationDescriptor?.metricPathCandidates ?? [] diff --git a/web/oss/src/components/EvalRunDetails/atoms/scenarioSteps.ts b/web/oss/src/components/EvalRunDetails/atoms/scenarioSteps.ts index aca7afb8b2..9329f6884d 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/scenarioSteps.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/scenarioSteps.ts @@ -122,7 +122,7 @@ export const scenarioStepsBatcherFamily = atomFamily(({runId}: {runId?: string | }), ) -export const scenarioStepsBatcherAtom = atom((get) => get(scenarioStepsBatcherFamily())) +export const scenarioStepsBatcherAtom = atom((get) => get(scenarioStepsBatcherFamily(undefined))) export const scenarioStepsQueryFamily = atomFamily( ({scenarioId, runId}: {scenarioId: string; runId?: string | null}) => diff --git a/web/oss/src/components/EvalRunDetails/atoms/table/columnAccess.ts b/web/oss/src/components/EvalRunDetails/atoms/table/columnAccess.ts index 7ee6e59766..b9422b4b34 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/table/columnAccess.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/table/columnAccess.ts @@ -101,7 +101,7 @@ const buildAnnotationSegmentVariants = (pathSegments: string[]): string[][] => { return variants } -const inferBooleanMetric = (column: EvaluationTableColumn): boolean => { +const inferBooleanMetric = (column: ColumnDescriptorInput): boolean => { const metricType = column.metricType?.toLowerCase() ?? "" const path = column.path.toLowerCase() const valueKey = column.valueKey?.toLowerCase() ?? "" diff --git a/web/oss/src/components/EvalRunDetails/atoms/table/columns.ts b/web/oss/src/components/EvalRunDetails/atoms/table/columns.ts index 189984e503..fae571407a 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/table/columns.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/table/columns.ts @@ -249,7 +249,7 @@ const registerStepGroup = ({ role: StepRole registry: Map groupIdOverride?: string - groupKindOverride?: EvaluationTableColumnGroup["kind"] + groupKindOverride?: StepGroupInfo["kind"] labelOverride?: string }) => { const key = stepMeta?.key ?? column.stepKey ?? `${role}:unknown` @@ -326,7 +326,7 @@ const tableColumnsBaseAtomFamily = atomFamily((runId: string | null) => const evaluatorQuery = get(evaluationEvaluatorsByRunQueryAtomFamily(runId)) const evaluators = evaluatorQuery?.data ?? [] - const mappings = Array.isArray(runData.camelRun?.data?.mappings) + const mappings: RawMapping[] = Array.isArray(runData.camelRun?.data?.mappings) ? runData.camelRun.data.mappings : [] diff --git a/web/oss/src/components/EvalRunDetails/atoms/table/run.ts b/web/oss/src/components/EvalRunDetails/atoms/table/run.ts index 669e0c16a7..d26f04baaf 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/table/run.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/table/run.ts @@ -2,6 +2,7 @@ import {fetchWorkflowsBatch} from "@agenta/entities/workflow" import {atomFamily, selectAtom} from "jotai/utils" import {atomWithQuery} from "jotai-tanstack-query" +import axios from "@/oss/lib/api/assets/axiosConfig" import {buildRunIndex} from "@/oss/lib/evaluations/buildRunIndex" import {snakeToCamelCaseKeys} from "@/oss/lib/helpers/casing" import { @@ -47,7 +48,10 @@ type EnsureEvaluatorRevisionsReason = interface EnsureEvaluatorRevisionsResult { run: EvaluationRun patched: boolean - reason: EnsureEvaluatorRevisionsReason + // Optional: the post-patch success path and the catch (error) path return without a + // `reason` at runtime (see lines below). Typed optional to match actual behavior; no + // consumer reads `reason`, so this is behavior-preserving. + reason?: EnsureEvaluatorRevisionsReason } const applyResolvedEvaluatorRefs = ({ @@ -330,7 +334,9 @@ export const evaluationRunQueryAtomFamily = atomFamily((runId: string | null) => rawRun, }) - const camelRun = snakeToCamelCaseKeys(normalizedRun) + const camelRun = snakeToCamelCaseKeys( + normalizedRun as unknown as Record, + ) const runIndex = buildRunIndex(camelRun) return {rawRun, camelRun, runIndex} }, @@ -376,7 +382,9 @@ export const evaluationRunWithProjectQueryAtomFamily = atomFamily( rawRun, }) - const camelRun = snakeToCamelCaseKeys(normalizedRun) + const camelRun = snakeToCamelCaseKeys( + normalizedRun as unknown as Record, + ) const runIndex = buildRunIndex(camelRun) return {rawRun, camelRun, runIndex} }, diff --git a/web/oss/src/components/EvalRunDetails/atoms/table/scenarios.ts b/web/oss/src/components/EvalRunDetails/atoms/table/scenarios.ts index 94c6f68e4e..f1a8a619f9 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/table/scenarios.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/table/scenarios.ts @@ -271,7 +271,9 @@ export const tableScenarioRowsQueryAtomFamily = atomFamily( const _requestId = `${runId}:${cursor ?? "root"}:${queryRequestCounter++}` const result = await fetchEvaluationScenarioWindow({ - projectId, + // `enabled` gates this queryFn on a truthy projectId, so it is + // non-null whenever this runs (mirrors the `!runId` guard above). + projectId: projectId!, runId, cursor, limit, diff --git a/web/oss/src/components/EvalRunDetails/atoms/table/testcases.ts b/web/oss/src/components/EvalRunDetails/atoms/table/testcases.ts index f65f03cc9a..7571d661ea 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/table/testcases.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/table/testcases.ts @@ -91,7 +91,9 @@ export const evaluationTestcaseBatcherFamily = atomFamily(({runId}: {runId?: str }), ) -export const evaluationTestcaseBatcherAtom = atom((get) => get(evaluationTestcaseBatcherFamily())) +export const evaluationTestcaseBatcherAtom = atom((get) => + get(evaluationTestcaseBatcherFamily(undefined)), +) export const evaluationTestcaseQueryAtomFamily = atomFamily( ({testcaseId, runId}: {testcaseId: string; runId?: string | null}) => diff --git a/web/oss/src/components/EvalRunDetails/atoms/table/types.ts b/web/oss/src/components/EvalRunDetails/atoms/table/types.ts index 952cbd6434..63ae8d9509 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/table/types.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/table/types.ts @@ -1,9 +1,12 @@ import type {EvaluatorDefinition, MetricColumnDefinition} from "@agenta/entities/workflow" +export type {MetricColumnDefinition} + export type EvaluationColumnKind = | "meta" | "testset" | "query" + | "input" | "invocation" | "annotation" | "evaluator" diff --git a/web/oss/src/components/EvalRunDetails/atoms/tableRows.ts b/web/oss/src/components/EvalRunDetails/atoms/tableRows.ts index a825ce5c4e..14727a5590 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/tableRows.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/tableRows.ts @@ -17,4 +17,5 @@ export interface PreviewTableRow { /** Timestamp for online evaluation scenarios (batch grouping) */ timestamp?: string | null __isSkeleton: boolean + [key: string]: unknown } diff --git a/web/oss/src/components/EvalRunDetails/atoms/traces.ts b/web/oss/src/components/EvalRunDetails/atoms/traces.ts index 9cab74d56b..447eda0662 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/traces.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/traces.ts @@ -160,14 +160,22 @@ const buildTraceDataFromEntry = ( }, } - const spanNodes = transformTracesResponseToTree(scopedResponse) + // OSS TracesResponse is the same backend payload shape the entities-package + // transform expects; align at the boundary, no data is converted. + const spanNodes = transformTracesResponseToTree( + scopedResponse as unknown as Parameters[0], + ) if (!spanNodes.length) return null const flat: TraceNode[] = [] spanNodes.forEach((span) => { const inferredTraceId = span.trace_id ?? traceId ?? (span.span_id ? `${span.span_id}-trace` : "trace") - convertSpanNodeToTraceNode(span, inferredTraceId, flat) + // `transformTracesResponseToTree` yields the entities-package TraceSpanNode, while + // `convertSpanNodeToTraceNode` is written against the structurally-equivalent OSS + // TraceSpanNode (same backend span shape). Align the annotation at the boundary; no + // data is converted. + convertSpanNodeToTraceNode(span as unknown as TraceSpanNode, inferredTraceId, flat) }) const treeEntry: TraceTree = { diff --git a/web/oss/src/components/EvalRunDetails/atoms/types.ts b/web/oss/src/components/EvalRunDetails/atoms/types.ts new file mode 100644 index 0000000000..83e9e712a0 --- /dev/null +++ b/web/oss/src/components/EvalRunDetails/atoms/types.ts @@ -0,0 +1,32 @@ +import type {IStepResponse} from "@/oss/lib/evaluations" + +/** + * A scenario step as surfaced through the batch result. + * + * The batch fetcher stores camel-cased step responses (`IStepResponse`), but the eval-run + * consumers also read backend snake_case / extended fields off each step at runtime + * (e.g. `trace`, `trace_id`, `data`, `inputs`, `testcase_id`, including nested access like + * `trace.nodes`). The index signature keeps those pass-through reads working without + * asserting a precise shape for fields the batch fetcher forwards verbatim. + */ +export type ScenarioStepEntry = IStepResponse & Record + +/** + * Per-scenario batch result produced by the scenario-steps batch fetcher. + * + * This describes the object shape that {@link scenarioStepsBatcherFamily} builds at + * runtime (see `scenarioSteps.ts`): one entry per scenario id, holding the camel-cased + * step responses for that scenario along with a count and an optional pagination cursor. + * + * `invocationSteps` / `annotationSteps` are optional sibling arrays some consumers read + * defensively (`?.`); the batch fetcher does not currently populate them, so they are + * `undefined` at runtime. + */ +export interface ScenarioStepsBatchResult { + scenarioId: string + steps: ScenarioStepEntry[] + count: number + next?: unknown + invocationSteps?: ScenarioStepEntry[] + annotationSteps?: ScenarioStepEntry[] +} diff --git a/web/oss/src/components/EvalRunDetails/atoms/variantConfig.ts b/web/oss/src/components/EvalRunDetails/atoms/variantConfig.ts index aebef9becf..8f6eb49b6b 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/variantConfig.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/variantConfig.ts @@ -35,7 +35,7 @@ const pickInvocationReference = (runQuery: any) => { return {stepKey: undefined, refs: undefined} } - const invocationKeys = Array.from(runData.runIndex.invocationKeys ?? []) + const invocationKeys = Array.from(runData.runIndex.invocationKeys ?? []) as string[] const primaryKey = invocationKeys[0] if (!primaryKey) { return {stepKey: undefined, refs: undefined} diff --git a/web/oss/src/components/EvalRunDetails/components/CompareRunsMenu.tsx b/web/oss/src/components/EvalRunDetails/components/CompareRunsMenu.tsx index 775efaf66c..c29a6cea9b 100644 --- a/web/oss/src/components/EvalRunDetails/components/CompareRunsMenu.tsx +++ b/web/oss/src/components/EvalRunDetails/components/CompareRunsMenu.tsx @@ -166,7 +166,7 @@ const CompareRunsPopoverContent = memo(({runId, availability}: CompareRunsPopove name: run.name || "Untitled run", status: run.status, description: (run as any)?.description ?? (run as any)?.summary ?? null, - createdAt: run.createdAt ?? run.created_at, + createdAt: run.createdAt ?? (run as any)?.created_at, testsetNames: Array.isArray(run.testsets) ? run.testsets.map((t) => t?.name || "Unnamed testset") : [], diff --git a/web/oss/src/components/EvalRunDetails/components/EvalTestcaseDrawerAdapter/drawerPayload.ts b/web/oss/src/components/EvalRunDetails/components/EvalTestcaseDrawerAdapter/drawerPayload.ts index 6f3d34234f..b49497dec2 100644 --- a/web/oss/src/components/EvalRunDetails/components/EvalTestcaseDrawerAdapter/drawerPayload.ts +++ b/web/oss/src/components/EvalRunDetails/components/EvalTestcaseDrawerAdapter/drawerPayload.ts @@ -1,4 +1,6 @@ export interface EvaluationDrawerPayload { + // Explicit index signature keeps the payload assignable to Record + [key: string]: unknown inputs: Record outputs: Record evaluators: Record diff --git a/web/oss/src/components/EvalRunDetails/components/EvaluatorMetricsChart/BarChart.tsx b/web/oss/src/components/EvalRunDetails/components/EvaluatorMetricsChart/BarChart.tsx index 508db235a5..f0e0a62673 100644 --- a/web/oss/src/components/EvalRunDetails/components/EvaluatorMetricsChart/BarChart.tsx +++ b/web/oss/src/components/EvalRunDetails/components/EvaluatorMetricsChart/BarChart.tsx @@ -7,10 +7,10 @@ import { BarChart as RechartsBarChart, ResponsiveContainer, Tooltip, - TooltipProps, XAxis, YAxis, } from "recharts" +import type {TooltipContentProps} from "recharts" type ChartDatum = Record @@ -20,7 +20,7 @@ interface BarChartProps { yKey: string colorKey?: string yDomain?: [number | "auto" | "dataMin", number | "auto" | "dataMax"] - xAxisProps?: Partial> + xAxisProps?: Partial> & {tickWidth?: number} yAxisProps?: Partial> cartesianGridProps?: Partial> chartProps?: Partial> @@ -102,8 +102,8 @@ const BarChart = ({ interval={xAxisInterval ?? 0} tick={({x, y, payload}) => ( @@ -143,7 +143,7 @@ const BarChart = ({ {tooltipLabel ? ( ) => { + content={({active, payload, label}: TooltipContentProps) => { if (!active || !payload?.length) return null const rows = payload.filter((p) => p?.value != null) if (!rows.length) return null diff --git a/web/oss/src/components/EvalRunDetails/components/EvaluatorMetricsChart/index.tsx b/web/oss/src/components/EvalRunDetails/components/EvaluatorMetricsChart/index.tsx index bf99328933..b86c3d3293 100644 --- a/web/oss/src/components/EvalRunDetails/components/EvaluatorMetricsChart/index.tsx +++ b/web/oss/src/components/EvalRunDetails/components/EvaluatorMetricsChart/index.tsx @@ -57,6 +57,8 @@ interface MetricStripEntry { const getMainEvaluatorSeries = (entries: MetricStripEntry[]) => entries.find((entry) => entry.isMain) ?? entries[0] +const BAR_RADIUS: [number, number, number, number] = [8, 8, 0, 0] + const computeDeltaPercent = (current: number | null, baseline: number | null) => { if (typeof current !== "number" || typeof baseline !== "number") return null if (!Number.isFinite(current) || !Number.isFinite(baseline) || baseline === 0) return null @@ -315,7 +317,7 @@ const EvaluatorMetricsChart = ({ deltaTone: "neutral", } - const comparisonEntries = comparisonSeries.map((entry) => { + const comparisonEntries = comparisonSeries.map((entry): MetricStripEntry => { const statsValue = entry.stats if (!statsValue) { return { @@ -414,13 +416,13 @@ const EvaluatorMetricsChart = ({ key: baseSeriesKey, name: resolvedRunName, color: resolvedBaseColor, - barProps: {radius: [8, 8, 0, 0], minPointSize: 2}, + barProps: {radius: BAR_RADIUS, minPointSize: 2}, }, ...comparisonSeries.map((entry) => ({ key: entry.runId, name: entry.runName, color: entry.color, - barProps: {radius: [8, 8, 0, 0], minPointSize: 2}, + barProps: {radius: BAR_RADIUS, minPointSize: 2}, })), ], [baseSeriesKey, comparisonSeries, resolvedBaseColor, resolvedRunName], @@ -496,13 +498,13 @@ const EvaluatorMetricsChart = ({ key: baseSeriesKey, name: resolvedRunName, color: resolvedBaseColor, - barProps: {radius: [8, 8, 0, 0], minPointSize: 2}, + barProps: {radius: BAR_RADIUS, minPointSize: 2}, }, ...comparisonBooleanHistograms.map((entry) => ({ key: entry.runId, name: entry.runName, color: entry.color, - barProps: {radius: [8, 8, 0, 0], minPointSize: 2}, + barProps: {radius: BAR_RADIUS, minPointSize: 2}, })), ] @@ -582,13 +584,13 @@ const EvaluatorMetricsChart = ({ key: baseSeriesKey, name: resolvedRunName, color: resolvedBaseColor, - barProps: {radius: [8, 8, 0, 0], minPointSize: 2}, + barProps: {radius: BAR_RADIUS, minPointSize: 2}, }, ...comparisonMaps.map((entry) => ({ key: entry.runId, name: entry.runName, color: entry.color, - barProps: {radius: [8, 8, 0, 0], minPointSize: 2}, + barProps: {radius: BAR_RADIUS, minPointSize: 2}, })), ] diff --git a/web/oss/src/components/EvalRunDetails/components/FocusDrawer.tsx b/web/oss/src/components/EvalRunDetails/components/FocusDrawer.tsx index 5a1b9a8441..bddab2cf9f 100644 --- a/web/oss/src/components/EvalRunDetails/components/FocusDrawer.tsx +++ b/web/oss/src/components/EvalRunDetails/components/FocusDrawer.tsx @@ -141,7 +141,8 @@ interface FocusDrawerSection { * Hook to compute sections for a given run */ const useFocusDrawerSections = (runId: string | null) => { - const {columnResult} = usePreviewTableData({runId: runId ?? undefined}) + // Hook tolerates a nullish runId at runtime (falsy atom-family key); typed as-is. + const {columnResult} = usePreviewTableData({runId: (runId ?? undefined) as string}) const descriptorMap = useAtomValue( useMemo(() => columnValueDescriptorMapAtomFamily(runId), [runId]), ) @@ -177,7 +178,9 @@ const useFocusDrawerSections = (runId: string | null) => { })) const staticColumns: SectionColumnEntry[] = - group.kind === "metric" && group.staticMetricColumns?.length + // Dead branch: the early return above excludes "metric" groups; cast keeps + // the exact runtime behavior while satisfying TS (typed as-is per WP-4e-2a). + (group.kind as string) === "metric" && group.staticMetricColumns?.length ? group.staticMetricColumns.map((definition) => { const column = buildStaticMetricColumn(group.id, definition) return { @@ -453,7 +456,7 @@ const ScenarioColumnValue = memo( const formattedValue = typeof rawFormattedValue === "boolean" ? String(rawFormattedValue) - : rawFormattedValue + : (rawFormattedValue as ReactNode) const isPlaceholder = formattedValue === METRIC_EMPTY_PLACEHOLDER @@ -1344,7 +1347,9 @@ export const FocusDrawerContent = ({ })) const staticColumns: SectionColumnEntry[] = - group.kind === "metric" && group.staticMetricColumns?.length + // Dead branch: the early return above excludes "metric" groups; cast keeps + // the exact runtime behavior while satisfying TS (typed as-is per WP-4e-2a). + (group.kind as string) === "metric" && group.staticMetricColumns?.length ? group.staticMetricColumns.map((definition) => { const column = buildStaticMetricColumn(group.id, definition) return { diff --git a/web/oss/src/components/EvalRunDetails/components/TableCells/MetricCell.tsx b/web/oss/src/components/EvalRunDetails/components/TableCells/MetricCell.tsx index f9d91f64ea..e721a5b180 100644 --- a/web/oss/src/components/EvalRunDetails/components/TableCells/MetricCell.tsx +++ b/web/oss/src/components/EvalRunDetails/components/TableCells/MetricCell.tsx @@ -110,7 +110,7 @@ const PreviewEvaluationMetricCell = ({ const errorCopyContent = `${stepError.message}${stepError.stacktrace ? `\n${stepError.stacktrace}` : ""}` return ( - +
{ + const projectId = useAtomValue(effectiveProjectIdAtom) const variantRefs = useAtomValue(useMemo(() => runInvocationRefsAtomFamily(runId), [runId])) const variantId = useMemo( () => toIdString(variantRefs.variantId ?? variantRefs.applicationVariantId ?? null), @@ -25,8 +27,10 @@ const ContextChipList = ({runId}: ContextChipListProps) => { return (
- {variantId ? : null} - + {variantId ? ( + + ) : null} +
) } diff --git a/web/oss/src/components/EvalRunDetails/components/views/ConfigurationView/components/EvaluatorSection.tsx b/web/oss/src/components/EvalRunDetails/components/views/ConfigurationView/components/EvaluatorSection.tsx index 6d586e0554..6e31356ed6 100644 --- a/web/oss/src/components/EvalRunDetails/components/views/ConfigurationView/components/EvaluatorSection.tsx +++ b/web/oss/src/components/EvalRunDetails/components/views/ConfigurationView/components/EvaluatorSection.tsx @@ -133,7 +133,9 @@ const EvaluatorCard = ({ differs?: boolean defaultCollapsed?: boolean }) => { - const rawEvaluator = evaluator.raw + const rawEvaluator = evaluator.raw as + | ({id?: string; slug?: string; name?: string} & Record) + | undefined const [view, setView] = useState<"details" | "json">("details") const [collapsed, setCollapsed] = useState(defaultCollapsed) diff --git a/web/oss/src/components/EvalRunDetails/components/views/ConfigurationView/components/InvocationSection.tsx b/web/oss/src/components/EvalRunDetails/components/views/ConfigurationView/components/InvocationSection.tsx index f30a94389f..a841ed8688 100644 --- a/web/oss/src/components/EvalRunDetails/components/views/ConfigurationView/components/InvocationSection.tsx +++ b/web/oss/src/components/EvalRunDetails/components/views/ConfigurationView/components/InvocationSection.tsx @@ -96,7 +96,9 @@ const InvocationSection = ({ const variantDisplayId = variantResolved?.id ?? variantId ?? undefined const variantVersion = variantResolved?.revision ?? - variantResolved?.version ?? + // VariantReference carries the version in `revision`; `version` is never set at + // runtime (dead fallback) — typed as-is per WP-4e-2a. + (variantResolved as any)?.version ?? applicationRevisionRef?.version ?? applicationRevisionRef?.revision ?? applicationVariantRef?.version ?? @@ -112,10 +114,12 @@ const InvocationSection = ({ // Use revisionId for the prompt config card (specific revision's params) const promptVariantKey = useMemo(() => { const configVariantRef = variantConfig?.variant_ref ?? {} + // variant_ref is declared as {id, slug, version, name}; the snake/camel variant-id + // fallbacks are for untyped raw payload keys — typed as-is per WP-4e-2a. const refId = toIdString( configVariantRef?.id ?? - configVariantRef?.variant_id ?? - configVariantRef?.variantId ?? + (configVariantRef as any)?.variant_id ?? + (configVariantRef as any)?.variantId ?? null, ) if (refId) return refId diff --git a/web/oss/src/components/EvalRunDetails/components/views/ConfigurationView/utils.ts b/web/oss/src/components/EvalRunDetails/components/views/ConfigurationView/utils.ts index d858f34967..dd01027e8c 100644 --- a/web/oss/src/components/EvalRunDetails/components/views/ConfigurationView/utils.ts +++ b/web/oss/src/components/EvalRunDetails/components/views/ConfigurationView/utils.ts @@ -174,11 +174,13 @@ const normalizePromptText = ( if (Array.isArray(list)) { list.forEach((item: any, index) => { if (item && typeof item === "object" && typeof item.url === "string") { + // Runtime shape carries `id` and omits `type`; renderers read only + // url/alt — typed as-is per WP-4e-2a. attachments.push({ id: (item.id ?? `${index}`) as string, url: item.url, alt: typeof item.alt === "string" ? item.alt : undefined, - }) + } as unknown as PromptPreviewAttachment) } }) } @@ -298,7 +300,7 @@ export const extractPromptSectionsFromVariantParams = ( } return messages - .map((message, index) => { + .map((message, index): PromptPreviewSection | null => { const label = capitalize(message?.role) || `Message ${index + 1}` const {text, attachments} = normalizePromptText(message?.content ?? message) const trimmed = text.trim() diff --git a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/BaseRunMetricsSection.tsx b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/BaseRunMetricsSection.tsx index 3b96690766..aa7b4ad1f4 100644 --- a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/BaseRunMetricsSection.tsx +++ b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/BaseRunMetricsSection.tsx @@ -135,7 +135,7 @@ const BaseRunMetricsSection = ({baseRunId, comparisonRunIds}: BaseRunMetricsSect const temporalCharts = useMemo(() => { if (!hasTemporalMetrics) return [] - const convertPoint = (point: TemporalMetricPoint) => { + const convertPoint = (point: TemporalMetricPoint): TemporalMetricsSeriesPoint | null => { const resolved = resolveMetricValue( point.stats, point.stats.count as number | undefined, diff --git a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/EvaluatorTemporalMetricsChart.tsx b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/EvaluatorTemporalMetricsChart.tsx index 21eacec993..a50eeb3f55 100644 --- a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/EvaluatorTemporalMetricsChart.tsx +++ b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/EvaluatorTemporalMetricsChart.tsx @@ -210,9 +210,9 @@ const EvaluatorTemporalMetricsChart = ({ formatTimestamp(Number(value))} - formatter={(value: any, dataKey: string) => { + formatter={(value, dataKey) => { if (typeof value !== "number") return value - const label = seriesLabelMap.get(dataKey) ?? dataKey + const label = seriesLabelMap.get(dataKey as string) ?? dataKey return [value.toFixed(isBoolean ? 1 : 3), label] }} /> diff --git a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/MetadataSummaryTable.tsx b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/MetadataSummaryTable.tsx index 295bf0e2f8..ef4a5804c1 100644 --- a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/MetadataSummaryTable.tsx +++ b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/MetadataSummaryTable.tsx @@ -1,4 +1,4 @@ -import {memo, useMemo, type ReactNode} from "react" +import {memo, useMemo, type ComponentType, type ReactNode} from "react" import {Table, Typography} from "antd" import type {ColumnsType} from "antd/es/table" @@ -8,6 +8,10 @@ import {LOW_PRIORITY, useAtomValueWithSchedule} from "jotai-scheduler" import {previewRunMetricStatsSelectorFamily} from "@/oss/components/Evaluations/atoms/runMetrics" import useEvaluatorReference from "@/oss/components/References/hooks/useEvaluatorReference" import type {BasicStats} from "@/oss/lib/metricUtils" +import type { + QueryConditionPayload, + QueryFilteringPayload, +} from "@/oss/services/onlineEvaluations/api" import {useProjectData} from "@/oss/state/project" import {evaluationQueryRevisionAtomFamily} from "../../../../atoms/query" @@ -22,10 +26,6 @@ import { evaluationRunIndexAtomFamily, evaluationRunQueryAtomFamily, } from "../../../../atoms/table/run" -import type { - QueryConditionPayload, - QueryFilteringPayload, -} from "../../../../services/onlineEvaluations/api" import {buildFrequencyChartData} from "../../../EvaluatorMetricsChart/utils/chartData" import {ApplicationReferenceLabel, TestsetTagList, VariantRevisionLabel} from "../../../references" import {useRunMetricData} from "../hooks/useRunMetricData" @@ -109,7 +109,7 @@ const QuerySummaryCell = ({runId}: MetadataCellProps) => { interface MetadataRowRecord { key: string label: ReactNode - Cell: (props: MetadataCellProps) => JSX.Element + Cell: ComponentType shouldDisplay?: (context: MetadataRowContext) => boolean } @@ -425,7 +425,7 @@ const METADATA_ROWS: MetadataRowRecord[] = [ {key: "invocation_errors", label: "Errors", Cell: InvocationErrorsCell}, ] -const EvaluatorNameLabel = ({evaluatorId}: {evaluatorId: string}) => { +const EvaluatorNameLabel = ({evaluatorId}: {evaluatorId?: string | null}) => { const projectId = useProjectData()?.projectId const x = useEvaluatorReference({evaluatorId, projectId}) return x?.reference?.name ?? "--" diff --git a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/MetricComparisonCard.tsx b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/MetricComparisonCard.tsx index fabbccc90d..409fae2563 100644 --- a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/MetricComparisonCard.tsx +++ b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/MetricComparisonCard.tsx @@ -239,7 +239,7 @@ const MetricComparisonCard = ({metric}: MetricComparisonCardProps) => { String(label)} - formatter={(value: number, _name, props) => { + formatter={(value, _name, props) => { const runKey = typeof props?.dataKey === "string" ? props.dataKey : "" const meta = runMetaMap.get(runKey) diff --git a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/OverviewPlaceholders.tsx b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/OverviewPlaceholders.tsx index 8969f65a73..7170bd640c 100644 --- a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/OverviewPlaceholders.tsx +++ b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/OverviewPlaceholders.tsx @@ -1,4 +1,4 @@ -import {useEffect, useMemo, useState} from "react" +import {useEffect, useMemo, useState, type ReactNode} from "react" import {Skeleton, Typography} from "antd" import clsx from "clsx" @@ -12,8 +12,8 @@ import { } from "recharts" interface PlaceholderProps { - title?: string - description?: string + title?: ReactNode + description?: ReactNode minHeight?: number variant?: "chart" | "list" } diff --git a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/hooks/useRunMetricData.ts b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/hooks/useRunMetricData.ts index bf46815a38..b006262646 100644 --- a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/hooks/useRunMetricData.ts +++ b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/hooks/useRunMetricData.ts @@ -1,6 +1,6 @@ import {useMemo} from "react" -import {atom, useAtomValue} from "jotai" +import {atom, useAtomValue, type ExtractAtomValue} from "jotai" import {LOW_PRIORITY, useAtomValueWithSchedule} from "jotai-scheduler" import {evaluationEvaluatorsByRunQueryAtomFamily} from "@/oss/components/EvalRunDetails/atoms/table/evaluators" @@ -11,6 +11,7 @@ import { runTemporalMetricKeysAtomFamily, runTemporalMetricSeriesAtomFamily, TemporalMetricPoint, + type RunLevelMetricSelection, } from "@/oss/components/Evaluations/atoms/runMetrics" import {humanizeMetricPath} from "@/oss/lib/evaluations/utils/metrics" import type {BasicStats} from "@/oss/lib/metricUtils" @@ -26,7 +27,10 @@ import { const emptyEvaluatorsAtom = atom({data: [], isPending: false, isFetching: false} as const) const emptyLoadableAtom = atom({state: "loading"} as const) -const emptyRunIndexAtom = atom(null as ReturnType | null) +// Typed as the family atom's unwrapped VALUE (RunIndex | null), not the atom itself. +const emptyRunIndexAtom = atom( + null as ExtractAtomValue>, +) const falseAtom = atom(false) const emptyTemporalSeriesAtom = atom>({}) const emptyMetricSelectionsAtom = atom([]) @@ -114,7 +118,7 @@ export interface RunMetricSelectionEntry { runId: string index: number runKey: string - selection: ReturnType + selection: RunLevelMetricSelection }[] } diff --git a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/utils/evaluatorMetrics.ts b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/utils/evaluatorMetrics.ts index 0c60f5f233..893a5977d2 100644 --- a/web/oss/src/components/EvalRunDetails/components/views/OverviewView/utils/evaluatorMetrics.ts +++ b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/utils/evaluatorMetrics.ts @@ -4,7 +4,8 @@ import {canonicalizeMetricKey} from "@/oss/lib/metricUtils" interface EvaluatorDefinitionLike { id?: string | null slug?: string | null - metrics?: {path?: string | null; name?: string | null}[] + name?: string | null + metrics?: {path?: string | null; name?: string | null; metricType?: string}[] } interface EvaluatorStepMeta { @@ -71,7 +72,7 @@ export const buildEvaluatorMetricEntries = ( statsMap: Record | null | undefined, evaluatorSteps: EvaluatorStepMeta[], fallbackMetricsByStep?: Record, - evaluatorDefinitions?: EvaluatorDefinitionLike[], + evaluatorDefinitions?: readonly EvaluatorDefinitionLike[], ): EvaluatorMetricEntry[] => { if (!evaluatorSteps.length) { return [] @@ -170,7 +171,7 @@ const normalizeMetricPath = (path: string) => { export const buildEvaluatorFallbackMetricsByStep = ( runIndex: RunIndex | null | undefined, - evaluatorDefinitions: EvaluatorDefinitionLike[], + evaluatorDefinitions: readonly EvaluatorDefinitionLike[], ): Record => { if (!runIndex || !evaluatorDefinitions.length) return {} @@ -210,7 +211,7 @@ export const buildEvaluatorFallbackMetricsByStep = ( (evaluatorRef.id && metricsById.get(evaluatorRef.id)) || [] if (!candidates.length) return - result[stepKey] = candidates.map((metric) => ({ + result[stepKey] = candidates.map((metric: EvaluatorMetricDefinition) => ({ canonicalKey: metric.canonicalKey, rawKey: metric.rawKey, fullKey: metric.fullKey.startsWith(`${stepKey}.`) diff --git a/web/oss/src/components/EvalRunDetails/components/views/SingleScenarioViewerPOC/ScenarioAnnotationPanel/useAnnotationState.ts b/web/oss/src/components/EvalRunDetails/components/views/SingleScenarioViewerPOC/ScenarioAnnotationPanel/useAnnotationState.ts index 7f930a4bf6..23cd70c528 100644 --- a/web/oss/src/components/EvalRunDetails/components/views/SingleScenarioViewerPOC/ScenarioAnnotationPanel/useAnnotationState.ts +++ b/web/oss/src/components/EvalRunDetails/components/views/SingleScenarioViewerPOC/ScenarioAnnotationPanel/useAnnotationState.ts @@ -405,7 +405,7 @@ export function useAnnotationState({ const slug = evaluator.slug if (!slug) continue - const requiredKeys: string[] = getOutputsSchema(evaluator)?.required ?? [] + const requiredKeys = (getOutputsSchema(evaluator)?.required ?? []) as string[] if (requiredKeys.length === 0) continue @@ -515,7 +515,8 @@ export function useAnnotationState({ if (!slug || map[slug]) continue // Skip if already found // Check if annotation has a step reference - const stepKey = ann.references?.step?.key + // `references` is declared with only `evaluator`; step refs exist on the raw payload. + const stepKey = (ann.references as {step?: {key?: string}} | undefined)?.step?.key if (stepKey) { map[slug] = stepKey } diff --git a/web/oss/src/components/EvalRunDetails/components/views/SingleScenarioViewerPOC/types.ts b/web/oss/src/components/EvalRunDetails/components/views/SingleScenarioViewerPOC/types.ts index 01c1f6095c..9c99372eb1 100644 --- a/web/oss/src/components/EvalRunDetails/components/views/SingleScenarioViewerPOC/types.ts +++ b/web/oss/src/components/EvalRunDetails/components/views/SingleScenarioViewerPOC/types.ts @@ -100,7 +100,8 @@ export interface ScenarioOutputCardProps { export interface AnnotationMetricField { value: unknown - type?: string + // string[] when the JSON-schema type is a union (e.g. ["string", "null"]). + type?: string | string[] minimum?: number maximum?: number items?: { diff --git a/web/oss/src/components/EvalRunDetails/hooks/usePreviewTableData.ts b/web/oss/src/components/EvalRunDetails/hooks/usePreviewTableData.ts index 69329939ef..6263b12cc6 100644 --- a/web/oss/src/components/EvalRunDetails/hooks/usePreviewTableData.ts +++ b/web/oss/src/components/EvalRunDetails/hooks/usePreviewTableData.ts @@ -10,8 +10,12 @@ import { import type {EvaluationTableColumnsResult} from "../atoms/table" export interface PreviewTableData { - columnResult?: EvaluationTableColumnsResult - columnsPending: boolean + // Non-optional: tableColumnsAtomFamily always yields a result (buildDefaultResult fallback). + columnResult: EvaluationTableColumnsResult + // The expression below short-circuits to `undefined` when `runQuery.data` is absent, so + // the runtime value is `boolean | undefined` (used only in boolean position by consumers). + // Typed to match actual behavior rather than coercing the value. + columnsPending: boolean | undefined } export const usePreviewTableData = ({runId}: {runId: string}): PreviewTableData => { diff --git a/web/oss/src/components/EvalRunDetails/utils/buildPreviewColumns.tsx b/web/oss/src/components/EvalRunDetails/utils/buildPreviewColumns.tsx index 16a28c4513..1f7fb3d915 100644 --- a/web/oss/src/components/EvalRunDetails/utils/buildPreviewColumns.tsx +++ b/web/oss/src/components/EvalRunDetails/utils/buildPreviewColumns.tsx @@ -5,6 +5,7 @@ import type {ColumnsType, ColumnType} from "antd/es/table" import clsx from "clsx" import {ColumnVisibilityHeader} from "@/oss/components/InfiniteVirtualTable" +import type {ExtendedColumnType} from "@/oss/components/InfiniteVirtualTable" import type { EvaluationTableColumn, @@ -119,6 +120,9 @@ export interface BuildPreviewColumnsResult { columns: ColumnsType } +/** antd column extended with the visibility-menu label consumed by useColumnVisibility */ +type VisibilityColumn = ExtendedColumnType + const createStaticMetricColumns = ( groupId: string, metrics: MetricColumnDefinition[], @@ -126,7 +130,7 @@ const createStaticMetricColumns = ( isSkeletonRow?: (record: RowType) => boolean getSkeletonContent: (context: SkeletonRenderContext) => React.ReactNode }, -): ColumnType[] => +): VisibilityColumn[] => metrics.map((metric) => { const pseudoColumn: EvaluationTableColumn = { id: `${groupId}::${metric.path}`, @@ -245,7 +249,7 @@ export function buildPreviewColumns({ } } - const buildLeafColumn = (column: EvaluationTableColumn): ColumnType | null => { + const buildLeafColumn = (column: EvaluationTableColumn): VisibilityColumn | null => { const widthByStepType: Record = { meta: 80, input: COLUMN_WIDTHS.input, @@ -454,7 +458,7 @@ export function buildPreviewColumns({ const orderedGroups = [...groups].sort((a, b) => (a.order ?? 0) - (b.order ?? 0)) - const builtColumns: ColumnsType = [] + const builtColumns: VisibilityColumn[] = [] const renderedColumnIds = new Set() // Include scenarioIndexStatus and timestamp columns as leading meta columns diff --git a/web/oss/src/components/EvalRunDetails/utils/buildSkeletonColumns.ts b/web/oss/src/components/EvalRunDetails/utils/buildSkeletonColumns.ts index 44e36c7758..5bebd16b57 100644 --- a/web/oss/src/components/EvalRunDetails/utils/buildSkeletonColumns.ts +++ b/web/oss/src/components/EvalRunDetails/utils/buildSkeletonColumns.ts @@ -52,17 +52,24 @@ const createMetaSkeletonColumns = (options?: { return columns } +// NOTE (latent runtime bug, typed as-is per WP-4e-2a): the "outputs" caller below invokes +// this with only 5 positional args, omitting `stepType` — so at runtime `startOrder`'s slot +// receives the order number (200) as `stepType`, and the real `startOrder` is `undefined` +// (making `order` NaN for that group). To type the function faithfully WITHOUT changing +// that behavior, `stepType` is widened to also accept the number that is actually passed, +// and `startOrder` is optional. Do not "fix" by inserting the missing argument — that would +// change the shipped skeleton columns. See QA flag. const createSkeletonGroupColumns = ( groupId: string, label: string, kind: EvaluationTableColumnGroup["kind"], columnKind: EvaluationColumnKind, - stepType: EvaluationTableColumn["stepType"], - startOrder: number, + stepType: EvaluationTableColumn["stepType"] | number, + startOrder?: number, ): {columns: EvaluationTableColumn[]; group: EvaluationTableColumnGroup} => { const columns: EvaluationTableColumn[] = [] for (let index = 0; index < SKELETON_COLUMNS_PER_GROUP; index += 1) { - const order = startOrder + index + const order = (startOrder as number) + index columns.push({ id: `skeleton:${groupId}:${index}`, label: `${label} ${index + 1}`, @@ -70,7 +77,7 @@ const createSkeletonGroupColumns = ( kind: columnKind, path: `${groupId}.${index}`, pathSegments: [groupId, `${index}`], - stepType, + stepType: stepType as EvaluationTableColumn["stepType"], order, width: stepType === "input" || stepType === "invocation" ? 320 : 200, minWidth: stepType === "input" || stepType === "invocation" ? 200 : 160, diff --git a/web/oss/src/components/EvalRunDetails/utils/renderChatMessages.tsx b/web/oss/src/components/EvalRunDetails/utils/renderChatMessages.tsx index 8c0f6ac64f..1171a785bb 100644 --- a/web/oss/src/components/EvalRunDetails/utils/renderChatMessages.tsx +++ b/web/oss/src/components/EvalRunDetails/utils/renderChatMessages.tsx @@ -170,7 +170,10 @@ export function renderChatMessages({ key={`${keyPrefix}-${i}`} className={clsx([ "w-full flex flex-col gap-2", - {"[&_.agenta-shared-editor]:!p-0": view === "table"}, + // `view` is narrowed to "single" | undefined after the early + // `view === "table"` return above, so this is always false at runtime; + // the cast keeps that exact behavior while satisfying TS. + {"[&_.agenta-shared-editor]:!p-0": (view as string) === "table"}, ])} > {editorType === "simple" ? ( @@ -179,7 +182,7 @@ export function renderChatMessages({ handleChange={() => {}} headerName={msg.role} headerClassName="capitalize" - initialValue={textContent} + initialValue={textContent as string} editorType="borderless" state="readOnly" placeholder="N/A" @@ -227,7 +230,10 @@ export function renderChatMessages({ {msg.role} @@ -248,7 +254,7 @@ export function renderChatMessages({
) } - initialValue={textContent} + initialValue={textContent as string} className="hover:!border-[transparent]" editorClassName="!text-xs" editorProps={{enableResize: true}} diff --git a/web/oss/src/components/EvaluationRunsTablePOC/atoms/view.ts b/web/oss/src/components/EvaluationRunsTablePOC/atoms/view.ts index 1f9a3c6532..37f2f5b1c6 100644 --- a/web/oss/src/components/EvaluationRunsTablePOC/atoms/view.ts +++ b/web/oss/src/components/EvaluationRunsTablePOC/atoms/view.ts @@ -593,7 +593,7 @@ export const evaluationRunsFilterOptionsAtom = atom((get) => { const evaluatorOptions = evaluatorData.length > 0 ? evaluatorData - .map((item) => { + .map((item): {label: string; value: string; slug?: string} | null => { const id = (typeof item.id === "string" && item.id.trim()) || (typeof (item as any).key === "string" && (item as any).key.trim()) || @@ -678,7 +678,11 @@ export const evaluationRunsVariantOptionsAtom = atom((get) => { const isLoading = loadables.some((result) => result.state === "loading") const variants = loadables.flatMap((result) => - result.state === "hasData" ? (result.data?.workflow_variants ?? []) : [], + // Latent bug typed as-is per WP-4e-2a: `result.data` is the query-observer object, + // so `workflow_variants` is read off the wrong level and is always undefined. + result.state === "hasData" + ? ((result.data as unknown as {workflow_variants?: any[]})?.workflow_variants ?? []) + : [], ) const seen = new Set() diff --git a/web/oss/src/components/EvaluationRunsTablePOC/components/EvaluationRunsDeleteButton.tsx b/web/oss/src/components/EvaluationRunsTablePOC/components/EvaluationRunsDeleteButton.tsx index 433083b35f..22a3dec7f2 100644 --- a/web/oss/src/components/EvaluationRunsTablePOC/components/EvaluationRunsDeleteButton.tsx +++ b/web/oss/src/components/EvaluationRunsTablePOC/components/EvaluationRunsDeleteButton.tsx @@ -4,6 +4,7 @@ import {Trash} from "@phosphor-icons/react" import {useAtom, useAtomValue, useSetAtom} from "jotai" import DeleteEvaluationModalButton from "@/oss/components/DeleteEvaluationModal/DeleteEvaluationModalButton" +import type {DeleteEvaluationKind} from "@/oss/components/DeleteEvaluationModal/types" import {EVALUATION_RUNS_QUERY_KEY_ROOT} from "../atoms/tableStore" import { @@ -40,7 +41,8 @@ const EvaluationRunsDeleteButton = () => { const deletionConfig = useMemo(() => { if (!selection.hasSelection) return undefined return { - evaluationKind: deleteContext.evaluationKind, + // EvaluationRunKind includes "all"; delete contexts only carry concrete kinds. + evaluationKind: deleteContext.evaluationKind as DeleteEvaluationKind, projectId: deleteContext.projectId, previewRunIds: selection.previewRunIds, invalidateQueryKeys: [EVALUATION_RUNS_QUERY_KEY_ROOT], diff --git a/web/oss/src/components/EvaluationRunsTablePOC/components/EvaluationRunsTable/export/referenceResolvers.ts b/web/oss/src/components/EvaluationRunsTablePOC/components/EvaluationRunsTable/export/referenceResolvers.ts index b3c85de3de..fe5f98d49e 100644 --- a/web/oss/src/components/EvaluationRunsTablePOC/components/EvaluationRunsTable/export/referenceResolvers.ts +++ b/web/oss/src/components/EvaluationRunsTablePOC/components/EvaluationRunsTable/export/referenceResolvers.ts @@ -10,7 +10,7 @@ import { evaluatorReferenceAtomFamily, previewTestsetReferenceAtomFamily, } from "@/oss/components/References/atoms/entityReferences" -import {getUniquePartOfId} from "@/oss/lib/helpers/utils" +import {getUniquePartOfId, isUuid} from "@/oss/lib/helpers/utils" import { formatVariantRevisionLabel, diff --git a/web/oss/src/components/EvaluationRunsTablePOC/components/EvaluationRunsTable/index.tsx b/web/oss/src/components/EvaluationRunsTablePOC/components/EvaluationRunsTable/index.tsx index 6de32cbfca..6568d9e6ff 100644 --- a/web/oss/src/components/EvaluationRunsTablePOC/components/EvaluationRunsTable/index.tsx +++ b/web/oss/src/components/EvaluationRunsTablePOC/components/EvaluationRunsTable/index.tsx @@ -9,6 +9,7 @@ import {useAtom, useAtomValue, useSetAtom, useStore} from "jotai" import dynamic from "next/dynamic" import {useRouter} from "next/router" +import type {DeleteEvaluationKind} from "@/oss/components/DeleteEvaluationModal/types" import {activePreviewProjectIdAtom} from "@/oss/components/EvalRunDetails/atoms/run" import {clearAllMetricStatsCaches} from "@/oss/components/EvalRunDetails/atoms/runMetrics" import { @@ -315,7 +316,8 @@ const EvaluationRunsTableActive = ({ const deletionConfig = useMemo(() => { if (!selectionSnapshot.hasSelection) return undefined return { - evaluationKind: deleteContext.evaluationKind, + // EvaluationRunKind includes "all"; delete contexts only carry concrete kinds. + evaluationKind: deleteContext.evaluationKind as DeleteEvaluationKind, projectId: deleteContext.projectId, previewRunIds: selectionSnapshot.previewRunIds, invalidateQueryKeys: [EVALUATION_RUNS_QUERY_KEY_ROOT], @@ -546,7 +548,8 @@ const EvaluationRunsTableActive = ({ const resolveColumnLabel = useCallback( ({column}: TableExportColumnContext) => { - const metadata = column?.exportMetadata as + // exportMetadata is stamped onto antd columns by createTableColumns (untyped). + const metadata = (column as {exportMetadata?: unknown})?.exportMetadata as | EvaluationRunsColumnExportMetadata | undefined if (!metadata || metadata.type !== "metric") { diff --git a/web/oss/src/components/EvaluationRunsTablePOC/components/cells/RunMetricCell/index.tsx b/web/oss/src/components/EvaluationRunsTablePOC/components/cells/RunMetricCell/index.tsx index 81db460387..6de6398d48 100644 --- a/web/oss/src/components/EvaluationRunsTablePOC/components/cells/RunMetricCell/index.tsx +++ b/web/oss/src/components/EvaluationRunsTablePOC/components/cells/RunMetricCell/index.tsx @@ -234,7 +234,8 @@ const RunMetricCellContent = memo( : formatEvaluatorMetricValue(stats, metricPathForSelection) let highlight: ReactNode = display - let fallback: ReactNode = stats ?? display + // MetricValueWithPopover's fallbackValue prop is `unknown` (accepts raw stats). + let fallback: unknown = stats ?? display let customChildren: ReactNode | undefined if (descriptor.kind === "evaluator") { diff --git a/web/oss/src/components/EvaluationRunsTablePOC/components/filters/EvaluationRunsHeaderFilters.tsx b/web/oss/src/components/EvaluationRunsTablePOC/components/filters/EvaluationRunsHeaderFilters.tsx index a05874dab8..742ddc663e 100644 --- a/web/oss/src/components/EvaluationRunsTablePOC/components/filters/EvaluationRunsHeaderFilters.tsx +++ b/web/oss/src/components/EvaluationRunsTablePOC/components/filters/EvaluationRunsHeaderFilters.tsx @@ -1,6 +1,6 @@ import {MouseEvent, useMemo, useState, useCallback} from "react" -import {Input, Tag, Tooltip, Typography} from "antd" +import {Input, Tag, Tooltip, Typography, type PopoverProps} from "antd" import clsx from "clsx" import {atom, useAtom, useAtomValue, useSetAtom} from "jotai" @@ -451,6 +451,8 @@ const EvaluationRunsHeaderFilters = () => { onOpenChange={handleFiltersOpenChange} popoverProps={{ arrow: false, + // antd v6 dropped the `body` semantic key (now container/content), so the + // `body` styles are ignored at runtime — typed as-is per WP-4e-2a. styles: { body: { maxWidth: "360px", @@ -463,7 +465,7 @@ const EvaluationRunsHeaderFilters = () => { boxShadow: "none", padding: 0, }, - }, + } as PopoverProps["styles"], }} renderContent={(close) => ( diff --git a/web/oss/src/components/EvaluationRunsTablePOC/types.ts b/web/oss/src/components/EvaluationRunsTablePOC/types.ts index 18c1a4eb0a..531c1c4908 100644 --- a/web/oss/src/components/EvaluationRunsTablePOC/types.ts +++ b/web/oss/src/components/EvaluationRunsTablePOC/types.ts @@ -2,10 +2,12 @@ import type {InfiniteTableRowBase} from "@/oss/components/InfiniteVirtualTable/t import type {WindowingState} from "@/oss/components/InfiniteVirtualTable/types" import type {SnakeToCamelCaseKeys} from "@/oss/lib/Types" -import type {LegacyAutoEvaluation} from "../../state/evaluations/legacyAtoms" - import type {EvaluationRun} from "@/agenta-oss-common/lib/hooks/usePreviewEvaluations/types" +// The original `@/oss/state/evaluations/legacyAtoms` module no longer exists, and `legacy` +// is only ever read through `any` casts — represented as an opaque record (per WP-4i). +export type LegacyAutoEvaluation = Record + export type PreviewEvaluationRun = SnakeToCamelCaseKeys export type EvaluationRunSource = "preview" | "legacy" diff --git a/web/oss/src/components/Evaluations/MetricDetailsPopover/assets/ResponsiveMetricChart.tsx b/web/oss/src/components/Evaluations/MetricDetailsPopover/assets/ResponsiveMetricChart.tsx index d30072ecf1..e7dd96bafe 100644 --- a/web/oss/src/components/Evaluations/MetricDetailsPopover/assets/ResponsiveMetricChart.tsx +++ b/web/oss/src/components/Evaluations/MetricDetailsPopover/assets/ResponsiveMetricChart.tsx @@ -313,7 +313,8 @@ const ResponsiveMetricChart: FC = memo( const barLeft = margin.left + xScaleVertical(d.edge as number) const barRight = - margin.left + xScaleVertical(d.edge + binSize) + margin.left + + xScaleVertical((d.edge as number) + binSize) const rawWidth = Math.abs(barRight - barLeft) const widthGap = Math.min( rawWidth * GAP_RATIO, @@ -389,7 +390,8 @@ const ResponsiveMetricChart: FC = memo( } const barTop = - margin.top + yScaleHorizontal(d.edge + binSize) + margin.top + + yScaleHorizontal((d.edge as number) + binSize) const barBottom = margin.top + yScaleHorizontal(d.edge as number) const rawHeight = Math.abs(barBottom - barTop) @@ -764,7 +766,8 @@ const ResponsiveMetricChart: FC = memo( )} – {format3Sig( - chartData[hoveredBin].edge + binSize, + (chartData[hoveredBin].edge as number) + + binSize, )} {binWidthText ? ( diff --git a/web/oss/src/components/Evaluations/components/MetricDetailsPreviewPopover.tsx b/web/oss/src/components/Evaluations/components/MetricDetailsPreviewPopover.tsx index ff16d54faa..8b2b39ad0a 100644 --- a/web/oss/src/components/Evaluations/components/MetricDetailsPreviewPopover.tsx +++ b/web/oss/src/components/Evaluations/components/MetricDetailsPreviewPopover.tsx @@ -14,6 +14,7 @@ import { ResponsiveFrequencyChart, ResponsiveMetricChart, buildChartData, + type ChartDatum, } from "@/oss/components/Evaluations/MetricDetailsPopover" import type {BasicStats} from "@/oss/lib/metricUtils" @@ -423,7 +424,8 @@ const MetricPopoverContent = ({ const frequencyChartData = hasHistogram ? [] : chartData - .map((entry) => { + // buildChartData only emits name/value; legacy label/count fallbacks typed as-is + .map((entry: ChartDatum & {label?: string | number; count?: number}) => { if (!entry) return null const label = entry.name ?? entry.label ?? "" const rawValue = entry.value ?? entry.count @@ -436,7 +438,7 @@ const MetricPopoverContent = ({ count: Number.isFinite(parsed) ? parsed : 0, } }) - .filter((entry): entry is {label: string | number; count: number} => Boolean(entry)) + .filter((entry): entry is NonNullable => Boolean(entry)) const hasFrequencyChart = frequencyChartData.length > 0 const isCategoricalMultiple = (source: unknown): boolean => { if (!source || typeof source !== "object") return false diff --git a/web/oss/src/components/Evaluators/Drawers/HumanEvaluatorDrawer/index.tsx b/web/oss/src/components/Evaluators/Drawers/HumanEvaluatorDrawer/index.tsx index 04a300de5e..2f4e18301a 100644 --- a/web/oss/src/components/Evaluators/Drawers/HumanEvaluatorDrawer/index.tsx +++ b/web/oss/src/components/Evaluators/Drawers/HumanEvaluatorDrawer/index.tsx @@ -16,6 +16,7 @@ import {useAtomValue, useSetAtom} from "jotai" import dynamic from "next/dynamic" import {AnnotateDrawerSteps} from "@/oss/components/SharedDrawers/AnnotateDrawer/assets/enum" +import type {CreateEvaluatorProps} from "@/oss/components/SharedDrawers/AnnotateDrawer/assets/types" import { closeHumanEvaluatorDrawerAtom, @@ -82,7 +83,11 @@ const HumanEvaluatorDrawer = () => { const createEvaluatorProps = useMemo( () => ({ mode, - evaluator: mode === "edit" ? evaluatorWorkflow || undefined : undefined, + // Workflow-revision shape passed where EvaluatorPreviewDto is expected (typed as-is) + evaluator: + mode === "edit" + ? ((evaluatorWorkflow || undefined) as CreateEvaluatorProps["evaluator"]) + : undefined, onSuccess: handleSuccess, skipPostCreateStepChange: mode === "create", }), diff --git a/web/oss/src/components/Evaluators/assets/evaluatorFiltering.ts b/web/oss/src/components/Evaluators/assets/evaluatorFiltering.ts index 8386db8d6b..1cca9b31b7 100644 --- a/web/oss/src/components/Evaluators/assets/evaluatorFiltering.ts +++ b/web/oss/src/components/Evaluators/assets/evaluatorFiltering.ts @@ -14,6 +14,7 @@ import { import {capitalize} from "@/oss/lib/helpers/utils" import {isDemo} from "@/oss/lib/helpers/utils" +import type {Evaluator} from "@/oss/lib/Types" import type {EvaluatorPreview} from "./types" @@ -129,9 +130,7 @@ export const getEvaluatorTagColor = (item: FilterableEvaluator): string | undefi * Uses `flags.is_recommended` from the catalog when available. * Falls back to the legacy ENABLED_EVALUATORS allowlist + !archived check. */ -export const filterEnabledEvaluators = >( - evaluators: T[], -): T[] => { +export const filterEnabledEvaluators = (evaluators: T[]): T[] => { return evaluators.filter((item) => { const key = (item as any)?.key as string | undefined if (!key) return false diff --git a/web/oss/src/components/Filters/Filters.tsx b/web/oss/src/components/Filters/Filters.tsx index 2712679f5d..6c1490734f 100644 --- a/web/oss/src/components/Filters/Filters.tsx +++ b/web/oss/src/components/Filters/Filters.tsx @@ -20,6 +20,8 @@ import { Space, TreeSelect, Typography, + type PopoverProps, + type TreeSelectProps, } from "antd" import {useAtomValue} from "jotai" import isEqual from "lodash/isEqual" @@ -860,7 +862,11 @@ const Filters: React.FC = ({ open={isFilterOpen} placement="bottomLeft" autoAdjustOverflow - styles={{body: {maxHeight: "70vh"}, root: {maxWidth: "100vw"}}} + // antd v6 dropped the `body` semantic key (now container/content), so the + // `body` styles are ignored at runtime — typed as-is per WP-4e-2a. + styles={ + {body: {maxHeight: "70vh"}, root: {maxWidth: "100vw"}} as PopoverProps["styles"] + } destroyOnHidden content={
diff --git a/web/oss/src/components/InfiniteVirtualTable/atoms/columnHiddenKeys.ts b/web/oss/src/components/InfiniteVirtualTable/atoms/columnHiddenKeys.ts index 7254984850..8751d59db0 100644 --- a/web/oss/src/components/InfiniteVirtualTable/atoms/columnHiddenKeys.ts +++ b/web/oss/src/components/InfiniteVirtualTable/atoms/columnHiddenKeys.ts @@ -81,17 +81,17 @@ const hiddenKeysAtomFamily = atomFamily( const storageAtom = atomWithStorage(storageKey, defaults) return atom( - (get, set) => { + (get) => { + // Atom reads must be pure: on version mismatch serve defaults and let the next write reconcile storage. const meta = get(metaAtom) if (meta.version !== version) { - set(storageAtom, defaults) - set(metaAtom, {version, updatedAt: Date.now()}) return defaults } return get(storageAtom) }, (get, set, next: Key[] | ((prev: Key[]) => Key[])) => { - const current = get(storageAtom) + const meta = get(metaAtom) + const current = meta.version !== version ? defaults : get(storageAtom) const resolved = typeof next === "function" ? next(current) : next set(storageAtom, resolved) set(metaAtom, {version, updatedAt: Date.now()}) diff --git a/web/oss/src/components/InfiniteVirtualTable/columns/cells.tsx b/web/oss/src/components/InfiniteVirtualTable/columns/cells.tsx index 039049a921..fb63d87c89 100644 --- a/web/oss/src/components/InfiniteVirtualTable/columns/cells.tsx +++ b/web/oss/src/components/InfiniteVirtualTable/columns/cells.tsx @@ -138,52 +138,54 @@ export const createViewportAwareCell = (opts: { className: clsx("ivt-cell ivt-cell--viewport-wrapper", opts.className), }) -const ColumnVisibilityAwareCell = memo( - ({ - row, - index, - columnKey, - render, - placeholder, - keepMounted = false, - }: { - row: Row - index: number - columnKey?: string - render: (row: Row, index: number, isVisible: boolean) => ReactNode - placeholder?: ReactNode | ((row: Row, index: number) => ReactNode) - keepMounted?: boolean - }) => { - const isVisible = useColumnVisibilityFlag(columnKey) - if (!keepMounted && !isVisible) { - if (placeholder) { - return ( -
- {typeof placeholder === "function" ? placeholder(row, index) : placeholder} -
- ) - } - return null - } - const content = render(row, index, isVisible) - - if (!content && !placeholder) { - if (!keepMounted) { - return null - } +const ColumnVisibilityAwareCellBase = ({ + row, + index, + columnKey, + render, + placeholder, + keepMounted = false, +}: { + row: Row + index: number + columnKey?: string + render: (row: Row, index: number, isVisible: boolean) => ReactNode + placeholder?: ReactNode | ((row: Row, index: number) => ReactNode) + keepMounted?: boolean +}) => { + const isVisible = useColumnVisibilityFlag(columnKey) + if (!keepMounted && !isVisible) { + if (placeholder) { return ( -
+
+ {typeof placeholder === "function" ? placeholder(row, index) : placeholder} +
) } + return null + } + const content = render(row, index, isVisible) + if (!content && !placeholder) { + if (!keepMounted) { + return null + } return ( -
- {content ?? - (typeof placeholder === "function" ? placeholder(row, index) : placeholder)} -
+
) - }, -) + } + + return ( +
+ {content ?? (typeof placeholder === "function" ? placeholder(row, index) : placeholder)} +
+ ) +} + +// memo() erases the generic call signature; cast restores it. +const ColumnVisibilityAwareCell = memo( + ColumnVisibilityAwareCellBase, +) as typeof ColumnVisibilityAwareCellBase export const createColumnVisibilityAwareCell = (opts: { columnKey?: string diff --git a/web/oss/src/components/InfiniteVirtualTable/columns/createStandardColumns.tsx b/web/oss/src/components/InfiniteVirtualTable/columns/createStandardColumns.tsx index 1dc8c6f722..c910ad908e 100644 --- a/web/oss/src/components/InfiniteVirtualTable/columns/createStandardColumns.tsx +++ b/web/oss/src/components/InfiniteVirtualTable/columns/createStandardColumns.tsx @@ -11,6 +11,8 @@ import {copyToClipboard} from "@/oss/lib/helpers/copyToClipboard" import ColumnVisibilityMenuTrigger from "../components/columnVisibility/ColumnVisibilityMenuTrigger" import type {InfiniteTableRowBase} from "../types" +import type {ExtendedColumnType} from "./types" + export interface TextColumnDef { type: "text" key: string @@ -125,7 +127,7 @@ export function createStandardColumns( }) } -function createTextColumn(def: TextColumnDef): ColumnType { +function createTextColumn(def: TextColumnDef): ExtendedColumnType { return { title: def.title, dataIndex: def.key, @@ -138,7 +140,7 @@ function createTextColumn(def: TextColumnDef): ColumnType { onHeaderCell: () => ({ style: {minWidth: def.width || 220}, }), - } as ColumnType + } } const formatDateCell = (value?: string | null) => { @@ -174,7 +176,7 @@ function createDateColumn(def: DateColumnDef): ColumnType { function createActionsColumn( def: ActionsColumnDef, -): ColumnType { +): ExtendedColumnType { const { items, width = 56, // TODO: try 61px here @@ -202,7 +204,7 @@ function createActionsColumn( fixed: "right", align: "center", // Lock actions column from being toggled in visibility menu - columnVisibilityLocked: true as any, + columnVisibilityLocked: true, onCell: () => ({className: "ag-table-actions-cell"}), render: (_, record) => { if (record.__isSkeleton) return null diff --git a/web/oss/src/components/InfiniteVirtualTable/columns/types.ts b/web/oss/src/components/InfiniteVirtualTable/columns/types.ts index 413df537a5..e25840aa51 100644 --- a/web/oss/src/components/InfiniteVirtualTable/columns/types.ts +++ b/web/oss/src/components/InfiniteVirtualTable/columns/types.ts @@ -1,6 +1,27 @@ import type {Key, ReactNode} from "react" -import type {ColumnsType} from "antd/es/table" +import type {ColumnsType, ColumnType} from "antd/es/table" + +/** + * antd column extended with the custom props the InfiniteVirtualTable layer + * consumes at runtime (column visibility menu, smart resizing, export). + */ +export type ExtendedColumnType = ColumnsType[number] & { + key?: Key + children?: ExtendedColumnType[] + /** Custom node shown for this column in the visibility menu */ + columnVisibilityTitle?: ReactNode + /** Label shown for this column in the visibility menu */ + columnVisibilityLabel?: string + /** Lock column from being hidden via the visibility menu */ + columnVisibilityLocked?: boolean + /** Hide the column by default (until toggled visible) */ + defaultHidden?: boolean + /** Max width constraint consumed by smart resizable columns */ + maxWidth?: number + /** Include the column in table export */ + exportEnabled?: boolean +} export interface TableColumnCell { render: (row: Row, rowIndex: number) => ReactNode @@ -29,7 +50,8 @@ export interface TableColumnConfig { shouldCellUpdate?: ColumnsType[number]["shouldCellUpdate"] exportLabel?: string exportEnabled?: boolean - exportDataIndex?: ColumnsType[number]["dataIndex"] + // Only ColumnType carries dataIndex (group columns don't), so index off ColumnType. + exportDataIndex?: ColumnType["dataIndex"] exportValue?: (row: Row, column?: ColumnsType[number], columnIndex?: number) => unknown exportFormatter?: ( value: unknown, diff --git a/web/oss/src/components/InfiniteVirtualTable/components/InfiniteVirtualTableInner.tsx b/web/oss/src/components/InfiniteVirtualTable/components/InfiniteVirtualTableInner.tsx index c2c544eb5f..9547976d0b 100644 --- a/web/oss/src/components/InfiniteVirtualTable/components/InfiniteVirtualTableInner.tsx +++ b/web/oss/src/components/InfiniteVirtualTable/components/InfiniteVirtualTableInner.tsx @@ -525,8 +525,9 @@ const InfiniteVirtualTableInnerBase = ({ active, }) - const mergedOnRow = useCallback( - (record: RecordType, index: number) => { + // Typed as antd's onRow so the merged props object stays assignable to TableProps. + const mergedOnRow = useCallback["onRow"]>>( + (record, index) => { const baseOnRow = finalTableProps.onRow const baseProps = baseOnRow ? baseOnRow(record, index) : {} const shortcutProps = getShortcutRowProps diff --git a/web/oss/src/components/InfiniteVirtualTable/hooks/useColumnVisibility.ts b/web/oss/src/components/InfiniteVirtualTable/hooks/useColumnVisibility.ts index 564c40ddb1..80a3fd2b18 100644 --- a/web/oss/src/components/InfiniteVirtualTable/hooks/useColumnVisibility.ts +++ b/web/oss/src/components/InfiniteVirtualTable/hooks/useColumnVisibility.ts @@ -6,6 +6,7 @@ import {useAtomValue} from "jotai" import {LOW_PRIORITY, useSetAtomWithSchedule} from "jotai-scheduler" import {getColumnHiddenKeysAtom} from "../atoms/columnHiddenKeys" +import type {ExtendedColumnType} from "../columns/types" type Key = string @@ -14,13 +15,7 @@ interface Options { defaultHiddenKeys?: Key[] } -type ColumnLike = ColumnsType[number] & { - key?: React.Key - children?: ColumnLike[] - columnVisibilityTitle?: ReactNode - columnVisibilityLabel?: string - columnVisibilityLocked?: boolean -} +type ColumnLike = ExtendedColumnType const isColumnLocked = (column: ColumnLike | null | undefined) => Boolean(column?.columnVisibilityLocked) diff --git a/web/oss/src/components/InfiniteVirtualTable/hooks/useExpandableRows.tsx b/web/oss/src/components/InfiniteVirtualTable/hooks/useExpandableRows.tsx index 6a4e058710..a301ea63c4 100644 --- a/web/oss/src/components/InfiniteVirtualTable/hooks/useExpandableRows.tsx +++ b/web/oss/src/components/InfiniteVirtualTable/hooks/useExpandableRows.tsx @@ -15,8 +15,8 @@ interface ExpandedRowState { interface UseExpandableRowsConfig { config: ExpandableRowConfig | undefined rowKey: TableProps["rowKey"] - // dataSource is available for future use (e.g., clearing cache on data change) - _dataSource?: RecordType[] + // dataSource is accepted but unused for now (e.g., clearing cache on data change) + dataSource?: RecordType[] } interface UseExpandableRowsReturn { diff --git a/web/oss/src/components/InfiniteVirtualTable/hooks/useTableKeyboardShortcuts.ts b/web/oss/src/components/InfiniteVirtualTable/hooks/useTableKeyboardShortcuts.ts index f8855e71e0..b15ad2a8be 100644 --- a/web/oss/src/components/InfiniteVirtualTable/hooks/useTableKeyboardShortcuts.ts +++ b/web/oss/src/components/InfiniteVirtualTable/hooks/useTableKeyboardShortcuts.ts @@ -50,14 +50,14 @@ interface NormalizedRowShortcuts { onExport?: (payload: {key: Key | null; record: RecordType | null; selection: Key[]}) => void } +export interface TableShortcutRowProps { + "data-ivt-row-key"?: Key + className?: string + onMouseEnter?: () => void +} + interface TableShortcutResult { - getRowProps?: ( - record: RecordType, - index: number, - ) => { - className?: string - onMouseEnter?: () => void - } + getRowProps?: (record: RecordType, index?: number) => TableShortcutRowProps | undefined } const DEFAULT_HIGHLIGHT_CLASS = "ivt-row--highlighted" @@ -121,7 +121,7 @@ const normalizeKeyboardShortcutConfig = ( const resolveRowKey = ( rowKey: InfiniteVirtualTableProps["rowKey"], record: RecordType, - index: number, + index?: number, ): Key | null => { if (typeof rowKey === "function") { const value = rowKey(record, index) @@ -479,7 +479,8 @@ function useTableKeyboardShortcuts({ const entry = highlightEntryRef.current if (!entry) return false const isSelected = selectedKeySet.has(entry.key) - const nextKeys = isSelected + // Annotated: array-literal construction widens Key's unique-symbol member to symbol. + const nextKeys: Key[] = isSelected ? selectedKeys.filter((key) => key !== entry.key) : [...selectedKeys, entry.key] triggerSelectionChange(nextKeys) @@ -516,12 +517,12 @@ function useTableKeyboardShortcuts({ }, [rowShortcuts, selectedKeySet, selectedKeys]) const getRowProps = useCallback( - (record: RecordType, index: number) => { + (record: RecordType, index?: number) => { if (!rowShortcuts.enabled) return undefined const key = resolveRowKey(rowKey, record, index) if (key === null || key === undefined) return undefined const isHighlighted = highlightedKey !== null && key === highlightedKey - const props: Record = {"data-ivt-row-key": key} + const props: TableShortcutRowProps = {"data-ivt-row-key": key} if (isHighlighted) { props.className = rowShortcuts.highlightClassName } diff --git a/web/oss/src/components/InfiniteVirtualTable/types.ts b/web/oss/src/components/InfiniteVirtualTable/types.ts index f2d5c28dd3..afe89dc7f0 100644 --- a/web/oss/src/components/InfiniteVirtualTable/types.ts +++ b/web/oss/src/components/InfiniteVirtualTable/types.ts @@ -139,7 +139,8 @@ export interface InfiniteVirtualTableRowSelection { indeterminate?: boolean } columnWidth?: number - fixed?: boolean + /** Matches antd's rowSelection.fixed (FixedType) — forwarded verbatim */ + fixed?: boolean | "left" | "right" /** Custom title for the selection column header (replaces checkbox) */ columnTitle?: React.ReactNode /** Custom render for the selection cell */ diff --git a/web/oss/src/components/Layout/assets/Breadcrumbs.tsx b/web/oss/src/components/Layout/assets/Breadcrumbs.tsx index 20b5495b5c..d6cf545535 100644 --- a/web/oss/src/components/Layout/assets/Breadcrumbs.tsx +++ b/web/oss/src/components/Layout/assets/Breadcrumbs.tsx @@ -67,7 +67,8 @@ const breadcrumbItemsGenerator = (breadcrumbs: BreadcrumbAtom): {title: React.Re }) } -const BreadcrumbContainer = memo(({appTheme}: {appTheme: string}) => { +// `appName` is accepted but unused: breadcrumbs derive the app label from breadcrumbAtom +const BreadcrumbContainer = memo(({appTheme}: {appTheme: string; appName?: string}) => { const classes = useStyles({themeMode: appTheme} as StyleProps) const breadcrumbs = useAtomValue(breadcrumbAtom) const [collapsed, setCollapsed] = useAtom(sidebarCollapsedAtom) diff --git a/web/oss/src/components/Onboarding/tours/evaluationResultsTour.ts b/web/oss/src/components/Onboarding/tours/evaluationResultsTour.ts index 8442f5ecec..cc2a11e50a 100644 --- a/web/oss/src/components/Onboarding/tours/evaluationResultsTour.ts +++ b/web/oss/src/components/Onboarding/tours/evaluationResultsTour.ts @@ -28,7 +28,7 @@ const evaluationResultsTour: OnboardingTour = { content: "The Overview tab shows aggregated metrics and summary statistics for your entire evaluation run.", selector: ".ant-tabs-nav .ant-tabs-tab:first-child", // Target the Overview tab - side: "right-end", // Position to the right, aligned to bottom + side: "right-bottom", // Position to the right, aligned to bottom showControls: true, showSkip: true, selectorRetryAttempts: 10, @@ -40,7 +40,7 @@ const evaluationResultsTour: OnboardingTour = { content: "The Scenarios tab shows detailed results for each test case. Click on any row to see inputs, outputs, and individual metric scores.", selector: ".ant-tabs-nav .ant-tabs-tab:nth-child(2)", // Target the Scenarios tab - side: "right-end", // Position to the right, aligned to bottom + side: "right-bottom", // Position to the right, aligned to bottom showControls: true, showSkip: true, selectorRetryAttempts: 10, diff --git a/web/oss/src/components/Playground/Components/Menus/SelectVariant/index.tsx b/web/oss/src/components/Playground/Components/Menus/SelectVariant/index.tsx index 8c5f634978..ab50eb16e6 100644 --- a/web/oss/src/components/Playground/Components/Menus/SelectVariant/index.tsx +++ b/web/oss/src/components/Playground/Components/Menus/SelectVariant/index.tsx @@ -506,7 +506,7 @@ const SelectVariant = ({ renderParentTitle={renderParentTitle} renderChildTitle={renderChildTitle} renderSelectedLabel={renderSelectedLabel} - popupMinWidth={280} + width={280} maxHeight={400} /> )} diff --git a/web/oss/src/components/Playground/Components/Modals/CreateVariantModal/assets/types.d.ts b/web/oss/src/components/Playground/Components/Modals/CreateVariantModal/assets/types.d.ts index 57c579f2fe..6bcc9092da 100644 --- a/web/oss/src/components/Playground/Components/Modals/CreateVariantModal/assets/types.d.ts +++ b/web/oss/src/components/Playground/Components/Modals/CreateVariantModal/assets/types.d.ts @@ -14,7 +14,7 @@ export interface CreateVariantModalContentProps { newVariantName: string setNewVariantName: (value: string) => void setNameExists: Dispatch> - variants: {variantName: string}[] + variants: {variantName?: string | null}[] nameExists: boolean note: string setNote: Dispatch> diff --git a/web/oss/src/components/Playground/Components/Modals/CreateVariantModal/index.tsx b/web/oss/src/components/Playground/Components/Modals/CreateVariantModal/index.tsx index 61568edc3c..c1475354c6 100644 --- a/web/oss/src/components/Playground/Components/Modals/CreateVariantModal/index.tsx +++ b/web/oss/src/components/Playground/Components/Modals/CreateVariantModal/index.tsx @@ -86,7 +86,9 @@ const CreateVariantModal: FC = ({ propsSetIsModalOpen(false) message.success(`Variant "${newVariantName}" created successfully`) } catch (error) { - message.error(`Failed to create variant: ${error.message}`) + message.error( + `Failed to create variant: ${error instanceof Error ? error.message : String(error)}`, + ) } finally { setIsSubmitting(false) } diff --git a/web/oss/src/components/Playground/Components/Modals/DeployVariantModal/types.d.ts b/web/oss/src/components/Playground/Components/Modals/DeployVariantModal/types.d.ts index 01896ee934..5495b93484 100644 --- a/web/oss/src/components/Playground/Components/Modals/DeployVariantModal/types.d.ts +++ b/web/oss/src/components/Playground/Components/Modals/DeployVariantModal/types.d.ts @@ -13,13 +13,13 @@ export interface ExtendedEnvironment extends AppEnvironmentDeployment { } export interface DeployVariantModalProps extends ModalProps { /** When deploying a whole variant (not a specific revision). Synonym: variantId. */ - parentVariantId?: string + parentVariantId?: string | null /** Optional alias supported by DeployVariantButton */ variantId?: string - revisionId?: string + revisionId?: string | null environments?: ExtendedEnvironment[] - variantName: string - revision: number | string + variantName?: string + revision?: number | string isLoading?: boolean - mutate: () => Promise + mutate?: () => void | Promise } diff --git a/web/oss/src/components/Playground/Components/PlaygroundFocusDrawerAdapter/drawerPayload.ts b/web/oss/src/components/Playground/Components/PlaygroundFocusDrawerAdapter/drawerPayload.ts index d3eaf95b8e..ac3269a69e 100644 --- a/web/oss/src/components/Playground/Components/PlaygroundFocusDrawerAdapter/drawerPayload.ts +++ b/web/oss/src/components/Playground/Components/PlaygroundFocusDrawerAdapter/drawerPayload.ts @@ -13,6 +13,8 @@ export interface PlaygroundDrawerOutputNodePayload { } export interface PlaygroundDrawerPayload { + // Index signature so the payload satisfies Record editor values + [key: string]: unknown inputs: Record suggestedFields: {key: string; label: string; type: string}[] outputs: { diff --git a/web/oss/src/components/Playground/Components/PlaygroundVariantConfig/index.tsx b/web/oss/src/components/Playground/Components/PlaygroundVariantConfig/index.tsx index 2eb9970883..77c7c87d9a 100644 --- a/web/oss/src/components/Playground/Components/PlaygroundVariantConfig/index.tsx +++ b/web/oss/src/components/Playground/Components/PlaygroundVariantConfig/index.tsx @@ -243,7 +243,7 @@ const PlaygroundVariantConfig: React.FC< embedded={embedded} variantNameOverride={variantNameOverride} revisionOverride={revisionOverride} - evaluatorLabel={evaluatorInfo?.label} + evaluatorLabel={evaluatorInfo?.label ?? undefined} hasPresets={hasPresets} onLoadPreset={() => setIsPresetModalOpen(true)} extraActions={isAgentHeaderMode ? undefined : viewModeSelector} diff --git a/web/oss/src/components/Playground/Components/TestsetDropdown/TestsetPreviewPanelWrapper.tsx b/web/oss/src/components/Playground/Components/TestsetDropdown/TestsetPreviewPanelWrapper.tsx index bc6de3439b..f6fb4d95d3 100644 --- a/web/oss/src/components/Playground/Components/TestsetDropdown/TestsetPreviewPanelWrapper.tsx +++ b/web/oss/src/components/Playground/Components/TestsetDropdown/TestsetPreviewPanelWrapper.tsx @@ -236,23 +236,15 @@ export function TestsetPreviewPanelWrapper({
- - - - + { + setIsAddColumnModalOpen(false) + setNewColumnName("") + }} + onConfirm={handleConfirmAddColumn} + confirmLabel="OK" + canConfirm={!!newColumnName.trim()} + /> ) diff --git a/web/oss/src/components/Playground/Components/TestsetDropdown/index.tsx b/web/oss/src/components/Playground/Components/TestsetDropdown/index.tsx index b86d8caed5..b8cd9a9cac 100644 --- a/web/oss/src/components/Playground/Components/TestsetDropdown/index.tsx +++ b/web/oss/src/components/Playground/Components/TestsetDropdown/index.tsx @@ -174,8 +174,9 @@ export function TestsetDropdown() { return Object.values( chatExecutions as Record, ).some( + // "success" typed as-is: MessageExecutionStatus never emits it (dead branch) (r) => - (r?.status === "complete" || r?.status === "success") && + (r?.status === "complete" || (r?.status as string) === "success") && !!r?.traceId, ) } @@ -233,7 +234,10 @@ export function TestsetDropdown() { const chatExecutions = store.get(executionByMessageIdAtomFamily(loadableId)) chatTraceReferences = Object.values(chatExecutions as Record) .filter( - (r) => (r?.status === "complete" || r?.status === "success") && !!r?.traceId, + // "success" typed as-is: MessageExecutionStatus never emits it (dead branch) + (r) => + (r?.status === "complete" || (r?.status as string) === "success") && + !!r?.traceId, ) .map(toTestsetTraceReference) .filter((reference): reference is TestsetTraceReference => !!reference) diff --git a/web/oss/src/components/Playground/Components/WebWorkerProvider/index.tsx b/web/oss/src/components/Playground/Components/WebWorkerProvider/index.tsx index 5171db7eeb..ddcfaf31e0 100644 --- a/web/oss/src/components/Playground/Components/WebWorkerProvider/index.tsx +++ b/web/oss/src/components/Playground/Components/WebWorkerProvider/index.tsx @@ -52,7 +52,8 @@ export const WebWorkerProvider = ({children}: WebWorkerProviderProps) => { // Inject worker bridge into playground state useEffect(() => { setExecutionWorkerBridge({ - postMessageToWorker, + // Bridge accepts unknown; the worker hook narrows to WorkerMessage internally + postMessageToWorker: postMessageToWorker as (message: unknown) => void, createWorkerMessage, }) diff --git a/web/oss/src/components/Playground/Playground.tsx b/web/oss/src/components/Playground/Playground.tsx index cb65552c1e..b0ca9db852 100644 --- a/web/oss/src/components/Playground/Playground.tsx +++ b/web/oss/src/components/Playground/Playground.tsx @@ -1,9 +1,13 @@ -import {type FC, useCallback, useEffect, useMemo} from "react" +import {type ComponentProps, type FC, useCallback, useEffect, useMemo} from "react" import {executeToolCall} from "@agenta/entities/gatewayTool" import {loadableController} from "@agenta/entities/loadable" import {testcaseMolecule} from "@agenta/entities/testcase" -import {GatewayToolAssistantActions, type PlaygroundUIProviders} from "@agenta/playground-ui" +import { + GatewayToolAssistantActions, + type ChatTurnAssistantActionsProps, + type PlaygroundUIProviders, +} from "@agenta/playground-ui" import {useLocalDraftWarning} from "@agenta/playground-ui/hooks" import {preloadEditorPlugins, SyncStateTag} from "@agenta/ui" import {useAtomValue, useSetAtom} from "jotai" @@ -108,8 +112,16 @@ const Playground: FC<{onboarding?: boolean}> = ({onboarding = false}) => { const providers = { SimpleSharedEditor, SharedGenerationResultUtils, - ChatTurnAssistantActions: (props) => ( - + ChatTurnAssistantActions: (props: ChatTurnAssistantActionsProps) => ( + ["onExecuteToolCall"] + } + /> ), // Third generation arm: agent-type entities render the agent-chat surface. The frame is // synchronous (real structure paints immediately); the AI SDK stays in the lazy conversation diff --git a/web/oss/src/components/PlaygroundRouter/PlaygroundLoadingShell.tsx b/web/oss/src/components/PlaygroundRouter/PlaygroundLoadingShell.tsx index 6eb54cab68..a506ebc98e 100644 --- a/web/oss/src/components/PlaygroundRouter/PlaygroundLoadingShell.tsx +++ b/web/oss/src/components/PlaygroundRouter/PlaygroundLoadingShell.tsx @@ -8,6 +8,8 @@ import {useAtomValue} from "jotai" import {playgroundEarlyAgentStateAtom} from "@/oss/state/workflow" interface PlaygroundLoadingShellProps { + /** Unused; accepted for next/dynamic `loading` compatibility (DynamicOptionsLoadingProps). */ + error?: Error | null /** Force the agent-flavored header. Onboarding always targets an agent, so it need not * wait for the early app-id signal to resolve. Defaults to the early agent-state atom. */ agent?: boolean diff --git a/web/oss/src/components/References/cells/ApplicationCells.tsx b/web/oss/src/components/References/cells/ApplicationCells.tsx index 76cc24f1ef..05f28ed2a8 100644 --- a/web/oss/src/components/References/cells/ApplicationCells.tsx +++ b/web/oss/src/components/References/cells/ApplicationCells.tsx @@ -3,6 +3,7 @@ import {useMemo} from "react" import {workflowMolecule} from "@agenta/entities/workflow" import {SkeletonLine} from "@agenta/ui/table" import {getDefaultStore, useAtomValue} from "jotai" +import type {Atom} from "jotai" import { useRunRowDetails, @@ -31,7 +32,8 @@ export const PreviewAppCellSkeleton = () => // scoped Jotai stores (e.g. EvaluationRunsTableStoreProvider) would otherwise // read stale defaults from the scoped store's isolated atom graph. const defaultStore = getDefaultStore() -const useDefaultAtomValue: typeof useAtomValue = (atom) => useAtomValue(atom, {store: defaultStore}) +const useDefaultAtomValue = ((atom: Atom) => + useAtomValue(atom, {store: defaultStore})) as typeof useAtomValue const CELL_CLASS = "flex h-full w-full min-w-0 flex-col justify-center gap-1 px-2 whitespace-nowrap overflow-hidden text-ellipsis" diff --git a/web/oss/src/components/References/cells/TestsetCells.tsx b/web/oss/src/components/References/cells/TestsetCells.tsx index b06f1d84d4..160be03e61 100644 --- a/web/oss/src/components/References/cells/TestsetCells.tsx +++ b/web/oss/src/components/References/cells/TestsetCells.tsx @@ -5,6 +5,7 @@ import {SkeletonLine} from "@agenta/ui/table" import {Tag} from "antd" import {getDefaultStore} from "jotai" import {useAtomValue} from "jotai" +import type {Atom} from "jotai" import { useRunRowReferences, @@ -20,7 +21,8 @@ import {revision} from "@/oss/state/entities/testset" // scoped Jotai stores (e.g. EvaluationRunsTableStoreProvider) would otherwise // read stale defaults from the scoped store's isolated atom graph. const defaultStore = getDefaultStore() -const useDefaultAtomValue: typeof useAtomValue = (atom) => useAtomValue(atom, {store: defaultStore}) +const useDefaultAtomValue = ((atom: Atom) => + useAtomValue(atom, {store: defaultStore})) as typeof useAtomValue const CELL_CLASS = "flex h-full w-full min-w-0 flex-col justify-center gap-1 px-2" diff --git a/web/oss/src/components/RequireWorkflowKind/index.tsx b/web/oss/src/components/RequireWorkflowKind/index.tsx index 6301862ad5..84ff751740 100644 --- a/web/oss/src/components/RequireWorkflowKind/index.tsx +++ b/web/oss/src/components/RequireWorkflowKind/index.tsx @@ -1,4 +1,4 @@ -import {type ReactNode} from "react" +import {type ReactElement, type ReactNode} from "react" import {Spin} from "antd" @@ -43,7 +43,7 @@ function RequireWorkflowKind({ if (ctx.isResolving) { return ( - (fallback as JSX.Element | null) ?? ( + (fallback as ReactElement | null) ?? (
@@ -60,7 +60,7 @@ function RequireWorkflowKind({ // in error state, let the page try to render — its own data atoms will // probably fail loudly, which is fine. Caller may pass `errorFallback` // to override. - return (errorFallback as JSX.Element | null) ?? <>{children} + return (errorFallback as ReactElement | null) ?? <>{children} } if (!ctx.workflowKind) { diff --git a/web/oss/src/components/SessionInspector/tabs/StreamsTab.tsx b/web/oss/src/components/SessionInspector/tabs/StreamsTab.tsx index f124bbcc2e..cd14516f0a 100644 --- a/web/oss/src/components/SessionInspector/tabs/StreamsTab.tsx +++ b/web/oss/src/components/SessionInspector/tabs/StreamsTab.tsx @@ -158,7 +158,8 @@ const StreamsTab = ({sessionId}: {sessionId: string}) => {
status
- {data?.status?.code ?? "—"} + {/* typed as-is: backend SessionStream has no `status` field, so this always falls back */} + {(data as {status?: {code?: string}} | null)?.status?.code ?? "—"}
watcher_id
diff --git a/web/oss/src/components/SharedDrawers/AddToTestsetDrawer/atoms/drawerState.ts b/web/oss/src/components/SharedDrawers/AddToTestsetDrawer/atoms/drawerState.ts index 6f3bb8cac4..457f3b6daa 100644 --- a/web/oss/src/components/SharedDrawers/AddToTestsetDrawer/atoms/drawerState.ts +++ b/web/oss/src/components/SharedDrawers/AddToTestsetDrawer/atoms/drawerState.ts @@ -119,6 +119,8 @@ export const previewEntityIdsAtom = atom([]) export const traceDataFromEntitiesAtom = atom((get): TestsetTraceData[] => { const spanIds = get(traceSpanIdsAtom) + // ag.data values are arbitrary JSON, not the string-valued KeyValuePair the + // TestsetTraceData type declares; kept as-is (downstream treats rows generically). return spanIds.map((spanId, index) => { const entity = get(traceSpanMolecule.selectors.data(spanId)) const isDirty = get(traceSpanMolecule.selectors.isDirty(spanId)) @@ -153,7 +155,7 @@ export const traceDataFromEntitiesAtom = atom((get): TestsetTraceData[] => { return { key: spanId, - data: agData, + data: agData as TestsetTraceData["data"], id: index + 1, isEdited: isDirty, originalData, @@ -256,8 +258,11 @@ export const removeTraceDataAtom = atom(null, (get, set, traceKey: string) => { const remainingSpanIds = spanIds.filter((id) => id !== traceKey) set(traceSpanIdsAtom, remainingSpanIds) - // Discard any draft for the removed span - set(traceSpanMolecule.actions.discard, traceKey) + // Discard any draft for the removed span. + // NOTE (latent runtime bug, typed as-is): traceSpanMolecule.actions only exposes + // prefetchByIds/evictByIds — discard/update live under reducers. These set() calls + // receive undefined and would throw if reached; kept as-is pending triage. + set((traceSpanMolecule as any).actions.discard, traceKey) if (remainingSpanIds.length > 0) { // Find the next span to preview @@ -501,7 +506,7 @@ export const updateEditedTraceAtom = atom( // If reverting to original, discard draft instead if (updatedString === originalString) { - set(traceSpanMolecule.actions.discard, spanId) + set((traceSpanMolecule as any).actions.discard, spanId) } else { // Update entity draft with new ag.data // The draft system expects attributes, so we build the new attributes @@ -510,7 +515,7 @@ export const updateEditedTraceAtom = atom( "ag.data": newAgData, } - set(traceSpanMolecule.actions.update, spanId, newAttributes) + set((traceSpanMolecule as any).actions.update, spanId, newAttributes) } // Update local entities to reflect the edited data in preview table @@ -564,7 +569,7 @@ export const revertEditedTraceAtom = atom( } // Discard the entity draft to revert to server state - set(traceSpanMolecule.actions.discard, spanId) + set((traceSpanMolecule as any).actions.discard, spanId) // Update local entities to reflect the reverted data if (getValueAtPath) { diff --git a/web/oss/src/components/SharedDrawers/AddToTestsetDrawer/components/DataPreviewEditor.tsx b/web/oss/src/components/SharedDrawers/AddToTestsetDrawer/components/DataPreviewEditor.tsx index 03395756d5..86bf3dbe43 100644 --- a/web/oss/src/components/SharedDrawers/AddToTestsetDrawer/components/DataPreviewEditor.tsx +++ b/web/oss/src/components/SharedDrawers/AddToTestsetDrawer/components/DataPreviewEditor.tsx @@ -1,4 +1,4 @@ -import {useCallback, useMemo} from "react" +import {useCallback, useMemo, type ComponentProps} from "react" import {traceSpanMolecule} from "@agenta/entities/trace" import {Typography} from "antd" @@ -89,7 +89,13 @@ export function DataPreviewEditor({ ["entity"] + } defaultEditMode="fields" showViewToggle={false} // Multi-span navigation diff --git a/web/oss/src/components/SharedDrawers/AddToTestsetDrawer/hooks/useTestsetDrawer.ts b/web/oss/src/components/SharedDrawers/AddToTestsetDrawer/hooks/useTestsetDrawer.ts index 4c9cf63705..2a01d7053e 100644 --- a/web/oss/src/components/SharedDrawers/AddToTestsetDrawer/hooks/useTestsetDrawer.ts +++ b/web/oss/src/components/SharedDrawers/AddToTestsetDrawer/hooks/useTestsetDrawer.ts @@ -99,10 +99,10 @@ export interface UseTestsetDrawerResult { onSaveEditedTrace: (value?: string) => void onRevertEditedTrace: () => void customSelectOptions: (divider?: boolean) => any[] - renderSelectedRevisionLabel: (labels: string[], selectedOptions?: any[]) => string + renderSelectedRevisionLabel: (labels: string[], selectedOptions?: any[]) => React.ReactNode // Refs - elemRef: React.RefObject + elemRef: React.RefObject } export function useTestsetDrawer(): UseTestsetDrawerResult { diff --git a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/AnnotateDrawerTitle/index.tsx b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/AnnotateDrawerTitle/index.tsx index 8ebc416bed..24be909afb 100644 --- a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/AnnotateDrawerTitle/index.tsx +++ b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/AnnotateDrawerTitle/index.tsx @@ -128,7 +128,7 @@ const AnnotateDrawerTitle = ({ updatedMetrics, selectedEvaluators, evaluators: (evaluators || []) as EvaluatorDto[], - traceSpanIds: traceSpanIds as AnnotateDrawerIdsType, + traceSpanIds: traceSpanIds as Required, invocationStepKey: traceSpanIds?.traceId || "", }) diff --git a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/SelectEvaluators/index.tsx b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/SelectEvaluators/index.tsx index c21e5b63ed..960a7f2478 100644 --- a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/SelectEvaluators/index.tsx +++ b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/SelectEvaluators/index.tsx @@ -19,7 +19,9 @@ const SelectEvaluators = ({ const filteredEvals = useMemo( () => - evaluators?.filter((value) => value.name.toLowerCase().includes(search.toLowerCase())), + evaluators?.filter((value) => + (value.name ?? "").toLowerCase().includes(search.toLowerCase()), + ), [search, evaluators], ) @@ -33,8 +35,12 @@ const SelectEvaluators = ({ const updated = [...prev, e.target.value] // Sort according to evaluators order return ( - evaluators?.map((ev) => ev.slug).filter((slug) => updated.includes(slug)) || - [] + evaluators + ?.map((ev) => ev.slug) + .filter( + (slug): slug is string => + typeof slug === "string" && updated.includes(slug), + ) || [] ) }) } @@ -66,10 +72,10 @@ const SelectEvaluators = ({ value={evaluator.slug} onChange={handleCheckboxChange} checked={ - selectedEvaluators.includes(evaluator.slug) || - annEvalSlugs.includes(evaluator.slug) + selectedEvaluators.includes(evaluator.slug ?? "") || + annEvalSlugs.includes(evaluator.slug ?? "") } - disabled={annEvalSlugs.includes(evaluator.slug)} + disabled={annEvalSlugs.includes(evaluator.slug ?? "")} className={clsx( "flex items-center", "[&_.ant-checkbox-label]:w-[96%]", diff --git a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/hooks/useEvaluatorSchemas.ts b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/hooks/useEvaluatorSchemas.ts index eba57bd0d0..dc66fd4bbb 100644 --- a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/hooks/useEvaluatorSchemas.ts +++ b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/hooks/useEvaluatorSchemas.ts @@ -66,7 +66,9 @@ export function useEvaluatorSchemas( return evaluatorRefs.map((ref, idx) => { const evaluator = evaluators[idx] - const outputSchema = resolveOutputSchema(evaluator?.data) + const outputSchema = resolveOutputSchema( + evaluator?.data as Parameters[0], + ) return { id: ref.id, diff --git a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/transforms.ts b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/transforms.ts index bebf19fdb8..4b8ee10f00 100644 --- a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/transforms.ts +++ b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/transforms.ts @@ -99,7 +99,7 @@ export const transformMetadata = ({ return metadataItem }) - .filter(Boolean) + .filter((item): item is NonNullable => Boolean(item)) return metadata.sort((a, b) => { const typePriority = (type: string) => { @@ -403,7 +403,7 @@ export const generateNewAnnotationPayloadData = ({ if (!updatedMetric || Object.keys(updatedMetric).length === 0) continue const outputsSchema = getEvaluatorOutputsSchema(evaluator) - const schemaProps = outputsSchema.properties ?? {} + const schemaProps: Record = outputsSchema.properties ?? {} const requiredKeys = outputsSchema.required ?? [] const metrics: Record = {} diff --git a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/types.d.ts b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/types.d.ts index cbec4c32d7..965f91c3f9 100644 --- a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/types.d.ts +++ b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/types.d.ts @@ -1,6 +1,6 @@ import {DrawerProps} from "antd" -import {TooltipButtonProps} from "@/oss/components/EnhancedUIs/Button" +import {EnhancedButtonProps} from "@/oss/components/EnhancedUIs/Button/types" import {AnnotationDto} from "@/oss/lib/hooks/useAnnotations/types" import {EvaluatorPreviewDto} from "@/oss/services/evaluations/api/evaluatorTypes" @@ -20,8 +20,8 @@ export interface UpdatedMetricType { } export type UpdatedMetricsType = Record> export interface AnnotateDrawerIdsType { - traceId: string - spanId: string + traceId?: string + spanId?: string } export interface AnnotateDrawerProps extends DrawerProps { data?: AnnotationDto[] @@ -48,7 +48,7 @@ export interface AnnotateDrawerTitleProps { createEvaluatorMode?: "create" | "edit" } -export interface AnnotateDrawerButtonProps extends TooltipButtonProps { +export interface AnnotateDrawerButtonProps extends EnhancedButtonProps { children?: React.ReactNode label?: React.ReactNode data?: AnnotationDto[] diff --git a/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionDrawerButton/index.tsx b/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionDrawerButton/index.tsx index 18085b0151..62533dad6f 100644 --- a/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionDrawerButton/index.tsx +++ b/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionDrawerButton/index.tsx @@ -7,8 +7,11 @@ import {useSetAtom} from "jotai" import {useQueryParamState} from "@/oss/state/appState" -import {openTraceDrawerAtom, setTraceDrawerActiveSpanAtom} from "./store/sessionDrawerStore" -import {SessionDrawerButtonProps} from "./types" +import { + openTraceDrawerAtom, + setTraceDrawerActiveSpanAtom, +} from "../../../TraceDrawer/store/traceDrawerStore" +import {SessionDrawerButtonProps} from "../../types" const SessionDrawerButton = ({ label, @@ -24,7 +27,8 @@ const SessionDrawerButton = ({ const traceId = useMemo(() => { const directTraceId = - result?.response?.trace_id || result?.metadata?.rawError?.detail?.trace_id + (result as any)?.response?.trace_id || + (result as any)?.metadata?.rawError?.detail?.trace_id if (directTraceId) return directTraceId const responseTrace = (result as any)?.response?.trace @@ -119,7 +123,7 @@ const SessionDrawerButton = ({ return false })() - return hasNodes || Boolean(result?.response?.trace) || Boolean(result?.error) + return hasNodes || Boolean((result as any)?.response?.trace) || Boolean(result?.error) }, [result]) const passthroughProps = { @@ -154,4 +158,4 @@ const SessionDrawerButton = ({ } export default SessionDrawerButton -export {default as TraceDrawer} from "./components/SessionDrawer" +export {default as TraceDrawer} from "../SessionDrawer" diff --git a/web/oss/src/components/SharedDrawers/SessionDrawer/store/sessionDrawerStore.ts b/web/oss/src/components/SharedDrawers/SessionDrawer/store/sessionDrawerStore.ts index fa06c4e99e..a28199ff31 100644 --- a/web/oss/src/components/SharedDrawers/SessionDrawer/store/sessionDrawerStore.ts +++ b/web/oss/src/components/SharedDrawers/SessionDrawer/store/sessionDrawerStore.ts @@ -135,10 +135,16 @@ export const sessionTracesAtom = atom((get) => { if (!data) return [] const transformed: TraceSpanNode[] = [] + // entities-package TraceSpanNode is the same backend span shape as the OSS type; + // align the annotation at the boundary, no data is converted. if (isTracesResponse(data)) { - transformed.push(...transformTracingResponse(transformTracesResponseToTree(data))) + transformed.push( + ...(transformTracingResponse( + transformTracesResponseToTree(data), + ) as unknown as TraceSpanNode[]), + ) } else if (isSpansResponse(data)) { - transformed.push(...transformTracingResponse(data.spans)) + transformed.push(...(transformTracingResponse(data.spans) as unknown as TraceSpanNode[])) } const filtred = transformed.filter((node) => node.trace_type !== "annotation") diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/AccordionTreePanel.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/AccordionTreePanel.tsx index 815fdb30d3..c1f8adf07c 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/AccordionTreePanel.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/AccordionTreePanel.tsx @@ -265,7 +265,8 @@ const AccordionTreePanel = ({ ...props }: AccordionTreePanelProps) => { const {token} = theme.useToken() - const classes = useStyles({bgColor, theme: token}) + // antd's GlobalToken is the runtime superset JSSTheme indexes into; align at the boundary + const classes = useStyles({bgColor, theme: token as unknown as JSSTheme}) const editorRef = useRef(null) const textViewerId = useId().replace(/:/g, "") diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/AnnotationTabItem/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/AnnotationTabItem/index.tsx index e644787a97..ea9059b661 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/AnnotationTabItem/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/AnnotationTabItem/index.tsx @@ -45,7 +45,8 @@ const AnnotationTabItem = ({annotations}: {annotations: AnnotationDto[]}) => { const allAnnMetrics = {...outputs.metrics, ...outputs.notes, ...outputs.extra} const evaluator = evaluators.find((e) => e.slug === ann.references?.evaluator?.slug) - const evalMetricsSchema = resolveOutputSchemaProperties(evaluator?.data) ?? {} + const evalMetricsSchema: Record = + resolveOutputSchemaProperties(evaluator?.data) ?? {} const grouped = Object.entries(allAnnMetrics).reduce( (acc, [key, value]) => { @@ -189,7 +190,8 @@ const AnnotationTabItem = ({annotations}: {annotations: AnnotationDto[]}) => { {Object.entries(groupedByReference).length > 0 ? ( Object.entries(groupedByReference).map(([key, annotations]) => { const [slug, kind] = key.split("::") - const evaluator = annotations?.[0]?.evaluator + // `evaluator` is not on AnnotationDto; dead access kept as-is (falls through to slug) + const evaluator = (annotations?.[0] as any)?.evaluator const evaluatorName = evaluator?.name || slug return ( diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/OverviewTabItem/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/OverviewTabItem/index.tsx index 682a361a02..bed810406e 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/OverviewTabItem/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/OverviewTabItem/index.tsx @@ -1,6 +1,6 @@ import {useMemo} from "react" -import {traceSpanMolecule} from "@agenta/entities/trace" +import {traceSpanMolecule, type TraceSpan as EntityTraceSpan} from "@agenta/entities/trace" import {Space} from "antd" import {useAtomValue} from "jotai" @@ -33,6 +33,9 @@ const OverviewTabItem = ({ const entityWithDrillIn = traceSpanMolecule as typeof traceSpanMolecule & { drillIn: NonNullable } + // OSS TraceSpanNode is the same backend span shape as the entities-package type + // the drill-in API expects; align at the boundary, no data is converted. + const drillInSpan = activeTrace as unknown as EntityTraceSpan const metaConfig = useAtomValue(spanMetaConfigurationAtomFamily(activeTrace)) const inputsFromSelectors = useAtomValue(spanDataInputsAtomFamily(activeTrace)) const outputsFromSelectors = useAtomValue(spanDataOutputsAtomFamily(activeTrace)) @@ -44,19 +47,19 @@ const OverviewTabItem = ({ const {inputs, outputs, internals, parameters} = useMemo( () => ({ inputs: - entityWithDrillIn.drillIn.getValueAtPath(activeTrace, ["ag", "data", "inputs"]) ?? + entityWithDrillIn.drillIn.getValueAtPath(drillInSpan, ["ag", "data", "inputs"]) ?? inputsFromSelectors, outputs: - entityWithDrillIn.drillIn.getValueAtPath(activeTrace, ["ag", "data", "outputs"]) ?? + entityWithDrillIn.drillIn.getValueAtPath(drillInSpan, ["ag", "data", "outputs"]) ?? outputsFromSelectors, internals: - entityWithDrillIn.drillIn.getValueAtPath(activeTrace, [ + entityWithDrillIn.drillIn.getValueAtPath(drillInSpan, [ "ag", "data", "internals", ]) ?? internalsFromSelectors, parameters: - entityWithDrillIn.drillIn.getValueAtPath(activeTrace, [ + entityWithDrillIn.drillIn.getValueAtPath(drillInSpan, [ "ag", "data", "parameters", diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/TraceTypeHeader/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/TraceTypeHeader/index.tsx index 5d1ba2806e..fd6a917a61 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/TraceTypeHeader/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/TraceTypeHeader/index.tsx @@ -93,9 +93,13 @@ const TraceTypeHeader = ({ } } - const agData = extractAgData(activeTrace) + // OSS TraceSpanNode is the same backend span shape as the entities-package type + // these helpers expect; align at the boundary, no data is converted. + const agData = extractAgData(activeTrace as unknown as Parameters[0]) const hasExtractableData = Boolean(agData?.inputs || agData?.parameters) - const hasApp = hasAppReference(activeTrace) + const hasApp = hasAppReference( + activeTrace as unknown as Parameters[0], + ) const isInvocation = INVOCATION_SPAN_TYPES.has(spanType) // Invocation spans (workflow, task, agent, chain) represent the unit diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceHeader/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceHeader/index.tsx index 84325469e1..2c7d45e0eb 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceHeader/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceHeader/index.tsx @@ -188,12 +188,20 @@ const TraceHeader = ({ }) let candidates: TraceSpanNode[] = [] + // entities-package TraceSpanNode is the same backend span shape as the + // OSS type; align the annotation at the boundary, no data is converted. if (isTracesResponse(response)) { - candidates = transformTracingResponse(transformTracesResponseToTree(response)) + candidates = transformTracingResponse( + transformTracesResponseToTree(response), + ) as unknown as TraceSpanNode[] } else if (isSpansResponse(response)) { - candidates = transformTracingResponse(response.spans) + candidates = transformTracingResponse( + response.spans, + ) as unknown as TraceSpanNode[] } else if (Array.isArray((response as any)?.spans)) { - candidates = transformTracingResponse((response as any).spans) + candidates = transformTracingResponse( + (response as any).spans, + ) as unknown as TraceSpanNode[] } if (!candidates.length) return null diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceLinkedSpans/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceLinkedSpans/index.tsx index 85eb23cd1a..09a7b86dbe 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceLinkedSpans/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceLinkedSpans/index.tsx @@ -54,7 +54,8 @@ const TraceLinkedSpans = () => { onClick={() => handleNavigate(link)} > {" "} - {link?.trace?.[0]?.span_name || link?.key} + {/* `trace` is not on TraceDrawerSpanLink; dead access kept as-is (falls through to key) */} + {(link as any)?.trace?.[0]?.span_name || link?.key} ) })} diff --git a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceReferences/index.tsx b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceReferences/index.tsx index 1d25bd4172..59a2aaaf10 100644 --- a/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceReferences/index.tsx +++ b/web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceReferences/index.tsx @@ -85,7 +85,7 @@ const TraceReferences = () => { case "testset": return ( } placement="bottomRight" - classNames={{body: "!p-0 w-[240px]"}} + // antd's PopoverClassNamesType doesn't declare `body`; kept as-is + classNames={{body: "!p-0 w-[240px]"} as any} arrow={false} >