Queries and terminals
TypeScript JQL roots, time bounds, select terminals, and result row shapes.
judgeval-js JQL source on GitHub
Root builders
traces(options?: { filter?: FilterInput }): QueryBuilder
spans(options?: { filter?: FilterInput }): QueryBuilder
sessions(options?: { filter?: FilterInput }): QueryBuilder| Source | Grain | Canonical fields |
|---|---|---|
traces | One row per trace | trace_id, span_id, span_name, name, input, output, duration, status, timestamp, session, customer, error |
spans | One row per span | Common fields plus cost, model, parent_span_id |
sessions | One row per session | Common fields plus error |
Field catalogs can evolve. Use client.discover("fields", { source: "spans" }) before generating
dynamic query UIs or relying on project-specific attributes.
Builder methods
.where(filter: FilterInput): QueryBuilder
.last(window: string): QueryBuilder
.since(since: string): QueryBuilder
.between(start: string, end: string): QueryBuilder
.rows(options?: { fields?: string[]; limit?: number }): QueryBuilder
.ids(): QueryBuilder
.count(by?: string): QueryBuilder
.recent(n: number): QueryBuilder
.top(n: number, by: string): QueryBuilder
.ranked(options?: { within?: string; by?: string; pick?: number | [number, number] }): QueryBuilder
.agg(options: { func; field; q? }): QueryBuilder
.agg(func, field, q?): QueryBuilder
.trend(options?: { metric?: "count" | "rate"; bucket?: string }): QueryBuilder
.pipe(): PipelineBuilder
.toJSON(): SourceQueryBuilders are immutable: every method returns a new builder. Calling .where()
multiple times combines the root filters with canonical all (AND). Calling
.last(), .since(), or .between() replaces any earlier time bound.
Serialize without executing with query.toJSON().
Time object
The JSON time object must contain exactly one key:
| Builder | JSON | Input |
|---|---|---|
.last(window) | {"last":"7d"} | Relative duration string |
.since(since) | {"since":"2026-07-01"} | Date/time string accepted by the server |
.between(start, end) | {"between":["2026-07-01","2026-07-08"]} | Exactly two date/time strings |
Omitting time searches all available history unless a deployment-level policy
adds a default window.
Select terminals
A source query can contain at most one select. In TypeScript, a second select silently replaces the first — the
builder does not throw. The server
also rejects a query containing both select and pipe.
| Terminal | Inputs and defaults | Result rows |
|---|---|---|
rows | fields?: string[], limit?: number | Requested fields, or the source's default row projection |
ids | None | Distinct ID columns for the grain: traces returns trace_id; spans returns both trace_id and span_id; sessions returns session_id |
count | by?: string | No by: {"count": number}; with by: {"key": value, "count": number} |
recent | n: int | Source rows ordered by newest timestamp |
top | n: int, by: string | Source rows ordered by the numeric field descending |
ranked | within?: string, by: "timestamp", pick: 1 | Traces/spans only. Positional rows plus _rn; pick is a nonzero rank or two-item range 1 <= a <= b |
agg | func, field, q? | Traces/spans only. Exactly one row: {"value": number | null} |
trend | metric: "count", bucket: "1d" | Count: {"bucket": datetime, "n": number}; rate: adds total and rate |
Aggregate rules
func is one of avg, sum, min, max, quantile, or
count_distinct. field is always required. q is required only for
quantile, rejected for every other function, and must satisfy 0 < q < 1.
Trend rules
metric is count or rate. bucket is a duration string such as
1d or 1w. Rate trends require a filter that defines the numerator.