"use client"; import { useState, useEffect } from "react"; import { PROVIDER_COLORS, getHttpStatusStyle as getStatusStyle, getProtocolColor, } from "@/shared/constants/colors"; import { formatDuration, formatApiKeyLabel } from "@/shared/utils/formatting"; // ─── Payload Code Block ───────────────────────────────────────────────────── function PayloadSection({ title, json, onCopy }) { const [copied, setCopied] = useState(false); const handleCopy = async () => { const success = await onCopy(); if (success !== false) { setCopied(true); setTimeout(() => setCopied(false), 2000); } }; return (

{title}

        {json}
      
); } // ─── Detail Modal ─────────────────────────────────────────────────────────── type StreamChunks = Record; export default function RequestLoggerDetail({ log, detail, loading, debugEnabled, onClose, onCopy, }) { // Close on Escape key useEffect(() => { const handler = (e) => { if (e.key === "Escape") onClose(); }; globalThis.addEventListener("keydown", handler); return () => globalThis.removeEventListener("keydown", handler); }, [onClose]); const statusStyle = getStatusStyle(log.status); const protocolKey = log.sourceFormat || log.provider; const protocol = getProtocolColor(protocolKey, log.provider); const providerColor = PROVIDER_COLORS[log.provider] || { bg: "#374151", text: "#fff", label: (log.provider || "-").toUpperCase(), }; const providerStatus = detail?.pipelinePayloads?.providerResponse?.status; const hasStatusDiscrepancy = providerStatus && providerStatus !== log.status; const formatDate = (iso) => { try { const d = new Date(iso); return ( d.toLocaleDateString("pt-BR") + ", " + d.toLocaleTimeString("en-US", { hour12: false }) ); } catch { return iso; } }; const toPrettyJson = (payload) => { if (payload === null || payload === undefined) return null; try { return JSON.stringify(payload, null, 2); } catch { return String(payload); } }; const pipelinePayloads = detail?.pipelinePayloads || null; const payloadSections = pipelinePayloads ? [ ["clientRawRequest", "Client Raw Request"], ["clientRequest", "Client Request"], ["openaiRequest", "OpenAI Request"], ["providerRequest", "Provider Request"], ["providerResponse", "Provider Response"], ["clientResponse", "Client Response"], ["error", "Pipeline Error"], ] .map(([key, title]) => ({ key, title, json: toPrettyJson(pipelinePayloads[key]), })) .filter((section) => section.json) : []; const requestJson = detail?.requestBody ? toPrettyJson(detail.requestBody) : null; const responseJson = detail?.responseBody ? toPrettyJson(detail.responseBody) : null; const streamChunksText = (() => { if (!debugEnabled || !detail?.pipelinePayloads?.streamChunks) return null; let chunks: StreamChunks = detail.pipelinePayloads.streamChunks; // If stored as a JSON string, try to parse it so we can render joined raw chunks if (typeof chunks === "string") { try { const parsed = JSON.parse(chunks); chunks = parsed; } catch { // Keep as string and return raw text (don't JSON-stringify) return chunks; } } if (chunks && typeof chunks === "object") { try { return Object.entries(chunks) .map(([stage, arr]) => { const joined = Array.isArray(arr) ? arr.join("") : String(arr); return `--- ${stage} ---\n${joined}`; }) .join("\n\n"); } catch { return toPrettyJson(chunks); } } return null; })(); const detailIssue = detail?.detailState === "missing" ? "Detailed payload artifact is no longer available for this log entry." : detail?.detailState === "corrupt" ? "Detailed payload artifact could not be parsed." : null; const tokenStats = { totalIn: detail?.tokens?.in ?? log.tokens?.in ?? 0, totalOut: detail?.tokens?.out ?? log.tokens?.out ?? 0, cacheRead: detail?.tokens?.cacheRead ?? log.tokens?.cacheRead, cacheWrite: detail?.tokens?.cacheWrite ?? log.tokens?.cacheWrite, reasoning: detail?.tokens?.reasoning ?? log.tokens?.reasoning, compressed: detail?.tokens?.compressed ?? log.tokens?.compressed, }; const formatTokenValue = (value) => (value != null ? value.toLocaleString() : "N/A"); const cacheSource = detail?.cacheSource || log.cacheSource || "upstream"; const cacheSourceLabel = cacheSource === "semantic" ? "Semantic (OmniRoute)" : "Upstream (Provider)"; const cacheSourceClassName = cacheSource === "semantic" ? "bg-emerald-500/20 text-emerald-700 dark:text-emerald-300 border-emerald-500/30" : "bg-sky-500/20 text-sky-700 dark:text-sky-300 border-sky-500/30"; return (
e.stopPropagation()} > {/* Modal Header */}
{log.status} {hasStatusDiscrepancy && ( Upstream: {providerStatus} )} {log.method}
{hasStatusDiscrepancy && ( OmniRoute returned {log.status} even though provider returned {providerStatus} )}
{log.path}
{/* Metadata Grid */}
Completed Time
{formatDate(log.timestamp)}
Duration
{formatDuration(log.duration)}
Input
Total In: {tokenStats.totalIn.toLocaleString()} Cache Read: {formatTokenValue(tokenStats.cacheRead)} Cache Write: {formatTokenValue(tokenStats.cacheWrite)} {tokenStats.compressed != null && tokenStats.compressed > 0 && (() => { const fromTokens = tokenStats.totalIn + tokenStats.compressed; const pct = Math.round((tokenStats.compressed / fromTokens) * 100); return ( Compressed: {fromTokens.toLocaleString()} → {tokenStats.totalIn.toLocaleString()} (-{pct}%) ); })()}
Output
Total Out: {tokenStats.totalOut.toLocaleString()} Reasoning: {formatTokenValue(tokenStats.reasoning)}
Model
{log.model}
Requested Model
{detail?.requestedModel || log.requestedModel || "—"}
Provider
{providerColor.label}
Req Protocol
{protocol.label}
Cache Source
{cacheSourceLabel}
Account
{detail?.account || log.account || "-"}
API Key
{formatApiKeyLabel( detail?.apiKeyName || log.apiKeyName, detail?.apiKeyId || log.apiKeyId )}
Combo
{detail?.comboName || log.comboName ? ( {detail?.comboName || log.comboName} ) : (
—
)}
{/* Error Message */} {(detail?.error || log.error) && (
Error
{detail?.error || log.error}
)} {detailIssue && (
Detail Status
{detailIssue}
)} {loading ? (
Loading request details...
) : ( <> {payloadSections.length > 0 && payloadSections.map((section) => ( onCopy(section.json)} /> ))} {streamChunksText && ( onCopy(streamChunksText)} /> )} {payloadSections.length === 0 && responseJson && ( onCopy(responseJson)} /> )} {payloadSections.length === 0 && requestJson && ( onCopy(requestJson)} /> )} {payloadSections.length === 0 && !requestJson && !responseJson && !loading && (
info

No payload data available for this log entry.

Enable detailed logging first if you want the four-stage client/provider payload view for new requests.

)} )}
); }