feat(agent-sessions): filter by model, agent, tool, environment, id, errors, cost and usage, and sort - #738
Conversation
96bb63c to
a987844
Compare
|
Rebased onto main after #741 (two-stage list). Rather than a full-scan fallback, the session-level filters and sorts now run on stage 1: migration 0025 materializes the per-span measures ( |
…errors, cost and usage, and sort The list could be sliced by framework and service and nothing else. This adds the dimensions a reader reaches for first, and a sort. Index (migration 0026): DeploymentEnv, Model, AgentName, ToolName, and the per-span measures IsLlmCall, IsToolCall, IsError, Tokens, Cost (with SpanId/ParentSpanId/Duration) on ai_trace_index — every one a fact of the GenAI span, coalesced across dialects and classified at insert by the new gen-ai-columns module the read side compiles the same expressions from. Nothing is backfilled; pre-0026 rows read ''/0 and drop out of the new facets and sums. Local store: v15 -> v16. Query, on the two-stage list: the counted filters are per-trace existence tests on the index level of both stages, so a model on the chat span and a tool on the tool span combine. The session-level filters (errors, duration, cost, tokens, LLM/tool calls, hide single-trace sessions) and the sort are HAVING/ORDER BY on the page's ranked row over sums of the index measures — no fan-out. Usage is summed with the detail page's deepest-reporter rule so a wrapper's roll-up is not double counted. Id search is a prefix match on either id column. Web: multi-select facets, range sections (with count/usd units), a search box, an errors chip, a sort menu, and model / calls / usage lanes on the row.
a987844 to
2973afb
Compare
|
Rebased again onto main: #749 took migration 0025 and local schema v15, so this PR's migration is now 0026 and its local-store edge v15 → v16. No other changes. |
🍁 Maple PR previewWarning Preview cleanup could not be confirmed. The Alchemy teardown outcome was Final commit |
Main landed 0026_ai_trace_index_filter_columns and local schema v16 (#738). The error-events attribute fallback moves to ClickHouse migration 0027 and the local chDB edge to v16 -> v17; generated artifacts regenerated on the merged tree.
Third version collision in a row. Main landed #738 (agent-session filter columns), taking migration 0026 and local schema v16 — the slots this branch moved into yesterday. As with the previous two, nothing semantic conflicts: two unrelated changes each took the next free number. - `0026_product_events_from_traces.ts` -> `0027_...`, `version: 26` -> `27`, export and every doc reference renamed, docs/product-events-funnels.md included. - `migrations/index.ts` and its test carry 0024, 0025, 0026 and 0027. `clickHouseSchemaVersion` stays "21" — all four are `requiredForIngest: false`. - Local edge re-derived via `local-schema:bump` for v17; the v16->v17 module body is the previous one unchanged apart from version plumbing. - Restored the same four local-store-migration test assertions that taking main's copy of that file reverts on every one of these merges. Schema is 39 tables / 42 MVs, local schema v17, 81 objects. Verified on the merged tree: `bun typecheck` 41/41, `bun run lint` clean, ClickHouse schema / local-manifest / Tinybird gates up to date, apps/api 2585 passed, apps/web 2382, packages/domain 703, query-engine 1373, apps/cli 534. `bun.lock` is byte-identical to main's. Note for the next merge: main's #750 adds a new `@maple/safe-fetch` workspace, so a worktree installed before the merge needs `bun install` again afterwards — without it, `@maple/scraper` typecheck and one ScrapeTargetsService lint rule fail for missing types rather than for anything in the diff. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
What
The Agent Sessions list could be sliced by framework and by service, and by nothing else. This adds the filters a reader reaches for first, and a sort.
Counted facets (sidebar, with session counts): environment, model, agent, tool — alongside framework and service, all now multi-select.
Session-level filters: id search (session id or trace id, prefix match — paste from a ticket or from the row itself), with-errors chip, session length, cost, tokens, LLM calls, tool calls, and "hide single-trace sessions" for orgs whose framework exposes no session key.
Sort: newest / oldest / longest / most expensive / most tokens / most errors / most LLM calls / most tool calls.
List row gains a model lane,
N calls · N toolsin the activity lane (traces/spans move to its tooltip), and a tokens/cost lane.How
Built on #741's two-stage list, the way that PR's "interaction" note asked for: every measure the sidebar filters or sorts on is materialized into
ai_trace_index, so stage 1 (aiSessionPageQuery, index-only, whole window) filters, ranks and pages on them, and stage 2 stays the page-bounded fan-out it is on main.ai_trace_indexand recreatesai_trace_index_mv: the facet dimensionsDeploymentEnv,Model,AgentName,ToolName, and the per-span measuresIsLlmCall,IsToolCall,IsError,Tokens,Cost, plusSpanId/ParentSpanId/Duration. All are facts of the GenAI span, coalesced and classified at insert by the newpackages/domain/src/tinybird/gen-ai-columns.ts(the dialect key lists,classifyAiSpan/isLlmCallandspanTokenBucketstranscribed to SQL), which the read side compiles from too. Nothing is backfilled; pre-0026 rows read''/0 and drop out of the new facets and sums. Local store: v15 → v16.HAVING countIf(Model IN (…)) > 0 …), so each selects exactly the population its facet counted and dimensions on different spans of one trace (model on the chat span, tool on the tool span, id on the turn span) combine. Facets grow from twoUNION ALLbranches to six, still index-only.HAVING/ORDER BYon stage 1's ranked row, over per-session sums of the index measures — no fan-out, so a 30-day window sorted by cost costs what perf(agent-sessions): rank the page on the index, then aggregate only that page #741's page costs. Two documented approximations: "with errors" means a failed agent span (the row's badge still counts every span), and the duration filter reads the agent-span extent (the true extent trails by minutes at most, per perf(agent-sessions): rank the page on the index, then aggregate only that page #741's measurement).totalTokens,cost) is summed with the detail page's deepest-reporter rule, one level deep: a wrapper span that rolls up its children's usage keeps only its excess. A raw ClickHouse lambda over the trace's(SpanId, ParentSpanId, Tokens, Cost)reporters, capped at 2 000 per trace.RangeFilterSectionlearnscountandusdunits.Verification
ai-trace-index-materialization.clickhouse.e2e.test.ts, on top of perf(agent-sessions): rank the page on the index, then aggregate only that page #741's two-stage scenarios): every new MV column per dialect, the deepest-reporter arithmetic on a roll-up (150 tokens where a naive sum reads 300), every filter including cross-span combinations, the sorts, and the facet counts. The SQL catalog analyzer sweep passes with the new shapes.ai_trace_indexentirely, so the page cannot render against it without rebuilding that workspace.Deploy — manual Tinybird step required
tinybird-cd.ymlis disabled (one failed run, Feb 2026; its GitHub environments do not exist), so nothing in CI applies datasource or materialized-view changes to production. After merge, from the merged checkout, for each long-lived workspace (staging first, then production and the us-east-1 mirror):Then confirm
GET /v0/datasourcesshows the twelve newai_trace_indexcolumns andai_trace_index_mvcarries the new SELECT. The SDK's in-place schema evolution has failed on a column add before (PR #452), which is why staging goes first. Until this runs, the Agent Sessions page fails withUNKNOWN_IDENTIFIERon the new columns — the read side has no fallback to the old schema.Not in this PR
Turn counts (the client's three-rule turn detection has no faithful SQL form), failure-kind facets, prompt/workflow version, user id, free-text search over messages.