@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.
Files changed (52) hide show
  1. package/README.md +156 -18
  2. package/dist/adapters/anthropic.cjs +195 -235
  3. package/dist/adapters/anthropic.cjs.map +1 -1
  4. package/dist/adapters/anthropic.d.cts +1 -1
  5. package/dist/adapters/anthropic.d.ts +1 -1
  6. package/dist/adapters/anthropic.mjs +195 -235
  7. package/dist/adapters/anthropic.mjs.map +1 -1
  8. package/dist/adapters/openai.cjs +256 -274
  9. package/dist/adapters/openai.cjs.map +1 -1
  10. package/dist/adapters/openai.d.cts +1 -1
  11. package/dist/adapters/openai.d.ts +1 -1
  12. package/dist/adapters/openai.mjs +256 -274
  13. package/dist/adapters/openai.mjs.map +1 -1
  14. package/dist/adapters/openrouter.cjs +256 -274
  15. package/dist/adapters/openrouter.cjs.map +1 -1
  16. package/dist/adapters/openrouter.d.cts +1 -1
  17. package/dist/adapters/openrouter.d.ts +1 -1
  18. package/dist/adapters/openrouter.mjs +256 -274
  19. package/dist/adapters/openrouter.mjs.map +1 -1
  20. package/dist/anthropic/index.cjs +195 -235
  21. package/dist/anthropic/index.cjs.map +1 -1
  22. package/dist/anthropic/index.d.cts +1 -1
  23. package/dist/anthropic/index.d.ts +1 -1
  24. package/dist/anthropic/index.mjs +195 -235
  25. package/dist/anthropic/index.mjs.map +1 -1
  26. package/dist/{client-CExQ8e1T.d.cts → client-C0UiaqVB.d.cts} +141 -61
  27. package/dist/{client-CExQ8e1T.d.ts → client-C0UiaqVB.d.ts} +141 -61
  28. package/dist/express/index.cjs +189 -246
  29. package/dist/express/index.cjs.map +1 -1
  30. package/dist/express/index.d.cts +1 -1
  31. package/dist/express/index.d.ts +1 -1
  32. package/dist/express/index.mjs +189 -246
  33. package/dist/express/index.mjs.map +1 -1
  34. package/dist/index.cjs +391 -175
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +13 -4
  37. package/dist/index.d.ts +13 -4
  38. package/dist/index.mjs +391 -175
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/openai/index.cjs +256 -274
  41. package/dist/openai/index.cjs.map +1 -1
  42. package/dist/openai/index.d.cts +1 -1
  43. package/dist/openai/index.d.ts +1 -1
  44. package/dist/openai/index.mjs +256 -274
  45. package/dist/openai/index.mjs.map +1 -1
  46. package/dist/openrouter/index.cjs +256 -274
  47. package/dist/openrouter/index.cjs.map +1 -1
  48. package/dist/openrouter/index.d.cts +1 -1
  49. package/dist/openrouter/index.d.ts +1 -1
  50. package/dist/openrouter/index.mjs +256 -274
  51. package/dist/openrouter/index.mjs.map +1 -1
  52. package/package.json +2 -2
@@ -1,2 +1,2 @@
1
1
  export { AnthropicClientLike, AnthropicCompressionOptions, AnthropicPromptCompressionFailure, AnthropicPromptCompressionOptions, AnthropicPromptCompressionRole, AnthropicPromptCompressionRoleOptions, AnthropicPromptCompressionRoleSetting, AnthropicPromptCompressionStats, AnthropicPromptCompressionTurnStats, AnthropicSamplingContext, AnthropicSamplingOptions, CompressionWrappedAnthropic, MeteredAnthropicSamplingOptions, SamplingWrappedAnthropic, WithMeteringAnthropicOptions, WrapAnthropicCallOptions, WrapAnthropicContext, WrapAnthropicOptions, WrappedAnthropic, withCompression, withMetering, withSampling, wrapAnthropic } from '../adapters/anthropic.cjs';
