@mastra/observability 1.17.8 → 1.17.9-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/dist/index.cjs +91 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +91 -2
- package/dist/index.js.map +1 -1
- package/dist/instances/base.d.ts.map +1 -1
- package/dist/metrics/pricing-data.jsonl +3950 -1836
- package/dist/model-tracing.d.ts.map +1 -1
- package/dist/span_processors/sensitive-data-filter.d.ts +2 -1
- package/dist/span_processors/sensitive-data-filter.d.ts.map +1 -1
- package/dist/usage.d.ts +18 -0
- package/dist/usage.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -1870,6 +1870,57 @@ var CardinalityFilter = class {
|
|
|
1870
1870
|
};
|
|
1871
1871
|
//#endregion
|
|
1872
1872
|
//#region src/usage.ts
|
|
1873
|
+
/**
|
|
1874
|
+
* For non-BYOK requests, `usage.cost` is the complete OpenRouter charge and
|
|
1875
|
+
* `usage.costDetails.upstreamInferenceCost` is only its upstream breakdown. For BYOK requests,
|
|
1876
|
+
* the upstream cost is billed separately and must be added to OpenRouter's own `usage.cost`.
|
|
1877
|
+
*
|
|
1878
|
+
* OpenRouter reports `usage.is_byok` on the wire, but published `@openrouter/ai-sdk-provider`
|
|
1879
|
+
* versions drop it from `providerMetadata.openrouter.usage`. When `isByok` is present it is
|
|
1880
|
+
* authoritative. When it is absent, only the unambiguous shapes are used: a non-BYOK response
|
|
1881
|
+
* reports an upstream cost that is absent, zero, or equal to `cost`, and a BYOK response reports
|
|
1882
|
+
* a zero `cost` with a positive upstream cost. Any other combination falls back to model price
|
|
1883
|
+
* inference rather than double-counting a non-BYOK charge or under-reporting a BYOK one.
|
|
1884
|
+
*/
|
|
1885
|
+
function extractOpenRouterCost(providerMetadata) {
|
|
1886
|
+
const usage = providerMetadata?.openrouter?.usage;
|
|
1887
|
+
if (!usage || typeof usage !== "object" || Array.isArray(usage)) return void 0;
|
|
1888
|
+
const cost = usage.cost;
|
|
1889
|
+
const isByok = usage.isByok;
|
|
1890
|
+
const costDetails = usage.costDetails;
|
|
1891
|
+
const upstreamCost = costDetails && typeof costDetails === "object" && !Array.isArray(costDetails) ? costDetails.upstreamInferenceCost : void 0;
|
|
1892
|
+
const isValid = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
1893
|
+
if (cost != null && !isValid(cost) || upstreamCost != null && !isValid(upstreamCost)) return void 0;
|
|
1894
|
+
const validCost = isValid(cost) ? cost : void 0;
|
|
1895
|
+
const validUpstreamCost = isValid(upstreamCost) ? upstreamCost : void 0;
|
|
1896
|
+
const byok = typeof isByok === "boolean" ? isByok : inferByok(validCost, validUpstreamCost);
|
|
1897
|
+
if (byok === void 0) return void 0;
|
|
1898
|
+
if (!byok) {
|
|
1899
|
+
if (validCost === void 0) return void 0;
|
|
1900
|
+
return {
|
|
1901
|
+
total: validCost,
|
|
1902
|
+
usedCost: true,
|
|
1903
|
+
usedUpstreamCost: false
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1906
|
+
if (validCost === void 0 && validUpstreamCost === void 0) return void 0;
|
|
1907
|
+
const total = (validCost ?? 0) + (validUpstreamCost ?? 0);
|
|
1908
|
+
if (!Number.isFinite(total)) return void 0;
|
|
1909
|
+
return {
|
|
1910
|
+
total,
|
|
1911
|
+
usedCost: validCost !== void 0,
|
|
1912
|
+
usedUpstreamCost: validUpstreamCost !== void 0
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
/**
|
|
1916
|
+
* Infer the BYOK mode from the cost fields alone. Returns `undefined` when the shape is
|
|
1917
|
+
* ambiguous, so the caller falls back to model price inference.
|
|
1918
|
+
*/
|
|
1919
|
+
function inferByok(cost, upstreamCost) {
|
|
1920
|
+
if (cost === void 0) return void 0;
|
|
1921
|
+
if (upstreamCost === void 0 || upstreamCost === 0 || upstreamCost === cost) return false;
|
|
1922
|
+
if (cost === 0) return true;
|
|
1923
|
+
}
|
|
1873
1924
|
function isV3RawUsage(raw) {
|
|
1874
1925
|
return typeof raw === "object" && raw !== null && "inputTokens" in raw;
|
|
1875
1926
|
}
|
|
@@ -2057,6 +2108,31 @@ function getGatewayCostContext({ stepProviderMetadata }) {
|
|
|
2057
2108
|
}
|
|
2058
2109
|
};
|
|
2059
2110
|
}
|
|
2111
|
+
function getOpenRouterCostContext({ providerMetadata, stepProviderMetadata }, model) {
|
|
2112
|
+
const metadata = stepProviderMetadata ?? (providerMetadata ? [providerMetadata] : void 0);
|
|
2113
|
+
if (!metadata?.some((step) => step?.openrouter !== void 0)) return void 0;
|
|
2114
|
+
const results = metadata.map(extractOpenRouterCost);
|
|
2115
|
+
if (results.some((result) => result === void 0)) return void 0;
|
|
2116
|
+
const costs = results;
|
|
2117
|
+
const estimatedCost = costs.reduce((total, result) => total + result.total, 0);
|
|
2118
|
+
if (!Number.isFinite(estimatedCost)) return void 0;
|
|
2119
|
+
const sdkCostFields = [];
|
|
2120
|
+
if (costs.some((result) => result.usedCost)) sdkCostFields.push("openrouter.usage.cost");
|
|
2121
|
+
if (costs.some((result) => result.usedUpstreamCost)) sdkCostFields.push("openrouter.usage.costDetails.upstreamInferenceCost");
|
|
2122
|
+
return {
|
|
2123
|
+
provider: "openrouter",
|
|
2124
|
+
model,
|
|
2125
|
+
estimatedCost,
|
|
2126
|
+
costUnit: "USD",
|
|
2127
|
+
costMetadata: {
|
|
2128
|
+
source: "provider_reported",
|
|
2129
|
+
sdkProvider: "openrouter",
|
|
2130
|
+
sdkCostField: sdkCostFields.join("+"),
|
|
2131
|
+
scope: "query_total",
|
|
2132
|
+
reportedStepCount: costs.length
|
|
2133
|
+
}
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2060
2136
|
function formatPreviewLabel(label, fallback) {
|
|
2061
2137
|
return typeof label === "string" && label.length > 0 ? label : fallback;
|
|
2062
2138
|
}
|
|
@@ -2239,9 +2315,16 @@ var ModelSpanTracker = class {
|
|
|
2239
2315
|
*/
|
|
2240
2316
|
endGeneration(options) {
|
|
2241
2317
|
const { usage, providerMetadata, stepProviderMetadata, ...spanOptions } = options ?? {};
|
|
2318
|
+
const model = spanOptions.attributes?.responseModel ?? this.#modelSpan?.attributes?.responseModel ?? this.#modelSpan?.attributes?.model;
|
|
2319
|
+
const providerCostContext = getOpenRouterCostContext({
|
|
2320
|
+
providerMetadata,
|
|
2321
|
+
stepProviderMetadata
|
|
2322
|
+
}, model);
|
|
2323
|
+
if (providerCostContext && !spanOptions.attributes) spanOptions.attributes = {};
|
|
2242
2324
|
if (spanOptions.attributes) {
|
|
2243
2325
|
spanOptions.attributes.completionStartTime = this.#completionStartTime;
|
|
2244
2326
|
spanOptions.attributes.usage = extractUsageMetrics(usage, providerMetadata);
|
|
2327
|
+
spanOptions.attributes.costContext = providerCostContext ?? spanOptions.attributes.costContext;
|
|
2245
2328
|
if (!spanOptions.attributes.costContext) spanOptions.attributes.costContext = getGatewayCostContext({ stepProviderMetadata });
|
|
2246
2329
|
}
|
|
2247
2330
|
this.#modelSpan?.end(spanOptions);
|
|
@@ -4930,7 +5013,12 @@ var BaseObservabilityInstance = class extends _mastra_core_base.MastraBase {
|
|
|
4930
5013
|
for (const processor of this.spanOutputProcessors) {
|
|
4931
5014
|
if (!span) break;
|
|
4932
5015
|
try {
|
|
4933
|
-
|
|
5016
|
+
const processed = processor.process(span);
|
|
5017
|
+
if (processed !== void 0 && processed !== span) {
|
|
5018
|
+
this.logger.error(`[Observability] Processor error [name=${processor.name}]: process() must return the span it received (or undefined to drop it), not a copy. Span dropped.`);
|
|
5019
|
+
return;
|
|
5020
|
+
}
|
|
5021
|
+
span = processed;
|
|
4934
5022
|
} catch (error) {
|
|
4935
5023
|
this.logger.error(`[Observability] Processor error [name=${processor.name}]`, error);
|
|
4936
5024
|
}
|
|
@@ -9230,9 +9318,10 @@ var SensitiveDataFilter = class {
|
|
|
9230
9318
|
/**
|
|
9231
9319
|
* Process a span by filtering sensitive data across its key fields.
|
|
9232
9320
|
* Fields processed: attributes, metadata, input, output, errorInfo, requestContext.
|
|
9321
|
+
* The span is mutated in place, as the SpanOutputProcessor contract requires.
|
|
9233
9322
|
*
|
|
9234
9323
|
* @param span - The input span to filter
|
|
9235
|
-
* @returns
|
|
9324
|
+
* @returns The same span instance with sensitive values redacted
|
|
9236
9325
|
*/
|
|
9237
9326
|
process(span) {
|
|
9238
9327
|
const indexedState = this.redactionStyle === "indexed" ? this.getTraceState(span.traceId) : void 0;
|