Skip to content

[refactor] The observability filter engine moves into @agenta/observability - #5956

Open
ardaerzin wants to merge 1 commit into
obs/wp1-observability-statefrom
obs/wp2-filter-engine
Open

[refactor] The observability filter engine moves into @agenta/observability#5956
ardaerzin wants to merge 1 commit into
obs/wp1-observability-statefrom
obs/wp2-filter-engine

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

Context

The filter logic behind the observability filter dialog decided which inputs to show, how to normalise a filter, and how to reconcile rows when trace_type changes. All of it sat inside a 1,983-line antd component in the app, so mobile could not filter traces without copying the rules.

Third of five stacked PRs. Base is obs/wp1-observability-state.

Changes

The engine moves to @agenta/observability/filters: planInputs, normalizeFilter, toUIValue, fieldConfigByOptionKey, getFilterColumns, reconcileFilterRows, the attribute-key tree builder and the export utilities. Unit tests come with them.

Field-menu icons stay out of the package. FILTER_COLUMNS is icon-free and getFilterColumns(attributeKeyOptions, icons) takes an icon map keyed by node label, so desktop can inject Phosphor and mobile can inject Lucide. The app's map lives in the new assets/filterColumnIcons.ts.

Two contracts worth knowing before you read the diff:

  • FilterValue is deliberately object, not Record<string, unknown>. Interfaces have no implicit index signature, so the stricter form rejects every named filter-value type.
  • reconcileFilterRows preserves array length and per-index order, because the dialog mutates its rows by index.

Tests / notes

  • @agenta/observability builds, lints and passes its unit tests, including 10 new ones covering reconcileFilterRows.
  • Verified in the browser that the field menu still renders all 14 top-level nodes with their icons after the icon map became host-injected.
  • Intermediate lanes in this stack may not build standalone. Only the tip is verified green.

@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Blocked Blocked Aug 12, 2026 12:17am

Request Review

@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. frontend refactoring A code change that neither fixes a bug nor adds a feature labels Aug 12, 2026
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added shared observability filter capabilities, including reusable filter menus, operators, value handling, and column configuration.
    • Added filter-column icons to improve visual navigation on desktop.
    • Filter rows now adapt to evaluator and application trace selections while preserving entered values and ordering.
  • Bug Fixes

    • Improved handling of missing filter values and reference-based filter selections.
  • Tests

    • Added coverage for filter switching, negated conditions, preserved rows, and value retention.

Walkthrough

The PR centralizes filter types, operators, codecs, adapters, column helpers, and row reconciliation in @agenta/observability. OSS consumers now use these exports, and observability columns can receive icons.

Changes

Filter API centralization

