mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-05 08:09:22 +00:00
Fixes the Agent Graph end-to-end — UI (openobserve/web) + service-graph backend (openobserve/core). Root causes were found and validated against live trace data. --- ## 1. UI: wrong graph until refresh + no independent graph-type selector The Agent Graph page embeds Traces' `ServiceGraph`, which read its viz/layout type from the shared `searchObj.meta` singleton and auto-loads on mount. - **Wrong graph on return (from Agent Behavior):** the effective stream fell back to the literal `default` trace stream before `loadAgents()` resolved, so ServiceGraph rendered that whole stream's service topology instead of the agent graph. Fixed: no `default` fallback in agent mode; render is gated behind `graphReady` (a resolved agent stream), with a spinner / "no agents" empty state otherwise; stale agent/stream selections reconciled on reload. - **No graph-type selector / inherited the Traces tab's type:** added `vizType`/`layoutType` prop overrides on `ServiceGraph` (computeds prefer props, else the shared store — Traces behavior unchanged), and gave the Agent Graph page its own Tree/Graph + layout selector with its own state and `agentGraph_*` localStorage keys. - **Stream picker** now lists only the distinct `source_stream`s of discovered agents (not agentless streams), annotated with per-stream agent counts, with an option tooltip and wider control. New `AgentGraphPage.spec.ts` (5 tests): gating, empty state, viz/layout independence, stream-picker scoping. `vue-tsc` app + vitest typecheck clean. ## 2. Backend: agent→model/tool edges mis-attributed to the service Model/tool spans (`chat`, `execute_tool`) don't carry `gen_ai.agent.name` — it lives on an ancestor `invoke_agent` span (confirmed as the norm across the OTel GenAI spec, Google ADK, OpenAI Agents SDK, OpenInference, CrewAI, LangGraph). The edge builder climbs ≤4 parent hops to find it, else falls back to `service_name`. When an intermediate span is missing (the spec permits omitting `invoke_agent`; inconsistent sampling / async context loss produce orphan LLM spans), the climb fails and the span mis-attributes to the service — a spurious `service → model` / `service → tool` edge. Fix: add a per-trace agent CTE (`MAX(gen_ai_agent_name) GROUP BY trace_id`) as a fallback level in the COALESCE, between the ancestor climb and the `service_name` fallback, for both edge queries. This matches the industry-recommended fallback (group by trace when the chain breaks). ### Validation (live introspect data, 2 streams, 7-day window) | stream | before | after | |---|---|---| | `sre_agent_traces_production` | `service → model` (47+3 reqs) | eliminated → o2_ai_agent (247) / sre_rca_agent (29) | | `sre_agent_traces_production_us2` | `service → model` (20 reqs) | eliminated → o2_ai_agent (279) | - No cross-agent contamination in the multi-agent stream (traces are single-agent). No tool-edge regression. - Non-agent traces: CTE returns nothing → NULL join → falls to `service_name` exactly as before (no behavior change). - Perf: single-column `GROUP BY trace_id` aggregate, ~+25% wallclock on the batch edge query; runs in the hourly job, not a hot path. Unit tests cover the COALESCE position and CTE builder. ## Not included / follow-up - **env/version in the agent dropdown** requires backend extractor + DB migration + API changes. Tracked separately. ## Note Full enterprise `cargo build` isn't runnable in the dev environment (the `o2_enterprise` crate is a resolution stub); the SQL-builder logic is verified via standalone rustc and the runtime behavior via the live dry-run above. CI runs the real enterprise build.