2
- import '../client-CExQ8e1T.cjs';
2
+ import '../client-C0UiaqVB.cjs';
@@ -1,2 +1,2 @@
1
1
  export { AnthropicClientLike, AnthropicCompressionOptions, AnthropicPromptCompressionFailure, AnthropicPromptCompressionOptions, AnthropicPromptCompressionRole, AnthropicPromptCompressionRoleOptions, AnthropicPromptCompressionRoleSetting, AnthropicPromptCompressionStats, AnthropicPromptCompressionTurnStats, AnthropicSamplingContext, AnthropicSamplingOptions, CompressionWrappedAnthropic, MeteredAnthropicSamplingOptions, SamplingWrappedAnthropic, WithMeteringAnthropicOptions, WrapAnthropicCallOptions, WrapAnthropicContext, WrapAnthropicOptions, WrappedAnthropic, withCompression, withMetering, withSampling, wrapAnthropic } from '../adapters/anthropic.js';
2
- import '../client-CExQ8e1T.js';
2
+ import '../client-C0UiaqVB.js';
@@ -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.4.0" ;
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 CUSTOM2"
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
- try {
1719
- await this.endCall(
1720
- {
1721
- callId: beginResponse.data.callId,
1722
- // Pass context for metric tracking
1723
- customerId: beginRequest.customerId,
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 retryable = isRetryableStatus(status);
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();
@@ -2221,6 +2256,43 @@ var AnthropicPromptCompressionStats = class {
2221
2256
  return this.totalOriginalCharacters > 0 ? this.totalCharactersSaved / this.totalOriginalCharacters : 0;
2222
2257
  }
2223
2258
  };
2259
+ var DeferredAnthropicApiPromise = class extends Promise {
2260
+ responseEnvelope;
2261
+ constructor(execute) {
2262
+ super((resolve) => resolve(void 0));
2263
+ this.responseEnvelope = Promise.resolve().then(execute);
2264
+ }
2265
+ then(onfulfilled, onrejected) {
2266
+ return this.responseEnvelope.then((result) => result.data).then(onfulfilled, onrejected);
2267
+ }
2268
+ catch(onrejected) {
2269
+ return this.then(void 0, onrejected);
2270
+ }
2271
+ finally(onfinally) {
2272
+ return this.responseEnvelope.then((result) => result.data).finally(onfinally ?? void 0);
2273
+ }
2274
+ withResponse() {
2275
+ return this.responseEnvelope;
2276
+ }
2277
+ async asResponse() {
2278
+ const result = await this.responseEnvelope;
2279
+ if (!("response" in result)) {
2280
+ throw new TypeError("The wrapped Anthropic result does not expose a raw response");
2281
+ }
2282
+ return result.response;
2283
+ }
2284
+ };
2285
+ async function resolveAnthropicResponseEnvelope(value) {
2286
+ if (isObjectRecord(value) && typeof value.withResponse === "function") {
2287
+ const withResponse = value.withResponse;
2288
+ const result = await withResponse.call(value);
2289
+ if (!isObjectRecord(result) || !("data" in result)) {
2290
+ throw new TypeError("Anthropic create().withResponse() returned an invalid result");
2291
+ }
2292
+ return result;
2293
+ }
2294
+ return { data: await value };
2295
+ }
2224
2296
  var USAGETAP_CORRELATION_HEADER = "x-usage-correlation-id";
2225
2297
  function withSampling(client, options = {}) {
2226
2298
  if (!client?.messages || typeof client.messages.create !== "function" || !options) {
@@ -2233,53 +2305,56 @@ function withSampling(client, options = {}) {
2233
2305
  const localPolicy = typeof policy.rate === "number" ? policy : void 0;
2234
2306
  const usageTap = usageTapClient ?? new UsageTapClient({ apiKey, sampling: localPolicy });
2235
2307
  const originalCreate = client.messages.create.bind(client.messages);
2236
- const create = async (params, requestOptions) => {
2237
- const { usageTap: callContext = {}, ...providerOptions } = requestOptions ?? {};
2238
- const decision = params.stream === true ? Promise.resolve(false) : usageTap.shouldSampleAsync({
2239
- customerId: callContext.customerId,
2240
- feature: callContext.feature,
2241
- input: params
2242
- }, localPolicy);
2243
- const startedAt = Date.now();
2244
- try {
2245
- const response = await originalCreate(
2246
- params,
2247
- Object.keys(providerOptions).length ? providerOptions : void 0
2248
- );
2249
- const selected = await decision;
2250
- if (selected) {
2251
- const record = isObjectRecord(response) ? response : {};
2252
- await usageTap.captureSample({
2253
- customerId: callContext.customerId,
2254
- feature: callContext.feature,
2255
- environment: callContext.environment,
2256
- tags: callContext.tags,
2257
- provider: "anthropic",
2258
- model: readString(record.model) ?? readString(params.model),
2259
- input: params,
2260
- output: response,
2261
- usage: record.usage,
2262
- latencyMs: Date.now() - startedAt
2263
- }).catch(() => void 0);
2264
- }
2265
- return response;
2266
- } catch (error) {
2267
- const selected = await decision;
2268
- if (selected) {
2269
- await usageTap.captureSample({
2270
- customerId: callContext.customerId,
2271
- feature: callContext.feature,
2272
- environment: callContext.environment,
2273
- tags: callContext.tags,
2274
- provider: "anthropic",
2275
- model: readString(params.model),
2276
- input: params,
2277
- latencyMs: Date.now() - startedAt,
2278
- error: error instanceof Error ? { name: error.name, message: error.message } : { message: String(error) }
2279
- }).catch(() => void 0);
2308
+ const create = (params, requestOptions) => {
2309
+ return new DeferredAnthropicApiPromise(async () => {
2310
+ const { usageTap: callContext = {}, ...providerOptions } = requestOptions ?? {};
2311
+ const decision = params.stream === true ? Promise.resolve(false) : usageTap.shouldSampleAsync({
2312
+ customerId: callContext.customerId,
2313
+ feature: callContext.feature,
2314
+ input: params
2315
+ }, localPolicy);
2316
+ const startedAt = Date.now();
2317
+ try {
2318
+ const result = await resolveAnthropicResponseEnvelope(originalCreate(
2319
+ params,
2320
+ Object.keys(providerOptions).length ? providerOptions : void 0
2321
+ ));
2322
+ const response = result.data;
2323
+ const selected = await decision;
2324
+ if (selected) {
2325
+ const record = isObjectRecord(response) ? response : {};
2326
+ await usageTap.captureSample({
2327
+ customerId: callContext.customerId,
2328
+ feature: callContext.feature,
2329
+ environment: callContext.environment,
2330
+ tags: callContext.tags,
2331
+ provider: "anthropic",
2332
+ model: readString(record.model) ?? readString(params.model),
2333
+ input: params,
2334
+ output: response,
2335
+ usage: record.usage,
2336
+ latencyMs: Date.now() - startedAt
2337
+ }).catch(() => void 0);
2338
+ }
2339
+ return result;
2340
+ } catch (error) {
2341
+ const selected = await decision;
2342
+ if (selected) {
2343
+ await usageTap.captureSample({
2344
+ customerId: callContext.customerId,
2345
+ feature: callContext.feature,
2346
+ environment: callContext.environment,
2347
+ tags: callContext.tags,
2348
+ provider: "anthropic",
2349
+ model: readString(params.model),
2350
+ input: params,
2351
+ latencyMs: Date.now() - startedAt,
2352
+ error: error instanceof Error ? { name: error.name, message: error.message } : { message: String(error) }
2353
+ }).catch(() => void 0);
2354
+ }
2355
+ throw error;
2280
2356
  }
2281
- throw error;
2282
- }
2357
+ });
2283
2358
  };
2284
2359
  const messages = new Proxy(client.messages, {
2285
2360
  get(target, prop, receiver) {
@@ -2320,7 +2395,12 @@ function withCompression(client, options = {}) {
2320
2395
  };
2321
2396
  const originalCreate = client.messages.create.bind(client.messages);
2322
2397
  const wrappedCreate = (params, requestOptions) => {
2323
- return compressAnthropicParams(params, usageTap, compression).then((outcome) => originalCreate(outcome.params, requestOptions));
2398
+ return new DeferredAnthropicApiPromise(async () => {
2399
+ const outcome = await compressAnthropicParams(params, usageTap, compression);
2400
+ return resolveAnthropicResponseEnvelope(
2401
+ originalCreate(outcome.params, requestOptions)
2402
+ );
2403
+ });
2324
2404
  };
2325
2405
  const proxiedMessages = new Proxy(client.messages, {
2326
2406
  get(target, prop, receiver) {
@@ -2415,20 +2495,22 @@ function createMessagesProxy(resource, usageTap, defaultContext, applyVendorHint
2415
2495
  withUsage,
2416
2496
  promptCompression
2417
2497
  } = splitUsageOptions(options);
2418
- return invokeMessagesCreate({
2419
- params,
2420
- requestOptions,
2421
- usageContext,
2422
- withUsage,
2423
- promptCompression,
2424
- originalCreate,
2425
- usageTap,
2426
- defaultContext,
2427
- applyVendorHints,
2428
- defaultPromptCompression,
2429
- promptCompressionStats,
2430
- defaultSampling
2431
- });
2498
+ return new DeferredAnthropicApiPromise(
2499
+ () => invokeMessagesCreate({
2500
+ params,
2501
+ requestOptions,
2502
+ usageContext,
2503
+ withUsage,
2504
+ promptCompression,
2505
+ originalCreate,
2506
+ usageTap,
2507
+ defaultContext,
2508
+ applyVendorHints,
2509
+ defaultPromptCompression,
2510
+ promptCompressionStats,
2511
+ defaultSampling
2512
+ })
2513
+ );
2432
2514
  });
2433
2515
  const handler = {
2434
2516
  get(target, prop, receiver) {
@@ -2441,10 +2523,9 @@ function createMessagesProxy(resource, usageTap, defaultContext, applyVendorHint
2441
2523
  return new Proxy(resource, handler);
2442
2524
  }
2443
2525
  async function invokeMessagesCreate(args) {
2444
- const beginRequest = withRuntimeCompressionContext(
2445
- resolveBeginRequest(args.defaultContext, args.usageContext),
2446
- "anthropic",
2447
- String(args.params.model)
2526
+ const beginRequest = resolveBeginRequest(
2527
+ args.defaultContext,
2528
+ args.usageContext
2448
2529
  );
2449
2530
  const begin = await args.usageTap.beginCall(
2450
2531
  beginRequest,
@@ -2475,17 +2556,23 @@ async function invokeMessagesCreate(args) {
2475
2556
  });
2476
2557
  ctx.setUsage(anthropicRequestExecutionMetadata(finalParams));
2477
2558
  const request = attachCorrelationHeader(args.requestOptions, ctx.begin.correlationId);
2478
- const response = await args.originalCreate(finalParams, request);
2559
+ const providerResult = await resolveAnthropicResponseEnvelope(
2560
+ args.originalCreate(finalParams, request)
2561
+ );
2562
+ const response = providerResult.data;
2479
2563
  providerCompleted = true;
2480
2564
  if (isStreamingRequest(finalParams)) {
2481
2565
  ensureAsyncIterable(response, "messages.create");
2482
- return wrapAnthropicStreamForUsageTap(
2483
- response,
2484
- state,
2485
- args.usageTap,
2486
- args.withUsage,
2487
- readString(finalParams.model)
2488
- );
2566
+ return {
2567
+ ...providerResult,
2568
+ data: wrapAnthropicStreamForUsageTap(
2569
+ response,
2570
+ state,
2571
+ args.usageTap,
2572
+ args.withUsage,
2573
+ readString(finalParams.model)
2574
+ )
2575
+ };
2489
2576
  }
2490
2577
  inferAnthropicUsage(response, readString(finalParams.model), ctx);
2491
2578
  await captureMeteredAnthropicSample({
@@ -2498,7 +2585,7 @@ async function invokeMessagesCreate(args) {
2498
2585
  startedAt: sampleStartedAt
2499
2586
  });
2500
2587
  await finalizeCall(state, args.usageTap, args.withUsage);
2501
- return response;
2588
+ return providerResult;
2502
2589
  } catch (error) {
2503
2590
  if (!state.error) {
2504
2591
  state.error = {
@@ -2581,70 +2668,19 @@ async function captureMeteredAnthropicSample({
2581
2668
  }).catch(() => void 0);
2582
2669
  }
2583
2670
  async function compressAnthropicParamsForCall(args) {
2584
- let compression = resolveEffectivePromptCompressionOptions(
2671
+ const compression = resolveEffectivePromptCompressionOptions(
2585
2672
  args.defaultPromptCompression,
2586
2673
  args.callPromptCompression
2587
2674
  );
2588
- const runtimePolicy = args.ctx.begin.data.runtimeCompressionPolicy;
2589
- const policyDriven = !compression && Boolean(runtimePolicy);
2590
- if (policyDriven && runtimePolicy) {
2591
- if (!runtimePolicy.selected) {
2592
- args.ctx.setUsage({
2593
- runtimeCompression: bypassedRuntimeMeasurement(runtimePolicy)
2594
- });
2595
- return args.params;
2596
- }
2597
- compression = anthropicPolicyCompressionOptions(runtimePolicy);
2598
- if (runtimePolicy.mode === "SHADOW") {
2599
- const startedAt2 = Date.now();
2600
- void compressAnthropicParams(
2601
- args.params,
2602
- args.usageTap,
2603
- compression,
2604
- args.withUsage?.signal
2605
- ).then((outcome2) => {
2606
- args.ctx.setUsage({
2607
- runtimeCompression: anthropicRuntimeMeasurement({
2608
- policy: runtimePolicy,
2609
- telemetry: buildPromptCompressionTelemetry(outcome2.segments),
2610
- latencyMs: Date.now() - startedAt2,
2611
- shadow: true,
2612
- originalPayload: args.params,
2613
- resultPayload: outcome2.params
2614
- })
2615
- });
2616
- }).catch(() => {
2617
- args.ctx.setUsage({
2618
- runtimeCompression: failedRuntimeMeasurement(
2619
- runtimePolicy,
2620
- Date.now() - startedAt2
2621
- )
2622
- });
2623
- });
2624
- return args.params;
2625
- }
2626
- }
2627
2675
  if (!compression) {
2628
2676
  return args.params;
2629
2677
  }
2630
- const startedAt = Date.now();
2631
2678
  const outcome = await compressAnthropicParams(
2632
2679
  args.params,
2633
2680
  args.usageTap,
2634
2681
  compression,
2635
2682
  args.withUsage?.signal
2636
2683
  );
2637
- if (policyDriven && runtimePolicy) {
2638
- const runtimeMeasurement = anthropicRuntimeMeasurement({
2639
- policy: runtimePolicy,
2640
- telemetry: buildPromptCompressionTelemetry(outcome.segments),
2641
- latencyMs: Date.now() - startedAt,
2642
- originalPayload: args.params,
2643
- resultPayload: outcome.params
2644
- });
2645
- args.ctx.setUsage({ runtimeCompression: runtimeMeasurement });
2646
- if (runtimeMeasurement.decision !== "compressed") return args.params;
2647
- }
2648
2684
  await recordCompressionOutcome({
2649
2685
  outcome,
2650
2686
  compression,
@@ -2656,76 +2692,6 @@ async function compressAnthropicParamsForCall(args) {
2656
2692
  });
2657
2693
  return outcome.params;
2658
2694
  }
2659
- function anthropicPolicyCompressionOptions(policy) {
2660
- const roles = Object.fromEntries(
2661
- ["system", "user", "tool", "assistant"].filter((role) => policy.snapshot.scope.messageRoles.includes(role)).map((role) => [role, true])
2662
- );
2663
- return {
2664
- provider: "usagetap",
2665
- roles,
2666
- minContextTokens: policy.snapshot.scope.minimumTokens,
2667
- failOpen: true
2668
- };
2669
- }
2670
- function bypassedRuntimeMeasurement(policy) {
2671
- return {
2672
- policyId: policy.policyId,
2673
- policyVersionId: policy.policyVersionId,
2674
- policyVersion: policy.version,
2675
- rolloutMode: policy.mode,
2676
- decision: "bypassed",
2677
- reasonCode: "not_in_rollout_sample",
2678
- methodsAttempted: [],
2679
- methodsApplied: [],
2680
- originalTokens: 0,
2681
- resultTokens: 0,
2682
- savedTokens: 0,
2683
- reductionPercentage: 0,
2684
- compressionLatencyMs: 0,
2685
- compressionComputeCostUsd: 0,
2686
- financialsEstimated: true
2687
- };
2688
- }
2689
- function failedRuntimeMeasurement(policy, latencyMs) {
2690
- return {
2691
- ...bypassedRuntimeMeasurement(policy),
2692
- decision: "fallback",
2693
- reasonCode: "transformation_failed",
2694
- methodsAttempted: ["deterministic"],
2695
- compressionLatencyMs: latencyMs
2696
- };
2697
- }
2698
- function anthropicRuntimeMeasurement(input) {
2699
- const telemetry = input.telemetry;
2700
- const originalTokens = telemetry?.originalTokens ?? estimatePromptTokens(JSON.stringify(input.originalPayload));
2701
- const resultTokens = telemetry?.compressedTokens ?? originalTokens;
2702
- const savedTokens = Math.max(0, telemetry?.savedTokens ?? 0);
2703
- const reductionPercentage = originalTokens > 0 ? savedTokens / originalTokens * 100 : 0;
2704
- const belowMinimumSize = originalTokens < input.policy.snapshot.scope.minimumTokens;
2705
- const latencyExceeded = input.latencyMs > input.policy.snapshot.gates.maximumLatencyMs;
2706
- const belowSavings = savedTokens < input.policy.snapshot.gates.minimumTokensRemoved || reductionPercentage < input.policy.snapshot.gates.minimumReductionPercentage;
2707
- const accepted = !belowMinimumSize && !latencyExceeded && !belowSavings;
2708
- const deepText = input.policy.snapshot.methods.deepText.enabled && !input.policy.snapshot.rollout.deterministicOnly && (input.policy.mode !== "CANARY" || input.policy.snapshot.rollout.deepTextCanaryAllowed);
2709
- const reasonCode = belowMinimumSize ? "below_minimum_size" : latencyExceeded ? "latency_budget_exceeded" : belowSavings ? "below_minimum_savings" : void 0;
2710
- const measurement = {
2711
- policyId: input.policy.policyId,
2712
- policyVersionId: input.policy.policyVersionId,
2713
- policyVersion: input.policy.version,
2714
- rolloutMode: input.policy.mode,
2715
- decision: accepted ? input.shadow ? "bypassed" : "compressed" : latencyExceeded ? "fallback" : "skipped",
2716
- ...reasonCode ? { reasonCode } : {},
2717
- methodsAttempted: ["deterministic", ...deepText ? ["deep_text"] : []],
2718
- methodsApplied: accepted ? ["deterministic"] : [],
2719
- originalTokens,
2720
- resultTokens: accepted ? resultTokens : originalTokens,
2721
- savedTokens: accepted ? savedTokens : 0,
2722
- reductionPercentage: accepted ? reductionPercentage : 0,
2723
- compressionLatencyMs: input.latencyMs,
2724
- compressionComputeCostUsd: 0,
2725
- financialsEstimated: true
2726
- };
2727
- return measurement;
2728
- }
2729
2695
  async function recordCompressionOutcome(args) {
2730
2696
  const telemetry = buildPromptCompressionTelemetry(args.outcome.segments);
2731
2697
  if (!telemetry) {
@@ -3168,10 +3134,6 @@ function resolveBeginRequest(defaults, override) {
3168
3134
  }
3169
3135
  const tags = mergeTags(base.tags, current.tags);
3170
3136
  const begin = { customerId };
3171
- const runtimeCompressionContext = current.runtimeCompressionContext ?? base.runtimeCompressionContext;
3172
- if (runtimeCompressionContext) {
3173
- begin.runtimeCompressionContext = runtimeCompressionContext;
3174
- }
3175
3137
  const requested = current.requested ?? base.requested;
3176
3138
  if (requested) begin.requested = requested;
3177
3139
  const feature = current.feature ?? base.feature;
@@ -3194,8 +3156,6 @@ function resolveBeginRequest(defaults, override) {
3194
3156
  if (customerUserEmail) begin.customerUserEmail = customerUserEmail;
3195
3157
  const stripeCustomerId = current.stripeCustomerId ?? base.stripeCustomerId;
3196
3158
  if (stripeCustomerId) begin.stripeCustomerId = stripeCustomerId;
3197
- const holdUsd = current.holdUsd ?? base.holdUsd;
3198
- if (typeof holdUsd === "number") begin.holdUsd = holdUsd;
3199
3159
  const batch = current.batch ?? base.batch;
3200
3160
  if (typeof batch === "boolean") begin.batch = batch;
3201
3161
  const pricingMode = current.pricingMode ?? base.pricingMode;
@@ -3331,21 +3291,21 @@ function applyAnthropicUsageRecord(usage, usageRecord) {
3331
3291
  if (cacheWriteInputTokens !== void 0) {
3332
3292
  usage.cacheWriteInputTokens = cacheWriteInputTokens;
3333
3293
  }
3294
+ if (isObjectRecord(usageRecord.cache_creation)) {
3295
+ const cacheWrite5m = readNumber(
3296
+ usageRecord.cache_creation.ephemeral_5m_input_tokens
3297
+ );
3298
+ const cacheWrite1h = readNumber(
3299
+ usageRecord.cache_creation.ephemeral_1h_input_tokens
3300
+ );
3301
+ if (cacheWrite5m !== void 0) usage.cacheWrite5mInputTokens = cacheWrite5m;
3302
+ if (cacheWrite1h !== void 0) usage.cacheWrite1hInputTokens = cacheWrite1h;
3303
+ }
3334
3304
  const baseInputTokens = readNumber(usageRecord.input_tokens ?? usageRecord.prompt_tokens);
3335
3305
  if (baseInputTokens !== void 0) {
3336
3306
  usage.inputTokens = baseInputTokens + (cachedInputTokens ?? 0) + (cacheWriteInputTokens ?? 0);
3337
3307
  }
3338
3308
  }
3339
- function withRuntimeCompressionContext(begin, provider, model) {
3340
- return {
3341
- ...begin,
3342
- runtimeCompressionContext: {
3343
- ...begin.runtimeCompressionContext ?? {},
3344
- provider,
3345
- model
3346
- }
3347
- };
3348
- }
3349
3309
  function accumulateAnthropicStreamUsage(chunk, fallbackModel, state) {
3350
3310
  const usage = extractAnthropicUsage(chunk, fallbackModel);
3351
3311
  if (usage) {