Skip to content

[FE/feat] Query Registry#4754

Draft
ardaerzin wants to merge 21 commits into
fe-chore/move-evals-to-packagesfrom
fe-feat/query-registry
Draft

[FE/feat] Query Registry#4754
ardaerzin wants to merge 21 commits into
fe-chore/move-evals-to-packagesfrom
fe-feat/query-registry

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

Summary

tba...

Testing

QA follow-up

query registry page & live evals

Checklist

  • I have included a video or screen recording for UI changes, or marked Demo as N/A
  • Relevant tests pass locally
  • Relevant linting and formatting pass locally
  • I have signed the CLA, or I will sign it when the bot prompts me

Contributor Resources

ardaerzin added 21 commits June 16, 2026 17:56
Add a /queries page to view and manage saved trace-filter queries used by live evaluations:

- New scoped @agenta/entities/query entity (create/edit/archive/unarchive, list, live match-count, matching-traces) over the Fern queries client
- Query Registry dashboard with grouped table, search, duplicate, and a manage drawer that reuses the shared Filters editor inline
- Toggle-able matching-traces preview reusing the observability columns + InfiniteVirtualTable shell
- Active list plus a dedicated /queries/archived route with restore, mirroring the Evaluators archived-route pattern
- Sidebar link, EE page stubs, and full-height layout wiring
- Repoint the live-eval Online Evaluation drawer at the shared create path
Reuse the observability annotation pipeline (collect invocation links → queryAllAnnotations → attachAnnotationsToTraces) and derive evaluatorSlugs from the enriched traces, so the preview renders the evaluator-metric columns like the Observability table.
…nged

applyFilter already no-ops when the draft equals the applied filter; reflect that in the button's disabled state for the always-visible inline editor (Query Registry drawer). The popover keeps Apply enabled as its primary close affordance.
…le baseline

mapFilterData (props → internal) is not a clean inverse of sanitizeFilterItems, so comparing the sanitized draft against the raw filterData always read 'changed' — leaving Apply enabled on open and letting a clean draft fire onApplyFilter, which dirtied the drawer's Save too. Run both sides of the comparison through the same map → explode → sanitize pipeline so an untouched draft compares equal.

Scoped to inline mode; the popover keeps Apply as its close affordance.
Queries are git-style entities (Query → Variant → Revision) with full commit/fork/revision-log on the backend, so model the edit drawer's draft state like the workflow/testset molecules instead of an ad-hoc form snapshot.

- @agenta/entities/query: queryMolecule (createMolecule over the head-revision query + draft atoms), with a SEMANTIC order-insensitive isDirty (name + filtering + windowing deep-diff) so change-then-revert reads as clean, plus saveQueryHeadAtom committing a new head revision via editSimpleQuery.
- Drawer: edit mode now drives the molecule (useController + reducers.update sync + saveQueryHeadAtom), replacing the snapshot-based dirty check; create stays on the one-shot path.
- Unit tests for the semantic dirty diff (order-insensitivity + revert-to-clean).

Revision history surfacing still depends on the backend simple-queries list returning variant_id (tracked in TODOS.md).
Each query (artifact) row in the registry expands to its earlier revisions, mirroring the workflow registry variants table (custom Name-cell toggle + tree-child rows, virtual-table-friendly), lazy-loaded on first expand.

- Repoint queryQueryRevisions to query by the artifact ref (query_refs), not variant_id — simple queries are single-variant, so this is the full history and needs no variant id (which the list doesn't return). No backend change.
- Revision child rows show a version badge + filter + created on/by; a loader placeholder shows while fetching; 'No earlier versions' when a query has only its head.
- Per-row action hiding (ActionItem.hidden) suppresses the menu on revision rows; row-click is a no-op on them.
- Corrected the stale TODOS.md note (revision history was never actually blocked on variant_id).

Mechanically the expand reuses useGroupedTreeData's pattern (controlled expandedRowKeys + expandIcon: null + custom cell toggle) without the flat-revisions store rework, preserving the active/archived tabs + search + archive that operate on the artifact.
- Lazy revisions never loaded: the custom Name-cell toggle drives expansion, but the fetch was wired to antd's onExpand, which never fires when the caret is hidden (expandIcon: null). Move the fetch into the toggle's handleExpand so expanding actually fetches.
- Expand toggle showed a bordered/focused box: it was a <button> (default chrome + focus ring). Switch to a plain <span onClick>, matching the workflow registry toggle.
- Revision/loader rows showed a selection checkbox: override rowSelection.getCheckboxProps to disable + hide the checkbox on those rows.
… workflow variants)

