@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.js
CHANGED
|
@@ -1845,6 +1845,57 @@ var CardinalityFilter = class {
|
|
|
1845
1845
|
};
|
|
1846
1846
|
//#endregion
|
|
1847
1847
|
//#region src/usage.ts
|
|
1848
|
+
/**
|
|
1849
|
+
* For non-BYOK requests, `usage.cost` is the complete OpenRouter charge and
|
|
1850
|
+
* `usage.costDetails.upstreamInferenceCost` is only its upstream breakdown. For BYOK requests,
|
|
1851
|
+
* the upstream cost is billed separately and must be added to OpenRouter's own `usage.cost`.
|
|
1852
|
+
*
|
|
1853
|
+
* OpenRouter reports `usage.is_byok` on the wire, but published `@openrouter/ai-sdk-provider`
|
|
1854
|
+
* versions drop it from `providerMetadata.openrouter.usage`. When `isByok` is present it is
|
|
1855
|
+
* authoritative. When it is absent, only the unambiguous shapes are used: a non-BYOK response
|
|
1856
|
+
* reports an upstream cost that is absent, zero, or equal to `cost`, and a BYOK response reports
|
|
1857
|
+
* a zero `cost` with a positive upstream cost. Any other combination falls back to model price
|
|
1858
|
+
* inference rather than double-counting a non-BYOK charge or under-reporting a BYOK one.
|
|
1859
|
+
*/
|
|
1860
|
+
function extractOpenRouterCost(providerMetadata) {
|
|
1861
|
+
const usage = providerMetadata?.openrouter?.usage;
|
|
1862
|
+
if (!usage || typeof usage !== "object" || Array.isArray(usage)) return void 0;
|
|
1863
|
+
const cost = usage.cost;
|
|
1864
|
+
const isByok = usage.isByok;
|
|
1865
|
+
const costDetails = usage.costDetails;
|
|
1866
|
+
const upstreamCost = costDetails && typeof costDetails === "object" && !Array.isArray(costDetails) ? costDetails.upstreamInferenceCost : void 0;
|
|
1867
|
+
const isValid = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
1868
|
+
if (cost != null && !isValid(cost) || upstreamCost != null && !isValid(upstreamCost)) return void 0;
|
|
1869
|
+
const validCost = isValid(cost) ? cost : void 0;
|
|
1870
|
+
const validUpstreamCost = isValid(upstreamCost) ? upstreamCost : void 0;
|
|
1871
|
+
const byok = typeof isByok === "boolean" ? isByok : inferByok(validCost, validUpstreamCost);
|
|
1872
|
+
if (byok === void 0) return void 0;
|
|
1873
|
+
if (!byok) {
|
|
1874
|
+
if (validCost === void 0) return void 0;
|
|
1875
|
+
return {
|
|
1876
|
+
total: validCost,
|
|
1877
|
+
usedCost: true,
|
|
1878
|
+
usedUpstreamCost: false
|
|
1879
|
+
};
|
|
1880
|
+
}
|
|
1881
|
+
if (validCost === void 0 && validUpstreamCost === void 0) return void 0;
|
|
1882
|
+
const total = (validCost ?? 0) + (validUpstreamCost ?? 0);
|
|
1883
|
+
if (!Number.isFinite(total)) return void 0;
|
|
1884
|
+
return {
|
|
1885
|
+
total,
|
|
1886
|
+
usedCost: validCost !== void 0,
|
|
1887
|
+
usedUpstreamCost: validUpstreamCost !== void 0
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
/**
|
|
1891
|
+
* Infer the BYOK mode from the cost fields alone. Returns `undefined` when the shape is
|
|
1892
|
+
* ambiguous, so the caller falls back to model price inference.
|
|
1893
|
+
*/
|
|
1894
|
+
function inferByok(cost, upstreamCost) {
|
|
1895
|
+
if (cost === void 0) return void 0;
|
|
1896
|
+
if (upstreamCost === void 0 || upstreamCost === 0 || upstreamCost === cost) return false;
|
|
1897
|
+
if (cost === 0) return true;
|
|
1898
|
+
}
|
|
1848
1899
|
function isV3RawUsage(raw) {
|
|
1849
1900
|
return typeof raw === "object" && raw !== null && "inputTokens" in raw;
|
|
1850
1901
|
}
|
|
@@ -2032,6 +2083,31 @@ function getGatewayCostContext({ stepProviderMetadata }) {
|
|
|
2032
2083
|
}
|
|
2033
2084
|
};
|
|
2034
2085
|
}
|
|
2086
|
+
function getOpenRouterCostContext({ providerMetadata, stepProviderMetadata }, model) {
|
|
2087
|
+
const metadata = stepProviderMetadata ?? (providerMetadata ? [providerMetadata] : void 0);
|
|
2088
|
+
if (!metadata?.some((step) => step?.openrouter !== void 0)) return void 0;
|
|
2089
|
+
const results = metadata.map(extractOpenRouterCost);
|
|
2090
|
+
if (results.some((result) => result === void 0)) return void 0;
|
|
2091
|
+
const costs = results;
|
|
2092
|
+
const estimatedCost = costs.reduce((total, result) => total + result.total, 0);
|
|
2093
|
+
if (!Number.isFinite(estimatedCost)) return void 0;
|
|
2094
|
+
const sdkCostFields = [];
|
|
2095
|
+
if (costs.some((result) => result.usedCost)) sdkCostFields.push("openrouter.usage.cost");
|
|
2096
|
+
if (costs.some((result) => result.usedUpstreamCost)) sdkCostFields.push("openrouter.usage.costDetails.upstreamInferenceCost");
|
|
2097
|
+
return {
|
|
2098
|
+
provider: "openrouter",
|
|
2099
|
+
model,
|
|
2100
|
+
estimatedCost,
|
|
2101
|
+
costUnit: "USD",
|
|
2102
|
+
costMetadata: {
|
|
2103
|
+
source: "provider_reported",
|
|
2104
|
+
sdkProvider: "openrouter",
|
|
2105
|
+
sdkCostField: sdkCostFields.join("+"),
|
|
2106
|
+
scope: "query_total",
|
|
2107
|
+
reportedStepCount: costs.length
|
|
2108
|
+
}
|
|
2109
|
+
};
|
|
2110
|
+
}
|
|
2035
2111
|
function formatPreviewLabel(label, fallback) {
|
|
2036
2112
|
return typeof label === "string" && label.length > 0 ? label : fallback;
|
|
2037
2113
|
}
|
|
@@ -2214,9 +2290,16 @@ var ModelSpanTracker = class {
|
|
|
2214
2290
|
*/
|
|
2215
2291
|
endGeneration(options) {
|
|
2216
2292
|
const { usage, providerMetadata, stepProviderMetadata, ...spanOptions } = options ?? {};
|
|
2293
|
+
const model = spanOptions.attributes?.responseModel ?? this.#modelSpan?.attributes?.responseModel ?? this.#modelSpan?.attributes?.model;
|
|
2294
|
+
const providerCostContext = getOpenRouterCostContext({
|
|
2295
|
+
providerMetadata,
|
|
2296
|
+
stepProviderMetadata
|
|
2297
|
+
}, model);
|
|
2298
|
+
if (providerCostContext && !spanOptions.attributes) spanOptions.attributes = {};
|
|
2217
2299
|
if (spanOptions.attributes) {
|
|
2218
2300
|
spanOptions.attributes.completionStartTime = this.#completionStartTime;
|
|
2219
2301
|
spanOptions.attributes.usage = extractUsageMetrics(usage, providerMetadata);
|
|
2302
|
+
spanOptions.attributes.costContext = providerCostContext ?? spanOptions.attributes.costContext;
|
|
2220
2303
|
if (!spanOptions.attributes.costContext) spanOptions.attributes.costContext = getGatewayCostContext({ stepProviderMetadata });
|
|
2221
2304
|
}
|
|
2222
2305
|
this.#modelSpan?.end(spanOptions);
|
|
@@ -4905,7 +4988,12 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
4905
4988
|
for (const processor of this.spanOutputProcessors) {
|
|
4906
4989
|
if (!span) break;
|
|
4907
4990
|
try {
|
|
4908
|
-
|
|
4991
|
+
const processed = processor.process(span);
|
|
4992
|
+
if (processed !== void 0 && processed !== span) {
|
|
4993
|
+
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.`);
|
|
4994
|
+
return;
|
|
4995
|
+
}
|
|
4996
|
+
span = processed;
|
|
4909
4997
|
} catch (error) {
|
|
4910
4998
|
this.logger.error(`[Observability] Processor error [name=${processor.name}]`, error);
|
|
4911
4999
|
}
|
|
@@ -9205,9 +9293,10 @@ var SensitiveDataFilter = class {
|
|
|
9205
9293
|
/**
|
|
9206
9294
|
* Process a span by filtering sensitive data across its key fields.
|
|
9207
9295
|
* Fields processed: attributes, metadata, input, output, errorInfo, requestContext.
|
|
9296
|
+
* The span is mutated in place, as the SpanOutputProcessor contract requires.
|
|
9208
9297
|
*
|
|
9209
9298
|
* @param span - The input span to filter
|
|
9210
|
-
* @returns
|
|
9299
|
+
* @returns The same span instance with sensitive values redacted
|
|
9211
9300
|
*/
|
|
9212
9301
|
process(span) {
|
|
9213
9302
|
const indexedState = this.redactionStyle === "indexed" ? this.getTraceState(span.traceId) : void 0;
|