@copilotz/admin 0.9.35 → 0.9.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +411 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -4
- package/dist/index.d.ts +14 -4
- package/dist/index.js +419 -91
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -43,11 +43,44 @@ async function mergeHeaders(headers, getRequestHeaders) {
|
|
|
43
43
|
async function parseJsonResponse(response) {
|
|
44
44
|
const payload = await response.json().catch(() => null);
|
|
45
45
|
if (!response.ok) {
|
|
46
|
-
const message = payload?.message ?? payload?.data?.message ?? `Admin request failed (${response.status})`;
|
|
46
|
+
const message = payload?.message ?? payload?.data?.message ?? payload?.error?.message ?? `Admin request failed (${response.status})`;
|
|
47
47
|
throw new Error(message);
|
|
48
48
|
}
|
|
49
49
|
return payload?.data ?? payload;
|
|
50
50
|
}
|
|
51
|
+
async function parseJsonEnvelopeResponse(response) {
|
|
52
|
+
const payload = await response.json().catch(() => null);
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
const message = payload?.message ?? payload?.data?.message ?? payload?.error?.message ?? `Admin request failed (${response.status})`;
|
|
55
|
+
throw new Error(message);
|
|
56
|
+
}
|
|
57
|
+
return payload;
|
|
58
|
+
}
|
|
59
|
+
function isRecord(value) {
|
|
60
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
61
|
+
}
|
|
62
|
+
function normalizeMessagePageInfo(value, messages) {
|
|
63
|
+
const oldestFromData = messages[0]?.id ?? null;
|
|
64
|
+
const newestFromData = messages[messages.length - 1]?.id ?? null;
|
|
65
|
+
if (!isRecord(value)) {
|
|
66
|
+
return {
|
|
67
|
+
hasMoreBefore: false,
|
|
68
|
+
oldestMessageId: oldestFromData,
|
|
69
|
+
newestMessageId: newestFromData
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
hasMoreBefore: value.hasMoreBefore === true,
|
|
74
|
+
oldestMessageId: typeof value.oldestMessageId === "string" ? value.oldestMessageId : oldestFromData,
|
|
75
|
+
newestMessageId: typeof value.newestMessageId === "string" ? value.newestMessageId : newestFromData
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function normalizeMessagePage(payload) {
|
|
79
|
+
const candidate = isRecord(payload) && isRecord(payload.data) && Array.isArray(payload.data.data) ? payload.data : payload;
|
|
80
|
+
const data = isRecord(candidate) && Array.isArray(candidate.data) ? candidate.data : Array.isArray(candidate) ? candidate : [];
|
|
81
|
+
const pageInfo = isRecord(candidate) ? normalizeMessagePageInfo(candidate.pageInfo, data) : normalizeMessagePageInfo(void 0, data);
|
|
82
|
+
return { data, pageInfo };
|
|
83
|
+
}
|
|
51
84
|
function createAdminClient(options = {}) {
|
|
52
85
|
const baseUrl = resolveBaseUrl(options.baseUrl);
|
|
53
86
|
const paths = { ...DEFAULT_PATHS, ...options.paths };
|
|
@@ -58,6 +91,13 @@ function createAdminClient(options = {}) {
|
|
|
58
91
|
});
|
|
59
92
|
return await parseJsonResponse(response);
|
|
60
93
|
};
|
|
94
|
+
const requestEnvelopeJson = async (path, params) => {
|
|
95
|
+
const url = buildUrl(baseUrl, path, params);
|
|
96
|
+
const response = await fetch(url.toString(), {
|
|
97
|
+
headers: await mergeHeaders({}, options.getRequestHeaders)
|
|
98
|
+
});
|
|
99
|
+
return await parseJsonEnvelopeResponse(response);
|
|
100
|
+
};
|
|
61
101
|
const writeJson = async (method, path, data, params) => {
|
|
62
102
|
const url = buildUrl(baseUrl, path, params);
|
|
63
103
|
const response = await fetch(url.toString(), {
|
|
@@ -100,12 +140,16 @@ function createAdminClient(options = {}) {
|
|
|
100
140
|
metric: filters.metric,
|
|
101
141
|
groupBy: filters.groupBy,
|
|
102
142
|
attribution: filters.attribution,
|
|
143
|
+
kind: filters.kind,
|
|
103
144
|
threadId: filters.threadId,
|
|
104
145
|
participantId: filters.participantId,
|
|
105
146
|
participantType: filters.participantType,
|
|
106
147
|
namespace: filters.namespace,
|
|
107
148
|
provider: filters.provider,
|
|
108
|
-
model: filters.model
|
|
149
|
+
model: filters.model,
|
|
150
|
+
resource: filters.resource,
|
|
151
|
+
operation: filters.operation,
|
|
152
|
+
status: filters.status
|
|
109
153
|
}),
|
|
110
154
|
listThreads: async (listOptions = {}) => await requestJson(`${paths.adminBase}/threads`, {
|
|
111
155
|
search: listOptions.search,
|
|
@@ -133,13 +177,16 @@ function createAdminClient(options = {}) {
|
|
|
133
177
|
getThread: async (threadId) => await requestJson(
|
|
134
178
|
`${paths.threadsBase}/${encodeURIComponent(threadId)}`
|
|
135
179
|
),
|
|
136
|
-
getThreadMessages: async (threadId, messageOptions = {}) =>
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
180
|
+
getThreadMessages: async (threadId, messageOptions = {}) => {
|
|
181
|
+
const payload = await requestEnvelopeJson(
|
|
182
|
+
`${paths.threadsBase}/${encodeURIComponent(threadId)}/messages`,
|
|
183
|
+
{
|
|
184
|
+
limit: messageOptions.limit ? String(messageOptions.limit) : void 0,
|
|
185
|
+
before: messageOptions.before
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
return normalizeMessagePage(payload);
|
|
189
|
+
},
|
|
143
190
|
getThreadEvent: async (threadId) => await requestJson(
|
|
144
191
|
`${paths.threadsBase}/${encodeURIComponent(threadId)}/events`
|
|
145
192
|
),
|
|
@@ -1355,7 +1402,11 @@ var EMPTY_USAGE_TOTALS = {
|
|
|
1355
1402
|
reasoningTokens: 0,
|
|
1356
1403
|
totalCalls: 0,
|
|
1357
1404
|
totalCostUsd: 0,
|
|
1358
|
-
|
|
1405
|
+
failedCalls: 0,
|
|
1406
|
+
totalCredits: 0,
|
|
1407
|
+
totalDurationMs: 0,
|
|
1408
|
+
totalTokens: 0,
|
|
1409
|
+
unpricedCalls: 0
|
|
1359
1410
|
};
|
|
1360
1411
|
var USAGE_CHART_COLORS = [
|
|
1361
1412
|
"hsl(var(--primary))",
|
|
@@ -1366,53 +1417,66 @@ var USAGE_CHART_COLORS = [
|
|
|
1366
1417
|
"hsl(var(--muted-foreground))"
|
|
1367
1418
|
];
|
|
1368
1419
|
function addUsageTotals(target, source) {
|
|
1369
|
-
target.cacheCreationInputCostUsd += source.cacheCreationInputCostUsd;
|
|
1370
|
-
target.cacheCreationInputTokens += source.cacheCreationInputTokens;
|
|
1371
|
-
target.cacheReadInputCostUsd += source.cacheReadInputCostUsd;
|
|
1372
|
-
target.cacheReadInputTokens += source.cacheReadInputTokens;
|
|
1373
|
-
target.inputCostUsd += source.inputCostUsd;
|
|
1374
|
-
target.inputTokens += source.inputTokens;
|
|
1375
|
-
target.outputCostUsd += source.outputCostUsd;
|
|
1376
|
-
target.outputTokens += source.outputTokens;
|
|
1377
|
-
target.reasoningCostUsd += source.reasoningCostUsd;
|
|
1378
|
-
target.reasoningTokens += source.reasoningTokens;
|
|
1379
|
-
target.totalCalls += source.totalCalls;
|
|
1380
|
-
target.totalCostUsd += source.totalCostUsd;
|
|
1381
|
-
target.
|
|
1420
|
+
target.cacheCreationInputCostUsd += safeUsageNumber(source.cacheCreationInputCostUsd);
|
|
1421
|
+
target.cacheCreationInputTokens += safeUsageNumber(source.cacheCreationInputTokens);
|
|
1422
|
+
target.cacheReadInputCostUsd += safeUsageNumber(source.cacheReadInputCostUsd);
|
|
1423
|
+
target.cacheReadInputTokens += safeUsageNumber(source.cacheReadInputTokens);
|
|
1424
|
+
target.inputCostUsd += safeUsageNumber(source.inputCostUsd);
|
|
1425
|
+
target.inputTokens += safeUsageNumber(source.inputTokens);
|
|
1426
|
+
target.outputCostUsd += safeUsageNumber(source.outputCostUsd);
|
|
1427
|
+
target.outputTokens += safeUsageNumber(source.outputTokens);
|
|
1428
|
+
target.reasoningCostUsd += safeUsageNumber(source.reasoningCostUsd);
|
|
1429
|
+
target.reasoningTokens += safeUsageNumber(source.reasoningTokens);
|
|
1430
|
+
target.totalCalls += safeUsageNumber(source.totalCalls);
|
|
1431
|
+
target.totalCostUsd += safeUsageNumber(source.totalCostUsd);
|
|
1432
|
+
target.failedCalls += safeUsageNumber(source.failedCalls);
|
|
1433
|
+
target.totalCredits += safeUsageNumber(source.totalCredits);
|
|
1434
|
+
target.totalDurationMs += safeUsageNumber(source.totalDurationMs);
|
|
1435
|
+
target.totalTokens += safeUsageNumber(source.totalTokens);
|
|
1436
|
+
target.unpricedCalls += safeUsageNumber(source.unpricedCalls);
|
|
1437
|
+
}
|
|
1438
|
+
function safeUsageNumber(value) {
|
|
1439
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
1382
1440
|
}
|
|
1383
1441
|
function getUsageTotalValue(totals, metricKind, dimension) {
|
|
1384
|
-
if (metricKind === "calls") return totals.totalCalls;
|
|
1442
|
+
if (metricKind === "calls") return safeUsageNumber(totals.totalCalls);
|
|
1443
|
+
if (metricKind === "duration") {
|
|
1444
|
+
return safeUsageNumber(totals.totalDurationMs);
|
|
1445
|
+
}
|
|
1446
|
+
if (metricKind === "credits") return safeUsageNumber(totals.totalCredits);
|
|
1447
|
+
if (metricKind === "failures") return safeUsageNumber(totals.failedCalls);
|
|
1448
|
+
if (metricKind === "unpriced") return safeUsageNumber(totals.unpricedCalls);
|
|
1385
1449
|
if (metricKind === "cost") {
|
|
1386
1450
|
switch (dimension) {
|
|
1387
1451
|
case "input":
|
|
1388
|
-
return totals.inputCostUsd;
|
|
1452
|
+
return safeUsageNumber(totals.inputCostUsd);
|
|
1389
1453
|
case "output":
|
|
1390
|
-
return totals.outputCostUsd;
|
|
1454
|
+
return safeUsageNumber(totals.outputCostUsd);
|
|
1391
1455
|
case "reasoning":
|
|
1392
|
-
return totals.reasoningCostUsd;
|
|
1456
|
+
return safeUsageNumber(totals.reasoningCostUsd);
|
|
1393
1457
|
case "cacheRead":
|
|
1394
|
-
return totals.cacheReadInputCostUsd;
|
|
1458
|
+
return safeUsageNumber(totals.cacheReadInputCostUsd);
|
|
1395
1459
|
case "cacheWrite":
|
|
1396
|
-
return totals.cacheCreationInputCostUsd;
|
|
1460
|
+
return safeUsageNumber(totals.cacheCreationInputCostUsd);
|
|
1397
1461
|
case "total":
|
|
1398
1462
|
default:
|
|
1399
|
-
return totals.totalCostUsd;
|
|
1463
|
+
return safeUsageNumber(totals.totalCostUsd);
|
|
1400
1464
|
}
|
|
1401
1465
|
}
|
|
1402
1466
|
switch (dimension) {
|
|
1403
1467
|
case "input":
|
|
1404
|
-
return totals.inputTokens;
|
|
1468
|
+
return safeUsageNumber(totals.inputTokens);
|
|
1405
1469
|
case "output":
|
|
1406
|
-
return totals.outputTokens;
|
|
1470
|
+
return safeUsageNumber(totals.outputTokens);
|
|
1407
1471
|
case "reasoning":
|
|
1408
|
-
return totals.reasoningTokens;
|
|
1472
|
+
return safeUsageNumber(totals.reasoningTokens);
|
|
1409
1473
|
case "cacheRead":
|
|
1410
|
-
return totals.cacheReadInputTokens;
|
|
1474
|
+
return safeUsageNumber(totals.cacheReadInputTokens);
|
|
1411
1475
|
case "cacheWrite":
|
|
1412
|
-
return totals.cacheCreationInputTokens;
|
|
1476
|
+
return safeUsageNumber(totals.cacheCreationInputTokens);
|
|
1413
1477
|
case "total":
|
|
1414
1478
|
default:
|
|
1415
|
-
return totals.totalTokens;
|
|
1479
|
+
return safeUsageNumber(totals.totalTokens);
|
|
1416
1480
|
}
|
|
1417
1481
|
}
|
|
1418
1482
|
function aggregateUsageRows(points, metricKind, dimension) {
|
|
@@ -1524,6 +1588,14 @@ function getUsageDimensionLabel(dimension) {
|
|
|
1524
1588
|
}
|
|
1525
1589
|
function getUsageGroupLabel(groupBy) {
|
|
1526
1590
|
switch (groupBy) {
|
|
1591
|
+
case "kind":
|
|
1592
|
+
return "Kind";
|
|
1593
|
+
case "resource":
|
|
1594
|
+
return "Resource";
|
|
1595
|
+
case "operation":
|
|
1596
|
+
return "Operation";
|
|
1597
|
+
case "status":
|
|
1598
|
+
return "Status";
|
|
1527
1599
|
case "thread":
|
|
1528
1600
|
return "Thread";
|
|
1529
1601
|
case "namespace":
|
|
@@ -1537,6 +1609,25 @@ function getUsageGroupLabel(groupBy) {
|
|
|
1537
1609
|
return "Participant";
|
|
1538
1610
|
}
|
|
1539
1611
|
}
|
|
1612
|
+
function getUsageMetricLabel(metricKind) {
|
|
1613
|
+
switch (metricKind) {
|
|
1614
|
+
case "cost":
|
|
1615
|
+
return "Spend";
|
|
1616
|
+
case "tokens":
|
|
1617
|
+
return "Tokens";
|
|
1618
|
+
case "duration":
|
|
1619
|
+
return "Duration";
|
|
1620
|
+
case "credits":
|
|
1621
|
+
return "Credits";
|
|
1622
|
+
case "failures":
|
|
1623
|
+
return "Failures";
|
|
1624
|
+
case "unpriced":
|
|
1625
|
+
return "Unpriced";
|
|
1626
|
+
case "calls":
|
|
1627
|
+
default:
|
|
1628
|
+
return "Calls";
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1540
1631
|
function formatUsageBucket(bucket, interval) {
|
|
1541
1632
|
const date = new Date(bucket);
|
|
1542
1633
|
if (Number.isNaN(date.getTime())) return bucket;
|
|
@@ -1579,6 +1670,9 @@ function formatMetricValue(value, metricKind) {
|
|
|
1579
1670
|
style: "currency"
|
|
1580
1671
|
}).format(value);
|
|
1581
1672
|
}
|
|
1673
|
+
if (metricKind === "duration") {
|
|
1674
|
+
return formatDuration(value);
|
|
1675
|
+
}
|
|
1582
1676
|
return formatNumber(value);
|
|
1583
1677
|
}
|
|
1584
1678
|
function formatCompactMetric(value, metricKind) {
|
|
@@ -1591,12 +1685,30 @@ function formatCompactMetric(value, metricKind) {
|
|
|
1591
1685
|
style: "currency"
|
|
1592
1686
|
}).format(value);
|
|
1593
1687
|
}
|
|
1688
|
+
if (metricKind === "duration") {
|
|
1689
|
+
if (value >= 36e5) return `${(value / 36e5).toFixed(1)}h`;
|
|
1690
|
+
if (value >= 6e4) return `${(value / 6e4).toFixed(1)}m`;
|
|
1691
|
+
if (value >= 1e3) return `${(value / 1e3).toFixed(1)}s`;
|
|
1692
|
+
return `${Math.round(value)}ms`;
|
|
1693
|
+
}
|
|
1594
1694
|
return new Intl.NumberFormat(void 0, {
|
|
1595
1695
|
compactDisplay: "short",
|
|
1596
1696
|
maximumFractionDigits: 1,
|
|
1597
1697
|
notation: "compact"
|
|
1598
1698
|
}).format(value);
|
|
1599
1699
|
}
|
|
1700
|
+
function formatDuration(value) {
|
|
1701
|
+
if (value >= 36e5) {
|
|
1702
|
+
return `${new Intl.NumberFormat(void 0, { maximumFractionDigits: 1 }).format(value / 36e5)} h`;
|
|
1703
|
+
}
|
|
1704
|
+
if (value >= 6e4) {
|
|
1705
|
+
return `${new Intl.NumberFormat(void 0, { maximumFractionDigits: 1 }).format(value / 6e4)} min`;
|
|
1706
|
+
}
|
|
1707
|
+
if (value >= 1e3) {
|
|
1708
|
+
return `${new Intl.NumberFormat(void 0, { maximumFractionDigits: 1 }).format(value / 1e3)} sec`;
|
|
1709
|
+
}
|
|
1710
|
+
return `${formatNumber(Math.round(value))} ms`;
|
|
1711
|
+
}
|
|
1600
1712
|
|
|
1601
1713
|
// src/modules/agents/index.tsx
|
|
1602
1714
|
import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
@@ -2704,7 +2816,9 @@ function ThreadsPage({ context }) {
|
|
|
2704
2816
|
align: "right",
|
|
2705
2817
|
id: "participants",
|
|
2706
2818
|
header: "Participants",
|
|
2707
|
-
render: (thread) => formatNumber(
|
|
2819
|
+
render: (thread) => formatNumber(
|
|
2820
|
+
Array.isArray(thread.participantIds) ? thread.participantIds.length : 0
|
|
2821
|
+
)
|
|
2708
2822
|
},
|
|
2709
2823
|
{
|
|
2710
2824
|
align: "right",
|
|
@@ -2755,8 +2869,8 @@ function ThreadInspector({
|
|
|
2755
2869
|
]).then(([nextThread, page]) => {
|
|
2756
2870
|
if (!active) return;
|
|
2757
2871
|
setThread(nextThread);
|
|
2758
|
-
setMessages(page.data);
|
|
2759
|
-
setPageInfo(page
|
|
2872
|
+
setMessages(Array.isArray(page?.data) ? page.data : []);
|
|
2873
|
+
setPageInfo(page?.pageInfo ?? null);
|
|
2760
2874
|
}).catch((cause) => {
|
|
2761
2875
|
if (active) setError(cause instanceof Error ? cause.message : "Failed to load thread");
|
|
2762
2876
|
}).finally(() => {
|
|
@@ -2776,8 +2890,11 @@ function ThreadInspector({
|
|
|
2776
2890
|
before: pageInfo.oldestMessageId,
|
|
2777
2891
|
limit: MESSAGE_PAGE_SIZE
|
|
2778
2892
|
});
|
|
2779
|
-
setMessages((current) => [
|
|
2780
|
-
|
|
2893
|
+
setMessages((current) => [
|
|
2894
|
+
...Array.isArray(page?.data) ? page.data : [],
|
|
2895
|
+
...current
|
|
2896
|
+
]);
|
|
2897
|
+
setPageInfo(page?.pageInfo ?? null);
|
|
2781
2898
|
} finally {
|
|
2782
2899
|
setIsLoadingMore(false);
|
|
2783
2900
|
}
|
|
@@ -2915,7 +3032,15 @@ import {
|
|
|
2915
3032
|
XAxis,
|
|
2916
3033
|
YAxis
|
|
2917
3034
|
} from "recharts";
|
|
2918
|
-
import {
|
|
3035
|
+
import {
|
|
3036
|
+
Activity as Activity3,
|
|
3037
|
+
AlertTriangle as AlertTriangle2,
|
|
3038
|
+
BarChart3,
|
|
3039
|
+
Clock,
|
|
3040
|
+
Coins,
|
|
3041
|
+
DollarSign,
|
|
3042
|
+
Sparkles as Sparkles2
|
|
3043
|
+
} from "lucide-react";
|
|
2919
3044
|
|
|
2920
3045
|
// src/components/ui/chart.tsx
|
|
2921
3046
|
import * as React12 from "react";
|
|
@@ -3043,6 +3168,22 @@ var USAGE_DIMENSIONS = [
|
|
|
3043
3168
|
"cacheRead",
|
|
3044
3169
|
"cacheWrite"
|
|
3045
3170
|
];
|
|
3171
|
+
var USAGE_WORKLOADS = [
|
|
3172
|
+
"all",
|
|
3173
|
+
"llm",
|
|
3174
|
+
"tool",
|
|
3175
|
+
"asset",
|
|
3176
|
+
"rag",
|
|
3177
|
+
"embedding"
|
|
3178
|
+
];
|
|
3179
|
+
var STATUS_OPTIONS = [
|
|
3180
|
+
"all",
|
|
3181
|
+
"completed",
|
|
3182
|
+
"failed",
|
|
3183
|
+
"cancelled",
|
|
3184
|
+
"aborted",
|
|
3185
|
+
"error"
|
|
3186
|
+
];
|
|
3046
3187
|
function usageModule() {
|
|
3047
3188
|
return {
|
|
3048
3189
|
group: "operate",
|
|
@@ -3069,11 +3210,12 @@ function UsagePage({ context }) {
|
|
|
3069
3210
|
"7d"
|
|
3070
3211
|
);
|
|
3071
3212
|
const [interval, setInterval] = React13.useState("day");
|
|
3213
|
+
const [workload, setWorkload] = React13.useState("all");
|
|
3072
3214
|
const [metricKind, setMetricKind] = React13.useState(
|
|
3073
|
-
"
|
|
3215
|
+
"calls"
|
|
3074
3216
|
);
|
|
3075
3217
|
const [dimension, setDimension] = React13.useState("total");
|
|
3076
|
-
const [groupBy, setGroupBy] = React13.useState("
|
|
3218
|
+
const [groupBy, setGroupBy] = React13.useState("kind");
|
|
3077
3219
|
const [attribution, setAttribution] = React13.useState(
|
|
3078
3220
|
"initiatedBy"
|
|
3079
3221
|
);
|
|
@@ -3082,6 +3224,11 @@ function UsagePage({ context }) {
|
|
|
3082
3224
|
const [participantId, setParticipantId] = React13.useState("");
|
|
3083
3225
|
const [provider, setProvider] = React13.useState("");
|
|
3084
3226
|
const [model, setModel] = React13.useState("");
|
|
3227
|
+
const [resource, setResource] = React13.useState("");
|
|
3228
|
+
const [operation, setOperation] = React13.useState("");
|
|
3229
|
+
const [status, setStatus] = React13.useState(
|
|
3230
|
+
"all"
|
|
3231
|
+
);
|
|
3085
3232
|
const [customFrom, setCustomFrom] = React13.useState("");
|
|
3086
3233
|
const [customTo, setCustomTo] = React13.useState("");
|
|
3087
3234
|
const [usage, setUsage] = React13.useState(null);
|
|
@@ -3091,6 +3238,32 @@ function UsagePage({ context }) {
|
|
|
3091
3238
|
() => getUsageRange(period, customFrom, customTo),
|
|
3092
3239
|
[customFrom, customTo, period]
|
|
3093
3240
|
);
|
|
3241
|
+
const metricOptions = React13.useMemo(
|
|
3242
|
+
() => getUsageMetricOptions(workload),
|
|
3243
|
+
[workload]
|
|
3244
|
+
);
|
|
3245
|
+
const groupOptions = React13.useMemo(
|
|
3246
|
+
() => getUsageGroupOptions(workload),
|
|
3247
|
+
[workload]
|
|
3248
|
+
);
|
|
3249
|
+
const showLlmFields = workload === "llm";
|
|
3250
|
+
const showResourceFields = workload !== "llm";
|
|
3251
|
+
const showDimension = metricKind === "tokens" || metricKind === "cost" && workload === "llm";
|
|
3252
|
+
React13.useEffect(() => {
|
|
3253
|
+
if (!metricOptions.includes(metricKind)) {
|
|
3254
|
+
setMetricKind(metricOptions[0]);
|
|
3255
|
+
}
|
|
3256
|
+
}, [metricKind, metricOptions]);
|
|
3257
|
+
React13.useEffect(() => {
|
|
3258
|
+
if (!groupOptions.includes(groupBy)) {
|
|
3259
|
+
setGroupBy(groupOptions[0]);
|
|
3260
|
+
}
|
|
3261
|
+
}, [groupBy, groupOptions]);
|
|
3262
|
+
React13.useEffect(() => {
|
|
3263
|
+
if (!showDimension && dimension !== "total") {
|
|
3264
|
+
setDimension("total");
|
|
3265
|
+
}
|
|
3266
|
+
}, [dimension, showDimension]);
|
|
3094
3267
|
React13.useEffect(() => {
|
|
3095
3268
|
let active = true;
|
|
3096
3269
|
setIsLoading(true);
|
|
@@ -3099,13 +3272,17 @@ function UsagePage({ context }) {
|
|
|
3099
3272
|
attribution,
|
|
3100
3273
|
from: range.from,
|
|
3101
3274
|
groupBy,
|
|
3275
|
+
kind: workload,
|
|
3102
3276
|
interval,
|
|
3103
3277
|
metric: metricKind,
|
|
3104
|
-
model: emptyToUndefined(model),
|
|
3278
|
+
model: showLlmFields ? emptyToUndefined(model) : void 0,
|
|
3105
3279
|
namespace: context.scope.namespace || void 0,
|
|
3280
|
+
operation: showResourceFields ? emptyToUndefined(operation) : void 0,
|
|
3106
3281
|
participantId: emptyToUndefined(participantId),
|
|
3107
3282
|
participantType,
|
|
3108
|
-
provider: emptyToUndefined(provider),
|
|
3283
|
+
provider: showLlmFields ? emptyToUndefined(provider) : void 0,
|
|
3284
|
+
resource: showResourceFields ? emptyToUndefined(resource) : void 0,
|
|
3285
|
+
status: status === "all" ? void 0 : status,
|
|
3109
3286
|
threadId: emptyToUndefined(threadId),
|
|
3110
3287
|
to: range.to
|
|
3111
3288
|
}).then((next) => {
|
|
@@ -3130,12 +3307,18 @@ function UsagePage({ context }) {
|
|
|
3130
3307
|
interval,
|
|
3131
3308
|
metricKind,
|
|
3132
3309
|
model,
|
|
3310
|
+
operation,
|
|
3133
3311
|
participantId,
|
|
3134
3312
|
participantType,
|
|
3135
3313
|
provider,
|
|
3136
3314
|
range.from,
|
|
3137
3315
|
range.to,
|
|
3138
|
-
|
|
3316
|
+
resource,
|
|
3317
|
+
showLlmFields,
|
|
3318
|
+
showResourceFields,
|
|
3319
|
+
status,
|
|
3320
|
+
threadId,
|
|
3321
|
+
workload
|
|
3139
3322
|
]);
|
|
3140
3323
|
const points = usage?.points ?? [];
|
|
3141
3324
|
const totals = usage?.totals ?? EMPTY_USAGE_TOTALS;
|
|
@@ -3152,9 +3335,10 @@ function UsagePage({ context }) {
|
|
|
3152
3335
|
PageHeader,
|
|
3153
3336
|
{
|
|
3154
3337
|
title: "Usage",
|
|
3155
|
-
description: "Inspect
|
|
3338
|
+
description: "Inspect metered LLM, tool, and resource activity by workload, actor, status, cost, duration, tokens, and credits.",
|
|
3156
3339
|
badges: [
|
|
3157
|
-
{ label:
|
|
3340
|
+
{ label: workload },
|
|
3341
|
+
{ label: getUsageMetricLabel(metricKind), variant: "secondary" },
|
|
3158
3342
|
{ label: getUsageGroupLabel(groupBy), variant: "secondary" },
|
|
3159
3343
|
...isLoading ? [{ label: "Loading" }] : []
|
|
3160
3344
|
]
|
|
@@ -3182,10 +3366,21 @@ function UsagePage({ context }) {
|
|
|
3182
3366
|
/* @__PURE__ */ jsx27(
|
|
3183
3367
|
UsageSelect,
|
|
3184
3368
|
{
|
|
3185
|
-
label: "
|
|
3369
|
+
label: "Workload",
|
|
3370
|
+
onValueChange: (value) => setWorkload(value),
|
|
3371
|
+
options: USAGE_WORKLOADS,
|
|
3372
|
+
value: workload,
|
|
3373
|
+
formatOption: getUsageKindLabel
|
|
3374
|
+
}
|
|
3375
|
+
),
|
|
3376
|
+
/* @__PURE__ */ jsx27(
|
|
3377
|
+
UsageSelect,
|
|
3378
|
+
{
|
|
3379
|
+
label: "Measure",
|
|
3186
3380
|
onValueChange: (value) => setMetricKind(value),
|
|
3187
|
-
options:
|
|
3188
|
-
value: metricKind
|
|
3381
|
+
options: metricOptions,
|
|
3382
|
+
value: metricKind,
|
|
3383
|
+
formatOption: getUsageMetricLabel
|
|
3189
3384
|
}
|
|
3190
3385
|
),
|
|
3191
3386
|
/* @__PURE__ */ jsx27(
|
|
@@ -3193,20 +3388,22 @@ function UsagePage({ context }) {
|
|
|
3193
3388
|
{
|
|
3194
3389
|
label: "Group",
|
|
3195
3390
|
onValueChange: (value) => setGroupBy(value),
|
|
3196
|
-
options:
|
|
3197
|
-
value: groupBy
|
|
3391
|
+
options: groupOptions,
|
|
3392
|
+
value: groupBy,
|
|
3393
|
+
formatOption: getUsageGroupLabel
|
|
3198
3394
|
}
|
|
3199
3395
|
),
|
|
3200
3396
|
/* @__PURE__ */ jsx27(
|
|
3201
3397
|
UsageSelect,
|
|
3202
3398
|
{
|
|
3203
|
-
label: "
|
|
3399
|
+
label: "Actor",
|
|
3204
3400
|
onValueChange: (value) => setAttribution(value),
|
|
3205
3401
|
options: ["initiatedBy", "generatedBy"],
|
|
3206
|
-
value: attribution
|
|
3402
|
+
value: attribution,
|
|
3403
|
+
formatOption: getUsageAttributionLabel
|
|
3207
3404
|
}
|
|
3208
3405
|
),
|
|
3209
|
-
/* @__PURE__ */ jsx27(
|
|
3406
|
+
showDimension && /* @__PURE__ */ jsx27(
|
|
3210
3407
|
UsageSelect,
|
|
3211
3408
|
{
|
|
3212
3409
|
label: "Dimension",
|
|
@@ -3241,12 +3438,21 @@ function UsagePage({ context }) {
|
|
|
3241
3438
|
/* @__PURE__ */ jsx27(
|
|
3242
3439
|
UsageSelect,
|
|
3243
3440
|
{
|
|
3244
|
-
label: "
|
|
3441
|
+
label: "Actor type",
|
|
3245
3442
|
onValueChange: (value) => setParticipantType(value),
|
|
3246
3443
|
options: ["all", "human", "agent", "job"],
|
|
3247
3444
|
value: participantType
|
|
3248
3445
|
}
|
|
3249
3446
|
),
|
|
3447
|
+
/* @__PURE__ */ jsx27(
|
|
3448
|
+
UsageSelect,
|
|
3449
|
+
{
|
|
3450
|
+
label: "Status",
|
|
3451
|
+
onValueChange: (value) => setStatus(value),
|
|
3452
|
+
options: STATUS_OPTIONS,
|
|
3453
|
+
value: status
|
|
3454
|
+
}
|
|
3455
|
+
),
|
|
3250
3456
|
/* @__PURE__ */ jsx27(
|
|
3251
3457
|
Input,
|
|
3252
3458
|
{
|
|
@@ -3265,46 +3471,86 @@ function UsagePage({ context }) {
|
|
|
3265
3471
|
value: participantId
|
|
3266
3472
|
}
|
|
3267
3473
|
),
|
|
3268
|
-
/* @__PURE__ */
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3474
|
+
showResourceFields && /* @__PURE__ */ jsxs19(Fragment2, { children: [
|
|
3475
|
+
/* @__PURE__ */ jsx27(
|
|
3476
|
+
Input,
|
|
3477
|
+
{
|
|
3478
|
+
className: "h-8 w-[170px]",
|
|
3479
|
+
onChange: (event) => setResource(event.target.value),
|
|
3480
|
+
placeholder: "Resource / tool",
|
|
3481
|
+
value: resource
|
|
3482
|
+
}
|
|
3483
|
+
),
|
|
3484
|
+
/* @__PURE__ */ jsx27(
|
|
3485
|
+
Input,
|
|
3486
|
+
{
|
|
3487
|
+
className: "h-8 w-[150px]",
|
|
3488
|
+
onChange: (event) => setOperation(event.target.value),
|
|
3489
|
+
placeholder: "Operation",
|
|
3490
|
+
value: operation
|
|
3491
|
+
}
|
|
3492
|
+
)
|
|
3493
|
+
] }),
|
|
3494
|
+
showLlmFields && /* @__PURE__ */ jsxs19(Fragment2, { children: [
|
|
3495
|
+
/* @__PURE__ */ jsx27(
|
|
3496
|
+
Input,
|
|
3497
|
+
{
|
|
3498
|
+
className: "h-8 w-[140px]",
|
|
3499
|
+
onChange: (event) => setProvider(event.target.value),
|
|
3500
|
+
placeholder: "Provider",
|
|
3501
|
+
value: provider
|
|
3502
|
+
}
|
|
3503
|
+
),
|
|
3504
|
+
/* @__PURE__ */ jsx27(
|
|
3505
|
+
Input,
|
|
3506
|
+
{
|
|
3507
|
+
className: "h-8 w-[140px]",
|
|
3508
|
+
onChange: (event) => setModel(event.target.value),
|
|
3509
|
+
placeholder: "Model",
|
|
3510
|
+
value: model
|
|
3511
|
+
}
|
|
3512
|
+
)
|
|
3513
|
+
] })
|
|
3286
3514
|
] }),
|
|
3287
3515
|
/* @__PURE__ */ jsx27(
|
|
3288
3516
|
MetricStrip,
|
|
3289
3517
|
{
|
|
3290
3518
|
items: [
|
|
3291
3519
|
{
|
|
3292
|
-
detail: `${totals.
|
|
3520
|
+
detail: `${formatMetricValue(totals.unpricedCalls, "unpriced")} unpriced`,
|
|
3293
3521
|
icon: DollarSign,
|
|
3294
|
-
label: "
|
|
3522
|
+
label: "Spend",
|
|
3295
3523
|
value: formatMetricValue(totals.totalCostUsd, "cost")
|
|
3296
3524
|
},
|
|
3297
3525
|
{
|
|
3298
|
-
detail: `${formatMetricValue(totals.
|
|
3526
|
+
detail: `${formatMetricValue(totals.failedCalls, "failures")} failed`,
|
|
3299
3527
|
icon: Activity3,
|
|
3528
|
+
label: "Calls",
|
|
3529
|
+
value: formatMetricValue(totals.totalCalls, "calls")
|
|
3530
|
+
},
|
|
3531
|
+
{
|
|
3532
|
+
detail: "Tool and resource runtime",
|
|
3533
|
+
icon: Clock,
|
|
3534
|
+
label: "Duration",
|
|
3535
|
+
value: formatMetricValue(totals.totalDurationMs, "duration")
|
|
3536
|
+
},
|
|
3537
|
+
{
|
|
3538
|
+
detail: `${formatMetricValue(totals.inputTokens, "tokens")} input`,
|
|
3539
|
+
icon: Sparkles2,
|
|
3300
3540
|
label: "Tokens",
|
|
3301
3541
|
value: formatMetricValue(totals.totalTokens, "tokens")
|
|
3302
3542
|
},
|
|
3303
3543
|
{
|
|
3304
|
-
detail:
|
|
3305
|
-
icon:
|
|
3306
|
-
label: "
|
|
3307
|
-
value: formatMetricValue(totals.
|
|
3544
|
+
detail: "Custom metering",
|
|
3545
|
+
icon: Coins,
|
|
3546
|
+
label: "Credits",
|
|
3547
|
+
value: formatMetricValue(totals.totalCredits, "credits")
|
|
3548
|
+
},
|
|
3549
|
+
{
|
|
3550
|
+
detail: "Failed or aborted work",
|
|
3551
|
+
icon: AlertTriangle2,
|
|
3552
|
+
label: "Failures",
|
|
3553
|
+
value: formatMetricValue(totals.failedCalls, "failures")
|
|
3308
3554
|
}
|
|
3309
3555
|
]
|
|
3310
3556
|
}
|
|
@@ -3313,7 +3559,7 @@ function UsagePage({ context }) {
|
|
|
3313
3559
|
EmptyState,
|
|
3314
3560
|
{
|
|
3315
3561
|
title: "No usage",
|
|
3316
|
-
description: "
|
|
3562
|
+
description: "Metered LLM, tool, and resource records will appear here after work is captured in the usage ledger."
|
|
3317
3563
|
}
|
|
3318
3564
|
) : /* @__PURE__ */ jsxs19(Fragment2, { children: [
|
|
3319
3565
|
/* @__PURE__ */ jsx27(Card, { className: "h-[320px] py-3", children: /* @__PURE__ */ jsx27(CardContent, { className: "h-full px-3", children: /* @__PURE__ */ jsx27(UsageChart, { chartState, metricKind }) }) }),
|
|
@@ -3392,6 +3638,7 @@ function UsageRowsTable({
|
|
|
3392
3638
|
totals
|
|
3393
3639
|
}) {
|
|
3394
3640
|
const totalValue = getUsageTotalValue(totals, metricKind, dimension);
|
|
3641
|
+
const valueHeader = (metricKind === "tokens" || metricKind === "cost") && dimension !== "total" ? `${getUsageDimensionLabel(dimension)} ${getUsageMetricLabel(metricKind)}` : getUsageMetricLabel(metricKind);
|
|
3395
3642
|
return /* @__PURE__ */ jsx27(
|
|
3396
3643
|
ResourceTable,
|
|
3397
3644
|
{
|
|
@@ -3409,7 +3656,7 @@ function UsageRowsTable({
|
|
|
3409
3656
|
{
|
|
3410
3657
|
align: "right",
|
|
3411
3658
|
id: "value",
|
|
3412
|
-
header:
|
|
3659
|
+
header: valueHeader,
|
|
3413
3660
|
render: (row) => formatMetricValue(row.value, metricKind)
|
|
3414
3661
|
},
|
|
3415
3662
|
{
|
|
@@ -3426,20 +3673,100 @@ function UsageRowsTable({
|
|
|
3426
3673
|
},
|
|
3427
3674
|
{
|
|
3428
3675
|
align: "right",
|
|
3429
|
-
id: "
|
|
3430
|
-
header: "
|
|
3431
|
-
render: (row) => formatMetricValue(
|
|
3676
|
+
id: "spend",
|
|
3677
|
+
header: "Spend",
|
|
3678
|
+
render: (row) => formatMetricValue(row.totalCostUsd, "cost")
|
|
3432
3679
|
},
|
|
3433
3680
|
{
|
|
3434
3681
|
align: "right",
|
|
3435
|
-
id: "
|
|
3436
|
-
header: "
|
|
3437
|
-
render: (row) => formatMetricValue(
|
|
3682
|
+
id: "duration",
|
|
3683
|
+
header: "Duration",
|
|
3684
|
+
render: (row) => formatMetricValue(row.totalDurationMs, "duration")
|
|
3685
|
+
},
|
|
3686
|
+
{
|
|
3687
|
+
align: "right",
|
|
3688
|
+
id: "tokens",
|
|
3689
|
+
header: "Tokens",
|
|
3690
|
+
render: (row) => formatMetricValue(row.totalTokens, "tokens")
|
|
3691
|
+
},
|
|
3692
|
+
{
|
|
3693
|
+
align: "right",
|
|
3694
|
+
id: "failures",
|
|
3695
|
+
header: "Failures",
|
|
3696
|
+
render: (row) => formatMetricValue(row.failedCalls, "failures")
|
|
3697
|
+
},
|
|
3698
|
+
{
|
|
3699
|
+
align: "right",
|
|
3700
|
+
id: "unpriced",
|
|
3701
|
+
header: "Unpriced",
|
|
3702
|
+
render: (row) => formatMetricValue(row.unpricedCalls, "unpriced")
|
|
3438
3703
|
}
|
|
3439
3704
|
]
|
|
3440
3705
|
}
|
|
3441
3706
|
);
|
|
3442
3707
|
}
|
|
3708
|
+
function getUsageMetricOptions(workload) {
|
|
3709
|
+
if (workload === "llm") {
|
|
3710
|
+
return ["cost", "tokens", "calls", "failures", "unpriced"];
|
|
3711
|
+
}
|
|
3712
|
+
if (workload === "tool") {
|
|
3713
|
+
return ["calls", "duration", "cost", "credits", "failures", "unpriced"];
|
|
3714
|
+
}
|
|
3715
|
+
return [
|
|
3716
|
+
"calls",
|
|
3717
|
+
"cost",
|
|
3718
|
+
"duration",
|
|
3719
|
+
"tokens",
|
|
3720
|
+
"credits",
|
|
3721
|
+
"failures",
|
|
3722
|
+
"unpriced"
|
|
3723
|
+
];
|
|
3724
|
+
}
|
|
3725
|
+
function getUsageGroupOptions(workload) {
|
|
3726
|
+
if (workload === "llm") {
|
|
3727
|
+
return ["participant", "model", "provider", "thread", "namespace", "status"];
|
|
3728
|
+
}
|
|
3729
|
+
if (workload === "tool") {
|
|
3730
|
+
return [
|
|
3731
|
+
"resource",
|
|
3732
|
+
"operation",
|
|
3733
|
+
"status",
|
|
3734
|
+
"participant",
|
|
3735
|
+
"thread",
|
|
3736
|
+
"namespace"
|
|
3737
|
+
];
|
|
3738
|
+
}
|
|
3739
|
+
return [
|
|
3740
|
+
"kind",
|
|
3741
|
+
"resource",
|
|
3742
|
+
"operation",
|
|
3743
|
+
"status",
|
|
3744
|
+
"participant",
|
|
3745
|
+
"thread",
|
|
3746
|
+
"namespace"
|
|
3747
|
+
];
|
|
3748
|
+
}
|
|
3749
|
+
function getUsageKindLabel(kind) {
|
|
3750
|
+
switch (kind) {
|
|
3751
|
+
case "all":
|
|
3752
|
+
return "All";
|
|
3753
|
+
case "llm":
|
|
3754
|
+
return "LLM";
|
|
3755
|
+
case "tool":
|
|
3756
|
+
return "Tools";
|
|
3757
|
+
case "asset":
|
|
3758
|
+
return "Assets";
|
|
3759
|
+
case "rag":
|
|
3760
|
+
return "RAG";
|
|
3761
|
+
case "embedding":
|
|
3762
|
+
return "Embeddings";
|
|
3763
|
+
default:
|
|
3764
|
+
return kind;
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
function getUsageAttributionLabel(attribution) {
|
|
3768
|
+
return attribution === "initiatedBy" ? "Initiator" : "Performer";
|
|
3769
|
+
}
|
|
3443
3770
|
function emptyToUndefined(value) {
|
|
3444
3771
|
const trimmed = value.trim();
|
|
3445
3772
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
@@ -3927,6 +4254,7 @@ export {
|
|
|
3927
4254
|
formatUsageBucket,
|
|
3928
4255
|
getUsageDimensionLabel,
|
|
3929
4256
|
getUsageGroupLabel,
|
|
4257
|
+
getUsageMetricLabel,
|
|
3930
4258
|
getUsageRange,
|
|
3931
4259
|
getUsageTotalValue,
|
|
3932
4260
|
mergeAdminConfig,
|