Make the parent row represent the latest revision, like the workflow variants table (comp-1 v5 + children v4..v1), instead of a version-less header.

- Entity: add queryRevisionsForQueries — one batched queryQueryRevisions over multiple query_refs, grouped client-side by queryId (QueryRevisionSummary now carries queryId). Reuses the existing latest-revision pattern instead of a backend change.
- Table: batch-fetch the visible page's revisions, enrich each head row with its head version badge + earlier-revision child rows. The expand toggle shows only when history exists; a spacer keeps single-revision rows aligned.
- Replaces the lazy per-expand fetch (and its loader/empty placeholder rows) with the eager batched load.
Other git-style entities collect a commit message on update; do the same for queries.

- Entity: add commitQueryRevision (git /queries/revisions/commit) which carries a message, unlike editSimpleQuery. saveQueryHeadAtom now commits via this when the head variant id is known (from the molecule's server data), falling back to editSimpleQuery otherwise; SaveQueryHeadParams gains an optional message.
- Drawer: edit Save opens a lightweight commit modal (EnhancedModal + optional message textarea) instead of committing silently; create stays a one-shot. Theme-aware modal, resets with the drawer.
- Test: commitQueryRevision payload contract (message + variant id).
Replace the bespoke commit modal with the reusable @agenta/entity-ui EntityCommitModal that other git-style entities use — version transition (vN → vN+1), filtering/windowing JSON diff preview, and commit message — for visual + behavioural consistency.

- entity-ui: add 'query' to EntityType (+ its display-label entry) and a queryModalAdapter (getDisplayName, archive deleteAtom, commitAtom wrapping saveQueryHeadAtom, dataAtom = queryMolecule.atoms.data, commitContextAtom providing the version + diff). Registered alongside the other adapters.
- Drawer: render the shared modal externally-controlled with the unwanted flows OFF — no commitModes (no save-mode/new-variant radio) and no createEntityFields (no name editing; the drawer owns the name). onSuccess refreshes the registry store + closes the drawer, solving the modal↔drawer↔list coordination.
After committing an edit, the registry's head rows refetch (paginated store invalidate), but the parent version badges + expandable revision rows come from the table's batched revision cache (React state), which was fetched once and never refreshed — so the version stayed stale and the new revision didn't appear.

Add a refresh signal (queryRegistryRevisionsRefreshAtom) bumped by invalidateQueryRegistryStore; the table drops its cached revisions when it fires, so the batched fetch re-runs and the version + child rows reflect the new revision.
QueryRevisionSummary already carries the revision message; thread it onto the head + revision rows and render a 'Commit message' column (ellipsis + tooltip), mirroring the workflow variants table's Commit notes.
Mirror the workflow registry: drop the auto-created v0 initial revision from the version history (Number(version) > 0), and flag the parent (head) row as the latest with a 'Last modified' tag + dot.
Match the workflow registry, where revision rows carry per-revision actions. Revision (child) rows can now be archived via the new archiveQueryRevision (/queries/revisions/{id}/archive) — any version including the head; the parent row still archives the whole query artifact. The archive confirm modal adapts its copy (version vs query).
Archiving a revision soft-deletes it, but it had no visible home — the Archived tab is artifact-level (whole queries). Queries use soft-delete + restore (unlike the workflow registry's hard delete), so surface archived revisions inline in the version history instead of letting them vanish.

- Entity: queryRevisionsForQueries gains includeArchived (the registry passes it); QueryRevisionSummary carries deletedAt; add unarchiveQueryRevision (/queries/revisions/{id}/unarchive).
- Table: head = latest non-archived revision; archived revisions render as children tagged 'Archived' (greyed). Their action menu swaps Archive → Restore; handleRestore branches revision vs query.
- The refresh signal already re-runs the batched fetch, so archive/restore reflect immediately.
Archived revisions previously rendered inline in the active list, which
was misleading (no other entity shows soft-deleted revisions among active
ones). They now surface as flat, restorable rows in the Archived tab
alongside archived queries; the active tab batch-fetches active revisions
only.
Exercises the query data atoms and the registry's read/archive logic against
a REAL running backend (no mocks): molecule head-revision fetch + isDirty
round-trip, querySimpleQueries listing, batched revision history after a
commit, single-revision archive/restore via the includeArchived split (the
Archived-tab logic), and whole-query archive/restore active-vs-archived split.

Reuses the existing ephemeral-account harness; the suite is skipIf(!hasBackend)
so it skips (never passes) when no backend is configured.
The workflow switcher's 'Evaluators' group reads nonHumanEvaluatorsAtom,
which resolves is_feedback from each evaluator's latest revision — fanning
out one batched POST /workflows/revisions/query over every evaluator in the
project. That ran on sidebar mount (e.g. opening the playground) just to
render a collapsed card.

Defer the subscription until the switcher is first opened: a one-way
switcherActivated latch (set from both Dropdowns' onOpenChange) swaps the
read between nonHumanEvaluatorsAtom and a stable empty atom, so the fan-out
never mounts until needed. Reopening is served from cache. The menu={{items}}
rendering is untouched, so the sticky group-title styling is unaffected.
…ent latch

The aggregate evaluator atoms (key map, meta map, non-human list, feedback
schemas, full-page list) each resolve EVERY evaluator's latest revision —
one batched POST /workflows/revisions/query over the whole project. Several
consumers read them eagerly on mount (the playground header's evaluator
picker + meta-map read, the sidebar switcher), so a plain playground load
fired the whole fan-out before the user touched anything.

Add a shared, one-way activation gate in evaluatorUtils: those atoms stay
dormant (return stable empty values, mount no revision query) until a consumer
that genuinely needs enrichment activates it.

- Adapter hooks (useEvaluatorEnrichedData + the enriched evaluator adapters)
  activate on mount by default, so every existing evaluator picker is
  unchanged. A new `lazy` option opts out.
- Playground: the header's 'Add evaluators' picker activates on pointer-enter/
  focus (lazy); the variant-config browse adapter is lazy on app playgrounds
  (where it's unused) and eager on evaluator entities. A cold app-playground
  load no longer fires the batch.
- Sidebar switcher activates on open (converged onto the shared gate).
- Filters + CreateQueueDrawer activate eagerly (they need the data on mount),
  so observability + annotation behaviour is preserved.
…te drawer mounts

Follow-up to the lazy enrichment gate. Two always-mounted consumers still
fanned out the per-evaluator latest-revision batch on a plain playground load,
because they read evaluator-list atoms that flow through the (ungated)
evaluatorRevisionFlagsMapAtom:

- The evaluator EntityPicker subscribes to the adapter's list atom on mount
  (even while closed) via useLevelData. The enriched evaluator adapter now
  holds that list empty while `lazy` and the enrichment gate is closed, so a
  closed picker subscribes to nothing.
- AnnotateDrawer is mounted (closed) in shared layouts incl. the playground and
  read humanEvaluatorsListDataAtom unconditionally. It now reads the list only
  when `open`.

Cold playground load no longer fires POST /workflows/revisions/query; the data
resolves when the picker is opened / the drawer opens. Evaluation-page
consumers are untouched.
…unds

The evaluator template catalog (GET /evaluators/catalog/templates) was fetched
on every playground load by two always-mounted readers of evaluatorTemplatesDataAtom:

- PlaygroundVariantConfig read it unconditionally, though it only uses the
  catalog once an evaluatorKey resolves (built-in evaluator URI). Now reads the
  catalog only for evaluator workflows — apps skip it (mirrors the workflow
  molecule, which already gates its catalog read on evaluatorKey).
- The enriched evaluator adapter read the templates map/data on mount even when
  lazy. Now holds them empty until the enrichment gate opens (same lazy
  condition as the list/maps), so the playground 'Add evaluators' picker fetches
  the catalog on open, not on mount.

It's a single static, 5-min-cached request (not the per-evaluator fan-out), but
this keeps a cold app-playground load free of it. Evaluator playgrounds and
other pickers are unchanged.
@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment Jun 19, 2026 1:41pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f9226dd2-97e5-4805-a262-0d70041910e8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fe-feat/query-registry

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 and usage tips.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant