From aa3e6997123a9cf84e51d1bd9e6c0bac27f6452b Mon Sep 17 00:00:00 2001 From: John | Elite Encoder Date: Sat, 5 Sep 2026 02:31:51 -0400 Subject: [PATCH] fix(usage): infer history modality without a competing Drizzle genesis. Keep the in-memory MCP store so this can land on main without racing Codex's waitlist migrations. Output joins stay a no-op until mcp_assets exists on that chain. --- app/api/pymthouse/account-requests/route.ts | 10 +- components/console/CallDetailDrawer.tsx | 455 +++++--------------- components/console/CallsSection.tsx | 5 +- components/console/CallsTable.tsx | 100 ++--- lib/console/account-usage.ts | 6 + lib/console/activity-assets.ts | 15 + lib/console/activity-media.test.ts | 75 ++++ lib/console/activity-media.ts | 199 +++++++++ lib/console/activity-output-match.test.ts | 165 +++++++ lib/console/activity-output-match.ts | 93 ++++ lib/console/capability-modality.test.ts | 156 +++++++ lib/console/capability-modality.ts | 268 ++++++++++++ lib/console/dev-mock.ts | 30 +- lib/console/history-window.test.ts | 32 ++ lib/console/history-window.ts | 35 ++ lib/console/mock-data.ts | 5 + lib/console/pymthouse-bff.ts | 17 +- lib/console/request-fee-display.test.ts | 43 ++ lib/console/request-fee-display.ts | 187 ++++++++ lib/console/signed-ticket-activity.ts | 31 +- lib/console/types.ts | 8 + lib/console/usage-capability-display.ts | 6 - lib/mcp/jwt.ts | 6 +- lib/mcp/log.ts | 6 +- lib/mcp/principal.test.ts | 24 ++ lib/mcp/principal.ts | 29 ++ lib/mcp/run-capability.test.ts | 11 + lib/mcp/run-capability.ts | 18 +- 28 files changed, 1589 insertions(+), 446 deletions(-) create mode 100644 lib/console/activity-assets.ts create mode 100644 lib/console/activity-media.test.ts create mode 100644 lib/console/activity-media.ts create mode 100644 lib/console/activity-output-match.test.ts create mode 100644 lib/console/activity-output-match.ts create mode 100644 lib/console/capability-modality.test.ts create mode 100644 lib/console/capability-modality.ts create mode 100644 lib/console/history-window.test.ts create mode 100644 lib/console/history-window.ts create mode 100644 lib/console/request-fee-display.test.ts create mode 100644 lib/console/request-fee-display.ts create mode 100644 lib/mcp/principal.test.ts create mode 100644 lib/mcp/principal.ts diff --git a/app/api/pymthouse/account-requests/route.ts b/app/api/pymthouse/account-requests/route.ts index 4d35ea3..95e5663 100644 --- a/app/api/pymthouse/account-requests/route.ts +++ b/app/api/pymthouse/account-requests/route.ts @@ -1,4 +1,5 @@ import { NextRequest, NextResponse } from "next/server"; +import { attachOutputsToTickets } from "@/lib/console/activity-assets"; import { fetchAccountRequestsForExternalUser } from "@/lib/console/pymthouse-bff"; import { requireConsoleSession } from "@/lib/console/session-user"; import { @@ -29,7 +30,14 @@ export async function GET(request: NextRequest) { cursor, limit, }); - return NextResponse.json(payload, { headers: PYMTHOUSE_NO_STORE_HEADERS }); + const items = await attachOutputsToTickets( + session.externalUserId, + payload.items + ); + return NextResponse.json( + { ...payload, items }, + { headers: PYMTHOUSE_NO_STORE_HEADERS } + ); } catch (error) { return pymthouseErrorResponse(error, "Requests fetch failed"); } diff --git a/components/console/CallDetailDrawer.tsx b/components/console/CallDetailDrawer.tsx index 585bd0c..06fbb1c 100644 --- a/components/console/CallDetailDrawer.tsx +++ b/components/console/CallDetailDrawer.tsx @@ -9,284 +9,14 @@ import { type WheelEvent as ReactWheelEvent, } from "react"; import { createPortal } from "react-dom"; -import { Maximize2, MoreVertical, Play, VolumeX } from "lucide-react"; -import { modalityTag } from "@/components/console/CallsTable"; import { formatCallMetric } from "@/lib/console/utils"; -import type { - AccountActivityRow, - AccountActivityStatus, -} from "@/lib/console/types"; - -const STATUS_LABEL: Record = { - active: "Streaming", - success: "Succeeded", - failed: "Failed", - timeout: "Timed out", -}; - -type MediaKind = "image" | "video" | "audio" | "text" | "json"; - -type MediaSpec = { - kind: MediaKind; - title: string; - label: string; - format: string; - metricLabel: string; - metricValue: string; - source: string; - imageUrl?: string; - text?: string; - json?: unknown; -}; - -const AUDIO_BARS = Array.from({ length: 64 }, (_, i) => { - const envelope = Math.sin((i / 64) * Math.PI); - const detail = Math.sin(i * 1.3) * 0.32 + Math.sin(i * 0.45) * 0.22; - return Math.max(12, Math.round((0.18 + envelope * 0.72 + detail * 0.2) * 96)); -}); - -function previewSeed(row: AccountActivityRow): string { - return encodeURIComponent( - `${row.id}-${row.pipeline}`.replace(/[^a-z0-9_-]+/gi, "-") - ); -} - -function previewImageUrl(row: AccountActivityRow, size = "1200/900"): string { - return `https://picsum.photos/seed/${previewSeed(row)}/${size}`; -} - -function samplePayload(row: AccountActivityRow): { - request: unknown; - response: unknown; -} { - const failed = row.status === "failed" || row.status === "timeout"; - const error = - row.status === "timeout" - ? { - error: "deadline_exceeded", - message: "No orchestrator responded in time.", - } - : { - error: "inference_failed", - message: "The pipeline returned a non-2xx status.", - }; - - switch (row.pipeline) { - case "text-to-image": - case "image-to-image": - return { - request: { - prompt: "a neon-lit city street at night, cinematic", - steps: 4, - seed: 41207, - }, - response: failed - ? error - : { - image_url: previewImageUrl(row, "1024/1024"), - width: 1024, - height: 1024, - }, - }; - case "image-to-video": - case "text-to-video": - case "video-to-video": - case "live-video-to-video": - return { - request: { - prompt: "wide cinematic production frame, soft natural motion", - duration_s: 6, - }, - response: failed - ? error - : { - video_url: "https://gateway.livepeer/out/render.mp4", - width: 1920, - height: 1080, - duration_s: 6, - }, - }; - case "transcoding": - case "live-transcoding": - return { - request: { - source_url: "https://gateway.livepeer/in/feed.mp4", - profiles: ["1080p", "720p", "480p"], - }, - response: failed - ? error - : { - playback_url: "https://gateway.livepeer/out/master.m3u8", - width: 1920, - height: 1080, - }, - }; - case "language": - case "text-generation": - return { - request: { - messages: [ - { - role: "user", - content: "Summarize the Livepeer whitepaper in 3 bullets.", - }, - ], - max_tokens: 512, - }, - response: failed - ? error - : { - text: "- Decentralized GPU network\n- Pay-per-use inference\n- Open, permissionless apps", - tokens: 187, - }, - }; - case "audio-to-text": - return { - request: { - audio_url: "https://gateway.livepeer/in/clip.wav", - language: "en", - }, - response: failed - ? error - : { - text: "Welcome back to the show. Today we're talking real-time AI video.", - duration_s: 12.4, - }, - }; - case "text-to-speech": - case "text-to-audio": - return { - request: { text: "Hello from the Livepeer network.", voice: "am_onyx" }, - response: failed - ? error - : { - audio_url: "https://gateway.livepeer/out/tts-8821.wav", - duration_s: 2.1, - }, - }; - case "video-understanding": - return { - request: { - video_url: "https://gateway.livepeer/in/feed.mp4", - task: "detect", - }, - response: failed - ? error - : { - detections: [ - { label: "person", confidence: 0.98 }, - { label: "bicycle", confidence: 0.83 }, - ], - }, - }; - default: - return { - request: { input: "...", pipeline: row.pipeline }, - response: failed ? error : { output: "...", pipeline: row.pipeline }, - }; - } -} - -function readText(value: unknown): string | undefined { - if (!value || typeof value !== "object") return undefined; - const text = (value as { text?: unknown }).text; - return typeof text === "string" ? text : undefined; -} - -function readTokenCount(value: unknown): string { - if (!value || typeof value !== "object") return "Text"; - const tokens = (value as { tokens?: unknown }).tokens; - return typeof tokens === "number" ? `${tokens} tokens` : "Text"; -} - -function mediaSpecForRow(row: AccountActivityRow): MediaSpec { - const payload = samplePayload(row); - const pipeline = row.pipeline.toLowerCase(); - const failed = row.status === "failed" || row.status === "timeout"; - const source = row.signerLabel || "Livepeer"; - - if (failed) { - return { - kind: "json", - title: `${row.model} request`, - label: "Error", - format: "JSON", - metricLabel: "Result", - metricValue: STATUS_LABEL[row.status], - source, - json: payload.response, - }; - } - - if (pipeline.includes("video") || pipeline.includes("transcoding")) { - return { - kind: "video", - title: - row.kind === "live" ? `${row.model} session` : `${row.model} video`, - label: "Video", - format: pipeline.includes("transcoding") ? "HLS" : "MP4", - metricLabel: "Dimensions", - metricValue: "1920 x 1080", - source, - imageUrl: previewImageUrl(row, "1280/720"), - }; - } - - if (pipeline.includes("image")) { - return { - kind: "image", - title: `${row.model} image`, - label: "Image", - format: "PNG", - metricLabel: "Dimensions", - metricValue: "1024 x 1024", - source, - imageUrl: previewImageUrl(row, "1024/1024"), - }; - } - - if (pipeline.includes("audio") || pipeline.includes("speech")) { - return { - kind: "audio", - title: `${row.model} audio`, - label: "Audio", - format: "WAV", - metricLabel: "Duration", - metricValue: - row.pipeline === "audio-to-text" ? "12.4s source" : "2.1s output", - source, - }; - } - - if ( - pipeline === "language" || - pipeline === "llm" || - pipeline.includes("text") - ) { - const text = readText(payload.response) ?? JSON.stringify(payload.response); - return { - kind: "text", - title: `${row.model} response`, - label: "Text", - format: "TXT", - metricLabel: "Length", - metricValue: readTokenCount(payload.response), - source, - text, - }; - } - - return { - kind: "json", - title: `${row.model} response`, - label: "Data", - format: "JSON", - metricLabel: "Result", - metricValue: STATUS_LABEL[row.status], - source, - json: payload.response, - }; -} +import Tooltip from "@/components/design-system/Tooltip"; +import { + mediaSpecForRow, + STATUS_LABEL, + type MediaSpec, +} from "@/lib/console/activity-media"; +import type { AccountActivityRow } from "@/lib/console/types"; function formatTimestamp(iso: string): string { const date = new Date(iso); @@ -322,17 +52,36 @@ function CapabilityChip({ children }: { children: ReactNode }) { ); } -function ImagePreview({ - src, - title, -}: { - src: string; - title: string; -}) { +function EmptyOutput() { + return ( +
+ No output stored for this job +
+ ); +} + +function PreviewLoader() { + return ( +
+
+ ); +} + +function ImagePreview({ src, title }: { src: string; title: string }) { const [failed, setFailed] = useState(false); + const [loaded, setLoaded] = useState(false); useEffect(() => { setFailed(false); + setLoaded(false); }, [src]); if (failed) { @@ -344,65 +93,39 @@ function ImagePreview({ } return ( - {title} setFailed(true)} - className="h-full w-full object-contain object-top lg:object-center" - /> +
+ {!loaded && } + {title} setLoaded(true)} + onError={() => setFailed(true)} + className={`h-full w-full object-contain object-top lg:object-center ${ + loaded ? "opacity-100" : "opacity-0" + }`} + /> +
); } -function VideoPreview({ poster }: { poster?: string }) { +function VideoPreview({ src }: { src?: string }) { + if (!src) return ; return ( -
- {poster && ( - - )} -
-
-
-
-
-
-
-
-
+