From ff8a579bdc2b12da2d2eb404c9b99afb82ba7558 Mon Sep 17 00:00:00 2001 From: Sai Nikhil Date: Thu, 11 Jun 2026 12:45:33 +0530 Subject: [PATCH] fix: eval templates removal (#12595) 1. This PR removes Evaluation templates from pipeline module 2. removes LLM evaluation node from pipeline editor 3. remove LLM evaluation creation tab from schema details --------- Co-authored-by: Ashish Kolhe <35160958+oasisk@users.noreply.github.com> Co-authored-by: udev --- src/handler/http/request/pipeline.rs | 40 +--- .../http/request/pipelines/backfill.rs | 32 ++- src/handler/http/request/pipelines/history.rs | 4 +- src/service/organization.rs | 4 +- src/service/pipeline/mod.rs | 150 ++++++++++++- web/src/components/logstream/Schema.spec.ts | 22 -- web/src/components/logstream/schema.vue | 62 +----- .../components/pipeline/PipelineEditor.vue | 23 -- .../pipeline/PipelineSectionTabs.vue | 12 +- web/src/components/pipeline/PipelineView.vue | 20 -- web/src/plugins/traces/TraceDetails.vue | 210 ------------------ web/src/views/Functions.spec.ts | 22 -- web/src/views/Functions.vue | 41 ---- 13 files changed, 191 insertions(+), 451 deletions(-) diff --git a/src/handler/http/request/pipeline.rs b/src/handler/http/request/pipeline.rs index b50f56731c..f239bedccb 100644 --- a/src/handler/http/request/pipeline.rs +++ b/src/handler/http/request/pipeline.rs @@ -137,7 +137,7 @@ pub async fn save_pipeline( } let pipeline_id = pipeline.id.to_string(); let pipeline_name = pipeline.name.clone(); - match pipeline::save_pipeline(pipeline).await { + match pipeline::save_user_pipeline(pipeline).await { Ok(()) => MetaHttpResponse::json( MetaHttpResponse::message(StatusCode::OK, "Pipeline created successfully") .with_id(pipeline_id) @@ -206,7 +206,7 @@ pub async fn list_pipelines( // Get List of allowed objects ends } - let pipelines = match pipeline::list_pipelines(&org_id, _permitted).await { + let pipelines = match pipeline::list_user_pipelines(&org_id, _permitted).await { Ok(pipelines) => pipelines, Err(e) => return e.into(), }; @@ -271,15 +271,7 @@ pub async fn list_pipelines( ) )] pub async fn get_pipeline(Path((org_id, pipeline_id)): Path<(String, String)>) -> Response { - if crate::service::db::pipeline::get_org_by_id(&pipeline_id) - .await - .as_deref() - != Some(org_id.as_str()) - { - return MetaHttpResponse::not_found(format!("Pipeline with id {pipeline_id} not found")); - } - - let meta_pipeline = match crate::service::db::pipeline::get_by_id(&pipeline_id).await { + let meta_pipeline = match pipeline::get_user_pipeline(&org_id, &pipeline_id).await { Ok(pipeline) => pipeline, Err(e) => return e.into(), }; @@ -378,15 +370,7 @@ pub async fn list_streams_with_pipeline(Path(org_id): Path) -> Response ) )] pub async fn delete_pipeline(Path((org_id, pipeline_id)): Path<(String, String)>) -> Response { - if crate::service::db::pipeline::get_org_by_id(&pipeline_id) - .await - .as_deref() - != Some(org_id.as_str()) - { - return MetaHttpResponse::not_found(format!("Pipeline with id {pipeline_id} not found")); - } - - match pipeline::delete_pipeline(&pipeline_id).await { + match pipeline::delete_user_pipeline(&org_id, &pipeline_id).await { Ok(()) => MetaHttpResponse::json(MetaHttpResponse::message( StatusCode::OK, "Pipeline deleted successfully", @@ -451,7 +435,7 @@ pub async fn delete_pipeline_bulk( let mut err = None; for id in req.ids { - match pipeline::delete_pipeline(&id).await { + match pipeline::delete_user_pipeline(&org_id, &id).await { Ok(()) => { successful.push(id); } @@ -504,7 +488,8 @@ pub async fn update_pipeline( Json(mut pipeline): Json, ) -> Response { pipeline.org = org_id; - match pipeline::update_pipeline(pipeline).await { + let org_id = pipeline.org.clone(); + match pipeline::update_user_pipeline(&org_id, pipeline).await { Ok(()) => MetaHttpResponse::json(MetaHttpResponse::message( StatusCode::OK, "Pipeline updated successfully", @@ -545,13 +530,6 @@ pub async fn enable_pipeline( Path((org_id, pipeline_id)): Path<(String, String)>, Query(query): Query>, ) -> Response { - if crate::service::db::pipeline::get_org_by_id(&pipeline_id) - .await - .as_deref() - != Some(org_id.as_str()) - { - return MetaHttpResponse::not_found(format!("Pipeline not found: {pipeline_id}")); - } let enable = query .get("value") .and_then(|v| v.parse::().ok()) @@ -562,7 +540,7 @@ pub async fn enable_pipeline( .and_then(|v| v.parse::().ok()) .unwrap_or_default(); - match pipeline::enable_pipeline(&org_id, &pipeline_id, enable, starts_from_now).await { + match pipeline::enable_user_pipeline(&org_id, &pipeline_id, enable, starts_from_now).await { Ok(()) => { let resp_msg = format!( "Pipeline successfully {}", @@ -644,7 +622,7 @@ pub async fn enable_pipeline_bulk( let mut err = None; for id in req.ids { - match pipeline::enable_pipeline(&org_id, &id, enable, starts_from_now).await { + match pipeline::enable_user_pipeline(&org_id, &id, enable, starts_from_now).await { Ok(()) => { successful.push(id); } diff --git a/src/handler/http/request/pipelines/backfill.rs b/src/handler/http/request/pipelines/backfill.rs index dbae41e106..f33620d6d3 100644 --- a/src/handler/http/request/pipelines/backfill.rs +++ b/src/handler/http/request/pipelines/backfill.rs @@ -26,6 +26,14 @@ use crate::common::meta::http::HttpResponse as MetaHttpResponse; #[cfg(feature = "enterprise")] use crate::service::alerts::backfill; +#[cfg(feature = "enterprise")] +async fn ensure_user_pipeline(org_id: &str, pipeline_id: &str) -> Result<(), Response> { + crate::service::pipeline::get_user_pipeline(org_id, pipeline_id) + .await + .map(|_| ()) + .map_err(Into::into) +} + #[derive(Debug, Serialize, Deserialize, ToSchema)] pub struct BackfillRequest { /// Start time in microseconds @@ -83,12 +91,8 @@ pub async fn create_backfill( Path((org_id, pipeline_id)): Path<(String, String)>, Json(req): Json, ) -> Response { - if crate::service::db::pipeline::get_org_by_id(&pipeline_id) - .await - .as_deref() - != Some(org_id.as_str()) - { - return MetaHttpResponse::not_found(format!("Pipeline with id {pipeline_id} not found")); + if let Err(response) = ensure_user_pipeline(&org_id, &pipeline_id).await { + return response; } log::info!( @@ -244,6 +248,10 @@ pub async fn list_backfills(Path(_org_id): Path) -> Response { pub async fn get_backfill( Path((org_id, pipeline_id, job_id)): Path<(String, String, String)>, ) -> Response { + if let Err(response) = ensure_user_pipeline(&org_id, &pipeline_id).await { + return response; + } + match backfill::get_backfill_job(&org_id, &job_id).await { Ok(job) => { // Verify the job belongs to the specified pipeline @@ -330,6 +338,10 @@ pub async fn enable_backfill( Path((org_id, pipeline_id, job_id)): Path<(String, String, String)>, Query(query): Query>, ) -> Response { + if let Err(response) = ensure_user_pipeline(&org_id, &pipeline_id).await { + return response; + } + let enable = query .get("value") .and_then(|v| v.parse::().ok()) @@ -441,6 +453,10 @@ pub async fn enable_backfill( pub async fn delete_backfill( Path((org_id, pipeline_id, job_id)): Path<(String, String, String)>, ) -> Response { + if let Err(response) = ensure_user_pipeline(&org_id, &pipeline_id).await { + return response; + } + // Verify the job belongs to the specified pipeline match backfill::get_backfill_job(&org_id, &job_id).await { Ok(job) => { @@ -554,6 +570,10 @@ pub async fn update_backfill( Path((org_id, pipeline_id, job_id)): Path<(String, String, String)>, Json(req): Json, ) -> Response { + if let Err(response) = ensure_user_pipeline(&org_id, &pipeline_id).await { + return response; + } + // Verify the job belongs to the specified pipeline match backfill::get_backfill_job(&org_id, &job_id).await { Ok(job) => { diff --git a/src/handler/http/request/pipelines/history.rs b/src/handler/http/request/pipelines/history.rs index f51797a6fa..b5ebb3c2a8 100644 --- a/src/handler/http/request/pipelines/history.rs +++ b/src/handler/http/request/pipelines/history.rs @@ -44,7 +44,7 @@ use crate::{ }, handler::http::{extractors::Headers, request::alerts::history::escape_like}, service::{ - db::pipeline::list_by_org as list_pipelines, + pipeline::list_user_pipelines, search::{self as SearchService}, }, }; @@ -562,7 +562,7 @@ pub async fn get_pipeline_history( /// Helper function to get all pipeline IDs for an organization async fn get_organization_pipeline_ids(org_id: &str) -> Result, anyhow::Error> { // Get all pipelines for the organization - let pipelines = list_pipelines(org_id).await?; + let pipelines = list_user_pipelines(org_id, None).await?; // Extract pipeline IDs let ids: Vec = pipelines.into_iter().map(|pipeline| pipeline.id).collect(); diff --git a/src/service/organization.rs b/src/service/organization.rs index 26dfe14bfb..acf6d1ca89 100644 --- a/src/service/organization.rs +++ b/src/service/organization.rs @@ -152,7 +152,9 @@ pub async fn get_summary(org_id: &str) -> OrgSummary { .collect::>() }; - let pipelines = db::pipeline::list_by_org(org_id).await.unwrap_or_default(); + let pipelines = super::pipeline::list_user_pipelines(org_id, None) + .await + .unwrap_or_default(); let pipeline_summary = PipelineSummary { num_realtime: pipelines .iter() diff --git a/src/service/pipeline/mod.rs b/src/service/pipeline/mod.rs index 0e4753e91e..fae015159f 100644 --- a/src/service/pipeline/mod.rs +++ b/src/service/pipeline/mod.rs @@ -15,7 +15,7 @@ use config::meta::{ pipeline::{ - Pipeline, + Pipeline, PipelineKind, components::{NodeData, PipelineSource}, }, search::SearchEventType, @@ -115,6 +115,18 @@ pub async fn save_pipeline(mut pipeline: Pipeline) -> Result<(), PipelineError> Ok(()) } +#[tracing::instrument(skip(pipeline))] +pub async fn save_user_pipeline(mut pipeline: Pipeline) -> Result<(), PipelineError> { + if let Ok(existing_pipeline) = pipeline::get_by_id(&pipeline.id).await + && (existing_pipeline.org != pipeline.org || !existing_pipeline.is_user()) + { + return Err(PipelineError::NotFound(pipeline.id)); + } + + pipeline.kind = PipelineKind::User; + save_pipeline(pipeline).await +} + #[tracing::instrument(skip(pipeline))] pub async fn update_pipeline(mut pipeline: Pipeline) -> Result<(), PipelineError> { let Ok(existing_pipeline) = pipeline::get_by_id(&pipeline.id).await else { @@ -212,6 +224,16 @@ pub async fn update_pipeline(mut pipeline: Pipeline) -> Result<(), PipelineError Ok(()) } +#[tracing::instrument(skip(pipeline))] +pub async fn update_user_pipeline( + org_id: &str, + mut pipeline: Pipeline, +) -> Result<(), PipelineError> { + get_user_pipeline(org_id, &pipeline.id).await?; + pipeline.kind = PipelineKind::User; + update_pipeline(pipeline).await +} + #[tracing::instrument] pub async fn list_pipelines( org_id: &str, @@ -234,6 +256,45 @@ pub async fn list_pipelines( .collect()) } +#[tracing::instrument] +pub async fn list_user_pipelines( + org_id: &str, + permitted: Option>, +) -> Result, PipelineError> { + Ok(pipeline::list_by_org(org_id) + .await? + .into_iter() + .filter(|pipeline| is_user_pipeline_visible(pipeline, org_id, permitted.as_ref())) + .collect()) +} + +fn is_user_pipeline_visible( + pipeline: &Pipeline, + org_id: &str, + permitted: Option<&Vec>, +) -> bool { + if !pipeline.is_user() { + return false; + } + + match permitted { + Some(permitted) => { + permitted.contains(&format!("pipeline:{}", pipeline.id)) + || permitted.contains(&format!("pipeline:_all_{org_id}")) + } + None => true, + } +} + +#[tracing::instrument] +pub async fn get_user_pipeline(org_id: &str, pipeline_id: &str) -> Result { + let pipeline = pipeline::get_by_id(pipeline_id).await?; + if pipeline.org != org_id || !pipeline.is_user() { + return Err(PipelineError::NotFound(pipeline_id.to_string())); + } + Ok(pipeline) +} + #[tracing::instrument] pub async fn list_pipeline_triggers(org_id: &str) -> Result, PipelineError> { Ok( @@ -294,6 +355,17 @@ pub async fn enable_pipeline( Ok(()) } +#[tracing::instrument] +pub async fn enable_user_pipeline( + org_id: &str, + pipeline_id: &str, + enable: bool, + starts_from_now: bool, +) -> Result<(), PipelineError> { + get_user_pipeline(org_id, pipeline_id).await?; + enable_pipeline(org_id, pipeline_id, enable, starts_from_now).await +} + #[tracing::instrument] pub async fn delete_pipeline(pipeline_id: &str) -> Result<(), PipelineError> { let Ok(existing_pipeline) = pipeline::get_by_id(pipeline_id).await else { @@ -337,3 +409,79 @@ pub async fn delete_pipeline(pipeline_id: &str) -> Result<(), PipelineError> { .await; Ok(()) } + +#[tracing::instrument] +pub async fn delete_user_pipeline(org_id: &str, pipeline_id: &str) -> Result<(), PipelineError> { + get_user_pipeline(org_id, pipeline_id).await?; + delete_pipeline(pipeline_id).await +} + +#[cfg(test)] +mod tests { + use config::meta::{ + pipeline::{ + Pipeline, PipelineKind, + components::{DerivedStream, PipelineSource}, + }, + stream::StreamParams, + }; + + use super::is_user_pipeline_visible; + + fn test_pipeline(id: &str, kind: PipelineKind) -> Pipeline { + Pipeline { + id: id.to_string(), + version: 1, + enabled: true, + org: "test_org".to_string(), + name: id.to_string(), + description: String::new(), + source: PipelineSource::Realtime(StreamParams::default()), + nodes: vec![], + edges: vec![], + kind, + } + } + + #[test] + fn test_is_user_pipeline_visible_excludes_evaluation_pipelines() { + let user_pipeline = test_pipeline("user_pipeline", PipelineKind::User); + let evaluation_pipeline = test_pipeline("evaluation_pipeline", PipelineKind::Evaluation); + + assert!(is_user_pipeline_visible(&user_pipeline, "test_org", None)); + assert!(!is_user_pipeline_visible( + &evaluation_pipeline, + "test_org", + None + )); + } + + #[test] + fn test_is_user_pipeline_visible_applies_permissions() { + let pipeline = test_pipeline("user_pipeline", PipelineKind::User); + + assert!(is_user_pipeline_visible( + &pipeline, + "test_org", + Some(&vec!["pipeline:user_pipeline".to_string()]) + )); + assert!(is_user_pipeline_visible( + &pipeline, + "test_org", + Some(&vec!["pipeline:_all_test_org".to_string()]) + )); + assert!(!is_user_pipeline_visible( + &pipeline, + "test_org", + Some(&vec!["pipeline:other_pipeline".to_string()]) + )); + } + + #[test] + fn test_is_user_pipeline_visible_keeps_scheduled_user_pipelines() { + let mut pipeline = test_pipeline("scheduled_pipeline", PipelineKind::User); + pipeline.source = PipelineSource::Scheduled(DerivedStream::default()); + + assert!(is_user_pipeline_visible(&pipeline, "test_org", None)); + } +} diff --git a/web/src/components/logstream/Schema.spec.ts b/web/src/components/logstream/Schema.spec.ts index e2419ed7b9..bfa9a8f9dc 100644 --- a/web/src/components/logstream/Schema.spec.ts +++ b/web/src/components/logstream/Schema.spec.ts @@ -2098,22 +2098,6 @@ describe("Schema Component Tests", () => { expect(names.length).toBe(3); }); - it("should compute llmEvalStreamFields", () => { - const fields = wrapper.vm.llmEvalStreamFields; - expect(Array.isArray(fields)).toBe(true); - expect(fields.length).toBe(3); - expect(fields[0]).toHaveProperty("label"); - expect(fields[0]).toHaveProperty("value"); - }); - - it("should mark llmEvalFormDirty to false when tab changes from llmEvaluation", () => { - wrapper.vm.llmEvalFormDirty = true; - wrapper.vm.updateActiveMainTab("llmEvaluation"); - // llmEvalFormDirty stays true for llm tab - wrapper.vm.updateActiveMainTab("schemaSettings"); - expect(wrapper.vm.llmEvalFormDirty).toBe(false); - }); - it("should compute hasUDSFieldInSelection", async () => { wrapper.vm.activeTab = "allFields"; wrapper.vm.selectedFields = [{ name: "message", isUserDefined: true }]; @@ -2408,12 +2392,6 @@ describe("Schema Component Tests", () => { afterEach(() => { w.unmount(); }); - it("should expose llmEvalStreamFields for traces streams", () => { - const fields = w.vm.llmEvalStreamFields; - expect(Array.isArray(fields)).toBe(true); - expect(fields.length).toBeGreaterThan(0); - }); - it("should show cross-linking tab when enable_cross_linking is true", async () => { store.state.zoConfig.enable_cross_linking = true; w.vm.updateActiveMainTab("crossLinking"); diff --git a/web/src/components/logstream/schema.vue b/web/src/components/logstream/schema.vue index 7e8d0e4416..fbdfdd5b10 100644 --- a/web/src/components/logstream/schema.vue +++ b/web/src/components/logstream/schema.vue @@ -333,19 +333,6 @@ along with this program. If not, see . label="Configuration" data-test="schema-configuration-tab" /> - - - -
@@ -810,32 +788,8 @@ along with this program. If not, see .
-
- - {{ t("logStream.cancel") }} - - - {{ t("logStream.updateSettings") }} - -
- -
@@ -1032,7 +986,6 @@ import DateTime from "@/components/DateTime.vue"; import AssociatedRegexPatterns from "./AssociatedRegexPatterns.vue"; import ODrawer from "@/lib/overlay/Drawer/ODrawer.vue"; import PerformanceFieldsDialog from "./PerformanceFieldsDialog.vue"; -import LlmEvaluationSettings from "./LlmEvaluationSettings.vue"; import OSpinner from "@/lib/feedback/Spinner/OSpinner.vue"; import OInput from "@/lib/forms/Input/OInput.vue"; import OSearchInput from "@/lib/forms/SearchInput/OSearchInput.vue"; @@ -1082,7 +1035,6 @@ export default defineComponent({ AssociatedRegexPatterns, ODrawer, PerformanceFieldsDialog, - LlmEvaluationSettings, CrossLinkManager, OButton, OIcon, @@ -1137,14 +1089,6 @@ export default defineComponent({ let previousSchemaVersion: any = null; const approxPartition = ref(false); - const llmEvalStreamFields = computed(() => - (indexData.value.schema || []).map((f: any) => ({ - label: f.name, - value: f.name, - })), - ); - const llmEvalSettingsRef = ref(null); - const llmEvalFormDirty = ref(false); const streamCrossLinks = ref([]); const orgCrossLinks = computed( () => @@ -2112,7 +2056,6 @@ export default defineComponent({ const updateActiveMainTab = (tab) => { activeMainTab.value = tab; - if (tab !== "llmEvaluation") llmEvalFormDirty.value = false; }; // Function to get missing FTS and Secondary Index fields @@ -2770,9 +2713,6 @@ export default defineComponent({ quickModeIcon, getConfigIcon, getTimelineIcon, - llmEvalStreamFields, - llmEvalSettingsRef, - llmEvalFormDirty, }; }, created() { diff --git a/web/src/components/pipeline/PipelineEditor.vue b/web/src/components/pipeline/PipelineEditor.vue index 2f964d5229..1aea1ef709 100644 --- a/web/src/components/pipeline/PipelineEditor.vue +++ b/web/src/components/pipeline/PipelineEditor.vue @@ -112,11 +112,6 @@ along with this program. If not, see . :open="true" @cancel:hideform="resetDialog" /> - { - if (config.isEnterprise == "true" && store.state.zoConfig.ai_enabled) { - // Insert LLM Evaluation node before the "Destination" section header - const destIdx = nodeTypes.findIndex( - (n) => n.isSectionHeader && n.label === "Destination", - ); - if (destIdx !== -1) { - nodeTypes.splice(destIdx, 0, { - label: "LLM Evaluation", - subtype: "llm_evaluation", - io_type: "default", - icon: "img:" + llmEvaluationImage, - tooltip: "LLM Evaluation Node", - isSectionHeader: false, - }); - } - } if (config.isEnterprise == "true") { nodeTypes.push({ label: "Remote", diff --git a/web/src/components/pipeline/PipelineSectionTabs.vue b/web/src/components/pipeline/PipelineSectionTabs.vue index 5d07b6644d..c98dc93ff6 100644 --- a/web/src/components/pipeline/PipelineSectionTabs.vue +++ b/web/src/components/pipeline/PipelineSectionTabs.vue @@ -16,7 +16,7 @@ along with this program. If not, see . -
- -
@@ -868,7 +843,6 @@ import OToggleGroupItem from "@/lib/core/ToggleGroup/OToggleGroupItem.vue"; import OButton from "@/lib/core/Button/OButton.vue"; import ODrawer from '@/lib/overlay/Drawer/ODrawer.vue'; import OIcon from "@/lib/core/Icon/OIcon.vue"; -import pipelineService from "@/services/pipelines"; import OSpinner from "@/lib/feedback/Spinner/OSpinner.vue"; import OTooltip from "@/lib/overlay/Tooltip/OTooltip.vue"; import OSearchInput from "@/lib/forms/SearchInput/OSearchInput.vue"; @@ -891,11 +865,6 @@ const FlameGraphView = defineAsyncComponent( () => import("@/components/traces/FlameGraphView.vue"), ); -// Import TraceEvaluationsView -const TraceEvaluationsView = defineAsyncComponent( - () => import("./TraceEvaluationsView.vue"), -); - // Import ThreadView (LLM Thread tab) const ThreadView = defineAsyncComponent( () => import("./ThreadView.vue"), @@ -983,7 +952,6 @@ export default defineComponent({ TraceDAG, TraceHeader, FlameGraphView, - TraceEvaluationsView, OToggleGroup, OToggleGroupItem, OButton, @@ -1370,13 +1338,6 @@ export default defineComponent({ return spans.some((span: any) => isLLMTrace(span)); }); - // Evaluation pipeline state - const evalPipelineExists = ref(false); - const evalPipelineStreamName = ref(null); - const evalData = ref([]); - const isLoadingEvalData = ref(false); - const traceEvaluationsViewRef = ref(null); - // Computed properties for new header const errorSpansCount = computed(() => { const spans = effectiveSpanList.value; @@ -1412,14 +1373,6 @@ export default defineComponent({ if (hasLLMSpans.value) { tabs.push({ label: "Thread", value: "thread" }); } - // Conditionally add Evaluations tab for LLM traces with evaluation data - if ( - hasLLMSpans.value && - evalPipelineExists.value && - evalData.value.length > 0 - ) { - tabs.push({ label: "Evaluations", value: "evaluations" }); - } return tabs; }); @@ -1498,37 +1451,6 @@ export default defineComponent({ }, ); - // Watch for stream and LLM spans to fetch evaluation pipeline - watch( - () => [currentTraceStreamName.value, hasLLMSpans.value], - async ([streamName, hasLlm]) => { - if (hasLlm && streamName) { - await fetchEvalPipeline(); - } else { - evalPipelineExists.value = false; - evalPipelineStreamName.value = null; - } - }, - { immediate: true }, - ); - - // Watch for trace ID changes to fetch evaluation data - watch( - () => [ - effectiveTraceId.value, - evalPipelineExists.value, - evalPipelineStreamName.value, - ], - async ([traceId, pipelineExists, streamName]) => { - if (pipelineExists && streamName && traceId) { - await fetchEvalData(); - } else { - evalData.value = []; - } - }, - { immediate: true }, - ); - const updateActiveTab = (tab: string) => { activeTab.value = tab; if(tab === 'map') { @@ -2657,130 +2579,6 @@ export default defineComponent({ await setupTraceDetails(); }; - /** - * Fetch LLM evaluation pipeline for the current trace stream - */ - const fetchEvalPipeline = async () => { - if (!currentTraceStreamName.value) { - evalPipelineExists.value = false; - return; - } - - try { - const orgId = store.state.selectedOrganization.identifier; - const res = await pipelineService.getPipelines(orgId); - const pipelines: any[] = res.data?.list || []; - - console.log( - "[TraceEval] Fetched pipelines:", - pipelines.length, - "Stream:", - currentTraceStreamName.value, - ); - - // Find pipeline with matching source stream and llm_evaluation node - const evalPipeline = pipelines.find( - (p: any) => - p.source?.stream_name === currentTraceStreamName.value && - p.source?.stream_type === "traces" && - p.nodes?.some((n: any) => n.data?.node_type === "llm_evaluation"), - ); - - if (evalPipeline) { - evalPipelineExists.value = true; - // Get the evaluation output stream name - const evalOutputNode = evalPipeline.nodes.find( - (n: any) => - n.io_type === "output" && n.data?.stream_type === "logs", - ); - evalPipelineStreamName.value = - evalOutputNode?.data?.stream_name || - `${currentTraceStreamName.value}_evaluations`; - console.log( - "[TraceEval] Found eval pipeline, stream:", - evalPipelineStreamName.value, - ); - } else { - console.log( - "[TraceEval] No eval pipeline found for stream:", - currentTraceStreamName.value, - ); - evalPipelineExists.value = false; - evalPipelineStreamName.value = null; - } - } catch (error) { - console.error("Error fetching evaluation pipeline:", error); - evalPipelineExists.value = false; - evalPipelineStreamName.value = null; - } - }; - - /** - * Fetch evaluation data for the current trace - */ - const fetchEvalData = async () => { - if ( - !evalPipelineExists.value || - !evalPipelineStreamName.value || - !effectiveTraceId.value - ) { - evalData.value = []; - return; - } - - isLoadingEvalData.value = true; - try { - console.log( - "[TraceEval] Fetching data from stream:", - evalPipelineStreamName.value, - "traceId:", - effectiveTraceId.value, - ); - - const req = { - query: { - sql: `SELECT * FROM "${evalPipelineStreamName.value}" WHERE trace_id = '${sanitizeTraceId(effectiveTraceId.value)}' ORDER BY _timestamp ASC`, - start_time: effectiveTimeRange.value.from - 60000000, - end_time: effectiveTimeRange.value.to + 60000000, - from: 0, - size: 100, - }, - }; - - const res = await searchService.search( - { - org_identifier: - (router.currentRoute.value.query?.org_identifier as string) || - store.state.selectedOrganization.identifier, - query: req, - page_type: "logs", - }, - "ui", - ); - - evalData.value = res.data?.hits || []; - console.log( - "[TraceEval] Fetched evaluation records:", - evalData.value.length, - ); - - // Load templates for the current org - if ( - traceEvaluationsViewRef.value?.loadTemplates && - effectiveOrgIdentifier.value - ) { - await traceEvaluationsViewRef.value.loadTemplates( - effectiveOrgIdentifier.value, - ); - } - } catch (error) { - console.error("Error fetching evaluation data:", error); - evalData.value = []; - } finally { - isLoadingEvalData.value = false; - } - }; - return { router, t, @@ -2905,14 +2703,6 @@ export default defineComponent({ // FlameGraph data flatSpans, traceMetadata, - // Evaluation data - evalPipelineExists, - evalPipelineStreamName, - evalData, - isLoadingEvalData, - traceEvaluationsViewRef, - fetchEvalPipeline, - fetchEvalData, formatLargeNumber, updateActiveTab }; diff --git a/web/src/views/Functions.spec.ts b/web/src/views/Functions.spec.ts index 8a0f05a68f..51a8739eac 100644 --- a/web/src/views/Functions.spec.ts +++ b/web/src/views/Functions.spec.ts @@ -358,28 +358,6 @@ describe("Functions.vue", () => { expect((wrapper.vm as any).isDetailView).toBe(false); }); - it("should compute pipelineSections excluding hidden pipelines", async () => { - wrapper = await createWrapper( - { zoConfig: { custom_hide_menus: "pipelines" } }, - "pipelines", - ); - const sections = (wrapper.vm as any).pipelineSections; - const streamPipelinesSection = sections.find( - (s: any) => s.key === "streamPipelines", - ); - expect(streamPipelinesSection?.visible).toBe(false); - }); - - it("should compute pipelineSections with streamPipelines present when not hidden", async () => { - wrapper = await createWrapper({}, "pipelines"); - const sections = (wrapper.vm as any).pipelineSections; - const streamPipelinesSection = sections.find( - (s: any) => s.key === "streamPipelines", - ); - // When not hidden, visible is not explicitly set to false - expect(streamPipelinesSection).toBeDefined(); - expect(streamPipelinesSection?.to?.name).toBe("pipelines"); - }); }); describe("Store Integration", () => { diff --git a/web/src/views/Functions.vue b/web/src/views/Functions.vue index cd40d11a49..9e5099866c 100644 --- a/web/src/views/Functions.vue +++ b/web/src/views/Functions.vue @@ -144,7 +144,6 @@ along with this program. If not, see .