Skip to content

[FE/feat] Query Registry#4754

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

[FE/feat] Query Registry#4754
ardaerzin wants to merge 22 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 22, 2026 2:05pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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: 9d780431-a8ae-4a65-b6b3-504649058b6c

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.

@ardaerzin ardaerzin marked this pull request as ready for review June 22, 2026 14:06
@ardaerzin ardaerzin requested a review from ashrafchowdury June 22, 2026 14:06
@dosubot dosubot Bot added size:XXL This PR changes 1000+ lines, ignoring generated files. feature Frontend labels Jun 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Preview URL https://gateway-production-1c04.up.railway.app/w
Project agenta-oss-pr-4754
Image tag pr-4754-5cc02da
Status Deployed
Railway logs Open logs
Workflow logs View workflow run
Updated at 2026-06-22T14:19:15.614Z

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

Labels

feature Frontend size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant