From 271228889399dbb2f00a1ce2cc6171a787e69af4 Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Wed, 22 Jul 2026 03:13:56 +0200 Subject: [PATCH 01/13] chore(frontend): exclude tests from app tsconfigs The playwright suites are owned and type-checked by the tests workspace, which holds the @playwright/test dependency; tests/manual scripts import state modules that no longer exist. --- web/ee/tsconfig.json | 2 +- web/oss/tsconfig.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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/tsconfig.json b/web/oss/tsconfig.json index dfe57cd1b2..80e4dfec6a 100644 --- a/web/oss/tsconfig.json +++ b/web/oss/tsconfig.json @@ -23,6 +23,7 @@ "include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx"], "exclude": [ "node_modules", + "tests", "src/components/OldPlayground/**/*.tsx", "src/**/*.test.ts", "src/**/*.test.tsx" From 63b49bd42bc7a11f14d20c6f48355ea627eba19d Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Wed, 22 Jul 2026 03:14:02 +0200 Subject: [PATCH 02/13] fix(frontend): restore removed types and repair stale imports - Restore Parameter, CorrectAnswer and _EvaluationScenario to lib/Types.ts (removed by cleanup while consumers remained) - Re-export MetricColumnDefinition from the EvalRunDetails table barrel - TooltipButtonProps was renamed EnhancedButtonProps; statusMap moved to @agenta/entity-ui/variant - Synthesize full Parameter objects in UseApiContent --- .../assets/UseApiContent.tsx | 7 ++++- .../EditorViews/SimpleSharedEditor/types.ts | 6 ++-- .../EvalRunDetails/atoms/table/types.ts | 2 ++ .../AnnotateDrawer/assets/types.d.ts | 4 +-- .../overview/variants/VariantPopover.tsx | 3 +- web/oss/src/lib/Types.ts | 30 +++++++++++++++++++ 6 files changed, 44 insertions(+), 8 deletions(-) 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/EditorViews/SimpleSharedEditor/types.ts b/web/oss/src/components/EditorViews/SimpleSharedEditor/types.ts index bb485b9e4d..b87c6a9a4a 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,8 +13,8 @@ export interface SimpleSharedEditorProps extends SharedEditorProps { isFormatVisible?: boolean isCopyVisible?: boolean formatDropdownProps?: DropdownProps - copyButtonProps?: TooltipButtonProps - minimizeButtonProps?: TooltipButtonProps + copyButtonProps?: EnhancedButtonProps + minimizeButtonProps?: EnhancedButtonProps disableFormatItems?: {text?: boolean; markdown?: boolean; json?: boolean; yaml?: boolean} minimizedHeight?: number showTextToMdOutside?: boolean diff --git a/web/oss/src/components/EvalRunDetails/atoms/table/types.ts b/web/oss/src/components/EvalRunDetails/atoms/table/types.ts index 952cbd6434..62d4729cbd 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/table/types.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/table/types.ts @@ -1,5 +1,7 @@ import type {EvaluatorDefinition, MetricColumnDefinition} from "@agenta/entities/workflow" +export type {MetricColumnDefinition} + export type EvaluationColumnKind = | "meta" | "testset" 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..f80b34b660 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" @@ -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/pages/overview/variants/VariantPopover.tsx b/web/oss/src/components/pages/overview/variants/VariantPopover.tsx index ee9a4fd535..fcbcdefe68 100644 --- a/web/oss/src/components/pages/overview/variants/VariantPopover.tsx +++ b/web/oss/src/components/pages/overview/variants/VariantPopover.tsx @@ -1,11 +1,10 @@ import type {AppEnvironmentDeployment} from "@agenta/entities/environment" import {useUserDisplayName} from "@agenta/entities/shared/user" import type {Workflow} from "@agenta/entities/workflow" -import {VariantNameCell} from "@agenta/entity-ui/variant" +import {statusMap, VariantNameCell} from "@agenta/entity-ui/variant" import {ArrowSquareOut} from "@phosphor-icons/react" import {Badge, Button, Flex, Popover, Tag, Typography} from "antd" -import {statusMap} from "@/oss/components/VariantDetailsWithStatus/components/EnvironmentStatus" import {usePlaygroundNavigation} from "@/oss/hooks/usePlaygroundNavigation" import {formatVariantIdWithHash} from "@/oss/lib/helpers/utils" diff --git a/web/oss/src/lib/Types.ts b/web/oss/src/lib/Types.ts index 2489102eaa..89a1be25d1 100644 --- a/web/oss/src/lib/Types.ts +++ b/web/oss/src/lib/Types.ts @@ -322,6 +322,23 @@ export enum EvaluationStatusType { ERROR = "error", } +export interface Parameter { + name: string + type: string + input: boolean + required: boolean + default?: any + enum?: string[] + minimum?: number + maximum?: number + choices?: Record +} + +export interface CorrectAnswer { + key: string + value: string +} + export interface _Evaluation { id: string appId: string @@ -353,6 +370,19 @@ export interface _Evaluation { variant_revision_ids: string[] } +export interface _EvaluationScenario { + id: string + evaluation_id: string + evaluation: _Evaluation + evaluators_configs: EvaluatorConfig[] + inputs: (TypedValue & {name: string})[] + outputs: {result: TypedValue; cost?: number; latency?: number}[] + correct_answers?: CorrectAnswer[] + is_pinned?: boolean + note?: string + results: {evaluator_config: string; result: TypedValue & {error: null | EvaluationError}}[] +} + type ValueType = number | string | boolean | GenericObject | null type ValueTypeOptions = | "text" From d19021f221494df0abd84990c4aec2f3fc4ea706 Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Wed, 22 Jul 2026 03:14:36 +0200 Subject: [PATCH 03/13] fix(frontend): resolve high-count tsc error clusters - useRunMetricData: type selection as the unwrapped value, not the atom - Webhook builders: narrow WebhookFormValues union before field access - filtersAtom: accept updater functions in the write signature - Organization settings: drop stale react-query v4 useErrorBoundary and migrate setQueriesData to the v5 filters shape - evaluations/utils: surface variantId from invocation metadata - PreviewTableRow: add index signature required by InfiniteTableRowBase --- .../EvalRunDetails/atoms/tableRows.ts | 1 + .../OverviewView/hooks/useRunMetricData.ts | 3 ++- .../Webhooks/utils/buildPreviewRequest.ts | 19 +++++----------- .../Webhooks/utils/buildSubscription.ts | 22 +++++-------------- .../src/components/pages/evaluations/utils.ts | 16 ++++++++++++++ .../pages/settings/Organization/index.tsx | 6 +---- .../state/newObservability/atoms/controls.ts | 3 ++- 7 files changed, 33 insertions(+), 37 deletions(-) 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/components/views/OverviewView/hooks/useRunMetricData.ts b/web/oss/src/components/EvalRunDetails/components/views/OverviewView/hooks/useRunMetricData.ts index bf46815a38..cf91cb2b4f 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 @@ -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" @@ -114,7 +115,7 @@ export interface RunMetricSelectionEntry { runId: string index: number runKey: string - selection: ReturnType + selection: RunLevelMetricSelection }[] } diff --git a/web/oss/src/components/Webhooks/utils/buildPreviewRequest.ts b/web/oss/src/components/Webhooks/utils/buildPreviewRequest.ts index 4b5c1465c7..ab5f77206e 100644 --- a/web/oss/src/components/Webhooks/utils/buildPreviewRequest.ts +++ b/web/oss/src/components/Webhooks/utils/buildPreviewRequest.ts @@ -173,18 +173,6 @@ export const buildPreviewRequest = ( formValues: WebhookFormValues, ctx?: PreviewContext, ): PreviewRequest => { - const { - provider, - url, - auth_mode, - auth_value, - github_sub_type, - github_repo, - github_pat, - github_workflow, - github_branch, - } = formValues - // Form stores headers as header_list (array of {key, value}), convert to Record const headerList = (formValues as any).header_list as {key: string; value: string}[] | undefined const customHeaders: Record = {} @@ -211,7 +199,8 @@ export const buildPreviewRequest = ( ...authHeader, }) - if (provider === "webhook") { + if (formValues.provider === "webhook") { + const {url, auth_mode, auth_value} = formValues const previewHeaders: Record = buildSystemHeaders( auth_mode === "authorization" ? { @@ -233,7 +222,9 @@ export const buildPreviewRequest = ( headers: finalHeaders, body: eventContext, } - } else if (provider === "github") { + } else if (formValues.provider === "github") { + const {github_sub_type, github_repo, github_pat, github_workflow, github_branch} = + formValues const subType = github_sub_type || "repository_dispatch" const repo = github_repo || "/" let finalUrl = GITHUB_URL_TEMPLATES[subType].replace("{repo}", repo) diff --git a/web/oss/src/components/Webhooks/utils/buildSubscription.ts b/web/oss/src/components/Webhooks/utils/buildSubscription.ts index 73cd543e92..efd29fa8c8 100644 --- a/web/oss/src/components/Webhooks/utils/buildSubscription.ts +++ b/web/oss/src/components/Webhooks/utils/buildSubscription.ts @@ -14,20 +14,7 @@ export const buildSubscription = ( isEdit: boolean, subscriptionId?: string, ): WebhookSubscriptionCreateRequest | WebhookSubscriptionEditRequest => { - const { - provider, - name, - event_types, - url, - headers, - auth_mode, - auth_value, - github_sub_type, - github_repo, - github_pat, - github_workflow, - github_branch, - } = formValues + const {provider, name, event_types} = formValues // Common data const baseSubscription = { @@ -35,7 +22,8 @@ export const buildSubscription = ( ...(isEdit && {id: subscriptionId}), } - if (provider === "webhook") { + if (formValues.provider === "webhook") { + const {url, headers, auth_mode, auth_value} = formValues const subscription: WebhookSubscriptionCreateRequest["subscription"] = { ...baseSubscription, data: { @@ -52,7 +40,9 @@ export const buildSubscription = ( } return {subscription} - } else if (provider === "github") { + } else if (formValues.provider === "github") { + const {github_sub_type, github_repo, github_pat, github_workflow, github_branch} = + formValues const subType = github_sub_type || "repository_dispatch" const repo = github_repo || "" let finalUrl = GITHUB_URL_TEMPLATES[subType].replace("{repo}", repo) diff --git a/web/oss/src/components/pages/evaluations/utils.ts b/web/oss/src/components/pages/evaluations/utils.ts index e2b2b34254..914ae9d999 100644 --- a/web/oss/src/components/pages/evaluations/utils.ts +++ b/web/oss/src/components/pages/evaluations/utils.ts @@ -18,6 +18,7 @@ const parseInvocationMetadata = ( appId?: string appName?: string revisionId?: string + variantId?: string variantName?: string revisionLabel?: string | number } | null => { @@ -83,6 +84,13 @@ const parseInvocationMetadata = ( invocationStep.key, ) + const rawVariantId = pickString( + variantRef?.variantId, + variantRef?.variant_id, + applicationRevision?.variantId, + applicationRevision?.variant_id, + ) + const rawRevisionId = pickString( variantRef?.id, variantRef?.revisionId, @@ -108,6 +116,7 @@ const parseInvocationMetadata = ( appId: rawAppId, appName: rawAppName, revisionId: rawRevisionId, + variantId: rawVariantId, variantName: rawVariantName, revisionLabel: revisionLabel ?? undefined, } @@ -119,6 +128,7 @@ export const extractPrimaryInvocation = ( appId?: string appName?: string revisionId?: string + variantId?: string variantName?: string revisionLabel?: string | number } | null => { @@ -141,6 +151,11 @@ export const extractPrimaryInvocation = ( (variant as any)?.id || (typeof variant?.revisionId === "string" ? variant.revisionId : undefined) || (typeof variant?.revision_id === "string" ? variant.revision_id : undefined), + variantId: + (typeof variant?.variantId === "string" ? variant.variantId : undefined) || + (typeof (variant as any)?.variant_id === "string" + ? (variant as any).variant_id + : undefined), variantName: variant?.variantName || variant?.name || (variant as any)?.slug, revisionLabel: (variant as any)?.revisionLabel || @@ -153,6 +168,7 @@ export const extractPrimaryInvocation = ( appId: metadataFromSteps?.appId ?? variantDetails?.appId, appName: metadataFromSteps?.appName ?? variantDetails?.appName, revisionId: variantDetails?.revisionId ?? metadataFromSteps?.revisionId, + variantId: variantDetails?.variantId ?? metadataFromSteps?.variantId, variantName: variantDetails?.variantName ?? metadataFromSteps?.variantName, revisionLabel: variantDetails?.revisionLabel ?? metadataFromSteps?.revisionLabel, } diff --git a/web/oss/src/components/pages/settings/Organization/index.tsx b/web/oss/src/components/pages/settings/Organization/index.tsx index b467ab7ee9..660e2a6c0c 100644 --- a/web/oss/src/components/pages/settings/Organization/index.tsx +++ b/web/oss/src/components/pages/settings/Organization/index.tsx @@ -150,7 +150,7 @@ const Organization: FC = () => { const updated = await updateOrganization(selectedOrg.id, payload, ignoreAxiosError) if (updated) { queryClient.setQueryData(["selectedOrg", selectedOrg.id], updated) - queryClient.setQueriesData(["orgs"], (old: any) => { + queryClient.setQueriesData({queryKey: ["orgs"]}, (old: any) => { if (!Array.isArray(old)) return old return old.map((org) => org.id === updated.id ? {...org, ...updated} : org, @@ -362,7 +362,6 @@ const Organization: FC = () => { onError: (error: any) => { message.error(error?.response?.data?.detail || "Failed to add SSO provider") }, - useErrorBoundary: false, throwOnError: false, }) @@ -379,7 +378,6 @@ const Organization: FC = () => { onError: (error: any) => { message.error(error?.response?.data?.detail || "Failed to update SSO provider") }, - useErrorBoundary: false, throwOnError: false, }) @@ -392,7 +390,6 @@ const Organization: FC = () => { onError: (error: any) => { message.error(error?.response?.data?.detail || "SSO provider connection test failed") }, - useErrorBoundary: false, throwOnError: false, }) @@ -405,7 +402,6 @@ const Organization: FC = () => { onError: (error: any) => { message.error(error?.response?.data?.detail || "Failed to delete SSO provider") }, - useErrorBoundary: false, throwOnError: false, }) diff --git a/web/oss/src/state/newObservability/atoms/controls.ts b/web/oss/src/state/newObservability/atoms/controls.ts index a300751a51..dbf32169ee 100644 --- a/web/oss/src/state/newObservability/atoms/controls.ts +++ b/web/oss/src/state/newObservability/atoms/controls.ts @@ -382,7 +382,8 @@ export const filtersAtomFamily = atomFamily((tab: ObservabilityTabInfo) => // Proxy filters atom export const filtersAtom = atom( (get) => get(filtersAtomFamily(get(observabilityTabAtom))), - (get, set, update: Filter[]) => set(filtersAtomFamily(get(observabilityTabAtom)), update), + (get, set, update: Filter[] | ((prev: Filter[]) => Filter[])) => + set(filtersAtomFamily(get(observabilityTabAtom)), update), ) // Table/UI controls ----------------------------------------------------------- From aacba410b3f77d4cdd96737836ad2c0a6aec44e0 Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Wed, 22 Jul 2026 03:14:47 +0200 Subject: [PATCH 04/13] chore(frontend): add tsc error inventory --- web/tsc-error-inventory.md | 160 +++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 web/tsc-error-inventory.md diff --git a/web/tsc-error-inventory.md b/web/tsc-error-inventory.md new file mode 100644 index 0000000000..0360b2a0c7 --- /dev/null +++ b/web/tsc-error-inventory.md @@ -0,0 +1,160 @@ +# TSC Error Inventory — OSS + EE apps + +Generated 2026-07-22 from `pnpm --filter @agenta/oss exec tsc --noEmit` and +`pnpm --filter @agenta/ee exec tsc --noEmit` (worktree `upbeat-shannon-c6fee8`, clean tree). + +## Headline numbers + +| App | Baseline | After quick-win pass (2026-07-22) | +| --- | --- | --- | +| OSS | 591 | **422** | +| EE | 525 | **391** | + +Quick wins QW1–QW3 and QW5–QW10 are DONE (QW4 TraceSpanNode deferred — see below). +Fixing exports also *surfaced* some previously-masked drift (broken imports resolve as +error-types that suppress downstream checks), so the net is smaller than the sum of +cluster sizes; the surfaced errors are real and belong to the medium clusters. + +| App | Errors (baseline) | Notes | +| --- | --- | --- | +| OSS | **591** | 532 in `src/`, 56 in `tests/`, 3 elsewhere | +| EE | **525** | **485 of these are shared `../oss/src` files** — duplicates of OSS errors | +| EE-only (files under `ee/src` + ee test fixtures) | **~40** | Billing page is the main hotspot | + +**Effective unique universe ≈ 630 errors.** Fixing an OSS-side error usually removes it +from both columns, so all prioritization below is done on the OSS list. + +## By error code (OSS) + +| Code | Count | Meaning | +| --- | --- | --- | +| TS2339 | 150 | Property does not exist on type | +| TS2322 | 123 | Type not assignable | +| TS2345 | 88 | Bad argument type | +| TS7006 | 47 | Implicit `any` parameter | +| TS2353 | 27 | Unknown property in object literal | +| TS2307 | 19 | Cannot find module | +| TS18046 | 18 | Value is of type `unknown` | +| TS2554/2769/2344/2304/2305 | ~50 | Arity, overload, constraint, missing name/export | +| rest | ~70 | long tail | + +## Hotspot directories (OSS) + +| Directory | Errors | +| --- | --- | +| `src/components/EvalRunDetails` | 190 | +| `src/components/pages` (observability, settings, overview, evaluations) | 78 | +| `src/components/SharedDrawers` | 53 | +| `tests/` (playwright + manual) | 56 | +| `src/components/Webhooks` | 18 | +| `src/components/Playground` | 17 | +| `src/components/EvaluationRunsTablePOC` | 16 | + +--- + +## Quick wins (one fix → many errors) + +Ordered by errors-killed-per-unit-of-work. The first two are config/dep-level and kill ~80 +errors across both apps without touching product code. + +### QW1 — Exclude/delete stale `tests/manual/datalayer` scripts (~25 errors) +`oss/tests/manual/datalayer/test-apps.ts` (18 errs) and `test-observability.ts` (6 errs) +import modules that no longer exist (`src/state/newApps/*`, `src/state/app/atoms/fetcher`, +`src/state/newObservability/atoms/queries` — verified gone). These are dead manual scripts. +**Fix:** delete them, or add `tests/manual` to `oss/tsconfig.json` `exclude`. + +### QW2 — `@playwright/test` unresolvable from OSS tsconfig (~9 direct + cascade) +`oss/tsconfig.json` includes `**/*.ts`, which pulls in `oss/tests/playwright/**`, but +`@playwright/test` is only a dependency of the `tests` workspace, not `@agenta/oss`. +Every playwright file then also produces downstream TS7006/TS2304 noise (~31 errors total +in `tests/playwright`). **Fix (choose one):** exclude `tests` from the app tsconfig (the +`tests` workspace has its own), or add `@playwright/test` as an OSS devDependency. + +### QW3 — `RunLevelMetricSelection` atom vs value mixup (~27 errors) +`EvalRunDetails/components/views/OverviewView/*` (BaseRunMetricsSection, +MetadataSummaryTable, OverviewSpiderChart, OverviewMetricComparison, useRunMetricData) +access `.stats`/`.state` directly on `Atom` — the selection is +passed around as an atom in the type but consumed as a plain value (or vice versa). +One type/unwrap decision in the shared hook/atom kills all 27. + +### QW4 — Duplicate `TraceSpanNode` type (16 errors) — DEFERRED, not actually quick +Two incompatible `TraceSpanNode` definitions coexist: +`packages/agenta-entities/src/trace/core/schema` vs `oss/src/services/tracing/types`. +Investigation showed the divergence runs through the whole `TraceSpan` base: OSS uses TS +enums (`TraceType.INVOCATION`) where entities uses zod string-literal unions, and entities +is `| null` everywhere OSS is `undefined`-only. Aliasing the OSS type to the entities type +would break every `=== TraceType.X` comparison (TS2367) in OSS consumers. Needs a focused +boundary refactor: re-export entities types from `oss/src/services/tracing/types`, replace +OSS enum value-usages with the entities enum objects (`TraceTypeEnum.enum.invocation`) or +plain literals, then delete the local interfaces. + +### QW5 — `WebhookFormValues` missing fields (~16 errors) +`Webhooks/utils/buildSubscription.ts` + `buildPreviewRequest.ts` read 8 properties +(`url`, `auth_mode`, `auth_value`, `github_pat`, `github_repo`, `github_branch`, +`github_workflow`, `github_sub_type`) that aren't on `WebhookFormValues`. Adding the +fields to the interface (they're clearly real form fields) clears all of them. + +### QW6 — `setFilters` doesn't accept an updater function (~16 errors) +`ObservabilityHeader/index.tsx` calls `setFilters((prev) => …)` 4× but the setter is +typed `(filters: Filter[]) => void`. Each call site yields 1× TS2345 + 2–3× TS7006. +**Fix:** widen the setter type to `SetStateAction` (it's almost certainly a +jotai/useState-backed setter) — one signature change kills 16. + +### QW7 — react-query v5 leftovers in Organization settings (~6 errors) +`pages/settings/Organization/index.tsx`: 4× `useErrorBoundary` (renamed to +`throwOnError` in v5) + `string[]` passed where `QueryFilters` expected. Mechanical +v4→v5 migration of one file (13 errors in the file total). + +### QW8 — Missing exports, 4 symbols (~16 errors) +- `MetricColumnDefinition` not exported from `EvalRunDetails/atoms/table` (4 errs) +- `Parameter` and `_EvaluationScenario` gone from `@/oss/lib/Types` (4 errs) +- `GenerationChatRow`/`GenerationInputRow` not exported from Playground state types (4 errs, tests) +- `TooltipButtonProps` / `statusMap` default-vs-named export confusion (2 errs) +Each is a one-line export (or an import-style fix at the call sites). + +### QW9 — URL params type missing `variantId` (~9 errors) +`References/cells/*`, `EvaluationRunsTablePOC/export/referenceResolvers.ts` read +`variantId` off a URL-params object typed without it (`appId/revisionId/variantName/…`). +One field added to the params type in `src/state/url` clears 9. + +### QW10 — `PreviewTableRow` doesn't satisfy `InfiniteTableRowBase` (~11 errors) +6× TS2344 + 5× TS2322 in EvalRunDetails table/query atoms trace to one constraint +mismatch. Fix the row type once (likely a missing `id`/index-signature member). + +**Quick-win subtotal: ~150 of 591 OSS errors (and their ~120 EE duplicates) from ~10 targeted fixes.** + +--- + +## Medium-effort clusters (real code drift, needs a bit of thought) + +- **EvalRunDetails remainder (~100 errs after QW3/8/10):** the largest concentration; + `Table.tsx`, `FocusDrawer(+Header)`, `EvaluatorMetricsChart/BarChart`, `ScenarioNavigator`, + `ConfigurationView/EvaluatorSection`, `atoms/query.ts`, `runMetrics.ts`. Mix of + TS2339/TS2322 from evolving run/metric entity types. Best attacked per-file after the + atom-level quick wins land, since many will collapse. +- **SharedDrawers remainder (~35 errs after QW4):** AnnotateDrawer transforms treat JSON + schema values as `{}` (`.type`, `.anyOf` on `{}` — needs a proper JSONSchema type); + AddToTestsetDrawer drawer-state typing; tracing store `discard` API drift. +- **Observability pages (~35 errs after QW6):** `getObservabilityColumns`, tracing + selectors, `usePostAuthRedirect` (7 errs — `unknown`-typed org/app data, TS18046 + cluster: `result`/`compatibleOrgs`/`appsData` need typed fetchers). +- **`state/url/playground.ts` (7)** + **`newObservability/selectors/tracing.ts` (7)**. +- **EE Billing (`ee/src/.../settings/Billing/index.tsx`, 7 + modal 1):** the only + EE-app hotspot. + +## Long tail / mechanical sweeps + +- **TS7006 implicit `any` (47):** parameter annotations; many disappear with QW2/QW6. +- **TS2322 `string | undefined` → `string` (11):** add guards/defaults at call sites. +- **TS18046 `unknown` (18):** type the fetch/query results instead of casting. +- **EE test fixtures (~25 errs):** `oss/tests/playwright/acceptance/*` + `tests/tests/fixtures` + — same root cause as QW2 (test workspace types leaking into app tsconfig). + +## Suggested attack order + +1. QW1 + QW2 (config only, −80 errors, zero product risk) +2. QW3–QW10 (−~130 more, each an isolated PR-able fix) +3. Re-run tsc, re-inventory EvalRunDetails — expect it to shrink well below 100 +4. Then the per-file medium clusters, EvalRunDetails first (biggest, and shared with EE) + +Raw outputs preserved at scratchpad `tsc-oss.txt` / `tsc-ee.txt` for this session. From e9a6022e5603ba637e33add4dd28da5b35d74a24 Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Wed, 22 Jul 2026 11:52:32 +0200 Subject: [PATCH 05/13] fix(frontend): type-check EvalRunDetails layer; oss tsc 422->347 Mirrors the vetted WP-4e-2a in-place fixes from fe-chore/move-evals-to-packages (adapted to OSS import paths) plus new fixes for the component layer: - restore PreviewTestCase to lib/Types; re-export MetricProcessor/MetricScope - add "input" to EvaluationColumnKind (backend mapping emits it) and type the visibility-label column extension in buildPreviewColumns - recharts v3 API drift in EvaluatorMetricsChart (TooltipContentProps, tuple radius, MetricStripEntry contextual typing) - widen evaluationType to EvaluationRunKind; type query atoms as nullable - latent runtime bugs typed as-is per WP-4e-2a convention (applyAggregatesToRaw, metricProcessor ReferenceErrors, dead metric-group branches) - flagged, not fixed --- .../EvalRunDetails/atoms/metricProcessor.ts | 6 +++- .../EvalRunDetails/atoms/metrics.ts | 10 ++++++ .../components/EvalRunDetails/atoms/query.ts | 12 +++---- .../EvalRunDetails/atoms/runMetrics.ts | 23 ++++++++++--- .../EvalRunDetails/atoms/runMetrics/types.ts | 2 ++ .../atoms/scenarioColumnValues.ts | 3 +- .../EvalRunDetails/atoms/table/columns.ts | 2 +- .../EvalRunDetails/atoms/table/types.ts | 1 + .../components/EvalRunDetails/atoms/traces.ts | 6 +++- .../components/EvalRunDetails/atoms/types.ts | 32 +++++++++++++++++++ .../EvalRunDetails/atoms/variantConfig.ts | 2 +- .../EvaluatorMetricsChart/BarChart.tsx | 10 +++--- .../EvaluatorMetricsChart/index.tsx | 16 ++++++---- .../EvalRunDetails/components/FocusDrawer.tsx | 8 +++-- .../components/EvaluatorSection.tsx | 4 ++- .../hooks/usePreviewTableData.ts | 5 ++- .../utils/buildPreviewColumns.tsx | 9 ++++-- .../utils/buildSkeletonColumns.ts | 15 ++++++--- .../utils/renderChatMessages.tsx | 14 +++++--- web/oss/src/lib/Types.ts | 12 +++++++ .../lib/hooks/usePreviewEvaluations/types.ts | 2 ++ web/oss/src/lib/traces/traceUtils.ts | 2 +- 22 files changed, 152 insertions(+), 44 deletions(-) create mode 100644 web/oss/src/components/EvalRunDetails/atoms/types.ts diff --git a/web/oss/src/components/EvalRunDetails/atoms/metricProcessor.ts b/web/oss/src/components/EvalRunDetails/atoms/metricProcessor.ts index dd8cb0d8f1..7c68ccafff 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/metricProcessor.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/metricProcessor.ts @@ -1,6 +1,8 @@ import axios from "@/oss/lib/api/assets/axiosConfig" import {canonicalizeMetricKey} from "@/oss/lib/metricUtils" +import type {EvaluationRunKind} from "../../EvaluationRunsTablePOC/types" + import {wasScenarioRecentlySaved} from "./metrics" import { MetricProcessor, @@ -14,6 +16,8 @@ import { ScenarioRefreshDetailResult, } from "./runMetrics/types" +export type {MetricProcessor, MetricScope} from "./runMetrics/types" + // Debug logger that only logs in development environments const isDev = process.env.NODE_ENV === "development" const metricProcessorDebug = { @@ -143,7 +147,7 @@ export const createMetricProcessor = ({ source, evaluationType, }: MetricProcessorOptions & { - evaluationType?: "auto" | "human" | "online" | null + evaluationType?: EvaluationRunKind | null }): MetricProcessor => { const state: MetricProcessorState = { pending: [], 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/table/columns.ts b/web/oss/src/components/EvalRunDetails/atoms/table/columns.ts index 189984e503..b9e1e26f68 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` diff --git a/web/oss/src/components/EvalRunDetails/atoms/table/types.ts b/web/oss/src/components/EvalRunDetails/atoms/table/types.ts index 62d4729cbd..63ae8d9509 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/table/types.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/table/types.ts @@ -6,6 +6,7 @@ export type EvaluationColumnKind = | "meta" | "testset" | "query" + | "input" | "invocation" | "annotation" | "evaluator" diff --git a/web/oss/src/components/EvalRunDetails/atoms/traces.ts b/web/oss/src/components/EvalRunDetails/atoms/traces.ts index 9cab74d56b..08e8e1fb8f 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/traces.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/traces.ts @@ -167,7 +167,11 @@ const buildTraceDataFromEntry = ( 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/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..0f462e1472 100644 --- a/web/oss/src/components/EvalRunDetails/components/FocusDrawer.tsx +++ b/web/oss/src/components/EvalRunDetails/components/FocusDrawer.tsx @@ -177,7 +177,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 { @@ -1344,7 +1346,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/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/hooks/usePreviewTableData.ts b/web/oss/src/components/EvalRunDetails/hooks/usePreviewTableData.ts index 69329939ef..7c8eeca344 100644 --- a/web/oss/src/components/EvalRunDetails/hooks/usePreviewTableData.ts +++ b/web/oss/src/components/EvalRunDetails/hooks/usePreviewTableData.ts @@ -11,7 +11,10 @@ import type {EvaluationTableColumnsResult} from "../atoms/table" export interface PreviewTableData { columnResult?: EvaluationTableColumnsResult - columnsPending: boolean + // 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..68229c1ff5 100644 --- a/web/oss/src/components/EvalRunDetails/utils/buildPreviewColumns.tsx +++ b/web/oss/src/components/EvalRunDetails/utils/buildPreviewColumns.tsx @@ -119,6 +119,9 @@ export interface BuildPreviewColumnsResult { columns: ColumnsType } +/** antd column extended with the visibility-menu label consumed by useColumnVisibility */ +type VisibilityColumn = ColumnsType[number] & {columnVisibilityLabel?: string} + const createStaticMetricColumns = ( groupId: string, metrics: MetricColumnDefinition[], @@ -126,7 +129,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 +248,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 +457,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/lib/Types.ts b/web/oss/src/lib/Types.ts index 89a1be25d1..ecb50ffe8c 100644 --- a/web/oss/src/lib/Types.ts +++ b/web/oss/src/lib/Types.ts @@ -68,6 +68,18 @@ export interface Testset { columns?: string[] } +export interface PreviewTestCase { + created_at: string + created_by_id: string + + id: string + set_id: string + testset_id: string + data: Record + /** Legacy testcases carry inputs instead of data */ + inputs?: Record +} + export interface PreviewTestset { id: string name: string diff --git a/web/oss/src/lib/hooks/usePreviewEvaluations/types.ts b/web/oss/src/lib/hooks/usePreviewEvaluations/types.ts index f2877f3865..2a56892fc3 100644 --- a/web/oss/src/lib/hooks/usePreviewEvaluations/types.ts +++ b/web/oss/src/lib/hooks/usePreviewEvaluations/types.ts @@ -46,6 +46,8 @@ export interface EvaluationRun { description: string /** ISO timestamp of when the run was created */ created_at: string + /** ISO timestamp of when the run was last updated (present on backend run payloads) */ + updated_at?: string /** ID of the user who created the run */ created_by_id: string /** Optional metadata object (arbitrary key-value pairs) */ diff --git a/web/oss/src/lib/traces/traceUtils.ts b/web/oss/src/lib/traces/traceUtils.ts index c4f94544e2..33a2f3ee2f 100644 --- a/web/oss/src/lib/traces/traceUtils.ts +++ b/web/oss/src/lib/traces/traceUtils.ts @@ -136,7 +136,7 @@ export function readInvocationResponse({ } const resolvedCandidates = Array.from( - new Set(candidatePaths.filter((p): p is string => typeof p === "string" && p.length)), + new Set(candidatePaths.filter((p): p is string => typeof p === "string" && p.length > 0)), ) const resolvedPath = resolvedCandidates[0] // --- END PATH RESOLUTION LOGIC --- From 61a0aeedf801bad0e4ef6011b06c164ae7ea8e2e Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Wed, 22 Jul 2026 13:27:57 +0200 Subject: [PATCH 06/13] fix(entities,entity-ui): updater-style refresh atom and optional variant id - createPaginatedEntityStore: refreshAtom/actions.refresh accept an optional value or updater (bare set() still bumps the counter) - clears the 'Expected 0 arguments' cluster across testset modals and other consumers - EnvironmentStatus: variant.id optional; the component already guards it --- .../src/shared/paginated/createPaginatedEntityStore.ts | 10 +++++----- .../src/variant/components/EnvironmentStatus.tsx | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/web/packages/agenta-entities/src/shared/paginated/createPaginatedEntityStore.ts b/web/packages/agenta-entities/src/shared/paginated/createPaginatedEntityStore.ts index 6d8cca2c68..0887813a3b 100644 --- a/web/packages/agenta-entities/src/shared/paginated/createPaginatedEntityStore.ts +++ b/web/packages/agenta-entities/src/shared/paginated/createPaginatedEntityStore.ts @@ -253,7 +253,7 @@ export interface PaginatedEntityStore< * * @deprecated Use `actions.refresh` instead for consistency */ - refreshAtom: WritableAtom + refreshAtom: WritableAtom number)], void> /** * Meta atom providing the query parameters. @@ -309,7 +309,7 @@ export interface PaginatedEntityStore< /** * Refresh the paginated data */ - refresh: WritableAtom + refresh: WritableAtom number)], void> } /** @@ -390,11 +390,11 @@ export function createPaginatedEntityStore< excludeRowIdsAtom, }) - // Create writable refresh atom + // Create writable refresh atom (setState-style value/updater optional; bare set() bumps the counter) const refreshAtom = atom( (get) => get(internalRefreshAtom), - (_get, set) => { - set(internalRefreshAtom, (prev) => prev + 1) + (_get, set, next?: number | ((prev: number) => number)) => { + set(internalRefreshAtom, next ?? ((prev: number) => prev + 1)) }, ) diff --git a/web/packages/agenta-entity-ui/src/variant/components/EnvironmentStatus.tsx b/web/packages/agenta-entity-ui/src/variant/components/EnvironmentStatus.tsx index a6d3bb10c9..212ac75f01 100644 --- a/web/packages/agenta-entity-ui/src/variant/components/EnvironmentStatus.tsx +++ b/web/packages/agenta-entity-ui/src/variant/components/EnvironmentStatus.tsx @@ -14,7 +14,8 @@ export const statusMap: Record = { } const EnvironmentStatus: FC<{ - variant: Pick + /** `id` is optional — without it the revision-deployment fallback lookup is skipped */ + variant: Pick & Partial> className?: string }> = ({variant, className}) => { // Fallback to environment entity if deployedIn is not embedded on the variant From 9a882d7ad503cabcc0d65a35b7ac435607279a2d Mon Sep 17 00:00:00 2001 From: Arda Erzin Date: Wed, 22 Jul 2026 13:32:46 +0200 Subject: [PATCH 07/13] fix(frontend): type-check observability, drawers, playground, onboarding layers; oss tsc 347->105 Parallel per-area pass, behavior-preserving throughout (latent runtime bugs are typed as-is with NOTE comments per the WP-4e-2a convention, not silently fixed): - TraceSpanNode OSS<->entities dual-type: aligned at every crossing with documented boundary casts (16 errors -> 0); annotations field added to the OSS node (drawer stores attach it at runtime) - SharedDrawers: broken SessionDrawerButton imports repaired, JSON-schema access typed, null-safety in SelectEvaluators/AnnotateDrawer, drawer payload/ref/label types aligned with runtime - observability: extended-column types for custom antd props, TraceRow/ SessionRow InfiniteTableRowBase conformance, traceTabsAtom updater support, ag-attributes selector typing at the producer - playground/url-state: removed drifted local duplicates of package types, eagerAtom->atom where deps are sync, modal/store prop alignment - onboarding/testsets/org: updater-widened widget UI atom, tour placement vocabulary fix, OnboardingLoader next/dynamic compat, org provider API types matched to the backend wire shape (settings/flags dicts) - EvalRunDetails remainder: WP-4e-2a-vetted atom fixes adapted, recharts v3 formatter/content signatures, stale import paths repointed Flagged for triage (typed as-is): AddToTestsetDrawer trace draft discard/ update call missing molecule actions; orphaned SessionDrawerButton --- .../src/components/EvalRunDetails/Table.tsx | 8 +-- .../EvalRunDetails/atoms/metricProcessor.ts | 6 ++- .../EvalRunDetails/atoms/scenarioSteps.ts | 2 +- .../atoms/table/columnAccess.ts | 2 +- .../EvalRunDetails/atoms/table/columns.ts | 2 +- .../EvalRunDetails/atoms/table/run.ts | 14 +++-- .../EvalRunDetails/atoms/table/scenarios.ts | 4 +- .../EvalRunDetails/atoms/table/testcases.ts | 4 +- .../components/EvalRunDetails/atoms/traces.ts | 6 ++- .../components/CompareRunsMenu.tsx | 2 +- .../drawerPayload.ts | 2 + .../EvalRunDetails/components/FocusDrawer.tsx | 5 +- .../components/TableCells/MetricCell.tsx | 2 +- .../ColumnVisibilityPopoverContent.tsx | 2 +- .../components/ContextChipList.tsx | 8 ++- .../components/InvocationSection.tsx | 10 ++-- .../views/ConfigurationView/utils.ts | 6 ++- .../components/BaseRunMetricsSection.tsx | 2 +- .../EvaluatorTemporalMetricsChart.tsx | 4 +- .../components/MetadataSummaryTable.tsx | 14 ++--- .../components/MetricComparisonCard.tsx | 2 +- .../components/OverviewPlaceholders.tsx | 6 +-- .../OverviewView/hooks/useRunMetricData.ts | 7 ++- .../OverviewView/utils/evaluatorMetrics.ts | 9 ++-- .../useAnnotationState.ts | 5 +- .../views/SingleScenarioViewerPOC/types.ts | 3 +- .../hooks/usePreviewTableData.ts | 3 +- .../EvaluationRunsTablePOC/atoms/view.ts | 8 ++- .../components/EvaluationRunsDeleteButton.tsx | 4 +- .../export/referenceResolvers.ts | 2 +- .../components/EvaluationRunsTable/index.tsx | 7 ++- .../components/cells/RunMetricCell/index.tsx | 3 +- .../filters/EvaluationRunsHeaderFilters.tsx | 6 ++- .../EvaluationRunsTablePOC/types.ts | 6 ++- .../Onboarding/tours/evaluationResultsTour.ts | 4 +- .../Components/Menus/SelectVariant/index.tsx | 2 +- .../CreateVariantModal/assets/types.d.ts | 2 +- .../Modals/CreateVariantModal/index.tsx | 4 +- .../Modals/DeployVariantModal/types.d.ts | 10 ++-- .../drawerPayload.ts | 2 + .../PlaygroundVariantConfig/index.tsx | 2 +- .../TestsetPreviewPanelWrapper.tsx | 26 ++++----- .../Components/TestsetDropdown/index.tsx | 8 ++- .../Components/WebWorkerProvider/index.tsx | 3 +- .../src/components/Playground/Playground.tsx | 20 +++++-- .../PlaygroundLoadingShell.tsx | 2 + .../AddToTestsetDrawer/atoms/drawerState.ts | 17 +++--- .../components/DataPreviewEditor.tsx | 10 +++- .../hooks/useTestsetDrawer.ts | 4 +- .../assets/AnnotateDrawerTitle/index.tsx | 2 +- .../assets/SelectEvaluators/index.tsx | 18 ++++--- .../assets/hooks/useEvaluatorSchemas.ts | 4 +- .../AnnotateDrawer/assets/transforms.ts | 4 +- .../AnnotateDrawer/assets/types.d.ts | 4 +- .../components/SessionDrawerButton/index.tsx | 14 +++-- .../SessionDrawer/store/sessionDrawerStore.ts | 10 +++- .../components/AccordionTreePanel.tsx | 3 +- .../components/AnnotationTabItem/index.tsx | 6 ++- .../components/OverviewTabItem/index.tsx | 13 +++-- .../components/TraceTypeHeader/index.tsx | 8 ++- .../components/TraceHeader/index.tsx | 14 +++-- .../TraceSidePanel/TraceLinkedSpans/index.tsx | 3 +- .../TraceSidePanel/TraceReferences/index.tsx | 2 +- .../components/TraceTree/index.tsx | 3 +- .../SharedDrawers/TraceDrawer/index.tsx | 5 +- .../TraceDrawer/store/openInPlayground.ts | 8 ++- .../TraceDrawer/store/traceDrawerStore.ts | 10 ++-- .../PlaygroundOnboarding/OnboardingLoader.tsx | 3 +- .../components/FiltersPreview.tsx | 2 + .../assets/getObservabilityColumns.tsx | 22 ++++++-- .../observability/components/NodeNameCell.tsx | 2 +- .../components/ObservabilityHeader/index.tsx | 6 ++- .../components/ObservabilityTable/index.tsx | 9 ++-- .../assets/getSessionColumns.tsx | 11 +++- .../components/SessionsTable/index.tsx | 3 +- .../components/TimestampCell.tsx | 2 +- .../dashboard/CustomAreaChart.tsx | 2 +- .../overview/variants/VariantPopover.tsx | 2 +- web/oss/src/hooks/usePostAuthRedirect.ts | 2 +- .../hooks/useEvaluationRunMetrics/index.ts | 9 ++-- .../hooks/useEvaluationRunMetrics/types.ts | 43 ++++----------- .../lib/hooks/usePreviewEvaluations/index.ts | 42 +++++++++++---- web/oss/src/lib/onboarding/widget/store.ts | 8 ++- .../src/services/evaluationRuns/api/types.ts | 6 +++ .../src/services/organization/api/index.ts | 50 +++++++++-------- web/oss/src/services/tracing/types/index.ts | 2 + web/oss/src/services/workspace/index.ts | 9 ++-- web/oss/src/state/app/selectors/app.ts | 3 +- .../shared/createPaginatedEntityStore.ts | 10 ++-- .../state/newObservability/atoms/controls.ts | 3 +- .../state/newObservability/atoms/queries.ts | 2 +- .../newObservability/atoms/queryHelpers.ts | 10 +++- .../state/newObservability/helpers/index.ts | 3 ++ .../newObservability/selectors/tracing.ts | 45 +++++++++++++--- .../newPlayground/workflowEntityBridge.ts | 6 ++- web/oss/src/state/org/index.ts | 2 +- web/oss/src/state/url/auth.ts | 12 +++-- web/oss/src/state/url/focusDrawer.ts | 2 +- web/oss/src/state/url/index.ts | 6 +-- web/oss/src/state/url/playground.ts | 53 ++++++++----------- 100 files changed, 509 insertions(+), 306 deletions(-) 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, ) => ( 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 @@ -704,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/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 b9e1e26f68..fae571407a 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/table/columns.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/table/columns.ts @@ -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/traces.ts b/web/oss/src/components/EvalRunDetails/atoms/traces.ts index 08e8e1fb8f..447eda0662 100644 --- a/web/oss/src/components/EvalRunDetails/atoms/traces.ts +++ b/web/oss/src/components/EvalRunDetails/atoms/traces.ts @@ -160,7 +160,11 @@ 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[] = [] 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/FocusDrawer.tsx b/web/oss/src/components/EvalRunDetails/components/FocusDrawer.tsx index 0f462e1472..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]), ) @@ -455,7 +456,7 @@ const ScenarioColumnValue = memo( const formattedValue = typeof rawFormattedValue === "boolean" ? String(rawFormattedValue) - : rawFormattedValue + : (rawFormattedValue as ReactNode) const isPlaceholder = formattedValue === METRIC_EMPTY_PLACEHOLDER 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/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 cf91cb2b4f..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" @@ -27,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([]) 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 7c8eeca344..6263b12cc6 100644 --- a/web/oss/src/components/EvalRunDetails/hooks/usePreviewTableData.ts +++ b/web/oss/src/components/EvalRunDetails/hooks/usePreviewTableData.ts @@ -10,7 +10,8 @@ import { import type {EvaluationTableColumnsResult} from "../atoms/table" export interface PreviewTableData { - columnResult?: EvaluationTableColumnsResult + // 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. 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/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/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 f80b34b660..965f91c3f9 100644 --- a/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/types.d.ts +++ b/web/oss/src/components/SharedDrawers/AnnotateDrawer/assets/types.d.ts @@ -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[] 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} >