发布

  • [OPIK-6941] [BE] [FE] feat: workspace-level span metric aggregation in dashboards (#7365)

    frostbyte_neo 发布于 2026-07-13 15:02:45 +00:00

    • [OPIK-6941] [BE] [FE] feat: workspace-level span metric aggregation in dashboards

    Add a workspace metrics endpoint (POST /v1/private/workspaces/metrics/spans)
    that aggregates span metrics (count, token usage, cost) across a set of
    projects — empty set means all projects in the workspace — with optional
    provider/model breakdown and configurable interval. The DAO builds the whole
    series in SQL (groupArray) like the existing workspace cost query; the service
    stays thin and returns WorkspaceMetricResponse. A dedicated
    WorkspaceSpanMetricRequest keeps the shared WorkspaceMetricRequest contract
    untouched.

    Frontend: the dashboard metric widget's Project field becomes a multi-select
    (reusing ProjectsSelectBox). One project keeps the existing per-project
    behavior and full metric set; two or more narrows the metric list to the span
    trio and routes to the workspace endpoint. The form is otherwise identical to
    main.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • feat(dashboards): workspace totals for the single-metric widget

    Add multi-project support to the single-metric (stat card) widget, mirroring the
    time-series widget: the Project field is a multi-select, and selecting two or more
    projects narrows the metric list to the span totals (count, token usage, cost)
    served by the workspace endpoint with interval=TOTAL, rendered as a single value.

    Extract the shared workspace-metric logic into dedicated modules to avoid
    duplicating flow-specific data across widgets:

    • lib/dashboard/workspaceMetrics.ts: supported metric names, editor/stat options,
      isWorkspaceMetric, and project-selection resolution (single vs workspace).
    • api/projects/useMetricData.ts: picks the per-project vs workspace metrics source,
      so MetricChartContainer no longer branches inline.

    The stats-endpoint metric catalog (metrics.ts) and useWorkspaceMetric are kept free
    of cross-flow constants.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • feat(dashboards): span filters and duration percentiles for workspace metrics

    Extend workspace-level span aggregation to match the per-project endpoint more
    closely:

    • Span filters: WorkspaceSpanMetricRequest carries a filters list, bound in
      getSpanMetric via FilterQueryBuilder (span + span-feedback-score strategies),
      reusing the filter slots already present in the copied SPAN_FILTERED_PREFIX. The
      time-series and single-metric widgets forward span filters to the workspace
      endpoint in multi-project mode.
    • Duration percentiles: SPAN_DURATION joins the supported workspace span metrics,
      computing quantiles(0.5, 0.9, 0.99) DB-side and fanning them into p50/p90/p99
      series (single percentile per group when a provider/model breakdown is set). It
      is exposed in the time-series widget only, since a percentile distribution has no
      single-value stat-card representation.

    Tests: duration parity vs the per-project endpoint, a filtered parity case proving
    the filter narrows results, and validation that a token-usage or duration breakdown
    without sub_metric returns 400.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • refactor(dashboards): drop workspace duration group-by; keep percentiles

    Duration across projects is percentile-only (p50/p90/p99); grouping a percentile
    by provider/model isn't needed. Remove the duration breakdown query and quantile
    sub_metric handling; the service now rejects a duration request with a breakdown
    (400), and the widgets hide the group-by control for duration in multi-project mode
    and never send a breakdown for it. Group by and span filters remain for the other
    workspace span metrics.

    Also fixes the filtered-parity test to type the filter list explicitly so it
    compiles under ECJ.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • refactor(dashboards): scope workspace aggregation to span token usage only

    Narrow the workspace span feature to a single metric — span token usage — with
    provider/model grouping and span filters. Drop span count, span cost, and span
    duration from workspace aggregation (they remain single-project only):

    • Backend: SUPPORTED_SPAN_METRICS is just SPAN_TOKEN_USAGE; removed the count/cost/
      duration queries and DAO methods, and the service now returns 400 for any other
      metric type. Grouping and filter wiring are unchanged.
    • Frontend: the time-series and stat-card metric lists expose only token usage in
      multi-project mode; removed the now-dead duration-in-workspace guards and the
      unused SPAN_COST metric-name entry.

    Tests: SpanMetricsTest now covers token-usage parity, provider breakdown, filtered
    parity, all-vs-subset, workspace isolation, and rejects the unsupported metrics.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • fix(dashboards): bound workspace "all projects" aggregation to a resolved project set

    Address PR review feedback on workspace-level span metrics:

    • Blocker (all-projects unbounded scan): the workspace endpoint resolves an
      empty project set to every project id in the workspace up front, so the DAO
      always queries a bounded project_id IN (...) list that prunes on the spans
      primary key instead of an unconstrained workspace-wide scan. This also
      removes the 30s-refetch amplification, since each refetch is now bounded.
    • Frontend "All projects" is now an explicit, dynamic selection (allProjects
      flag) that sends the empty "all" signal, rather than select-all expanding to
      a capped/frozen list of currently-loaded ids (no silent under-count, no stale
      snapshot). Kept distinct from the empty/not-configured state.
    • DRY: extracted the shared SPAN_FILTERED_PREFIX into SpanMetricsQueries, used
      by both ProjectMetricsDAO and WorkspaceMetricsDAO with a parameterized project
      predicate; drove the span filter-strategy add/bind passes from one list.
    • Fixed the stat-card span-filter error that never cleared in multi-project +
      trace-source mode; dropped the unreachable SPAN_COUNT fallback and a stale
      count/cost comment; documented the metrics-editor single-project asymmetry.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • fix(dashboards): source filters, group by, and usage keys for "all projects" widgets

    In "all projects" mode there is no selected project, so the editor's representative
    projectId was empty — which hid the usage-metrics field (blocking group-by for span
    token usage) and starved the filter field and metadata autocompletes. Fall back to the
    first project in the workspace (from the cache the project dropdown already populated) as
    the representative for those project-scoped option lists, so filters and grouping are
    usable when aggregating across all projects. The stored selections still apply to the
    workspace-wide aggregation; only the option lists borrow a representative project.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

    • docs(dashboards): soften "all projects" scan-cost wording in workspace span metrics

    Address thiagohora's follow-up review: the Javadoc on WorkspaceSpanMetricRequest
    and the comment on WorkspaceMetricsService claimed the resolved-to-explicit
    project set is "never an unconstrained workspace-wide span scan". That's
    misleading for large tenants — project_id IN (<all ids>) reads roughly the
    same granules as a full workspace scan, since the id/time window can't prune at
    the primary-key level across many disjoint project prefixes. Reword both to note
    the query is bounded to the workspace's projects but remains full-scan-equivalent
    for tenants with many projects.

    Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com


    Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com

    下载附件