Layer / File(s) Summary
Shared filter contracts and exports
web/packages/agenta-observability/src/filters/*, web/packages/agenta-observability/src/etl/exportUtils.ts
Adds shared filter-menu types, operator sets, public barrel exports, and package-local imports.
Typed filter processing and columns
web/packages/agenta-observability/src/filters/fieldAdapter.ts, web/packages/agenta-observability/src/filters/valueCodec.ts, web/packages/agenta-observability/src/filters/getFilterColumns.ts
Replaces any-based filter fields and callbacks with shared types. Adds optional recursive column icon assignment.
Evaluator row reconciliation
web/packages/agenta-observability/src/filters/reconcileFilterRows.ts, web/packages/agenta-observability/tests/unit/reconcileFilterRows.test.ts
Adds trace-type-based reconciliation for permanent reference rows and tests workflow, operator, reference, ordering, and value handling.
OSS consumer migration and icons
web/oss/src/components/Filters/*, web/oss/src/components/pages/evaluations/onlineEvaluation/*, web/oss/src/components/pages/observability/assets/*
Updates OSS imports to shared observability and UI exports. Adds filter-column icons and normalizes missing filter values to an empty string.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Mergeability Score: 🔵 Low · up to 0baad

Multi-value trace-type filters can cause the dialog to reconcile rows incorrectly and show the wrong filter state. The change is otherwise bounded, but this edge case should be fixed and the required frontend formatting check completed before merge.

Sequence Diagram(s)

sequenceDiagram
  participant FilterUI
  participant ObservabilityFilters
  participant FieldConfigMap
  FilterUI->>ObservabilityFilters: submit filter rows and trace_type
  ObservabilityFilters->>FieldConfigMap: resolve evaluator or application field
  FieldConfigMap-->>ObservabilityFilters: matching field metadata
  ObservabilityFilters-->>FilterUI: reconciled filter rows
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: moving the observability filter engine into @agenta/observability.
Description check ✅ Passed The description directly explains the filter engine migration, exported APIs, host-injected icons, and related tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch obs/wp2-filter-engine

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@dosubot dosubot Bot added the tests label Aug 12, 2026
@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
web/oss/src/components/Filters/types.d.ts (1)

15-16: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reduce this comment to one short line.

Lines 15-16 add a two-line comment for a direct type re-export. Replace it with one short line or remove it.

Proposed change
-// The filter-menu model belongs to the observability filter engine; re-exported
-// here (type-only, so nothing lands in the bundle) for the app's existing callers.
+// Re-export observability filter types for existing callers.

As per coding guidelines, “Keep in-code comments to at most one short line; use longer comments only for genuinely surprising constraints such as bugs, races, or ordering requirements.”

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 4b4bf8c8-bd47-41f5-b4a4-8167abfbb607

📥 Commits

Reviewing files that changed from the base of the PR and between 6b4cc1b and 0baadf7.

📒 Files selected for processing (22)
  • web/oss/src/components/Filters/Filters.tsx
  • web/oss/src/components/Filters/helpers/utils.ts
  • web/oss/src/components/Filters/types.d.ts
  • web/oss/src/components/pages/evaluations/onlineEvaluation/EmptyStateOnlineEvaluation/EmptyStateOnlineEvaluation.tsx
  • web/oss/src/components/pages/evaluations/onlineEvaluation/OnlineEvaluationDrawer.tsx
  • web/oss/src/components/pages/evaluations/onlineEvaluation/assets/helpers.ts
  • web/oss/src/components/pages/evaluations/onlineEvaluation/components/FiltersPreview.tsx
  • web/oss/src/components/pages/observability/assets/filterColumnIcons.ts
  • web/oss/src/components/pages/observability/assets/utils.ts
  • web/packages/agenta-observability/src/etl/exportUtils.ts
  • web/packages/agenta-observability/src/filters/attributeKeyOptions.ts
  • web/packages/agenta-observability/src/filters/fieldAdapter.ts
  • web/packages/agenta-observability/src/filters/getFilterColumns.ts
  • web/packages/agenta-observability/src/filters/index.ts
  • web/packages/agenta-observability/src/filters/operatorRegistry.ts
  • web/packages/agenta-observability/src/filters/operatorSets.ts
  • web/packages/agenta-observability/src/filters/reconcileFilterRows.ts
  • web/packages/agenta-observability/src/filters/referenceUtils.ts
  • web/packages/agenta-observability/src/filters/rulesEngine.ts
  • web/packages/agenta-observability/src/filters/types.ts
  • web/packages/agenta-observability/src/filters/valueCodec.ts
  • web/packages/agenta-observability/tests/unit/reconcileFilterRows.test.ts
💤 Files with no reviewable changes (1)
  • web/oss/src/components/pages/observability/assets/utils.ts

Comment on lines +31 to +40
const rawValue = Array.isArray(tt?.value) ? tt?.value[0] : tt?.value
const isAffirm = op === "is" || op === "in"
const isNeg = op === "is_not" || op === "not_in"
const normalize = (x: unknown): "annotation" | "invocation" | null =>
x === "annotation" ? "annotation" : x === "invocation" ? "invocation" : null
const flip = (x: unknown): "annotation" | "invocation" | null =>
x === "annotation" ? "invocation" : x === "invocation" ? "annotation" : null
let effective: "annotation" | "invocation" | null = null
if (tt && isAffirm) effective = normalize(rawValue)
else if (tt && isNeg) effective = flip(rawValue)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not infer a trace type from a multi-value condition.

Line 31 selects only the first value. trace_type in ["annotation", "invocation"] matches both trace types. trace_type not_in ["annotation", "invocation"] matches neither trace type. In both cases, effective is undetermined.

Only reconcile when the condition contains exactly one value. Otherwise, return the existing rows unchanged. Add tests for both multi-value cases.

Proposed fix
-    const rawValue = Array.isArray(tt?.value) ? tt?.value[0] : tt?.value
+    const rawValues = Array.isArray(tt?.value)
+        ? tt.value
+        : tt?.value === undefined
+          ? []
+          : [tt.value]
+    if (rawValues.length !== 1) return rows
+    const rawValue = rawValues[0]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const rawValue = Array.isArray(tt?.value) ? tt?.value[0] : tt?.value
const isAffirm = op === "is" || op === "in"
const isNeg = op === "is_not" || op === "not_in"
const normalize = (x: unknown): "annotation" | "invocation" | null =>
x === "annotation" ? "annotation" : x === "invocation" ? "invocation" : null
const flip = (x: unknown): "annotation" | "invocation" | null =>
x === "annotation" ? "invocation" : x === "invocation" ? "annotation" : null
let effective: "annotation" | "invocation" | null = null
if (tt && isAffirm) effective = normalize(rawValue)
else if (tt && isNeg) effective = flip(rawValue)
const rawValues = Array.isArray(tt?.value)
? tt.value
: tt?.value === undefined
? []
: [tt.value]
if (rawValues.length !== 1) return rows
const rawValue = rawValues[0]
const isAffirm = op === "is" || op === "in"
const isNeg = op === "is_not" || op === "not_in"
const normalize = (x: unknown): "annotation" | "invocation" | null =>
x === "annotation" ? "annotation" : x === "invocation" ? "invocation" : null
const flip = (x: unknown): "annotation" | "invocation" | null =>
x === "annotation" ? "invocation" : x === "invocation" ? "annotation" : null
let effective: "annotation" | "invocation" | null = null
if (tt && isAffirm) effective = normalize(rawValue)
else if (tt && isNeg) effective = flip(rawValue)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

frontend refactoring A code change that neither fixes a bug nor adds a feature size:XL This PR changes 500-999 lines, ignoring generated files. tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant