mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-06 00:09:22 +00:00
587089a01c8a20d82c1c4e94093a43c0c5fb7b44
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
39b2b3ca77 |
feat: add agent_options.output_format (csv/md_table) to _search response (#13343)
Design at: #13343 ## What `_search` gains an optional `agent_options.output_format` parameter (`json` | `csv` | `md_table`, default `json`). When set to `csv`/`md_table`, the response's `hits` array is rendered as a single compact string block: ```json { "query": { "sql": "...", "start_time": ..., "end_time": ... }, "agent_options": { "output_format": "csv" } } ``` Response then carries three new optional fields (never serialized otherwise): `format` (the format actually used), `data` (the formatted block), `advisory` (note about server-side formatting decisions), with `columns` reporting the column order and `hits` emptied. ## Why Agent/MCP consumers pay per token, and a JSON hits array repeats every key on every row — the repeated keys, not whitespace, are the dominant cost (minify only gets to ~78%). csv removes them: ~40% fewer tokens than minified JSON on typical log results, letting the same context budget hold ~1.7x more rows. `md_table` (~8% more than csv) aligns better for small result sets. This is the first piece of the Agent query-optimization (AX) track; `agent_options` is the extension point for the follow-ups (token-budget pagination, query budget/continuation). ## Design - **Serialization edge only**: formatting runs in the `_search` handler after `SearchService::cache::search` returns. Engine, partition scheduling and result cache always see original JSON hits; cached entries never contain formatted strings, and the cache key is unchanged, so a UI (json) query and an agent (csv) query share the same cache entry. - **Model-friendly escaping**: newlines inside cells become a literal `\n` so no record ever spans physical lines (multi-line RFC 4180 quoted cells are a known LLM parsing hazard); commas/quotes still get standard csv quoting so rows stay machine-parsable. `md_table` escapes `|`. Nested objects/arrays are minified JSON in the cell. - **Column order**: server-provided `columns` when present, otherwise first-seen key order with `_timestamp` promoted to the front. - **Sparse fallback**: results with >= 20 columns and > 50% empty cells (typical `select *` on a wide stream) fall back to ndjson — per-row keys are cheaper and less error-prone there than a mostly-empty grid. The fallback is announced via `advisory`, never silent. Non-object rows fall back the same way. - **Zero impact when unset**: requests without `agent_options` produce byte-for-byte identical responses. The remaining 9 files changed are mechanical `agent_options: None` additions to internal `Request` struct literals. - The `_search` `x-o2-mcp` tool description now mentions the option, and `SearchAgentOptions` flows into the generated OpenAPI/MCP tool schema automatically. ## Testing - 9 unit tests in `agent_format.rs`: json no-op, csv basics + `_timestamp` promotion, newline/comma/quote/nested escaping, missing/null cells, server column order, md_table pipe escaping, sparse fallback, non-object fallback, empty hits. - Verified against a running local instance: default path unchanged (no new keys), csv/md_table output with all escaping cases, sparse stream (32 cols, 90% empty) falls back to ndjson with advisory, invalid `output_format` returns 422 listing valid variants, `SearchAgentOptions` present in `/api-doc/openapi.json`. - `cargo check --workspace`, `cargo clippy -p openobserve-api-query`, `cargo fmt` clean. |
||
|
|
9ede45bbf7 |
fix: Agent Behavior signals (loop/failure taxonomy) + Agent Graph fixes (#13279)
## What
Adds **Agent Behavior signals** — a PB-safe rollup that surfaces two
behavioural questions the platform couldn't answer before: *is an agent
stuck in a loop?* and *why is it failing?* Plus a batch of Agent Graph /
AI Observability UX and correctness fixes found while building it.
Companion changes land in **o2-enterprise**
(`feat/agent-signals-enterprise-split`): the SQL builders, mappers,
config-driven failure taxonomy, the service-graph agent-classification
fix, and the RBAC route entry.
## Backend (agent-signals)
- Bounded-key rollup co-located in the service-graph job
(alert-manager-only, reuses its watermark + self-ingest). Groups only on
agent/tool/class — never trace_id — so it stays PB-safe.
- Config-driven **failure taxonomy** (rules as data, evolvable without
code) + config-driven error-detail columns; ancestor-agent resolution so
error spans attribute to the owning agent.
- Read API `GET /{org}/traces/agent_signals` (dual `#[cfg]`, reads the
derived `_agent_signals` stream) + RBAC route entry (enterprise
`route_permissions`) mapping it to `traces` read.
- OSS/enterprise split respected: pure SQL/mapping in enterprise, thin
gated I/O in OSS.
- Fix: `traces/latest` only narrows to a UUIDv7 trace_id's embedded time
when that time is inside the caller's window (fixes "trace not found"
for time-shifted/re-ingested traces).
## Frontend (AI Observability)
- New **Agent Behavior** page under Monitor: looping-agents +
failure-taxonomy tables, each row opening an actionable detail drawer
(real grouped error messages / worst-repeat traces), click-through to
Trace Details in a new tab.
- Agent-node **Behavior tab** on the Agent Graph node drawer (reuses the
same signals).
- Nav rename: LLM Insights → **Insights**, LLM Sessions → **Sessions**.
- **Agent** is the default scope across the AI pages, with the
Agent|Stream toggle placed consistently (left scope bar); explicit
URL/localStorage choices still win.
- Removed the duplicate in-table refresh on Sessions.
## Agent Graph fixes
- **Agent classification**: agents that also call tools now correctly
classify as `service_type: "agent"` (they glow), fixing a latent
precedence bug where the tool/model client-role overrode the agent role
and `is_real_service` forced agents to plain services. Rust
`classify_entity` brought in line with the (already-correct) TS twin.
- **Drag-to-pan restored**: the shared ChartRenderer armed
`dataZoomSelect` cursor unconditionally, hijacking drag away from roam
pan. Disabled for this graph (no dataZoom).
- **Nodes scale on zoom** (`nodeScaleRatio: 1`) so zooming enlarges
nodes/labels, not just spacing.
## Testing
- Enterprise unit tests: agent-signals SQL/mappers/config,
classification precedence, RBAC route resolution — all pass.
- FE: type-check + lint clean.
- Verified end-to-end on real re-ingested introspection data: taxonomy
unclassified rate ~100% → ~1–3%, agents resolved, both agents
classify/glow, trace-open works.
## Notes
- `Cargo.toml`/`Cargo.lock` and unrelated Slack-bot files were
intentionally excluded from the commits (local build-config drift).
---------
Co-authored-by: ktx-vaidehi <vaidehi.akhani@kiara.tech>
Co-authored-by: ktx-vaidehi <134508096+ktx-vaidehi@users.noreply.github.com>
|
||
|
|
b835ff2f86 |
refactor: consolidate vrl/js into transform crate and extract super_cluster_queue crate (#13324)
## Summary Two crate-split refactors continuing the workspace decomposition: **1. `transform` crate (renamed from `openobserve-vrl`, `src/vrl` → `src/transform`)** - Now the only crate depending on `vrl`, `vector-enrichment` and `rquickjs` directly; downstream crates use `transform::vrl::` / `transform::vector_enrichment::` re-export paths and drop their direct dependencies - The QuickJS runtime (`common/utils/js.rs`) moved into `transform::js` (js_security checks gated behind the crate's `enterprise` feature); `apply_vrl_fn`, `convert_to_vrl`/`convert_from_vrl` and `TRANSFORM_FAILED` moved from core - Exception: `src/config` keeps its direct `vrl` dependency (it sits below `transform` in the dependency graph) **2. `super_cluster_queue` extracted from the root crate into a workspace member** - Only depends on `openobserve-core`, `infra`, `config` and `o2_enterprise`, so it builds in parallel with `api` and edits no longer recompile the root crate (which re-embeds `web/dist` on every rebuild) - Gated behind its own `enterprise` feature — compiles as an empty crate in OSS builds so `cargo --workspace` keeps working against the `o2_enterprise` stub; `vectorscan` wired through for `re_pattern.rs` - Root `lib.rs` re-exports the crate, so `openobserve::super_cluster_queue::init()` in `main.rs` is unchanged Pairs with the `Cargo.toml.openobserve` template sync PR in o2-enterprise (must merge together). ## Test plan - `cargo check --workspace --all-targets` (OSS) passes - `cargo check -p openobserve --no-default-features --features enterprise` with the synced enterprise template passes - `cargo clippy -p super_cluster_queue --features enterprise,vectorscan` — zero warnings - `cargo clippy -- -D warnings` (CI invocation) passes; `cargo fmt --all` clean |
||
|
|
1ad116eb96 |
fix: mcp issues (#13196)
Fixes several MCP-related API issues: - Enrich `x-o2-mcp` metadata with `summary_fields` on kv list, backfill list, alert templates, dashboard annotations, and search jobs so MCP tools return well-shaped summaries. - Add missing `org_id`/`dashboard_id` OpenAPI path params to the timed annotations list endpoint. - Return an empty result (instead of a 500) from pipeline history when the triggers stream doesn't exist yet. - Return a properly-shaped `PaginatedResponse` (preserving the query-range warning) from the traces `get_latest_users` endpoint when there are no matching hits. - Sanitize error-message headers so error responses propagate the real status/body instead of failing with a 500. |
||
|
|
9b4ec202c2 |
feat: expose trace/session analysis endpoints via MCP (#13235)
Design at: #13235 (design described in this PR description) ## Summary MCP tools are auto-generated from the OpenAPI spec, filtered/described via the `x-o2-mcp` extension. Two gaps kept trace/session analysis from working well over MCP: 1. **`GetSessionDetails` was not an MCP tool at all.** The endpoint (`/{org_id}/{stream_name}/traces/session/details`) was registered in the axum router but missing from the `paths()` list in `openapi.rs`, so it never entered the OpenAPI spec and was invisible to MCP. Without it an LLM can list sessions but cannot drill into a session's per-turn traces. 2. **The traces endpoints had no `x-o2-mcp` metadata.** `GetLatestTraces`, `GetLatestSessions`, `GetLatestUsers`, `GetTraceDAG` were exposed only with their long OpenAPI descriptions and no `category`, hurting `tool_search` (BM25) discoverability and wasting tokens. ## Changes - Register `get_session_details` in `openapi.rs` → becomes MCP tool `GetSessionDetails` - Add `x-o2-mcp` with `category: "traces"` and short descriptions to `GetLatestTraces`, `GetLatestSessions`, `GetSessionDetails`, `GetLatestUsers`, `GetTraceDAG` - Mark `GetLatestTraces` as `pinned: true` so it appears directly in `tools/list` (alongside SearchSQL/StreamList/GetSchema/QueryRangeMetrics/GetIncident), letting LLMs start trace analysis without a `tool_search` round-trip No behavior change for regular HTTP API consumers; `GetSessionDetails` additionally becomes visible in Swagger. ## Testing - `cargo check -p openobserve-api-query -p openobserve-api` passes |
||
|
|
bcea47f644 |
refactor: extract management API crate (#13202)
## Summary - add the `openobserve-api-management` crate under `src/api_management` - physically move management handlers, models, and authentication helpers out of `openobserve-api` - preserve the existing API module paths through re-exports - move shared stream permission checking into `openobserve-core` to avoid a management-to-query dependency - allow the new crate's `AGPL-3.0` license in `deny.toml` (fixes the cargo-deny `check` job) - keep router, OpenAPI generation, and rate-limit path mapping in `openobserve-api` ## Dependency boundary `openobserve-api-management` depends on `openobserve-api-common` and `openobserve-core`; it does not depend on `openobserve-api-query`. ## Note on `split-debuginfo` Removing `split-debuginfo = "packed"` from `[profile.release-profiling]` is intentional (not a formatting artifact): profiling builds now keep DWARF debuginfo embedded in the binary, so profiling artifacts can be symbolized at runtime without shipping a separate debuginfo file. The o2-enterprise overlay `Cargo.toml.openobserve` is kept in sync. ## Companion PR - openobserve/o2-enterprise#2175 ## Validation - OSS check with `mimalloc` - OSS strict clippy with all targets - enterprise check and strict clippy - cloud check and strict clippy - `cargo test -p openobserve-api-management --lib`: 300 passed - `cargo deny check licenses` - `cargo fmt --all` - `git diff --check` Build-time benchmarking is intentionally deferred for this stage. |
||
|
|
cd8610cafa |
refactor: extract shared and query API crates (#13199)
## Summary
- add `openobserve-api-common` for HTTP extractors and request DTOs
shared across API domain crates
- add `openobserve-api-query` and physically move the search, PromQL,
and traces handlers (about 16.4K lines)
- preserve the existing `handler::http::request::{search,promql,traces}`
paths through re-exports so routing, Swagger generation, and rate-limit
metadata remain compatible
- forward enterprise, cloud, vectorscan, and vortex features through the
new crate boundary
- avoid `#[path]` source inclusion
## Enterprise overlay
Requires openobserve/o2-enterprise#2174, which registers the two new
workspace crates in `Cargo.toml.openobserve`.
## Validation
- `cargo check -p openobserve --features mimalloc`
- enterprise check with `--no-default-features --features
enterprise,mimalloc`
- cloud check with `--no-default-features --features cloud,mimalloc`
- OSS and cloud/enterprise all-targets Clippy with `-D warnings`
- `openobserve-api-common`: 9 tests passed
- `openobserve-api-query`: 136 independent tests passed single-threaded;
the unchanged DB-dependent saved-view test was excluded because
standalone crate tests do not initialize the infra database
- `cargo fmt --all -- --check`
Build-time benchmarking is intentionally deferred until the crate-split
series is ready for a controlled `release-profiling` comparison.
|