@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.cjs
CHANGED
|
@@ -63,6 +63,7 @@ __export(index_exports, {
|
|
|
63
63
|
formatUsageBucket: () => formatUsageBucket,
|
|
64
64
|
getUsageDimensionLabel: () => getUsageDimensionLabel,
|
|
65
65
|
getUsageGroupLabel: () => getUsageGroupLabel,
|
|
66
|
+
getUsageMetricLabel: () => getUsageMetricLabel,
|
|
66
67
|
getUsageRange: () => getUsageRange,
|
|
67
68
|
getUsageTotalValue: () => getUsageTotalValue,
|
|
68
69
|
mergeAdminConfig: () => mergeAdminConfig,
|
|
@@ -120,11 +121,44 @@ async function mergeHeaders(headers, getRequestHeaders) {
|
|
|
120
121
|
async function parseJsonResponse(response) {
|
|
121
122
|
const payload = await response.json().catch(() => null);
|
|
122
123
|
if (!response.ok) {
|
|
123
|
-
const message = payload?.message ?? payload?.data?.message ?? `Admin request failed (${response.status})`;
|
|
124
|
+
const message = payload?.message ?? payload?.data?.message ?? payload?.error?.message ?? `Admin request failed (${response.status})`;
|
|
124
125
|
throw new Error(message);
|
|
125
126
|
}
|
|
126
127
|
return payload?.data ?? payload;
|
|
127
128
|
}
|
|
129
|
+
async function parseJsonEnvelopeResponse(response) {
|
|
130
|
+
const payload = await response.json().catch(() => null);
|
|
131
|
+
if (!response.ok) {
|
|
132
|
+
const message = payload?.message ?? payload?.data?.message ?? payload?.error?.message ?? `Admin request failed (${response.status})`;
|
|
133
|
+
throw new Error(message);
|
|
134
|
+
}
|
|
135
|
+
return payload;
|
|
136
|
+
}
|
|
137
|
+
function isRecord(value) {
|
|
138
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
139
|
+
}
|
|
140
|
+
function normalizeMessagePageInfo(value, messages) {
|
|
141
|
+
const oldestFromData = messages[0]?.id ?? null;
|
|
142
|
+
const newestFromData = messages[messages.length - 1]?.id ?? null;
|
|
143
|
+
if (!isRecord(value)) {
|
|
144
|
+
return {
|
|
145
|
+
hasMoreBefore: false,
|
|
146
|
+
oldestMessageId: oldestFromData,
|
|
147
|
+
newestMessageId: newestFromData
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
hasMoreBefore: value.hasMoreBefore === true,
|
|
152
|
+
oldestMessageId: typeof value.oldestMessageId === "string" ? value.oldestMessageId : oldestFromData,
|
|
153
|
+
newestMessageId: typeof value.newestMessageId === "string" ? value.newestMessageId : newestFromData
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function normalizeMessagePage(payload) {
|
|
157
|
+
const candidate = isRecord(payload) && isRecord(payload.data) && Array.isArray(payload.data.data) ? payload.data : payload;
|
|
158
|
+
const data = isRecord(candidate) && Array.isArray(candidate.data) ? candidate.data : Array.isArray(candidate) ? candidate : [];
|
|
159
|
+
const pageInfo = isRecord(candidate) ? normalizeMessagePageInfo(candidate.pageInfo, data) : normalizeMessagePageInfo(void 0, data);
|
|
160
|
+
return { data, pageInfo };
|
|
161
|
+
}
|
|
128
162
|
function createAdminClient(options = {}) {
|
|
129
163
|
const baseUrl = resolveBaseUrl(options.baseUrl);
|
|
130
164
|
const paths = { ...DEFAULT_PATHS, ...options.paths };
|
|
@@ -135,6 +169,13 @@ function createAdminClient(options = {}) {
|
|
|
135
169
|
});
|
|
136
170
|
return await parseJsonResponse(response);
|
|
137
171
|
};
|
|
172
|
+
const requestEnvelopeJson = async (path, params) => {
|
|
173
|
+
const url = buildUrl(baseUrl, path, params);
|
|
174
|
+
const response = await fetch(url.toString(), {
|
|
175
|
+
headers: await mergeHeaders({}, options.getRequestHeaders)
|
|
176
|
+
});
|
|
177
|
+
return await parseJsonEnvelopeResponse(response);
|
|
178
|
+
};
|
|
138
179
|
const writeJson = async (method, path, data, params) => {
|
|
139
180
|
const url = buildUrl(baseUrl, path, params);
|
|
140
181
|
const response = await fetch(url.toString(), {
|
|
@@ -177,12 +218,16 @@ function createAdminClient(options = {}) {
|
|
|
177
218
|
metric: filters.metric,
|
|
178
219
|
groupBy: filters.groupBy,
|
|
179
220
|
attribution: filters.attribution,
|
|
221
|
+
kind: filters.kind,
|
|
180
222
|
threadId: filters.threadId,
|
|
181
223
|
participantId: filters.participantId,
|
|
182
224
|
participantType: filters.participantType,
|
|
183
225
|
namespace: filters.namespace,
|
|
184
226
|
provider: filters.provider,
|
|
185
|
-
model: filters.model
|
|
227
|
+
model: filters.model,
|
|
228
|
+
resource: filters.resource,
|
|
229
|
+
operation: filters.operation,
|
|
230
|
+
status: filters.status
|
|
186
231
|
}),
|
|
187
232
|
listThreads: async (listOptions = {}) => await requestJson(`${paths.adminBase}/threads`, {
|
|
188
233
|
search: listOptions.search,
|
|
@@ -210,13 +255,16 @@ function createAdminClient(options = {}) {
|
|
|
210
255
|
getThread: async (threadId) => await requestJson(
|
|
211
256
|
`${paths.threadsBase}/${encodeURIComponent(threadId)}`
|
|
212
257
|
),
|
|
213
|
-
getThreadMessages: async (threadId, messageOptions = {}) =>
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
258
|
+
getThreadMessages: async (threadId, messageOptions = {}) => {
|
|
259
|
+
const payload = await requestEnvelopeJson(
|
|
260
|
+
`${paths.threadsBase}/${encodeURIComponent(threadId)}/messages`,
|
|
261
|
+
{
|
|
262
|
+
limit: messageOptions.limit ? String(messageOptions.limit) : void 0,
|
|
263
|
+
before: messageOptions.before
|
|
264
|
+
}
|
|
265
|
+
);
|
|
266
|
+
return normalizeMessagePage(payload);
|
|
267
|
+
},
|
|
220
268
|
getThreadEvent: async (threadId) => await requestJson(
|
|
221
269
|
`${paths.threadsBase}/${encodeURIComponent(threadId)}/events`
|
|
222
270
|
),
|
|
@@ -1426,7 +1474,11 @@ var EMPTY_USAGE_TOTALS = {
|
|
|
1426
1474
|
reasoningTokens: 0,
|
|
1427
1475
|
totalCalls: 0,
|
|
1428
1476
|
totalCostUsd: 0,
|
|
1429
|
-
|
|
1477
|
+
failedCalls: 0,
|
|
1478
|
+
totalCredits: 0,
|
|
1479
|
+
totalDurationMs: 0,
|
|
1480
|
+
totalTokens: 0,
|
|
1481
|
+
unpricedCalls: 0
|
|
1430
1482
|
};
|
|
1431
1483
|
var USAGE_CHART_COLORS = [
|
|
1432
1484
|
"hsl(var(--primary))",
|
|
@@ -1437,53 +1489,66 @@ var USAGE_CHART_COLORS = [
|
|
|
1437
1489
|
"hsl(var(--muted-foreground))"
|
|
1438
1490
|
];
|
|
1439
1491
|
function addUsageTotals(target, source) {
|
|
1440
|
-
target.cacheCreationInputCostUsd += source.cacheCreationInputCostUsd;
|
|
1441
|
-
target.cacheCreationInputTokens += source.cacheCreationInputTokens;
|
|
1442
|
-
target.cacheReadInputCostUsd += source.cacheReadInputCostUsd;
|
|
1443
|
-
target.cacheReadInputTokens += source.cacheReadInputTokens;
|
|
1444
|
-
target.inputCostUsd += source.inputCostUsd;
|
|
1445
|
-
target.inputTokens += source.inputTokens;
|
|
1446
|
-
target.outputCostUsd += source.outputCostUsd;
|
|
1447
|
-
target.outputTokens += source.outputTokens;
|
|
1448
|
-
target.reasoningCostUsd += source.reasoningCostUsd;
|
|
1449
|
-
target.reasoningTokens += source.reasoningTokens;
|
|
1450
|
-
target.totalCalls += source.totalCalls;
|
|
1451
|
-
target.totalCostUsd += source.totalCostUsd;
|
|
1452
|
-
target.
|
|
1492
|
+
target.cacheCreationInputCostUsd += safeUsageNumber(source.cacheCreationInputCostUsd);
|
|
1493
|
+
target.cacheCreationInputTokens += safeUsageNumber(source.cacheCreationInputTokens);
|
|
1494
|
+
target.cacheReadInputCostUsd += safeUsageNumber(source.cacheReadInputCostUsd);
|
|
1495
|
+
target.cacheReadInputTokens += safeUsageNumber(source.cacheReadInputTokens);
|
|
1496
|
+
target.inputCostUsd += safeUsageNumber(source.inputCostUsd);
|
|
1497
|
+
target.inputTokens += safeUsageNumber(source.inputTokens);
|
|
1498
|
+
target.outputCostUsd += safeUsageNumber(source.outputCostUsd);
|
|
1499
|
+
target.outputTokens += safeUsageNumber(source.outputTokens);
|
|
1500
|
+
target.reasoningCostUsd += safeUsageNumber(source.reasoningCostUsd);
|
|
1501
|
+
target.reasoningTokens += safeUsageNumber(source.reasoningTokens);
|
|
1502
|
+
target.totalCalls += safeUsageNumber(source.totalCalls);
|
|
1503
|
+
target.totalCostUsd += safeUsageNumber(source.totalCostUsd);
|
|
1504
|
+
target.failedCalls += safeUsageNumber(source.failedCalls);
|
|
1505
|
+
target.totalCredits += safeUsageNumber(source.totalCredits);
|
|
1506
|
+
target.totalDurationMs += safeUsageNumber(source.totalDurationMs);
|
|
1507
|
+
target.totalTokens += safeUsageNumber(source.totalTokens);
|
|
1508
|
+
target.unpricedCalls += safeUsageNumber(source.unpricedCalls);
|
|
1509
|
+
}
|
|
1510
|
+
function safeUsageNumber(value) {
|
|
1511
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
1453
1512
|
}
|
|
1454
1513
|
function getUsageTotalValue(totals, metricKind, dimension) {
|
|
1455
|
-
if (metricKind === "calls") return totals.totalCalls;
|
|
1514
|
+
if (metricKind === "calls") return safeUsageNumber(totals.totalCalls);
|
|
1515
|
+
if (metricKind === "duration") {
|
|
1516
|
+
return safeUsageNumber(totals.totalDurationMs);
|
|
1517
|
+
}
|
|
1518
|
+
if (metricKind === "credits") return safeUsageNumber(totals.totalCredits);
|
|
1519
|
+
if (metricKind === "failures") return safeUsageNumber(totals.failedCalls);
|
|
1520
|
+
if (metricKind === "unpriced") return safeUsageNumber(totals.unpricedCalls);
|
|
1456
1521
|
if (metricKind === "cost") {
|
|
1457
1522
|
switch (dimension) {
|
|
1458
1523
|
case "input":
|
|
1459
|
-
return totals.inputCostUsd;
|
|
1524
|
+
return safeUsageNumber(totals.inputCostUsd);
|
|
1460
1525
|
case "output":
|
|
1461
|
-
return totals.outputCostUsd;
|
|
1526
|
+
return safeUsageNumber(totals.outputCostUsd);
|
|
1462
1527
|
case "reasoning":
|
|
1463
|
-
return totals.reasoningCostUsd;
|
|
1528
|
+
return safeUsageNumber(totals.reasoningCostUsd);
|
|
1464
1529
|
case "cacheRead":
|
|
1465
|
-
return totals.cacheReadInputCostUsd;
|
|
1530
|
+
return safeUsageNumber(totals.cacheReadInputCostUsd);
|
|
1466
1531
|
case "cacheWrite":
|
|
1467
|
-
return totals.cacheCreationInputCostUsd;
|
|
1532
|
+
return safeUsageNumber(totals.cacheCreationInputCostUsd);
|
|
1468
1533
|
case "total":
|
|
1469
1534
|
default:
|
|
1470
|
-
return totals.totalCostUsd;
|
|
1535
|
+
return safeUsageNumber(totals.totalCostUsd);
|
|
1471
1536
|
}
|
|
1472
1537
|
}
|
|
1473
1538
|
switch (dimension) {
|
|
1474
1539
|
case "input":
|
|
1475
|
-
return totals.inputTokens;
|
|
1540
|
+
return safeUsageNumber(totals.inputTokens);
|
|
1476
1541
|
case "output":
|
|
1477
|
-
return totals.outputTokens;
|
|
1542
|
+
return safeUsageNumber(totals.outputTokens);
|
|
1478
1543
|
case "reasoning":
|
|
1479
|
-
return totals.reasoningTokens;
|
|
1544
|
+
return safeUsageNumber(totals.reasoningTokens);
|
|
1480
1545
|
case "cacheRead":
|
|
1481
|
-
return totals.cacheReadInputTokens;
|
|
1546
|
+
return safeUsageNumber(totals.cacheReadInputTokens);
|
|
1482
1547
|
case "cacheWrite":
|
|
1483
|
-
return totals.cacheCreationInputTokens;
|
|
1548
|
+
return safeUsageNumber(totals.cacheCreationInputTokens);
|
|
1484
1549
|
case "total":
|
|
1485
1550
|
default:
|
|
1486
|
-
return totals.totalTokens;
|
|
1551
|
+
return safeUsageNumber(totals.totalTokens);
|
|
1487
1552
|
}
|
|
1488
1553
|
}
|
|
1489
1554
|
function aggregateUsageRows(points, metricKind, dimension) {
|
|
@@ -1595,6 +1660,14 @@ function getUsageDimensionLabel(dimension) {
|
|
|
1595
1660
|
}
|
|
1596
1661
|
function getUsageGroupLabel(groupBy) {
|
|
1597
1662
|
switch (groupBy) {
|
|
1663
|
+
case "kind":
|
|
1664
|
+
return "Kind";
|
|
1665
|
+
case "resource":
|
|
1666
|
+
return "Resource";
|
|
1667
|
+
case "operation":
|
|
1668
|
+
return "Operation";
|
|
1669
|
+
case "status":
|
|
1670
|
+
return "Status";
|
|
1598
1671
|
case "thread":
|
|
1599
1672
|
return "Thread";
|
|
1600
1673
|
case "namespace":
|
|
@@ -1608,6 +1681,25 @@ function getUsageGroupLabel(groupBy) {
|
|
|
1608
1681
|
return "Participant";
|
|
1609
1682
|
}
|
|
1610
1683
|
}
|
|
1684
|
+
function getUsageMetricLabel(metricKind) {
|
|
1685
|
+
switch (metricKind) {
|
|
1686
|
+
case "cost":
|
|
1687
|
+
return "Spend";
|
|
1688
|
+
case "tokens":
|
|
1689
|
+
return "Tokens";
|
|
1690
|
+
case "duration":
|
|
1691
|
+
return "Duration";
|
|
1692
|
+
case "credits":
|
|
1693
|
+
return "Credits";
|
|
1694
|
+
case "failures":
|
|
1695
|
+
return "Failures";
|
|
1696
|
+
case "unpriced":
|
|
1697
|
+
return "Unpriced";
|
|
1698
|
+
case "calls":
|
|
1699
|
+
default:
|
|
1700
|
+
return "Calls";
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1611
1703
|
function formatUsageBucket(bucket, interval) {
|
|
1612
1704
|
const date = new Date(bucket);
|
|
1613
1705
|
if (Number.isNaN(date.getTime())) return bucket;
|
|
@@ -1650,6 +1742,9 @@ function formatMetricValue(value, metricKind) {
|
|
|
1650
1742
|
style: "currency"
|
|
1651
1743
|
}).format(value);
|
|
1652
1744
|
}
|
|
1745
|
+
if (metricKind === "duration") {
|
|
1746
|
+
return formatDuration(value);
|
|
1747
|
+
}
|
|
1653
1748
|
return formatNumber(value);
|
|
1654
1749
|
}
|
|
1655
1750
|
function formatCompactMetric(value, metricKind) {
|
|
@@ -1662,12 +1757,30 @@ function formatCompactMetric(value, metricKind) {
|
|
|
1662
1757
|
style: "currency"
|
|
1663
1758
|
}).format(value);
|
|
1664
1759
|
}
|
|
1760
|
+
if (metricKind === "duration") {
|
|
1761
|
+
if (value >= 36e5) return `${(value / 36e5).toFixed(1)}h`;
|
|
1762
|
+
if (value >= 6e4) return `${(value / 6e4).toFixed(1)}m`;
|
|
1763
|
+
if (value >= 1e3) return `${(value / 1e3).toFixed(1)}s`;
|
|
1764
|
+
return `${Math.round(value)}ms`;
|
|
1765
|
+
}
|
|
1665
1766
|
return new Intl.NumberFormat(void 0, {
|
|
1666
1767
|
compactDisplay: "short",
|
|
1667
1768
|
maximumFractionDigits: 1,
|
|
1668
1769
|
notation: "compact"
|
|
1669
1770
|
}).format(value);
|
|
1670
1771
|
}
|
|
1772
|
+
function formatDuration(value) {
|
|
1773
|
+
if (value >= 36e5) {
|
|
1774
|
+
return `${new Intl.NumberFormat(void 0, { maximumFractionDigits: 1 }).format(value / 36e5)} h`;
|
|
1775
|
+
}
|
|
1776
|
+
if (value >= 6e4) {
|
|
1777
|
+
return `${new Intl.NumberFormat(void 0, { maximumFractionDigits: 1 }).format(value / 6e4)} min`;
|
|
1778
|
+
}
|
|
1779
|
+
if (value >= 1e3) {
|
|
1780
|
+
return `${new Intl.NumberFormat(void 0, { maximumFractionDigits: 1 }).format(value / 1e3)} sec`;
|
|
1781
|
+
}
|
|
1782
|
+
return `${formatNumber(Math.round(value))} ms`;
|
|
1783
|
+
}
|
|
1671
1784
|
|
|
1672
1785
|
// src/modules/agents/index.tsx
|
|
1673
1786
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
@@ -2759,7 +2872,9 @@ function ThreadsPage({ context }) {
|
|
|
2759
2872
|
align: "right",
|
|
2760
2873
|
id: "participants",
|
|
2761
2874
|
header: "Participants",
|
|
2762
|
-
render: (thread) => formatNumber(
|
|
2875
|
+
render: (thread) => formatNumber(
|
|
2876
|
+
Array.isArray(thread.participantIds) ? thread.participantIds.length : 0
|
|
2877
|
+
)
|
|
2763
2878
|
},
|
|
2764
2879
|
{
|
|
2765
2880
|
align: "right",
|
|
@@ -2810,8 +2925,8 @@ function ThreadInspector({
|
|
|
2810
2925
|
]).then(([nextThread, page]) => {
|
|
2811
2926
|
if (!active) return;
|
|
2812
2927
|
setThread(nextThread);
|
|
2813
|
-
setMessages(page.data);
|
|
2814
|
-
setPageInfo(page
|
|
2928
|
+
setMessages(Array.isArray(page?.data) ? page.data : []);
|
|
2929
|
+
setPageInfo(page?.pageInfo ?? null);
|
|
2815
2930
|
}).catch((cause) => {
|
|
2816
2931
|
if (active) setError(cause instanceof Error ? cause.message : "Failed to load thread");
|
|
2817
2932
|
}).finally(() => {
|
|
@@ -2831,8 +2946,11 @@ function ThreadInspector({
|
|
|
2831
2946
|
before: pageInfo.oldestMessageId,
|
|
2832
2947
|
limit: MESSAGE_PAGE_SIZE
|
|
2833
2948
|
});
|
|
2834
|
-
setMessages((current) => [
|
|
2835
|
-
|
|
2949
|
+
setMessages((current) => [
|
|
2950
|
+
...Array.isArray(page?.data) ? page.data : [],
|
|
2951
|
+
...current
|
|
2952
|
+
]);
|
|
2953
|
+
setPageInfo(page?.pageInfo ?? null);
|
|
2836
2954
|
} finally {
|
|
2837
2955
|
setIsLoadingMore(false);
|
|
2838
2956
|
}
|
|
@@ -3090,6 +3208,22 @@ var USAGE_DIMENSIONS = [
|
|
|
3090
3208
|
"cacheRead",
|
|
3091
3209
|
"cacheWrite"
|
|
3092
3210
|
];
|
|
3211
|
+
var USAGE_WORKLOADS = [
|
|
3212
|
+
"all",
|
|
3213
|
+
"llm",
|
|
3214
|
+
"tool",
|
|
3215
|
+
"asset",
|
|
3216
|
+
"rag",
|
|
3217
|
+
"embedding"
|
|
3218
|
+
];
|
|
3219
|
+
var STATUS_OPTIONS = [
|
|
3220
|
+
"all",
|
|
3221
|
+
"completed",
|
|
3222
|
+
"failed",
|
|
3223
|
+
"cancelled",
|
|
3224
|
+
"aborted",
|
|
3225
|
+
"error"
|
|
3226
|
+
];
|
|
3093
3227
|
function usageModule() {
|
|
3094
3228
|
return {
|
|
3095
3229
|
group: "operate",
|
|
@@ -3116,11 +3250,12 @@ function UsagePage({ context }) {
|
|
|
3116
3250
|
"7d"
|
|
3117
3251
|
);
|
|
3118
3252
|
const [interval, setInterval] = import_react8.default.useState("day");
|
|
3253
|
+
const [workload, setWorkload] = import_react8.default.useState("all");
|
|
3119
3254
|
const [metricKind, setMetricKind] = import_react8.default.useState(
|
|
3120
|
-
"
|
|
3255
|
+
"calls"
|
|
3121
3256
|
);
|
|
3122
3257
|
const [dimension, setDimension] = import_react8.default.useState("total");
|
|
3123
|
-
const [groupBy, setGroupBy] = import_react8.default.useState("
|
|
3258
|
+
const [groupBy, setGroupBy] = import_react8.default.useState("kind");
|
|
3124
3259
|
const [attribution, setAttribution] = import_react8.default.useState(
|
|
3125
3260
|
"initiatedBy"
|
|
3126
3261
|
);
|
|
@@ -3129,6 +3264,11 @@ function UsagePage({ context }) {
|
|
|
3129
3264
|
const [participantId, setParticipantId] = import_react8.default.useState("");
|
|
3130
3265
|
const [provider, setProvider] = import_react8.default.useState("");
|
|
3131
3266
|
const [model, setModel] = import_react8.default.useState("");
|
|
3267
|
+
const [resource, setResource] = import_react8.default.useState("");
|
|
3268
|
+
const [operation, setOperation] = import_react8.default.useState("");
|
|
3269
|
+
const [status, setStatus] = import_react8.default.useState(
|
|
3270
|
+
"all"
|
|
3271
|
+
);
|
|
3132
3272
|
const [customFrom, setCustomFrom] = import_react8.default.useState("");
|
|
3133
3273
|
const [customTo, setCustomTo] = import_react8.default.useState("");
|
|
3134
3274
|
const [usage, setUsage] = import_react8.default.useState(null);
|
|
@@ -3138,6 +3278,32 @@ function UsagePage({ context }) {
|
|
|
3138
3278
|
() => getUsageRange(period, customFrom, customTo),
|
|
3139
3279
|
[customFrom, customTo, period]
|
|
3140
3280
|
);
|
|
3281
|
+
const metricOptions = import_react8.default.useMemo(
|
|
3282
|
+
() => getUsageMetricOptions(workload),
|
|
3283
|
+
[workload]
|
|
3284
|
+
);
|
|
3285
|
+
const groupOptions = import_react8.default.useMemo(
|
|
3286
|
+
() => getUsageGroupOptions(workload),
|
|
3287
|
+
[workload]
|
|
3288
|
+
);
|
|
3289
|
+
const showLlmFields = workload === "llm";
|
|
3290
|
+
const showResourceFields = workload !== "llm";
|
|
3291
|
+
const showDimension = metricKind === "tokens" || metricKind === "cost" && workload === "llm";
|
|
3292
|
+
import_react8.default.useEffect(() => {
|
|
3293
|
+
if (!metricOptions.includes(metricKind)) {
|
|
3294
|
+
setMetricKind(metricOptions[0]);
|
|
3295
|
+
}
|
|
3296
|
+
}, [metricKind, metricOptions]);
|
|
3297
|
+
import_react8.default.useEffect(() => {
|
|
3298
|
+
if (!groupOptions.includes(groupBy)) {
|
|
3299
|
+
setGroupBy(groupOptions[0]);
|
|
3300
|
+
}
|
|
3301
|
+
}, [groupBy, groupOptions]);
|
|
3302
|
+
import_react8.default.useEffect(() => {
|
|
3303
|
+
if (!showDimension && dimension !== "total") {
|
|
3304
|
+
setDimension("total");
|
|
3305
|
+
}
|
|
3306
|
+
}, [dimension, showDimension]);
|
|
3141
3307
|
import_react8.default.useEffect(() => {
|
|
3142
3308
|
let active = true;
|
|
3143
3309
|
setIsLoading(true);
|
|
@@ -3146,13 +3312,17 @@ function UsagePage({ context }) {
|
|
|
3146
3312
|
attribution,
|
|
3147
3313
|
from: range.from,
|
|
3148
3314
|
groupBy,
|
|
3315
|
+
kind: workload,
|
|
3149
3316
|
interval,
|
|
3150
3317
|
metric: metricKind,
|
|
3151
|
-
model: emptyToUndefined(model),
|
|
3318
|
+
model: showLlmFields ? emptyToUndefined(model) : void 0,
|
|
3152
3319
|
namespace: context.scope.namespace || void 0,
|
|
3320
|
+
operation: showResourceFields ? emptyToUndefined(operation) : void 0,
|
|
3153
3321
|
participantId: emptyToUndefined(participantId),
|
|
3154
3322
|
participantType,
|
|
3155
|
-
provider: emptyToUndefined(provider),
|
|
3323
|
+
provider: showLlmFields ? emptyToUndefined(provider) : void 0,
|
|
3324
|
+
resource: showResourceFields ? emptyToUndefined(resource) : void 0,
|
|
3325
|
+
status: status === "all" ? void 0 : status,
|
|
3156
3326
|
threadId: emptyToUndefined(threadId),
|
|
3157
3327
|
to: range.to
|
|
3158
3328
|
}).then((next) => {
|
|
@@ -3177,12 +3347,18 @@ function UsagePage({ context }) {
|
|
|
3177
3347
|
interval,
|
|
3178
3348
|
metricKind,
|
|
3179
3349
|
model,
|
|
3350
|
+
operation,
|
|
3180
3351
|
participantId,
|
|
3181
3352
|
participantType,
|
|
3182
3353
|
provider,
|
|
3183
3354
|
range.from,
|
|
3184
3355
|
range.to,
|
|
3185
|
-
|
|
3356
|
+
resource,
|
|
3357
|
+
showLlmFields,
|
|
3358
|
+
showResourceFields,
|
|
3359
|
+
status,
|
|
3360
|
+
threadId,
|
|
3361
|
+
workload
|
|
3186
3362
|
]);
|
|
3187
3363
|
const points = usage?.points ?? [];
|
|
3188
3364
|
const totals = usage?.totals ?? EMPTY_USAGE_TOTALS;
|
|
@@ -3199,9 +3375,10 @@ function UsagePage({ context }) {
|
|
|
3199
3375
|
PageHeader,
|
|
3200
3376
|
{
|
|
3201
3377
|
title: "Usage",
|
|
3202
|
-
description: "Inspect
|
|
3378
|
+
description: "Inspect metered LLM, tool, and resource activity by workload, actor, status, cost, duration, tokens, and credits.",
|
|
3203
3379
|
badges: [
|
|
3204
|
-
{ label:
|
|
3380
|
+
{ label: workload },
|
|
3381
|
+
{ label: getUsageMetricLabel(metricKind), variant: "secondary" },
|
|
3205
3382
|
{ label: getUsageGroupLabel(groupBy), variant: "secondary" },
|
|
3206
3383
|
...isLoading ? [{ label: "Loading" }] : []
|
|
3207
3384
|
]
|
|
@@ -3229,10 +3406,21 @@ function UsagePage({ context }) {
|
|
|
3229
3406
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3230
3407
|
UsageSelect,
|
|
3231
3408
|
{
|
|
3232
|
-
label: "
|
|
3409
|
+
label: "Workload",
|
|
3410
|
+
onValueChange: (value) => setWorkload(value),
|
|
3411
|
+
options: USAGE_WORKLOADS,
|
|
3412
|
+
value: workload,
|
|
3413
|
+
formatOption: getUsageKindLabel
|
|
3414
|
+
}
|
|
3415
|
+
),
|
|
3416
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3417
|
+
UsageSelect,
|
|
3418
|
+
{
|
|
3419
|
+
label: "Measure",
|
|
3233
3420
|
onValueChange: (value) => setMetricKind(value),
|
|
3234
|
-
options:
|
|
3235
|
-
value: metricKind
|
|
3421
|
+
options: metricOptions,
|
|
3422
|
+
value: metricKind,
|
|
3423
|
+
formatOption: getUsageMetricLabel
|
|
3236
3424
|
}
|
|
3237
3425
|
),
|
|
3238
3426
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
@@ -3240,20 +3428,22 @@ function UsagePage({ context }) {
|
|
|
3240
3428
|
{
|
|
3241
3429
|
label: "Group",
|
|
3242
3430
|
onValueChange: (value) => setGroupBy(value),
|
|
3243
|
-
options:
|
|
3244
|
-
value: groupBy
|
|
3431
|
+
options: groupOptions,
|
|
3432
|
+
value: groupBy,
|
|
3433
|
+
formatOption: getUsageGroupLabel
|
|
3245
3434
|
}
|
|
3246
3435
|
),
|
|
3247
3436
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3248
3437
|
UsageSelect,
|
|
3249
3438
|
{
|
|
3250
|
-
label: "
|
|
3439
|
+
label: "Actor",
|
|
3251
3440
|
onValueChange: (value) => setAttribution(value),
|
|
3252
3441
|
options: ["initiatedBy", "generatedBy"],
|
|
3253
|
-
value: attribution
|
|
3442
|
+
value: attribution,
|
|
3443
|
+
formatOption: getUsageAttributionLabel
|
|
3254
3444
|
}
|
|
3255
3445
|
),
|
|
3256
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3446
|
+
showDimension && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3257
3447
|
UsageSelect,
|
|
3258
3448
|
{
|
|
3259
3449
|
label: "Dimension",
|
|
@@ -3288,12 +3478,21 @@ function UsagePage({ context }) {
|
|
|
3288
3478
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3289
3479
|
UsageSelect,
|
|
3290
3480
|
{
|
|
3291
|
-
label: "
|
|
3481
|
+
label: "Actor type",
|
|
3292
3482
|
onValueChange: (value) => setParticipantType(value),
|
|
3293
3483
|
options: ["all", "human", "agent", "job"],
|
|
3294
3484
|
value: participantType
|
|
3295
3485
|
}
|
|
3296
3486
|
),
|
|
3487
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3488
|
+
UsageSelect,
|
|
3489
|
+
{
|
|
3490
|
+
label: "Status",
|
|
3491
|
+
onValueChange: (value) => setStatus(value),
|
|
3492
|
+
options: STATUS_OPTIONS,
|
|
3493
|
+
value: status
|
|
3494
|
+
}
|
|
3495
|
+
),
|
|
3297
3496
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3298
3497
|
Input,
|
|
3299
3498
|
{
|
|
@@ -3312,46 +3511,86 @@ function UsagePage({ context }) {
|
|
|
3312
3511
|
value: participantId
|
|
3313
3512
|
}
|
|
3314
3513
|
),
|
|
3315
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3514
|
+
showResourceFields && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
3515
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3516
|
+
Input,
|
|
3517
|
+
{
|
|
3518
|
+
className: "h-8 w-[170px]",
|
|
3519
|
+
onChange: (event) => setResource(event.target.value),
|
|
3520
|
+
placeholder: "Resource / tool",
|
|
3521
|
+
value: resource
|
|
3522
|
+
}
|
|
3523
|
+
),
|
|
3524
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3525
|
+
Input,
|
|
3526
|
+
{
|
|
3527
|
+
className: "h-8 w-[150px]",
|
|
3528
|
+
onChange: (event) => setOperation(event.target.value),
|
|
3529
|
+
placeholder: "Operation",
|
|
3530
|
+
value: operation
|
|
3531
|
+
}
|
|
3532
|
+
)
|
|
3533
|
+
] }),
|
|
3534
|
+
showLlmFields && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
3535
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3536
|
+
Input,
|
|
3537
|
+
{
|
|
3538
|
+
className: "h-8 w-[140px]",
|
|
3539
|
+
onChange: (event) => setProvider(event.target.value),
|
|
3540
|
+
placeholder: "Provider",
|
|
3541
|
+
value: provider
|
|
3542
|
+
}
|
|
3543
|
+
),
|
|
3544
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3545
|
+
Input,
|
|
3546
|
+
{
|
|
3547
|
+
className: "h-8 w-[140px]",
|
|
3548
|
+
onChange: (event) => setModel(event.target.value),
|
|
3549
|
+
placeholder: "Model",
|
|
3550
|
+
value: model
|
|
3551
|
+
}
|
|
3552
|
+
)
|
|
3553
|
+
] })
|
|
3333
3554
|
] }),
|
|
3334
3555
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3335
3556
|
MetricStrip,
|
|
3336
3557
|
{
|
|
3337
3558
|
items: [
|
|
3338
3559
|
{
|
|
3339
|
-
detail: `${totals.
|
|
3560
|
+
detail: `${formatMetricValue(totals.unpricedCalls, "unpriced")} unpriced`,
|
|
3340
3561
|
icon: import_lucide_react12.DollarSign,
|
|
3341
|
-
label: "
|
|
3562
|
+
label: "Spend",
|
|
3342
3563
|
value: formatMetricValue(totals.totalCostUsd, "cost")
|
|
3343
3564
|
},
|
|
3344
3565
|
{
|
|
3345
|
-
detail: `${formatMetricValue(totals.
|
|
3566
|
+
detail: `${formatMetricValue(totals.failedCalls, "failures")} failed`,
|
|
3346
3567
|
icon: import_lucide_react12.Activity,
|
|
3568
|
+
label: "Calls",
|
|
3569
|
+
value: formatMetricValue(totals.totalCalls, "calls")
|
|
3570
|
+
},
|
|
3571
|
+
{
|
|
3572
|
+
detail: "Tool and resource runtime",
|
|
3573
|
+
icon: import_lucide_react12.Clock,
|
|
3574
|
+
label: "Duration",
|
|
3575
|
+
value: formatMetricValue(totals.totalDurationMs, "duration")
|
|
3576
|
+
},
|
|
3577
|
+
{
|
|
3578
|
+
detail: `${formatMetricValue(totals.inputTokens, "tokens")} input`,
|
|
3579
|
+
icon: import_lucide_react12.Sparkles,
|
|
3347
3580
|
label: "Tokens",
|
|
3348
3581
|
value: formatMetricValue(totals.totalTokens, "tokens")
|
|
3349
3582
|
},
|
|
3350
3583
|
{
|
|
3351
|
-
detail:
|
|
3352
|
-
icon: import_lucide_react12.
|
|
3353
|
-
label: "
|
|
3354
|
-
value: formatMetricValue(totals.
|
|
3584
|
+
detail: "Custom metering",
|
|
3585
|
+
icon: import_lucide_react12.Coins,
|
|
3586
|
+
label: "Credits",
|
|
3587
|
+
value: formatMetricValue(totals.totalCredits, "credits")
|
|
3588
|
+
},
|
|
3589
|
+
{
|
|
3590
|
+
detail: "Failed or aborted work",
|
|
3591
|
+
icon: import_lucide_react12.AlertTriangle,
|
|
3592
|
+
label: "Failures",
|
|
3593
|
+
value: formatMetricValue(totals.failedCalls, "failures")
|
|
3355
3594
|
}
|
|
3356
3595
|
]
|
|
3357
3596
|
}
|
|
@@ -3360,7 +3599,7 @@ function UsagePage({ context }) {
|
|
|
3360
3599
|
EmptyState,
|
|
3361
3600
|
{
|
|
3362
3601
|
title: "No usage",
|
|
3363
|
-
description: "
|
|
3602
|
+
description: "Metered LLM, tool, and resource records will appear here after work is captured in the usage ledger."
|
|
3364
3603
|
}
|
|
3365
3604
|
) : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
3366
3605
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Card, { className: "h-[320px] py-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CardContent, { className: "h-full px-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(UsageChart, { chartState, metricKind }) }) }),
|
|
@@ -3439,6 +3678,7 @@ function UsageRowsTable({
|
|
|
3439
3678
|
totals
|
|
3440
3679
|
}) {
|
|
3441
3680
|
const totalValue = getUsageTotalValue(totals, metricKind, dimension);
|
|
3681
|
+
const valueHeader = (metricKind === "tokens" || metricKind === "cost") && dimension !== "total" ? `${getUsageDimensionLabel(dimension)} ${getUsageMetricLabel(metricKind)}` : getUsageMetricLabel(metricKind);
|
|
3442
3682
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3443
3683
|
ResourceTable,
|
|
3444
3684
|
{
|
|
@@ -3456,7 +3696,7 @@ function UsageRowsTable({
|
|
|
3456
3696
|
{
|
|
3457
3697
|
align: "right",
|
|
3458
3698
|
id: "value",
|
|
3459
|
-
header:
|
|
3699
|
+
header: valueHeader,
|
|
3460
3700
|
render: (row) => formatMetricValue(row.value, metricKind)
|
|
3461
3701
|
},
|
|
3462
3702
|
{
|
|
@@ -3473,20 +3713,100 @@ function UsageRowsTable({
|
|
|
3473
3713
|
},
|
|
3474
3714
|
{
|
|
3475
3715
|
align: "right",
|
|
3476
|
-
id: "
|
|
3477
|
-
header: "
|
|
3478
|
-
render: (row) => formatMetricValue(
|
|
3716
|
+
id: "spend",
|
|
3717
|
+
header: "Spend",
|
|
3718
|
+
render: (row) => formatMetricValue(row.totalCostUsd, "cost")
|
|
3719
|
+
},
|
|
3720
|
+
{
|
|
3721
|
+
align: "right",
|
|
3722
|
+
id: "duration",
|
|
3723
|
+
header: "Duration",
|
|
3724
|
+
render: (row) => formatMetricValue(row.totalDurationMs, "duration")
|
|
3725
|
+
},
|
|
3726
|
+
{
|
|
3727
|
+
align: "right",
|
|
3728
|
+
id: "tokens",
|
|
3729
|
+
header: "Tokens",
|
|
3730
|
+
render: (row) => formatMetricValue(row.totalTokens, "tokens")
|
|
3731
|
+
},
|
|
3732
|
+
{
|
|
3733
|
+
align: "right",
|
|
3734
|
+
id: "failures",
|
|
3735
|
+
header: "Failures",
|
|
3736
|
+
render: (row) => formatMetricValue(row.failedCalls, "failures")
|
|
3479
3737
|
},
|
|
3480
3738
|
{
|
|
3481
3739
|
align: "right",
|
|
3482
|
-
id: "
|
|
3483
|
-
header: "
|
|
3484
|
-
render: (row) => formatMetricValue(
|
|
3740
|
+
id: "unpriced",
|
|
3741
|
+
header: "Unpriced",
|
|
3742
|
+
render: (row) => formatMetricValue(row.unpricedCalls, "unpriced")
|
|
3485
3743
|
}
|
|
3486
3744
|
]
|
|
3487
3745
|
}
|
|
3488
3746
|
);
|
|
3489
3747
|
}
|
|
3748
|
+
function getUsageMetricOptions(workload) {
|
|
3749
|
+
if (workload === "llm") {
|
|
3750
|
+
return ["cost", "tokens", "calls", "failures", "unpriced"];
|
|
3751
|
+
}
|
|
3752
|
+
if (workload === "tool") {
|
|
3753
|
+
return ["calls", "duration", "cost", "credits", "failures", "unpriced"];
|
|
3754
|
+
}
|
|
3755
|
+
return [
|
|
3756
|
+
"calls",
|
|
3757
|
+
"cost",
|
|
3758
|
+
"duration",
|
|
3759
|
+
"tokens",
|
|
3760
|
+
"credits",
|
|
3761
|
+
"failures",
|
|
3762
|
+
"unpriced"
|
|
3763
|
+
];
|
|
3764
|
+
}
|
|
3765
|
+
function getUsageGroupOptions(workload) {
|
|
3766
|
+
if (workload === "llm") {
|
|
3767
|
+
return ["participant", "model", "provider", "thread", "namespace", "status"];
|
|
3768
|
+
}
|
|
3769
|
+
if (workload === "tool") {
|
|
3770
|
+
return [
|
|
3771
|
+
"resource",
|
|
3772
|
+
"operation",
|
|
3773
|
+
"status",
|
|
3774
|
+
"participant",
|
|
3775
|
+
"thread",
|
|
3776
|
+
"namespace"
|
|
3777
|
+
];
|
|
3778
|
+
}
|
|
3779
|
+
return [
|
|
3780
|
+
"kind",
|
|
3781
|
+
"resource",
|
|
3782
|
+
"operation",
|
|
3783
|
+
"status",
|
|
3784
|
+
"participant",
|
|
3785
|
+
"thread",
|
|
3786
|
+
"namespace"
|
|
3787
|
+
];
|
|
3788
|
+
}
|
|
3789
|
+
function getUsageKindLabel(kind) {
|
|
3790
|
+
switch (kind) {
|
|
3791
|
+
case "all":
|
|
3792
|
+
return "All";
|
|
3793
|
+
case "llm":
|
|
3794
|
+
return "LLM";
|
|
3795
|
+
case "tool":
|
|
3796
|
+
return "Tools";
|
|
3797
|
+
case "asset":
|
|
3798
|
+
return "Assets";
|
|
3799
|
+
case "rag":
|
|
3800
|
+
return "RAG";
|
|
3801
|
+
case "embedding":
|
|
3802
|
+
return "Embeddings";
|
|
3803
|
+
default:
|
|
3804
|
+
return kind;
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3807
|
+
function getUsageAttributionLabel(attribution) {
|
|
3808
|
+
return attribution === "initiatedBy" ? "Initiator" : "Performer";
|
|
3809
|
+
}
|
|
3490
3810
|
function emptyToUndefined(value) {
|
|
3491
3811
|
const trimmed = value.trim();
|
|
3492
3812
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
@@ -3975,6 +4295,7 @@ function useCopilotzAdmin(options = {}) {
|
|
|
3975
4295
|
formatUsageBucket,
|
|
3976
4296
|
getUsageDimensionLabel,
|
|
3977
4297
|
getUsageGroupLabel,
|
|
4298
|
+
getUsageMetricLabel,
|
|
3978
4299
|
getUsageRange,
|
|
3979
4300
|
getUsageTotalValue,
|
|
3980
4301
|
mergeAdminConfig,
|