diff --git a/pdl-live-react/src/helpers.ts b/pdl-live-react/src/helpers.ts
index 340c73f6f..685f7f3aa 100644
--- a/pdl-live-react/src/helpers.ts
+++ b/pdl-live-react/src/helpers.ts
@@ -187,6 +187,19 @@ export function hasModelUsage(
)
}
+export function completionRate(
+ block: ModelBlockWithUsage & PdlBlockWithTiming,
+) {
+ return (
+ block.pdl__usage.completion_tokens /
+ ((block.pdl__timing.end_nanos - block.pdl__timing.start_nanos) / 1000000000)
+ )
+}
+
+export function ptcRatio(block: ModelBlockWithUsage) {
+ return block.pdl__usage.prompt_tokens / block.pdl__usage.completion_tokens
+}
+
/** Does the given block have context/background information? */
export function hasContextInformation(
block: unknown | PdlBlock,
diff --git a/pdl-live-react/src/view/detail/DrawerContentBody.tsx b/pdl-live-react/src/view/detail/DrawerContentBody.tsx
index 7dd578ae0..26a2150c7 100644
--- a/pdl-live-react/src/view/detail/DrawerContentBody.tsx
+++ b/pdl-live-react/src/view/detail/DrawerContentBody.tsx
@@ -3,6 +3,7 @@ import { Tab, TabTitleText } from "@patternfly/react-core"
const BlockNotFound = lazy(() => import("./BlockNotFound"))
const DefContent = lazy(() => import("./DefContent"))
+const UsageTabContent = lazy(() => import("./UsageTabContent"))
const SourceTabContent = lazy(() => import("./SourceTabContent"))
const ContextTabContent = lazy(() => import("./ContextTabContent"))
const SummaryTabContent = lazy(() => import("./SummaryTabContent"))
@@ -10,6 +11,7 @@ const RawTraceTabContent = lazy(() => import("./RawTraceTabContent"))
import {
hasContextInformation,
+ hasModelUsage,
hasResult,
type NonScalarPdlBlock as Model,
} from "../../helpers"
@@ -54,6 +56,18 @@ function blockBody(block: Model) {
)
}
+ if (hasModelUsage(block)) {
+ tabs.splice(
+ 1,
+ 0,
+ Usage}>
+
+
+
+ ,
+ )
+ }
+
return tabs
}
diff --git a/pdl-live-react/src/view/detail/UsageTabContent.tsx b/pdl-live-react/src/view/detail/UsageTabContent.tsx
new file mode 100644
index 000000000..9f5663942
--- /dev/null
+++ b/pdl-live-react/src/view/detail/UsageTabContent.tsx
@@ -0,0 +1,55 @@
+import {
+ DescriptionList,
+ DescriptionListGroup,
+ DescriptionListDescription,
+ DescriptionListTerm,
+} from "@patternfly/react-core"
+
+import {
+ completionRate,
+ ptcRatio,
+ type ModelBlockWithUsage,
+ type PdlBlockWithTiming,
+} from "../../helpers"
+
+export default function UsageTabContent({
+ block,
+}: {
+ block: ModelBlockWithUsage & PdlBlockWithTiming
+}) {
+ return {descriptionItems(block)}
+}
+
+function descriptionItems(block: ModelBlockWithUsage & PdlBlockWithTiming) {
+ return (
+ <>
+
+ Completion Rate
+
+ {completionRate(block).toFixed(0)} tokens/sec
+
+
+
+
+ Prompt/Completion Ratio
+
+ {(ptcRatio(block) * 100).toFixed(2)}%
+
+
+
+
+ Prompt Tokens Consumed
+
+ {block.pdl__usage.prompt_tokens}
+
+
+
+
+ Completion Tokens Consumed
+
+ {block.pdl__usage.completion_tokens}
+
+
+ >
+ )
+}
diff --git a/pdl-live-react/src/view/masonry/MasonryTile.tsx b/pdl-live-react/src/view/masonry/MasonryTile.tsx
index 4bef5c788..c79e15c67 100644
--- a/pdl-live-react/src/view/masonry/MasonryTile.tsx
+++ b/pdl-live-react/src/view/masonry/MasonryTile.tsx
@@ -53,6 +53,8 @@ export default function MasonryTile({
footer1Value,
footer2Key,
footer2Value,
+ footer3Key,
+ footer3Value,
stability,
actions: tileActions = [],
block,
@@ -119,6 +121,7 @@ export default function MasonryTile({
const hasFooter =
(footer1Key && footer1Value) ||
(footer2Key && footer2Value) ||
+ (footer3Key && footer3Value) ||
(stability?.length ?? 0) > 0
const footer = hasFooter && (
@@ -138,6 +141,14 @@ export default function MasonryTile({
)}
+ {footer3Key && (
+
+ {footer3Key}
+
+ {footer3Value}
+
+
+ )}
{stability &&
stability.map((m) => (
`T=${m.temperature} Stability`),