@mastra/observability 1.17.1-alpha.0 → 1.17.1-alpha.1
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/CHANGELOG.md +9 -0
- package/README.md +3 -1
- package/dist/index.cjs +73 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +73 -5
- package/dist/index.js.map +1 -1
- package/dist/metrics/estimator.d.ts.map +1 -1
- package/dist/metrics/pricing-registry.d.ts.map +1 -1
- package/dist/metrics/types.d.ts +4 -0
- package/dist/metrics/types.d.ts.map +1 -1
- package/dist/metrics/usage-metrics.d.ts.map +1 -1
- package/dist/usage.d.ts.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @mastra/observability
|
|
2
2
|
|
|
3
|
+
## 1.17.1-alpha.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fixed Anthropic cache-write cost estimates by applying TTL-specific rates without double counting aggregate tokens. ([#21563](https://github.com/mastra-ai/mastra/pull/21563))
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`d7e6745`](https://github.com/mastra-ai/mastra/commit/d7e67456954863c55440ea9c49bc6ceb9949972d), [`9acb50f`](https://github.com/mastra-ai/mastra/commit/9acb50f71cec9c362f06820033f90ae6b1f8282f), [`46e9e3f`](https://github.com/mastra-ai/mastra/commit/46e9e3f73babe1bc70080a596cf2ac0b9da48519), [`3f9a190`](https://github.com/mastra-ai/mastra/commit/3f9a19057c027155867b9317294ee4ca7bd0581a), [`e8808e3`](https://github.com/mastra-ai/mastra/commit/e8808e3d8eb585a2565be53e56a7e0e1477352a4), [`d4be8c1`](https://github.com/mastra-ai/mastra/commit/d4be8c1739d22d621e3f78790e1dd5eb5ecc3589), [`a5d2eb1`](https://github.com/mastra-ai/mastra/commit/a5d2eb10347eade1ae2816d88f466c25186c54a5), [`e81744c`](https://github.com/mastra-ai/mastra/commit/e81744cd13c46619c142dc521dc0baac47607a84)]:
|
|
10
|
+
- @mastra/core@1.60.0-alpha.4
|
|
11
|
+
|
|
3
12
|
## 1.17.1-alpha.0
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -56,9 +56,11 @@ Metrics are automatically extracted from span lifecycle events by `AutoExtracted
|
|
|
56
56
|
- `mastra_workflow_duration_ms`
|
|
57
57
|
- `mastra_model_duration_ms`
|
|
58
58
|
- `mastra_model_total_input_tokens` / `mastra_model_total_output_tokens`
|
|
59
|
-
- `mastra_model_input_text_tokens` / `mastra_model_input_cache_read_tokens` / `mastra_model_input_cache_write_tokens` / `mastra_model_input_audio_tokens` / `mastra_model_input_image_tokens`
|
|
59
|
+
- `mastra_model_input_text_tokens` / `mastra_model_input_cache_read_tokens` / `mastra_model_input_cache_write_tokens` / `mastra_model_input_cache_write_5m_tokens` / `mastra_model_input_cache_write_1h_tokens` / `mastra_model_input_audio_tokens` / `mastra_model_input_image_tokens`
|
|
60
60
|
- `mastra_model_output_text_tokens` / `mastra_model_output_reasoning_tokens` / `mastra_model_output_audio_tokens` / `mastra_model_output_image_tokens`
|
|
61
61
|
|
|
62
|
+
For Anthropic models, the aggregate cache-write metric remains available while the 5-minute and 1-hour metrics preserve the provider's TTL-specific token counts and pricing.
|
|
63
|
+
|
|
62
64
|
Auto-extracted metrics carry labels: `entity_type`, `entity_name`, `status`, plus `model` and `provider` on model generation spans.
|
|
63
65
|
|
|
64
66
|
### Structured logging
|
package/dist/index.cjs
CHANGED
|
@@ -1102,6 +1102,8 @@ const MINIFIED_METER_TO_CANONICAL = {
|
|
|
1102
1102
|
ot: "output_tokens",
|
|
1103
1103
|
icrt: "input_cache_read_tokens",
|
|
1104
1104
|
icwt: "input_cache_write_tokens",
|
|
1105
|
+
icwt5m: "input_cache_write_5m_tokens",
|
|
1106
|
+
icwt1h: "input_cache_write_1h_tokens",
|
|
1105
1107
|
iat: "input_audio_tokens",
|
|
1106
1108
|
oat: "output_audio_tokens",
|
|
1107
1109
|
ort: "output_reasoning_tokens"
|
|
@@ -1158,6 +1160,15 @@ function parsePricingModelText(content) {
|
|
|
1158
1160
|
}
|
|
1159
1161
|
return pricingModels;
|
|
1160
1162
|
}
|
|
1163
|
+
function expandRates(row, tier) {
|
|
1164
|
+
const rates = Object.fromEntries(Object.entries(tier.r).map(([meter, value]) => [MINIFIED_METER_TO_CANONICAL[meter], value.c]));
|
|
1165
|
+
const cacheWriteRate = rates.input_cache_write_tokens;
|
|
1166
|
+
if (row.m.includes("claude") && typeof cacheWriteRate === "number") {
|
|
1167
|
+
rates.input_cache_write_5m_tokens ??= cacheWriteRate;
|
|
1168
|
+
rates.input_cache_write_1h_tokens ??= cacheWriteRate * 1.6;
|
|
1169
|
+
}
|
|
1170
|
+
return rates;
|
|
1171
|
+
}
|
|
1161
1172
|
function expandPricingModelRow(row) {
|
|
1162
1173
|
return new PricingModel({
|
|
1163
1174
|
id: row.i,
|
|
@@ -1172,7 +1183,7 @@ function expandPricingModelRow(row) {
|
|
|
1172
1183
|
op: condition.op,
|
|
1173
1184
|
value: condition.value
|
|
1174
1185
|
})),
|
|
1175
|
-
rates:
|
|
1186
|
+
rates: expandRates(row, tier)
|
|
1176
1187
|
}))
|
|
1177
1188
|
});
|
|
1178
1189
|
}
|
|
@@ -1303,6 +1314,8 @@ const PricingMeter = {
|
|
|
1303
1314
|
INPUT_AUDIO_TOKENS: "input_audio_tokens",
|
|
1304
1315
|
INPUT_CACHE_READ_TOKENS: "input_cache_read_tokens",
|
|
1305
1316
|
INPUT_CACHE_WRITE_TOKENS: "input_cache_write_tokens",
|
|
1317
|
+
INPUT_CACHE_WRITE_5M_TOKENS: "input_cache_write_5m_tokens",
|
|
1318
|
+
INPUT_CACHE_WRITE_1H_TOKENS: "input_cache_write_1h_tokens",
|
|
1306
1319
|
INPUT_IMAGE_TOKENS: "input_image_tokens",
|
|
1307
1320
|
OUTPUT_TOKENS: "output_tokens",
|
|
1308
1321
|
OUTPUT_AUDIO_TOKENS: "output_audio_tokens",
|
|
@@ -1315,6 +1328,8 @@ const TokenMetrics = {
|
|
|
1315
1328
|
INPUT_TEXT: "mastra_model_input_text_tokens",
|
|
1316
1329
|
INPUT_CACHE_READ: "mastra_model_input_cache_read_tokens",
|
|
1317
1330
|
INPUT_CACHE_WRITE: "mastra_model_input_cache_write_tokens",
|
|
1331
|
+
INPUT_CACHE_WRITE_5M: "mastra_model_input_cache_write_5m_tokens",
|
|
1332
|
+
INPUT_CACHE_WRITE_1H: "mastra_model_input_cache_write_1h_tokens",
|
|
1318
1333
|
INPUT_AUDIO: "mastra_model_input_audio_tokens",
|
|
1319
1334
|
INPUT_IMAGE: "mastra_model_input_image_tokens",
|
|
1320
1335
|
OUTPUT_TEXT: "mastra_model_output_text_tokens",
|
|
@@ -1344,6 +1359,8 @@ function getTokenMetricSamples(usage) {
|
|
|
1344
1359
|
pushIfPositive(TokenMetrics.INPUT_TEXT, usage.inputDetails.text);
|
|
1345
1360
|
pushIfPositive(TokenMetrics.INPUT_CACHE_READ, usage.inputDetails.cacheRead);
|
|
1346
1361
|
pushIfPositive(TokenMetrics.INPUT_CACHE_WRITE, usage.inputDetails.cacheWrite);
|
|
1362
|
+
pushIfPositive(TokenMetrics.INPUT_CACHE_WRITE_5M, usage.inputDetails.cacheWrite5m);
|
|
1363
|
+
pushIfPositive(TokenMetrics.INPUT_CACHE_WRITE_1H, usage.inputDetails.cacheWrite1h);
|
|
1347
1364
|
pushIfPositive(TokenMetrics.INPUT_AUDIO, usage.inputDetails.audio);
|
|
1348
1365
|
pushIfPositive(TokenMetrics.INPUT_IMAGE, usage.inputDetails.image);
|
|
1349
1366
|
}
|
|
@@ -1410,15 +1427,40 @@ function estimateCosts(args, pricingRegistry = PricingRegistry.getGlobal()) {
|
|
|
1410
1427
|
results.set(TokenMetrics.INPUT_CACHE_READ, result.costContext);
|
|
1411
1428
|
inputDetailResults.push(result);
|
|
1412
1429
|
}
|
|
1413
|
-
|
|
1430
|
+
const cacheWriteDetailResults = [];
|
|
1431
|
+
const cacheWrite5m = usage.inputDetails?.cacheWrite5m ?? 0;
|
|
1432
|
+
const cacheWrite1h = usage.inputDetails?.cacheWrite1h ?? 0;
|
|
1433
|
+
if (cacheWrite5m > 0) {
|
|
1434
|
+
const result = estimateCostForMeter({
|
|
1435
|
+
meter: PricingMeter.INPUT_CACHE_WRITE_5M_TOKENS,
|
|
1436
|
+
tokenCount: cacheWrite5m,
|
|
1437
|
+
...estimateFields
|
|
1438
|
+
});
|
|
1439
|
+
results.set(TokenMetrics.INPUT_CACHE_WRITE_5M, result.costContext);
|
|
1440
|
+
cacheWriteDetailResults.push(result);
|
|
1441
|
+
inputDetailResults.push(result);
|
|
1442
|
+
}
|
|
1443
|
+
if (cacheWrite1h > 0) {
|
|
1444
|
+
const result = estimateCostForMeter({
|
|
1445
|
+
meter: PricingMeter.INPUT_CACHE_WRITE_1H_TOKENS,
|
|
1446
|
+
tokenCount: cacheWrite1h,
|
|
1447
|
+
...estimateFields
|
|
1448
|
+
});
|
|
1449
|
+
results.set(TokenMetrics.INPUT_CACHE_WRITE_1H, result.costContext);
|
|
1450
|
+
cacheWriteDetailResults.push(result);
|
|
1451
|
+
inputDetailResults.push(result);
|
|
1452
|
+
}
|
|
1453
|
+
const unclassifiedCacheWrite = Math.max(0, (usage.inputDetails?.cacheWrite ?? 0) - cacheWrite5m - cacheWrite1h);
|
|
1454
|
+
if (unclassifiedCacheWrite > 0) {
|
|
1414
1455
|
const result = estimateCostForMeter({
|
|
1415
1456
|
meter: PricingMeter.INPUT_CACHE_WRITE_TOKENS,
|
|
1416
|
-
tokenCount:
|
|
1457
|
+
tokenCount: unclassifiedCacheWrite,
|
|
1417
1458
|
...estimateFields
|
|
1418
1459
|
});
|
|
1419
|
-
|
|
1460
|
+
cacheWriteDetailResults.push(result);
|
|
1420
1461
|
inputDetailResults.push(result);
|
|
1421
1462
|
}
|
|
1463
|
+
if (cacheWriteDetailResults.length > 0) setCombinedCostContext(results, TokenMetrics.INPUT_CACHE_WRITE, cacheWriteDetailResults, pricingModel, costMetadata);
|
|
1422
1464
|
if (usage.inputDetails?.image) {
|
|
1423
1465
|
const result = estimateCostForMeter({
|
|
1424
1466
|
meter: PricingMeter.INPUT_IMAGE_TOKENS,
|
|
@@ -1495,6 +1537,20 @@ function estimateCosts(args, pricingRegistry = PricingRegistry.getGlobal()) {
|
|
|
1495
1537
|
function applyErrorContextForUsage(results, usage, errorContext) {
|
|
1496
1538
|
for (const sample of getTokenMetricSamples(usage)) results.set(sample.name, errorContext);
|
|
1497
1539
|
}
|
|
1540
|
+
function setCombinedCostContext(results, metric, detailResults, pricingModel, costMetadata) {
|
|
1541
|
+
const estimatedCosts = detailResults.map((result) => result.costContext.estimatedCost).filter((value) => typeof value === "number");
|
|
1542
|
+
const hasFailedCost = detailResults.some((result) => !result.success);
|
|
1543
|
+
results.set(metric, {
|
|
1544
|
+
provider: pricingModel.provider,
|
|
1545
|
+
model: pricingModel.model,
|
|
1546
|
+
...estimatedCosts.length > 0 && { estimatedCost: estimatedCosts.reduce((sum, value) => sum + value, 0) },
|
|
1547
|
+
...estimatedCosts.length > 0 && { costUnit: pricingModel.currency },
|
|
1548
|
+
costMetadata: hasFailedCost ? {
|
|
1549
|
+
...costMetadata,
|
|
1550
|
+
error: "partial_cost"
|
|
1551
|
+
} : { ...costMetadata }
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1498
1554
|
function setAggregateCostContext(args) {
|
|
1499
1555
|
const { results, totalMetric, fallbackMeter, totalTokenCount, detailResults, pricingModel, pricingTier, costMetadata } = args;
|
|
1500
1556
|
if (totalTokenCount == null) return;
|
|
@@ -1735,14 +1791,24 @@ function extractUsageMetrics(usage, providerMetadata) {
|
|
|
1735
1791
|
if (isDefined(aiSdkDetails?.cacheReadTokens)) inputDetails.cacheRead = aiSdkDetails.cacheReadTokens;
|
|
1736
1792
|
if (isDefined(aiSdkDetails?.cacheWriteTokens)) inputDetails.cacheWrite = aiSdkDetails.cacheWriteTokens;
|
|
1737
1793
|
if (!isDefined(inputDetails.cacheRead) && isDefined(usage.cachedInputTokens)) inputDetails.cacheRead = usage.cachedInputTokens;
|
|
1794
|
+
if (isDefined(usage.cacheCreationInputTokens5m)) inputDetails.cacheWrite5m = usage.cacheCreationInputTokens5m;
|
|
1795
|
+
if (isDefined(usage.cacheCreationInputTokens1h)) inputDetails.cacheWrite1h = usage.cacheCreationInputTokens1h;
|
|
1738
1796
|
if (!isDefined(inputDetails.cacheWrite) && isDefined(usage.cacheCreationInputTokens)) inputDetails.cacheWrite = usage.cacheCreationInputTokens;
|
|
1797
|
+
if (!isDefined(inputDetails.cacheWrite) && (isDefined(inputDetails.cacheWrite5m) || isDefined(inputDetails.cacheWrite1h))) inputDetails.cacheWrite = (inputDetails.cacheWrite5m ?? 0) + (inputDetails.cacheWrite1h ?? 0);
|
|
1739
1798
|
if (isDefined(usage.reasoningTokens)) outputDetails.reasoning = usage.reasoningTokens;
|
|
1740
1799
|
const anthropic = providerMetadata?.anthropic;
|
|
1741
1800
|
if (anthropic) {
|
|
1742
1801
|
const rawV3InputUsage = isV3RawUsage(usage.raw) ? usage.raw.inputTokens : void 0;
|
|
1743
1802
|
const hasV3CachedTotals = rawV3InputUsage?.total !== void 0 && (rawV3InputUsage.cacheRead !== void 0 || rawV3InputUsage.cacheWrite !== void 0);
|
|
1744
1803
|
if (!isDefined(inputDetails.cacheRead) && isDefined(anthropic.cacheReadInputTokens)) inputDetails.cacheRead = anthropic.cacheReadInputTokens;
|
|
1745
|
-
|
|
1804
|
+
const cacheWrite5m = anthropic.cacheCreation?.ephemeral_5m_input_tokens ?? anthropic.cacheCreation?.ephemeral5mInputTokens;
|
|
1805
|
+
const cacheWrite1h = anthropic.cacheCreation?.ephemeral_1h_input_tokens ?? anthropic.cacheCreation?.ephemeral1hInputTokens;
|
|
1806
|
+
if (!isDefined(inputDetails.cacheWrite5m) && isDefined(cacheWrite5m)) inputDetails.cacheWrite5m = cacheWrite5m;
|
|
1807
|
+
if (!isDefined(inputDetails.cacheWrite1h) && isDefined(cacheWrite1h)) inputDetails.cacheWrite1h = cacheWrite1h;
|
|
1808
|
+
if (!isDefined(inputDetails.cacheWrite)) {
|
|
1809
|
+
if (isDefined(anthropic.cacheCreationInputTokens)) inputDetails.cacheWrite = anthropic.cacheCreationInputTokens;
|
|
1810
|
+
else if (isDefined(cacheWrite5m) || isDefined(cacheWrite1h)) inputDetails.cacheWrite = (cacheWrite5m ?? 0) + (cacheWrite1h ?? 0);
|
|
1811
|
+
}
|
|
1746
1812
|
if (!(hasV3CachedTotals || isDefined(usage.cachedInputTokens) && usage.cachedInputTokens > 0 || isDefined(usage.cacheCreationInputTokens) && usage.cacheCreationInputTokens > 0) && (isDefined(inputDetails.cacheRead) || isDefined(inputDetails.cacheWrite))) inputTokens = (usage.inputTokens ?? 0) + (inputDetails.cacheRead ?? 0) + (inputDetails.cacheWrite ?? 0);
|
|
1747
1813
|
}
|
|
1748
1814
|
const google = providerMetadata?.google;
|
|
@@ -1783,6 +1849,8 @@ function mergeInputDetails(a, b) {
|
|
|
1783
1849
|
text: addOptional(a.text, b.text),
|
|
1784
1850
|
cacheRead: addOptional(a.cacheRead, b.cacheRead),
|
|
1785
1851
|
cacheWrite: addOptional(a.cacheWrite, b.cacheWrite),
|
|
1852
|
+
cacheWrite5m: addOptional(a.cacheWrite5m, b.cacheWrite5m),
|
|
1853
|
+
cacheWrite1h: addOptional(a.cacheWrite1h, b.cacheWrite1h),
|
|
1786
1854
|
audio: addOptional(a.audio, b.audio),
|
|
1787
1855
|
image: addOptional(a.image, b.image)
|
|
1788
1856
|
};
|