@usagetap/sdk 1.4.0 → 1.7.0
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/README.md +156 -18
- package/dist/adapters/anthropic.cjs +195 -235
- package/dist/adapters/anthropic.cjs.map +1 -1
- package/dist/adapters/anthropic.d.cts +1 -1
- package/dist/adapters/anthropic.d.ts +1 -1
- package/dist/adapters/anthropic.mjs +195 -235
- package/dist/adapters/anthropic.mjs.map +1 -1
- package/dist/adapters/openai.cjs +256 -274
- package/dist/adapters/openai.cjs.map +1 -1
- package/dist/adapters/openai.d.cts +1 -1
- package/dist/adapters/openai.d.ts +1 -1
- package/dist/adapters/openai.mjs +256 -274
- package/dist/adapters/openai.mjs.map +1 -1
- package/dist/adapters/openrouter.cjs +256 -274
- package/dist/adapters/openrouter.cjs.map +1 -1
- package/dist/adapters/openrouter.d.cts +1 -1
- package/dist/adapters/openrouter.d.ts +1 -1
- package/dist/adapters/openrouter.mjs +256 -274
- package/dist/adapters/openrouter.mjs.map +1 -1
- package/dist/anthropic/index.cjs +195 -235
- package/dist/anthropic/index.cjs.map +1 -1
- package/dist/anthropic/index.d.cts +1 -1
- package/dist/anthropic/index.d.ts +1 -1
- package/dist/anthropic/index.mjs +195 -235
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/{client-CExQ8e1T.d.cts → client-C0UiaqVB.d.cts} +141 -61
- package/dist/{client-CExQ8e1T.d.ts → client-C0UiaqVB.d.ts} +141 -61
- package/dist/express/index.cjs +189 -246
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.d.cts +1 -1
- package/dist/express/index.d.ts +1 -1
- package/dist/express/index.mjs +189 -246
- package/dist/express/index.mjs.map +1 -1
- package/dist/index.cjs +391 -175
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -4
- package/dist/index.d.ts +13 -4
- package/dist/index.mjs +391 -175
- package/dist/index.mjs.map +1 -1
- package/dist/openai/index.cjs +256 -274
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.d.cts +1 -1
- package/dist/openai/index.d.ts +1 -1
- package/dist/openai/index.mjs +256 -274
- package/dist/openai/index.mjs.map +1 -1
- package/dist/openrouter/index.cjs +256 -274
- package/dist/openrouter/index.cjs.map +1 -1
- package/dist/openrouter/index.d.cts +1 -1
- package/dist/openrouter/index.d.ts +1 -1
- package/dist/openrouter/index.mjs +256 -274
- package/dist/openrouter/index.mjs.map +1 -1
- package/package.json +2 -2
|
@@ -1022,6 +1022,8 @@ var SummarizationResource = class {
|
|
|
1022
1022
|
};
|
|
1023
1023
|
var GatewayResource = class {
|
|
1024
1024
|
chat;
|
|
1025
|
+
/** Buffered OpenAI Responses-compatible requests. */
|
|
1026
|
+
responses;
|
|
1025
1027
|
models;
|
|
1026
1028
|
batches;
|
|
1027
1029
|
transport;
|
|
@@ -1043,6 +1045,15 @@ var GatewayResource = class {
|
|
|
1043
1045
|
})
|
|
1044
1046
|
}
|
|
1045
1047
|
};
|
|
1048
|
+
this.responses = {
|
|
1049
|
+
create: (params, options) => this.transport.request({
|
|
1050
|
+
method: "POST",
|
|
1051
|
+
path: "/v1/responses",
|
|
1052
|
+
body: params,
|
|
1053
|
+
options,
|
|
1054
|
+
response: "json"
|
|
1055
|
+
})
|
|
1056
|
+
};
|
|
1046
1057
|
this.models = {
|
|
1047
1058
|
list: (options) => this.transport.request({
|
|
1048
1059
|
method: "GET",
|
|
@@ -1128,7 +1139,7 @@ var USER_AGENT = "UsageTapClient";
|
|
|
1128
1139
|
var CANONICAL_MEDIA_TYPE2 = "application/vnd.usagetap.v1+json";
|
|
1129
1140
|
var DEFAULT_BASE_URL = "https://api.usagetap.com";
|
|
1130
1141
|
var DEFAULT_RUN_INACTIVITY_MS = 60 * 60 * 1e3;
|
|
1131
|
-
var SDK_VERSION = "1.
|
|
1142
|
+
var SDK_VERSION = "1.7.0" ;
|
|
1132
1143
|
var HAS_WINDOW = typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
|
|
1133
1144
|
var UsageTapClient = class {
|
|
1134
1145
|
/** OpenAI-compatible chat, model, and native batch operations. */
|
|
@@ -1530,9 +1541,18 @@ var UsageTapClient = class {
|
|
|
1530
1541
|
responseTokens: request.responseTokens,
|
|
1531
1542
|
cachedInputTokens: request.cachedInputTokens,
|
|
1532
1543
|
cacheWriteInputTokens: request.cacheWriteInputTokens,
|
|
1544
|
+
cacheWrite5mInputTokens: request.cacheWrite5mInputTokens,
|
|
1545
|
+
cacheWrite1hInputTokens: request.cacheWrite1hInputTokens,
|
|
1533
1546
|
reasoningTokens: request.reasoningTokens,
|
|
1534
1547
|
searches: request.searches,
|
|
1535
1548
|
audioSeconds: request.audioSeconds,
|
|
1549
|
+
imageInputCount: request.imageInputCount,
|
|
1550
|
+
imageInputTokens: request.imageInputTokens,
|
|
1551
|
+
imageOutputCount: request.imageOutputCount,
|
|
1552
|
+
imageOutputTokens: request.imageOutputTokens,
|
|
1553
|
+
audioInputTokens: request.audioInputTokens,
|
|
1554
|
+
cachedAudioInputTokens: request.cachedAudioInputTokens,
|
|
1555
|
+
audioOutputTokens: request.audioOutputTokens,
|
|
1536
1556
|
costUsd: response.data.costUSD
|
|
1537
1557
|
},
|
|
1538
1558
|
correlationId: response.correlationId
|
|
@@ -1619,10 +1639,10 @@ var UsageTapClient = class {
|
|
|
1619
1639
|
"incrementCustomMeter requires meterSlot"
|
|
1620
1640
|
);
|
|
1621
1641
|
}
|
|
1622
|
-
if (!["CUSTOM1", "CUSTOM2"].includes(request.meterSlot)) {
|
|
1642
|
+
if (!["CUSTOM1", "CUSTOM2", "AGENTIC_API"].includes(request.meterSlot)) {
|
|
1623
1643
|
throw new UsageTapError(
|
|
1624
1644
|
"USAGETAP_BAD_REQUEST",
|
|
1625
|
-
"meterSlot must be CUSTOM1 or
|
|
1645
|
+
"meterSlot must be CUSTOM1, CUSTOM2 or AGENTIC_API"
|
|
1626
1646
|
);
|
|
1627
1647
|
}
|
|
1628
1648
|
if (typeof request.amount !== "number" || !Number.isFinite(request.amount) || request.amount <= 0) {
|
|
@@ -1695,6 +1715,28 @@ var UsageTapClient = class {
|
|
|
1695
1715
|
let handlerResult;
|
|
1696
1716
|
let handlerError;
|
|
1697
1717
|
let endCallError;
|
|
1718
|
+
let finalizationDeferred = false;
|
|
1719
|
+
let finalizationPromise;
|
|
1720
|
+
const finalize = () => {
|
|
1721
|
+
if (!finalizationPromise) {
|
|
1722
|
+
finalizationPromise = this.endCall(
|
|
1723
|
+
{
|
|
1724
|
+
callId: beginResponse.data.callId,
|
|
1725
|
+
// Pass context for metric tracking
|
|
1726
|
+
customerId: beginRequest.customerId,
|
|
1727
|
+
feature: beginRequest.feature ?? this.defaultFeature,
|
|
1728
|
+
tags: beginRequest.tags ?? this.defaultTags,
|
|
1729
|
+
...usage,
|
|
1730
|
+
error: errorPayload
|
|
1731
|
+
},
|
|
1732
|
+
{
|
|
1733
|
+
...options,
|
|
1734
|
+
correlationId: beginResponse.correlationId
|
|
1735
|
+
}
|
|
1736
|
+
).then(() => void 0);
|
|
1737
|
+
}
|
|
1738
|
+
return finalizationPromise;
|
|
1739
|
+
};
|
|
1698
1740
|
const context = {
|
|
1699
1741
|
begin: beginResponse,
|
|
1700
1742
|
setUsage: (u) => {
|
|
@@ -1702,6 +1744,10 @@ var UsageTapClient = class {
|
|
|
1702
1744
|
},
|
|
1703
1745
|
setError: (err) => {
|
|
1704
1746
|
errorPayload = err;
|
|
1747
|
+
},
|
|
1748
|
+
deferFinalization: () => {
|
|
1749
|
+
finalizationDeferred = true;
|
|
1750
|
+
return finalize;
|
|
1705
1751
|
}
|
|
1706
1752
|
};
|
|
1707
1753
|
try {
|
|
@@ -1715,24 +1761,12 @@ var UsageTapClient = class {
|
|
|
1715
1761
|
};
|
|
1716
1762
|
}
|
|
1717
1763
|
} finally {
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
feature: beginRequest.feature ?? this.defaultFeature,
|
|
1725
|
-
tags: beginRequest.tags ?? this.defaultTags,
|
|
1726
|
-
...usage,
|
|
1727
|
-
error: errorPayload
|
|
1728
|
-
},
|
|
1729
|
-
{
|
|
1730
|
-
...options,
|
|
1731
|
-
correlationId: beginResponse.correlationId
|
|
1732
|
-
}
|
|
1733
|
-
);
|
|
1734
|
-
} catch (error) {
|
|
1735
|
-
endCallError = error;
|
|
1764
|
+
if (handlerError || !finalizationDeferred) {
|
|
1765
|
+
try {
|
|
1766
|
+
await finalize();
|
|
1767
|
+
} catch (error) {
|
|
1768
|
+
endCallError = error;
|
|
1769
|
+
}
|
|
1736
1770
|
}
|
|
1737
1771
|
}
|
|
1738
1772
|
if (handlerError) {
|
|
@@ -2074,7 +2108,8 @@ var UsageTapClient = class {
|
|
|
2074
2108
|
}
|
|
2075
2109
|
toHttpError(status, payload, correlationId) {
|
|
2076
2110
|
const code = mapStatusToErrorCode(status);
|
|
2077
|
-
const
|
|
2111
|
+
const apiCode = payload?.error?.code ?? payload?.result?.code ?? "UNKNOWN";
|
|
2112
|
+
const retryable = isRetryableStatus(status) || isRetryableApiCode(apiCode);
|
|
2078
2113
|
const message = payload?.error?.message ?? payload?.result?.message ?? `UsageTap responded with HTTP ${status}`;
|
|
2079
2114
|
return new UsageTapError(code, message, {
|
|
2080
2115
|
status,
|
|
@@ -2107,7 +2142,7 @@ function isRetryableStatus(status) {
|
|
|
2107
2142
|
}
|
|
2108
2143
|
function isRetryableApiCode(code) {
|
|
2109
2144
|
const normalized = code.toUpperCase();
|
|
2110
|
-
return normalized.includes("TRANSIENT") || normalized.includes("RETRY") || normalized.includes("TIMEOUT") || normalized.includes("THROTTLE") || normalized.includes("RATE_LIMIT");
|
|
2145
|
+
return normalized === "PAYG_CONFLICT" || normalized.includes("TRANSIENT") || normalized.includes("RETRY") || normalized.includes("TIMEOUT") || normalized.includes("THROTTLE") || normalized.includes("RATE_LIMIT");
|
|
2111
2146
|
}
|
|
2112
2147
|
function mapApiCodeToError(code) {
|
|
2113
2148
|
const normalized = code.toUpperCase();
|
|
@@ -2247,25 +2282,29 @@ function createOpenAIAdapter(init) {
|
|
|
2247
2282
|
const result = await usageTap.withUsage(
|
|
2248
2283
|
params.begin,
|
|
2249
2284
|
async (ctx) => {
|
|
2285
|
+
const settle = deferUsageFinalization(ctx);
|
|
2250
2286
|
ctx.setUsage({ providerUsed: provider });
|
|
2251
2287
|
const { stream, onComplete } = await params.call(client, {
|
|
2252
2288
|
hints: ctx.begin.data.vendorHints,
|
|
2253
2289
|
begin: ctx.begin
|
|
2254
2290
|
});
|
|
2255
|
-
const wrapped = wrapStreamForUsageTap(stream, async () => {
|
|
2256
|
-
if (!onComplete) return;
|
|
2291
|
+
const wrapped = wrapStreamForUsageTap(stream, async (termination) => {
|
|
2257
2292
|
try {
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2293
|
+
if (termination === "complete" && onComplete) {
|
|
2294
|
+
const maybeUsage = await onComplete();
|
|
2295
|
+
if (maybeUsage) {
|
|
2296
|
+
ctx.setUsage(maybeUsage);
|
|
2297
|
+
}
|
|
2261
2298
|
}
|
|
2262
2299
|
} catch (error) {
|
|
2263
2300
|
ctx.setError({
|
|
2264
2301
|
code: "USAGE_FINALIZE_ERROR",
|
|
2265
2302
|
message: error instanceof Error ? error.message : String(error)
|
|
2266
2303
|
});
|
|
2304
|
+
await settle();
|
|
2267
2305
|
throw error;
|
|
2268
2306
|
}
|
|
2307
|
+
await settle();
|
|
2269
2308
|
}, ctx);
|
|
2270
2309
|
const finalize = async () => {
|
|
2271
2310
|
await wrapped.__usageTapFinalize?.();
|
|
@@ -2753,13 +2792,13 @@ function createResponsesProxy(resource, usageTap, defaultContext, applyVendorHin
|
|
|
2753
2792
|
withUsage,
|
|
2754
2793
|
promptCompression
|
|
2755
2794
|
} = splitUsageOptions(options);
|
|
2756
|
-
const beginRequest =
|
|
2795
|
+
const beginRequest = responsesBeginRequest(
|
|
2757
2796
|
resolveBeginRequest(defaultContext, usageContext),
|
|
2758
|
-
|
|
2759
|
-
String(params.model)
|
|
2797
|
+
params
|
|
2760
2798
|
);
|
|
2761
2799
|
const wantsStream = isStreamingRequest(params);
|
|
2762
2800
|
return usageTap.withUsage(beginRequest, async (ctx) => {
|
|
2801
|
+
const settle = wantsStream ? deferUsageFinalization(ctx) : void 0;
|
|
2763
2802
|
const sampleStartedAt = Date.now();
|
|
2764
2803
|
const sampleDecision = wantsStream ? Promise.resolve(false) : startMeteredOpenAISampleDecision({
|
|
2765
2804
|
usageTap,
|
|
@@ -2784,12 +2823,31 @@ function createResponsesProxy(resource, usageTap, defaultContext, applyVendorHin
|
|
|
2784
2823
|
const apiPromise2 = originalCreate(finalParams, request);
|
|
2785
2824
|
const wrappedPromise2 = transformApiPromise(apiPromise2, (rawStream) => {
|
|
2786
2825
|
ensureAsyncIterable(rawStream, "responses.create");
|
|
2787
|
-
const wrappedStream = wrapStreamForUsageTap(rawStream, async () => {
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2826
|
+
const wrappedStream = wrapStreamForUsageTap(rawStream, async (termination) => {
|
|
2827
|
+
try {
|
|
2828
|
+
if (termination === "complete") {
|
|
2829
|
+
const usage = await extractUsageFromStream(rawStream, ctx.begin.data.vendorHints, provider);
|
|
2830
|
+
if (usage) {
|
|
2831
|
+
ctx.setUsage(usage);
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
} catch (error) {
|
|
2835
|
+
ctx.setError({
|
|
2836
|
+
code: "USAGE_FINALIZE_ERROR",
|
|
2837
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2838
|
+
});
|
|
2839
|
+
throw error;
|
|
2840
|
+
} finally {
|
|
2841
|
+
await settle?.();
|
|
2791
2842
|
}
|
|
2792
|
-
}, ctx)
|
|
2843
|
+
}, ctx, (chunk) => {
|
|
2844
|
+
tryInferUsageFromStreamChunk(
|
|
2845
|
+
chunk,
|
|
2846
|
+
ctx.begin.data.vendorHints,
|
|
2847
|
+
ctx,
|
|
2848
|
+
provider
|
|
2849
|
+
);
|
|
2850
|
+
});
|
|
2793
2851
|
return wrappedStream;
|
|
2794
2852
|
});
|
|
2795
2853
|
return wrappedPromise2;
|
|
@@ -2845,13 +2903,10 @@ function createChatCompletionsProxy(resource, usageTap, defaultContext, applyVen
|
|
|
2845
2903
|
withUsage,
|
|
2846
2904
|
promptCompression
|
|
2847
2905
|
} = splitUsageOptions(options);
|
|
2848
|
-
const beginRequest =
|
|
2849
|
-
resolveBeginRequest(defaultContext, usageContext),
|
|
2850
|
-
"openai",
|
|
2851
|
-
String(params.model)
|
|
2852
|
-
);
|
|
2906
|
+
const beginRequest = resolveBeginRequest(defaultContext, usageContext);
|
|
2853
2907
|
const wantsStream = isStreamingRequest(params);
|
|
2854
2908
|
return usageTap.withUsage(beginRequest, async (ctx) => {
|
|
2909
|
+
const settle = wantsStream ? deferUsageFinalization(ctx) : void 0;
|
|
2855
2910
|
const sampleStartedAt = Date.now();
|
|
2856
2911
|
const sampleDecision = wantsStream ? Promise.resolve(false) : startMeteredOpenAISampleDecision({
|
|
2857
2912
|
usageTap,
|
|
@@ -2860,7 +2915,7 @@ function createChatCompletionsProxy(resource, usageTap, defaultContext, applyVen
|
|
|
2860
2915
|
input: params
|
|
2861
2916
|
});
|
|
2862
2917
|
const hintedParams = applyVendorHints ? applyChatVendorHints(params, ctx.begin.data.vendorHints) : params;
|
|
2863
|
-
const
|
|
2918
|
+
const compressedParams = await compressChatParamsForCall({
|
|
2864
2919
|
params: hintedParams,
|
|
2865
2920
|
usageTap,
|
|
2866
2921
|
ctx,
|
|
@@ -2870,18 +2925,38 @@ function createChatCompletionsProxy(resource, usageTap, defaultContext, applyVen
|
|
|
2870
2925
|
withUsage,
|
|
2871
2926
|
operation: "chat.completions.create"
|
|
2872
2927
|
});
|
|
2928
|
+
const finalParams = wantsStream ? ensureOpenAIStreamUsage(compressedParams) : compressedParams;
|
|
2873
2929
|
ctx.setUsage(openAIRequestExecutionMetadata(finalParams, provider));
|
|
2874
2930
|
const request = attachCorrelationHeader(requestOptions, ctx.begin.correlationId);
|
|
2875
2931
|
if (wantsStream) {
|
|
2876
2932
|
const apiPromise2 = originalCreate(finalParams, request);
|
|
2877
2933
|
const wrappedPromise2 = transformApiPromise(apiPromise2, (rawStream) => {
|
|
2878
2934
|
ensureAsyncIterable(rawStream, "chat.completions.create");
|
|
2879
|
-
const wrappedStream2 = wrapStreamForUsageTap(rawStream, async () => {
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2935
|
+
const wrappedStream2 = wrapStreamForUsageTap(rawStream, async (termination) => {
|
|
2936
|
+
try {
|
|
2937
|
+
if (termination === "complete") {
|
|
2938
|
+
const usage = await extractUsageFromStream(rawStream, ctx.begin.data.vendorHints, provider);
|
|
2939
|
+
if (usage) {
|
|
2940
|
+
ctx.setUsage(usage);
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
} catch (error) {
|
|
2944
|
+
ctx.setError({
|
|
2945
|
+
code: "USAGE_FINALIZE_ERROR",
|
|
2946
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2947
|
+
});
|
|
2948
|
+
throw error;
|
|
2949
|
+
} finally {
|
|
2950
|
+
await settle?.();
|
|
2883
2951
|
}
|
|
2884
|
-
}, ctx)
|
|
2952
|
+
}, ctx, (chunk) => {
|
|
2953
|
+
tryInferUsageFromStreamChunk(
|
|
2954
|
+
chunk,
|
|
2955
|
+
ctx.begin.data.vendorHints,
|
|
2956
|
+
ctx,
|
|
2957
|
+
provider
|
|
2958
|
+
);
|
|
2959
|
+
});
|
|
2885
2960
|
return wrappedStream2;
|
|
2886
2961
|
});
|
|
2887
2962
|
return wrappedPromise2;
|
|
@@ -2923,14 +2998,11 @@ function createChatCompletionsProxy(resource, usageTap, defaultContext, applyVen
|
|
|
2923
2998
|
withUsage,
|
|
2924
2999
|
promptCompression
|
|
2925
3000
|
} = splitUsageOptions(options);
|
|
2926
|
-
const beginRequest =
|
|
2927
|
-
resolveBeginRequest(defaultContext, usageContext),
|
|
2928
|
-
"openai",
|
|
2929
|
-
String(params.model)
|
|
2930
|
-
);
|
|
3001
|
+
const beginRequest = resolveBeginRequest(defaultContext, usageContext);
|
|
2931
3002
|
return usageTap.withUsage(beginRequest, async (ctx) => {
|
|
3003
|
+
const settle = deferUsageFinalization(ctx);
|
|
2932
3004
|
const hintedParams = applyVendorHints ? applyChatVendorHints(params, ctx.begin.data.vendorHints) : params;
|
|
2933
|
-
const
|
|
3005
|
+
const compressedParams = await compressChatParamsForCall({
|
|
2934
3006
|
params: hintedParams,
|
|
2935
3007
|
usageTap,
|
|
2936
3008
|
ctx,
|
|
@@ -2940,21 +3012,41 @@ function createChatCompletionsProxy(resource, usageTap, defaultContext, applyVen
|
|
|
2940
3012
|
withUsage,
|
|
2941
3013
|
operation: "chat.completions.stream"
|
|
2942
3014
|
});
|
|
3015
|
+
const finalParams = ensureOpenAIStreamUsage(compressedParams);
|
|
2943
3016
|
ctx.setUsage(openAIRequestExecutionMetadata(finalParams, provider));
|
|
2944
3017
|
const request = attachCorrelationHeader(requestOptions, ctx.begin.correlationId);
|
|
2945
3018
|
const apiPromise = originalStream(finalParams, request);
|
|
2946
3019
|
const wrappedPromise = transformApiPromise(apiPromise, (rawStream) => {
|
|
2947
3020
|
ensureAsyncIterable(rawStream, "chat.completions.stream");
|
|
2948
|
-
const wrappedStreamInner = wrapStreamForUsageTap(rawStream, async () => {
|
|
2949
|
-
|
|
2950
|
-
|
|
3021
|
+
const wrappedStreamInner = wrapStreamForUsageTap(rawStream, async (termination) => {
|
|
3022
|
+
try {
|
|
3023
|
+
if (termination === "complete") {
|
|
3024
|
+
const usage = await extractUsageFromStream(
|
|
3025
|
+
rawStream,
|
|
3026
|
+
ctx.begin.data.vendorHints,
|
|
3027
|
+
provider
|
|
3028
|
+
);
|
|
3029
|
+
if (usage) {
|
|
3030
|
+
ctx.setUsage(usage);
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
} catch (error) {
|
|
3034
|
+
ctx.setError({
|
|
3035
|
+
code: "USAGE_FINALIZE_ERROR",
|
|
3036
|
+
message: error instanceof Error ? error.message : String(error)
|
|
3037
|
+
});
|
|
3038
|
+
throw error;
|
|
3039
|
+
} finally {
|
|
3040
|
+
await settle();
|
|
3041
|
+
}
|
|
3042
|
+
}, ctx, (chunk) => {
|
|
3043
|
+
tryInferUsageFromStreamChunk(
|
|
3044
|
+
chunk,
|
|
2951
3045
|
ctx.begin.data.vendorHints,
|
|
3046
|
+
ctx,
|
|
2952
3047
|
provider
|
|
2953
3048
|
);
|
|
2954
|
-
|
|
2955
|
-
ctx.setUsage(usage);
|
|
2956
|
-
}
|
|
2957
|
-
}, ctx);
|
|
3049
|
+
});
|
|
2958
3050
|
return wrappedStreamInner;
|
|
2959
3051
|
});
|
|
2960
3052
|
return wrappedPromise;
|
|
@@ -2974,70 +3066,19 @@ function createChatCompletionsProxy(resource, usageTap, defaultContext, applyVen
|
|
|
2974
3066
|
return new Proxy(resource, handler);
|
|
2975
3067
|
}
|
|
2976
3068
|
async function compressChatParamsForCall(args) {
|
|
2977
|
-
|
|
3069
|
+
const compression = resolveEffectivePromptCompressionOptions(
|
|
2978
3070
|
args.defaultPromptCompression,
|
|
2979
3071
|
args.callPromptCompression
|
|
2980
3072
|
);
|
|
2981
|
-
const runtimePolicy = args.ctx.begin.data.runtimeCompressionPolicy;
|
|
2982
|
-
const policyDriven = !compression && Boolean(runtimePolicy);
|
|
2983
|
-
if (policyDriven && runtimePolicy) {
|
|
2984
|
-
if (!runtimePolicy.selected) {
|
|
2985
|
-
args.ctx.setUsage({
|
|
2986
|
-
runtimeCompression: bypassedRuntimeMeasurement(runtimePolicy)
|
|
2987
|
-
});
|
|
2988
|
-
return args.params;
|
|
2989
|
-
}
|
|
2990
|
-
compression = openAIPolicyCompressionOptions(runtimePolicy);
|
|
2991
|
-
if (runtimePolicy.mode === "SHADOW") {
|
|
2992
|
-
const startedAt2 = Date.now();
|
|
2993
|
-
void compressChatParams(
|
|
2994
|
-
args.params,
|
|
2995
|
-
args.usageTap,
|
|
2996
|
-
compression,
|
|
2997
|
-
args.withUsage?.signal
|
|
2998
|
-
).then((outcome2) => {
|
|
2999
|
-
args.ctx.setUsage({
|
|
3000
|
-
runtimeCompression: openAIRuntimeMeasurement({
|
|
3001
|
-
policy: runtimePolicy,
|
|
3002
|
-
telemetry: buildPromptCompressionTelemetry(outcome2.segments),
|
|
3003
|
-
latencyMs: Date.now() - startedAt2,
|
|
3004
|
-
shadow: true,
|
|
3005
|
-
originalPayload: args.params,
|
|
3006
|
-
resultPayload: outcome2.params
|
|
3007
|
-
})
|
|
3008
|
-
});
|
|
3009
|
-
}).catch(() => {
|
|
3010
|
-
args.ctx.setUsage({
|
|
3011
|
-
runtimeCompression: failedRuntimeMeasurement(
|
|
3012
|
-
runtimePolicy,
|
|
3013
|
-
Date.now() - startedAt2
|
|
3014
|
-
)
|
|
3015
|
-
});
|
|
3016
|
-
});
|
|
3017
|
-
return args.params;
|
|
3018
|
-
}
|
|
3019
|
-
}
|
|
3020
3073
|
if (!compression) {
|
|
3021
3074
|
return args.params;
|
|
3022
3075
|
}
|
|
3023
|
-
const startedAt = Date.now();
|
|
3024
3076
|
const outcome = await compressChatParams(
|
|
3025
3077
|
args.params,
|
|
3026
3078
|
args.usageTap,
|
|
3027
3079
|
compression,
|
|
3028
3080
|
args.withUsage?.signal
|
|
3029
3081
|
);
|
|
3030
|
-
if (policyDriven && runtimePolicy) {
|
|
3031
|
-
const runtimeMeasurement = openAIRuntimeMeasurement({
|
|
3032
|
-
policy: runtimePolicy,
|
|
3033
|
-
telemetry: buildPromptCompressionTelemetry(outcome.segments),
|
|
3034
|
-
latencyMs: Date.now() - startedAt,
|
|
3035
|
-
originalPayload: args.params,
|
|
3036
|
-
resultPayload: outcome.params
|
|
3037
|
-
});
|
|
3038
|
-
args.ctx.setUsage({ runtimeCompression: runtimeMeasurement });
|
|
3039
|
-
if (runtimeMeasurement.decision !== "compressed") return args.params;
|
|
3040
|
-
}
|
|
3041
3082
|
await recordCompressionOutcome({
|
|
3042
3083
|
outcome,
|
|
3043
3084
|
compression,
|
|
@@ -3050,70 +3091,19 @@ async function compressChatParamsForCall(args) {
|
|
|
3050
3091
|
return outcome.params;
|
|
3051
3092
|
}
|
|
3052
3093
|
async function compressResponsesParamsForCall(args) {
|
|
3053
|
-
|
|
3094
|
+
const compression = resolveEffectivePromptCompressionOptions(
|
|
3054
3095
|
args.defaultPromptCompression,
|
|
3055
3096
|
args.callPromptCompression
|
|
3056
3097
|
);
|
|
3057
|
-
const runtimePolicy = args.ctx.begin.data.runtimeCompressionPolicy;
|
|
3058
|
-
const policyDriven = !compression && Boolean(runtimePolicy);
|
|
3059
|
-
if (policyDriven && runtimePolicy) {
|
|
3060
|
-
if (!runtimePolicy.selected) {
|
|
3061
|
-
args.ctx.setUsage({
|
|
3062
|
-
runtimeCompression: bypassedRuntimeMeasurement(runtimePolicy)
|
|
3063
|
-
});
|
|
3064
|
-
return args.params;
|
|
3065
|
-
}
|
|
3066
|
-
compression = openAIPolicyCompressionOptions(runtimePolicy);
|
|
3067
|
-
if (runtimePolicy.mode === "SHADOW") {
|
|
3068
|
-
const startedAt2 = Date.now();
|
|
3069
|
-
void compressResponsesParams(
|
|
3070
|
-
args.params,
|
|
3071
|
-
args.usageTap,
|
|
3072
|
-
compression,
|
|
3073
|
-
args.withUsage?.signal
|
|
3074
|
-
).then((outcome2) => {
|
|
3075
|
-
args.ctx.setUsage({
|
|
3076
|
-
runtimeCompression: openAIRuntimeMeasurement({
|
|
3077
|
-
policy: runtimePolicy,
|
|
3078
|
-
telemetry: buildPromptCompressionTelemetry(outcome2.segments),
|
|
3079
|
-
latencyMs: Date.now() - startedAt2,
|
|
3080
|
-
shadow: true,
|
|
3081
|
-
originalPayload: args.params,
|
|
3082
|
-
resultPayload: outcome2.params
|
|
3083
|
-
})
|
|
3084
|
-
});
|
|
3085
|
-
}).catch(() => {
|
|
3086
|
-
args.ctx.setUsage({
|
|
3087
|
-
runtimeCompression: failedRuntimeMeasurement(
|
|
3088
|
-
runtimePolicy,
|
|
3089
|
-
Date.now() - startedAt2
|
|
3090
|
-
)
|
|
3091
|
-
});
|
|
3092
|
-
});
|
|
3093
|
-
return args.params;
|
|
3094
|
-
}
|
|
3095
|
-
}
|
|
3096
3098
|
if (!compression) {
|
|
3097
3099
|
return args.params;
|
|
3098
3100
|
}
|
|
3099
|
-
const startedAt = Date.now();
|
|
3100
3101
|
const outcome = await compressResponsesParams(
|
|
3101
3102
|
args.params,
|
|
3102
3103
|
args.usageTap,
|
|
3103
3104
|
compression,
|
|
3104
3105
|
args.withUsage?.signal
|
|
3105
3106
|
);
|
|
3106
|
-
if (policyDriven && runtimePolicy) {
|
|
3107
|
-
const runtimeMeasurement = openAIRuntimeMeasurement({
|
|
3108
|
-
policy: runtimePolicy,
|
|
3109
|
-
telemetry: buildPromptCompressionTelemetry(outcome.segments),
|
|
3110
|
-
latencyMs: Date.now() - startedAt,
|
|
3111
|
-
originalPayload: args.params,
|
|
3112
|
-
resultPayload: outcome.params
|
|
3113
|
-
});
|
|
3114
|
-
args.ctx.setUsage({ runtimeCompression: runtimeMeasurement });
|
|
3115
|
-
if (runtimeMeasurement.decision !== "compressed") return args.params;
|
|
3116
|
-
}
|
|
3117
3107
|
await recordCompressionOutcome({
|
|
3118
3108
|
outcome,
|
|
3119
3109
|
compression,
|
|
@@ -3125,79 +3115,6 @@ async function compressResponsesParamsForCall(args) {
|
|
|
3125
3115
|
});
|
|
3126
3116
|
return outcome.params;
|
|
3127
3117
|
}
|
|
3128
|
-
function openAIPolicyCompressionOptions(policy) {
|
|
3129
|
-
const roles = Object.fromEntries(
|
|
3130
|
-
["system", "user", "tool", "assistant"].filter((role) => policy.snapshot.scope.messageRoles.includes(role)).map((role) => [role, true])
|
|
3131
|
-
);
|
|
3132
|
-
return {
|
|
3133
|
-
provider: "usagetap",
|
|
3134
|
-
roles,
|
|
3135
|
-
minContextTokens: policy.snapshot.scope.minimumTokens,
|
|
3136
|
-
failOpen: true
|
|
3137
|
-
};
|
|
3138
|
-
}
|
|
3139
|
-
function bypassedRuntimeMeasurement(policy) {
|
|
3140
|
-
return {
|
|
3141
|
-
policyId: policy.policyId,
|
|
3142
|
-
policyVersionId: policy.policyVersionId,
|
|
3143
|
-
policyVersion: policy.version,
|
|
3144
|
-
rolloutMode: policy.mode,
|
|
3145
|
-
decision: "bypassed",
|
|
3146
|
-
reasonCode: "not_in_rollout_sample",
|
|
3147
|
-
methodsAttempted: [],
|
|
3148
|
-
methodsApplied: [],
|
|
3149
|
-
originalTokens: 0,
|
|
3150
|
-
resultTokens: 0,
|
|
3151
|
-
savedTokens: 0,
|
|
3152
|
-
reductionPercentage: 0,
|
|
3153
|
-
compressionLatencyMs: 0,
|
|
3154
|
-
compressionComputeCostUsd: 0,
|
|
3155
|
-
financialsEstimated: true
|
|
3156
|
-
};
|
|
3157
|
-
}
|
|
3158
|
-
function failedRuntimeMeasurement(policy, latencyMs) {
|
|
3159
|
-
return {
|
|
3160
|
-
...bypassedRuntimeMeasurement(policy),
|
|
3161
|
-
decision: "fallback",
|
|
3162
|
-
reasonCode: "transformation_failed",
|
|
3163
|
-
methodsAttempted: ["deterministic"],
|
|
3164
|
-
compressionLatencyMs: latencyMs
|
|
3165
|
-
};
|
|
3166
|
-
}
|
|
3167
|
-
function openAIRuntimeMeasurement(input) {
|
|
3168
|
-
const telemetry = input.telemetry;
|
|
3169
|
-
const originalTokens = telemetry?.originalTokens ?? estimatePromptTokens(JSON.stringify(input.originalPayload));
|
|
3170
|
-
const resultTokens = telemetry?.compressedTokens ?? originalTokens;
|
|
3171
|
-
const savedTokens = Math.max(0, telemetry?.savedTokens ?? 0);
|
|
3172
|
-
const reductionPercentage = originalTokens > 0 ? savedTokens / originalTokens * 100 : 0;
|
|
3173
|
-
const belowMinimumSize = originalTokens < input.policy.snapshot.scope.minimumTokens;
|
|
3174
|
-
const latencyExceeded = input.latencyMs > input.policy.snapshot.gates.maximumLatencyMs;
|
|
3175
|
-
const belowSavings = savedTokens < input.policy.snapshot.gates.minimumTokensRemoved || reductionPercentage < input.policy.snapshot.gates.minimumReductionPercentage;
|
|
3176
|
-
const accepted = !belowMinimumSize && !latencyExceeded && !belowSavings;
|
|
3177
|
-
const deepText = input.policy.snapshot.methods.deepText.enabled && !input.policy.snapshot.rollout.deterministicOnly && (input.policy.mode !== "CANARY" || input.policy.snapshot.rollout.deepTextCanaryAllowed);
|
|
3178
|
-
const reasonCode = belowMinimumSize ? "below_minimum_size" : latencyExceeded ? "latency_budget_exceeded" : belowSavings ? "below_minimum_savings" : void 0;
|
|
3179
|
-
const measurement = {
|
|
3180
|
-
policyId: input.policy.policyId,
|
|
3181
|
-
policyVersionId: input.policy.policyVersionId,
|
|
3182
|
-
policyVersion: input.policy.version,
|
|
3183
|
-
rolloutMode: input.policy.mode,
|
|
3184
|
-
decision: accepted ? input.shadow ? "bypassed" : "compressed" : latencyExceeded ? "fallback" : "skipped",
|
|
3185
|
-
...reasonCode ? { reasonCode } : {},
|
|
3186
|
-
methodsAttempted: [
|
|
3187
|
-
"deterministic",
|
|
3188
|
-
...deepText ? ["deep_text"] : []
|
|
3189
|
-
],
|
|
3190
|
-
methodsApplied: accepted ? ["deterministic"] : [],
|
|
3191
|
-
originalTokens,
|
|
3192
|
-
resultTokens: accepted ? resultTokens : originalTokens,
|
|
3193
|
-
savedTokens: accepted ? savedTokens : 0,
|
|
3194
|
-
reductionPercentage: accepted ? reductionPercentage : 0,
|
|
3195
|
-
compressionLatencyMs: input.latencyMs,
|
|
3196
|
-
compressionComputeCostUsd: 0,
|
|
3197
|
-
financialsEstimated: true
|
|
3198
|
-
};
|
|
3199
|
-
return measurement;
|
|
3200
|
-
}
|
|
3201
3118
|
async function recordCompressionOutcome(args) {
|
|
3202
3119
|
const telemetry = buildPromptCompressionTelemetry(args.outcome.segments);
|
|
3203
3120
|
if (!telemetry) {
|
|
@@ -3720,10 +3637,6 @@ function resolveBeginRequest(defaults, override) {
|
|
|
3720
3637
|
}
|
|
3721
3638
|
const tags = mergeTags(base.tags, current.tags);
|
|
3722
3639
|
const begin = { customerId };
|
|
3723
|
-
const runtimeCompressionContext = current.runtimeCompressionContext ?? base.runtimeCompressionContext;
|
|
3724
|
-
if (runtimeCompressionContext) {
|
|
3725
|
-
begin.runtimeCompressionContext = runtimeCompressionContext;
|
|
3726
|
-
}
|
|
3727
3640
|
const requested = current.requested ?? base.requested;
|
|
3728
3641
|
if (requested) begin.requested = requested;
|
|
3729
3642
|
const feature = current.feature ?? base.feature;
|
|
@@ -3744,8 +3657,6 @@ function resolveBeginRequest(defaults, override) {
|
|
|
3744
3657
|
if (customerUserEmail) begin.customerUserEmail = customerUserEmail;
|
|
3745
3658
|
const stripeCustomerId = current.stripeCustomerId ?? base.stripeCustomerId;
|
|
3746
3659
|
if (stripeCustomerId) begin.stripeCustomerId = stripeCustomerId;
|
|
3747
|
-
const holdUsd = current.holdUsd ?? base.holdUsd;
|
|
3748
|
-
if (typeof holdUsd === "number") begin.holdUsd = holdUsd;
|
|
3749
3660
|
const batch = current.batch ?? base.batch;
|
|
3750
3661
|
if (typeof batch === "boolean") begin.batch = batch;
|
|
3751
3662
|
const pricingMode = current.pricingMode ?? base.pricingMode;
|
|
@@ -3755,16 +3666,25 @@ function resolveBeginRequest(defaults, override) {
|
|
|
3755
3666
|
}
|
|
3756
3667
|
return begin;
|
|
3757
3668
|
}
|
|
3758
|
-
function
|
|
3669
|
+
function responsesBeginRequest(begin, params) {
|
|
3670
|
+
if (!responsesRequestUsesWebSearch(params)) return begin;
|
|
3759
3671
|
return {
|
|
3760
3672
|
...begin,
|
|
3761
|
-
|
|
3762
|
-
...begin.
|
|
3763
|
-
|
|
3764
|
-
model
|
|
3673
|
+
requested: {
|
|
3674
|
+
...begin.requested ?? {},
|
|
3675
|
+
search: true
|
|
3765
3676
|
}
|
|
3766
3677
|
};
|
|
3767
3678
|
}
|
|
3679
|
+
function responsesRequestUsesWebSearch(params) {
|
|
3680
|
+
if (!params || typeof params !== "object") return false;
|
|
3681
|
+
const tools = params.tools;
|
|
3682
|
+
return Array.isArray(tools) && tools.some((tool) => {
|
|
3683
|
+
if (!tool || typeof tool !== "object") return false;
|
|
3684
|
+
const type = tool.type;
|
|
3685
|
+
return type === "web_search" || type === "web_search_preview";
|
|
3686
|
+
});
|
|
3687
|
+
}
|
|
3768
3688
|
function transformApiPromise(apiPromise, onResolve, onReject) {
|
|
3769
3689
|
const resolvedPromise = Promise.resolve(apiPromise).then(onResolve, onReject);
|
|
3770
3690
|
if (isObjectRecord(apiPromise)) {
|
|
@@ -3995,6 +3915,11 @@ function inferUsageFromResponse(response, hints, provider = "openai") {
|
|
|
3995
3915
|
return void 0;
|
|
3996
3916
|
}
|
|
3997
3917
|
const cachedInputTokens = candidate.usage.prompt_tokens_details?.cached_tokens ?? candidate.usage.input_tokens_details?.cached_tokens ?? candidate.usage.cached_tokens;
|
|
3918
|
+
const cacheWriteInputTokens = candidate.usage.prompt_tokens_details?.cache_write_tokens ?? candidate.usage.prompt_tokens_details?.cache_creation_tokens ?? candidate.usage.input_tokens_details?.cache_write_tokens ?? candidate.usage.input_tokens_details?.cache_creation_tokens ?? candidate.usage.cache_creation_input_tokens ?? candidate.usage.cache_write_input_tokens ?? candidate.usage.cache_write_tokens;
|
|
3919
|
+
const cacheWrite5mInputTokens = candidate.usage.cache_write_5m_input_tokens ?? candidate.usage.cache_creation?.ephemeral_5m_input_tokens;
|
|
3920
|
+
const cacheWrite1hInputTokens = candidate.usage.cache_write_1h_input_tokens ?? candidate.usage.cache_creation?.ephemeral_1h_input_tokens;
|
|
3921
|
+
const outputSearches = Array.isArray(candidate.output) ? candidate.output.filter((item) => item?.type === "web_search_call").length : 0;
|
|
3922
|
+
const searches = candidate.usage.searches ?? candidate.usage.web_search_queries ?? candidate.usage.server_tool_use?.web_search_requests ?? outputSearches;
|
|
3998
3923
|
const responseEffort = normalizeExecutionReasoningEffort(
|
|
3999
3924
|
candidate.reasoning?.effort
|
|
4000
3925
|
);
|
|
@@ -4004,12 +3929,21 @@ function inferUsageFromResponse(response, hints, provider = "openai") {
|
|
|
4004
3929
|
inputTokens: candidate.usage.prompt_tokens ?? candidate.usage.input_tokens,
|
|
4005
3930
|
responseTokens: candidate.usage.completion_tokens ?? candidate.usage.output_tokens,
|
|
4006
3931
|
cachedInputTokens,
|
|
3932
|
+
cacheWriteInputTokens,
|
|
3933
|
+
cacheWrite5mInputTokens,
|
|
3934
|
+
cacheWrite1hInputTokens,
|
|
3935
|
+
audioInputTokens: candidate.usage.prompt_tokens_details?.audio_tokens ?? candidate.usage.input_tokens_details?.audio_tokens,
|
|
3936
|
+
cachedAudioInputTokens: candidate.usage.prompt_tokens_details?.cached_audio_tokens ?? candidate.usage.input_tokens_details?.cached_audio_tokens ?? candidate.usage.prompt_tokens_details?.cached_tokens_details?.audio_tokens ?? candidate.usage.input_tokens_details?.cached_tokens_details?.audio_tokens,
|
|
3937
|
+
imageInputTokens: candidate.usage.prompt_tokens_details?.image_tokens ?? candidate.usage.input_tokens_details?.image_tokens,
|
|
3938
|
+
imageOutputTokens: candidate.usage.completion_tokens_details?.image_tokens ?? candidate.usage.output_tokens_details?.image_tokens,
|
|
3939
|
+
audioOutputTokens: candidate.usage.completion_tokens_details?.audio_tokens ?? candidate.usage.output_tokens_details?.audio_tokens,
|
|
4007
3940
|
reasoningTokens: candidate.usage.completion_tokens_details?.reasoning_tokens ?? candidate.usage.output_tokens_details?.reasoning_tokens,
|
|
4008
3941
|
...responseEffort ? {
|
|
4009
3942
|
reasoningEffort: responseEffort,
|
|
4010
3943
|
reasoningEffortSource: "provider_response"
|
|
4011
3944
|
} : {},
|
|
4012
|
-
...typeof candidate.reasoning?.type === "string" ? { reasoningMode: candidate.reasoning.type } : typeof candidate.reasoning?.mode === "string" ? { reasoningMode: candidate.reasoning.mode } : {}
|
|
3945
|
+
...typeof candidate.reasoning?.type === "string" ? { reasoningMode: candidate.reasoning.type } : typeof candidate.reasoning?.mode === "string" ? { reasoningMode: candidate.reasoning.mode } : {},
|
|
3946
|
+
...typeof searches === "number" && searches > 0 ? { searches } : {}
|
|
4013
3947
|
};
|
|
4014
3948
|
}
|
|
4015
3949
|
function normalizeExecutionReasoningEffort(value) {
|
|
@@ -4026,29 +3960,64 @@ function openAIRequestExecutionMetadata(params, provider) {
|
|
|
4026
3960
|
const budget = typeof rawBudget === "number" && Number.isInteger(rawBudget) && rawBudget >= 0 ? rawBudget : void 0;
|
|
4027
3961
|
return {
|
|
4028
3962
|
providerUsed: provider,
|
|
3963
|
+
...typeof record.model === "string" ? { modelUsed: record.model } : {},
|
|
4029
3964
|
...effort ? { reasoningEffort: effort, reasoningEffortSource: "provider_request" } : {},
|
|
4030
3965
|
...mode ? { reasoningMode: mode } : {},
|
|
4031
3966
|
...budget !== void 0 ? { reasoningBudgetTokens: budget } : {}
|
|
4032
3967
|
};
|
|
4033
3968
|
}
|
|
4034
|
-
function
|
|
3969
|
+
function tryInferUsageFromStreamChunk(chunk, hints, ctx, provider) {
|
|
3970
|
+
const payload = isObjectRecord(chunk) && isObjectRecord(chunk.response) ? chunk.response : chunk;
|
|
3971
|
+
const inferred = inferUsageFromResponse(payload, hints, provider);
|
|
3972
|
+
if (inferred) {
|
|
3973
|
+
ctx.setUsage(inferred);
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
function ensureOpenAIStreamUsage(params) {
|
|
3977
|
+
if (!isObjectRecord(params)) {
|
|
3978
|
+
return params;
|
|
3979
|
+
}
|
|
3980
|
+
const streamOptions = isObjectRecord(params.stream_options) ? params.stream_options : {};
|
|
3981
|
+
return {
|
|
3982
|
+
...params,
|
|
3983
|
+
stream_options: {
|
|
3984
|
+
...streamOptions,
|
|
3985
|
+
include_usage: true
|
|
3986
|
+
}
|
|
3987
|
+
};
|
|
3988
|
+
}
|
|
3989
|
+
function deferUsageFinalization(ctx) {
|
|
3990
|
+
return ctx.deferFinalization?.() ?? (() => Promise.resolve());
|
|
3991
|
+
}
|
|
3992
|
+
function wrapStreamForUsageTap(source, finalize, ctx, onChunk) {
|
|
4035
3993
|
const getIterator = source[Symbol.asyncIterator];
|
|
4036
3994
|
if (typeof getIterator !== "function") {
|
|
4037
3995
|
throw new TypeError("Stream is not async iterable");
|
|
4038
3996
|
}
|
|
4039
3997
|
const iterator = getIterator.call(source);
|
|
4040
3998
|
let completed = false;
|
|
4041
|
-
const invokeFinalize = async () => {
|
|
3999
|
+
const invokeFinalize = async (termination, error) => {
|
|
4042
4000
|
if (completed) return;
|
|
4043
4001
|
completed = true;
|
|
4002
|
+
if (termination === "cancel" || termination === "manual") {
|
|
4003
|
+
ctx.setError({
|
|
4004
|
+
code: "STREAM_ABORTED",
|
|
4005
|
+
message: termination === "cancel" ? "Provider stream consumption was cancelled before completion" : "Provider stream was finalized before completion"
|
|
4006
|
+
});
|
|
4007
|
+
} else if (termination === "error") {
|
|
4008
|
+
ctx.setError({
|
|
4009
|
+
code: "VENDOR_ERROR",
|
|
4010
|
+
message: error instanceof Error ? error.message : String(error)
|
|
4011
|
+
});
|
|
4012
|
+
}
|
|
4044
4013
|
try {
|
|
4045
|
-
await finalize();
|
|
4046
|
-
} catch (
|
|
4014
|
+
await finalize(termination);
|
|
4015
|
+
} catch (error2) {
|
|
4047
4016
|
ctx.setError({
|
|
4048
4017
|
code: "USAGE_FINALIZE_ERROR",
|
|
4049
|
-
message:
|
|
4018
|
+
message: error2 instanceof Error ? error2.message : String(error2)
|
|
4050
4019
|
});
|
|
4051
|
-
throw
|
|
4020
|
+
throw error2;
|
|
4052
4021
|
}
|
|
4053
4022
|
};
|
|
4054
4023
|
const prototype = Object.getPrototypeOf(source) ?? Object.prototype;
|
|
@@ -4072,12 +4041,15 @@ function wrapStreamForUsageTap(source, finalize, ctx) {
|
|
|
4072
4041
|
value: async (...args) => {
|
|
4073
4042
|
try {
|
|
4074
4043
|
const result = await iterator.next(...args);
|
|
4044
|
+
if (!result.done) {
|
|
4045
|
+
onChunk?.(result.value);
|
|
4046
|
+
}
|
|
4075
4047
|
if (result.done) {
|
|
4076
|
-
await invokeFinalize();
|
|
4048
|
+
await invokeFinalize("complete");
|
|
4077
4049
|
}
|
|
4078
4050
|
return result;
|
|
4079
4051
|
} catch (error) {
|
|
4080
|
-
await invokeFinalize().catch(() => void 0);
|
|
4052
|
+
await invokeFinalize("error", error).catch(() => void 0);
|
|
4081
4053
|
throw error;
|
|
4082
4054
|
}
|
|
4083
4055
|
},
|
|
@@ -4086,39 +4058,49 @@ function wrapStreamForUsageTap(source, finalize, ctx) {
|
|
|
4086
4058
|
});
|
|
4087
4059
|
Object.defineProperty(wrapped, "return", {
|
|
4088
4060
|
value: async (value) => {
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4061
|
+
try {
|
|
4062
|
+
if (typeof iterator.return === "function") {
|
|
4063
|
+
const rawResult = await iterator.return(value);
|
|
4064
|
+
if (!isIteratorResult(rawResult)) {
|
|
4065
|
+
throw new TypeError("Iterator.return() returned an invalid result");
|
|
4066
|
+
}
|
|
4067
|
+
await invokeFinalize("cancel");
|
|
4068
|
+
return rawResult;
|
|
4093
4069
|
}
|
|
4094
|
-
await invokeFinalize();
|
|
4095
|
-
return
|
|
4070
|
+
await invokeFinalize("cancel");
|
|
4071
|
+
return { done: true, value };
|
|
4072
|
+
} catch (error) {
|
|
4073
|
+
await invokeFinalize("error", error).catch(() => void 0);
|
|
4074
|
+
throw error;
|
|
4096
4075
|
}
|
|
4097
|
-
await invokeFinalize();
|
|
4098
|
-
return { done: true, value };
|
|
4099
4076
|
},
|
|
4100
4077
|
configurable: true,
|
|
4101
4078
|
writable: true
|
|
4102
4079
|
});
|
|
4103
4080
|
Object.defineProperty(wrapped, "throw", {
|
|
4104
4081
|
value: async (error) => {
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4082
|
+
try {
|
|
4083
|
+
if (typeof iterator.throw === "function") {
|
|
4084
|
+
const rawResult = await iterator.throw(error);
|
|
4085
|
+
if (!isIteratorResult(rawResult)) {
|
|
4086
|
+
throw new TypeError("Iterator.throw() returned an invalid result");
|
|
4087
|
+
}
|
|
4088
|
+
await invokeFinalize("error", error);
|
|
4089
|
+
return rawResult;
|
|
4109
4090
|
}
|
|
4110
|
-
await invokeFinalize();
|
|
4111
|
-
|
|
4091
|
+
await invokeFinalize("error", error);
|
|
4092
|
+
throw error;
|
|
4093
|
+
} catch (thrownError) {
|
|
4094
|
+
await invokeFinalize("error", thrownError).catch(() => void 0);
|
|
4095
|
+
throw thrownError;
|
|
4112
4096
|
}
|
|
4113
|
-
await invokeFinalize();
|
|
4114
|
-
throw error;
|
|
4115
4097
|
},
|
|
4116
4098
|
configurable: true,
|
|
4117
4099
|
writable: true
|
|
4118
4100
|
});
|
|
4119
4101
|
Object.defineProperty(wrapped, "__usageTapFinalize", {
|
|
4120
4102
|
value: async () => {
|
|
4121
|
-
await invokeFinalize();
|
|
4103
|
+
await invokeFinalize("manual");
|
|
4122
4104
|
},
|
|
4123
4105
|
configurable: true
|
|
4124
4106
|
});
|