diff --git a/open-sse/handlers/chatCore/streamingPipeline.ts b/open-sse/handlers/chatCore/streamingPipeline.ts index d67803918b..429b3d79de 100644 --- a/open-sse/handlers/chatCore/streamingPipeline.ts +++ b/open-sse/handlers/chatCore/streamingPipeline.ts @@ -23,6 +23,17 @@ import { createPiiSseTransform as defaultPiiSse } from "@/lib/streamingPiiTransf import { isFeatureFlagEnabled as defaultFeatureFlag } from "@/shared/utils/featureFlags"; import { OMNIROUTE_RESPONSE_HEADERS } from "@/shared/constants/headers"; import { SSE_HEARTBEAT_INTERVAL_MS } from "../../config/constants.ts"; +/** + * Pipeline assembly instrumentation — performance.mark() along the SSE hot path. + * Marks are visible to Node.js perf_hooks consumers and DevTools' Performance + * panel when NODE_OPTIONS=--enable-node-performance-clinician or similar. + * + * Each call to assembleStreamingPipeline creates one measure record: + * "omni-pipeline" — wall-clock duration of the full transform chain assembly. + */ +const PIPELINE_START = "omni-pipeline-start"; +const PIPELINE_END = "omni-pipeline-end"; +const PIPELINE_MEASURE = "omni-pipeline"; type HeadersLike = Headers | Record | null | undefined; @@ -61,6 +72,7 @@ export function assembleStreamingPipeline( }, deps: StreamingPipelineDeps = DEFAULT_DEPS ) { + performance.mark(PIPELINE_START); // ── Phase 9.3: Progress tracking (opt-in) ── const progressEnabled = deps.wantsProgress(args.clientRawRequestHeaders); let finalStream; @@ -77,7 +89,9 @@ export function assembleStreamingPipeline( } if (progressEnabled) { - const progressTransform = deps.createProgressTransform({ signal: args.streamController.signal }); + const progressTransform = deps.createProgressTransform({ + signal: args.streamController.signal, + }); // Chain: provider → transform → progress → client finalStream = piiStream.pipeThrough(progressTransform); args.responseHeaders[OMNIROUTE_RESPONSE_HEADERS.progress] = "enabled"; @@ -95,5 +109,7 @@ export function assembleStreamingPipeline( if (args.echoModel) { finalStream = finalStream.pipeThrough(deps.createModelEchoTransform(args.echoModel)); } + performance.mark(PIPELINE_END); + performance.measure(PIPELINE_MEASURE, PIPELINE_START, PIPELINE_END); return finalStream; } diff --git a/open-sse/utils/stream.ts b/open-sse/utils/stream.ts index 581f1f6342..e145ab4290 100644 --- a/open-sse/utils/stream.ts +++ b/open-sse/utils/stream.ts @@ -639,6 +639,16 @@ export function createSSEStream(options: StreamOptions = {}) { dropResponsesCommentary, } = options; const signatureNamespace = connectionId; + // Request-body-size metric (for monitoring payload size distribution & correlation with TTFT). + // The size is JSON-serialised byte count; stored as a performance mark detail so monitoring + // tools can query performance.getEntriesByType("mark") filtered by name. + let bodySize = 0; + try { + bodySize = body ? new TextEncoder().encode(JSON.stringify(body)).length : 0; + } catch { + /* body may not be JSON-serialisable (e.g. FormData, Blob) — metric stays 0 */ + } + if (bodySize > 0) performance.mark("omni-request-body-size", { detail: bodySize }); // Drop internal commentary-phase Responses output before forwarding (#6199). // Explicit option wins; otherwise read the feature flag (default on). Resolved