@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
@@ -1024,6 +1024,8 @@ var SummarizationResource = class {
1024
1024
  };
1025
1025
  var GatewayResource = class {
1026
1026
  chat;
1027
+ /** Buffered OpenAI Responses-compatible requests. */
1028
+ responses;
1027
1029
  models;
1028
1030
  batches;
1029
1031
  transport;
@@ -1045,6 +1047,15 @@ var GatewayResource = class {
1045
1047
  })
1046
1048
  }
1047
1049
  };
1050
+ this.responses = {
1051
+ create: (params, options) => this.transport.request({
1052
+ method: "POST",
1053
+ path: "/v1/responses",
1054
+ body: params,
1055
+ options,
1056
+ response: "json"
1057
+ })
1058
+ };
1048
1059
  this.models = {
1049
1060
  list: (options) => this.transport.request({
1050
1061
  method: "GET",
@@ -1130,7 +1141,7 @@ var USER_AGENT = "UsageTapClient";
1130
1141
  var CANONICAL_MEDIA_TYPE2 = "application/vnd.usagetap.v1+json";
1131
1142
  var DEFAULT_BASE_URL = "https://api.usagetap.com";
1132
1143
  var DEFAULT_RUN_INACTIVITY_MS = 60 * 60 * 1e3;
1133
- var SDK_VERSION = "1.4.0" ;
1144
+ var SDK_VERSION = "1.7.0" ;
1134
1145
  var HAS_WINDOW = typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
1135
1146
  var UsageTapClient = class {
1136
1147
  /** OpenAI-compatible chat, model, and native batch operations. */
@@ -1532,9 +1543,18 @@ var UsageTapClient = class {
1532
1543
  responseTokens: request.responseTokens,
1533
1544
  cachedInputTokens: request.cachedInputTokens,
1534
1545
  cacheWriteInputTokens: request.cacheWriteInputTokens,
1546
+ cacheWrite5mInputTokens: request.cacheWrite5mInputTokens,
1547
+ cacheWrite1hInputTokens: request.cacheWrite1hInputTokens,
1535
1548
  reasoningTokens: request.reasoningTokens,
1536
1549
  searches: request.searches,
1537
1550
  audioSeconds: request.audioSeconds,
1551
+ imageInputCount: request.imageInputCount,
1552
+ imageInputTokens: request.imageInputTokens,
1553
+ imageOutputCount: request.imageOutputCount,
1554
+ imageOutputTokens: request.imageOutputTokens,
1555
+ audioInputTokens: request.audioInputTokens,
1556
+ cachedAudioInputTokens: request.cachedAudioInputTokens,
1557
+ audioOutputTokens: request.audioOutputTokens,
1538
1558
  costUsd: response.data.costUSD
1539
1559
  },
1540
1560
  correlationId: response.correlationId
@@ -1621,10 +1641,10 @@ var UsageTapClient = class {
1621
1641
  "incrementCustomMeter requires meterSlot"
1622
1642
  );
1623
1643
  }
1624
- if (!["CUSTOM1", "CUSTOM2"].includes(request.meterSlot)) {
1644
+ if (!["CUSTOM1", "CUSTOM2", "AGENTIC_API"].includes(request.meterSlot)) {
1625
1645
  throw new UsageTapError(
1626
1646
  "USAGETAP_BAD_REQUEST",
1627
- "meterSlot must be CUSTOM1 or CUSTOM2"
1647
+ "meterSlot must be CUSTOM1, CUSTOM2 or AGENTIC_API"
1628
1648
  );
1629
1649
  }
1630
1650
  if (typeof request.amount !== "number" || !Number.isFinite(request.amount) || request.amount <= 0) {
@@ -1697,6 +1717,28 @@ var UsageTapClient = class {
1697
1717
  let handlerResult;
1698
1718
  let handlerError;
1699
1719
  let endCallError;
1720
+ let finalizationDeferred = false;
1721
+ let finalizationPromise;
1722
+ const finalize = () => {
1723
+ if (!finalizationPromise) {
1724
+ finalizationPromise = this.endCall(
1725
+ {
1726
+ callId: beginResponse.data.callId,
1727
+ // Pass context for metric tracking
1728
+ customerId: beginRequest.customerId,
1729
+ feature: beginRequest.feature ?? this.defaultFeature,
1730
+ tags: beginRequest.tags ?? this.defaultTags,
1731
+ ...usage,
1732
+ error: errorPayload
1733
+ },
1734
+ {
1735
+ ...options,
1736
+ correlationId: beginResponse.correlationId
1737
+ }
1738
+ ).then(() => void 0);
1739
+ }
1740
+ return finalizationPromise;
1741
+ };
1700
1742
  const context = {
1701
1743
  begin: beginResponse,
1702
1744
  setUsage: (u) => {
@@ -1704,6 +1746,10 @@ var UsageTapClient = class {
1704
1746
  },
1705
1747
  setError: (err) => {
1706
1748
  errorPayload = err;
1749
+ },
1750
+ deferFinalization: () => {
1751
+ finalizationDeferred = true;
1752
+ return finalize;
1707
1753
  }
1708
1754
  };
1709
1755
  try {
@@ -1717,24 +1763,12 @@ var UsageTapClient = class {
1717
1763
  };
1718
1764
  }
1719
1765
  } finally {
1720
- try {
1721
- await this.endCall(
1722
- {
1723
- callId: beginResponse.data.callId,
1724
- // Pass context for metric tracking
1725
- customerId: beginRequest.customerId,
1726
- feature: beginRequest.feature ?? this.defaultFeature,
1727
- tags: beginRequest.tags ?? this.defaultTags,
1728
- ...usage,
1729
- error: errorPayload
1730
- },
1731
- {
1732
- ...options,
1733
- correlationId: beginResponse.correlationId
1734
- }
1735
- );
1736
- } catch (error) {
1737
- endCallError = error;
1766
+ if (handlerError || !finalizationDeferred) {
1767
+ try {
1768
+ await finalize();
1769
+ } catch (error) {
1770
+ endCallError = error;
1771
+ }
1738
1772
  }
1739
1773
  }
1740
1774
  if (handlerError) {
@@ -2076,7 +2110,8 @@ var UsageTapClient = class {
2076
2110
  }
2077
2111
  toHttpError(status, payload, correlationId) {
2078
2112
  const code = mapStatusToErrorCode(status);
2079
- const retryable = isRetryableStatus(status);
2113
+ const apiCode = payload?.error?.code ?? payload?.result?.code ?? "UNKNOWN";
2114
+ const retryable = isRetryableStatus(status) || isRetryableApiCode(apiCode);
2080
2115
  const message = payload?.error?.message ?? payload?.result?.message ?? `UsageTap responded with HTTP ${status}`;
2081
2116
  return new UsageTapError(code, message, {
2082
2117
  status,
@@ -2109,7 +2144,7 @@ function isRetryableStatus(status) {
2109
2144
  }
2110
2145
  function isRetryableApiCode(code) {
2111
2146
  const normalized = code.toUpperCase();
2112
- return normalized.includes("TRANSIENT") || normalized.includes("RETRY") || normalized.includes("TIMEOUT") || normalized.includes("THROTTLE") || normalized.includes("RATE_LIMIT");
2147
+ return normalized === "PAYG_CONFLICT" || normalized.includes("TRANSIENT") || normalized.includes("RETRY") || normalized.includes("TIMEOUT") || normalized.includes("THROTTLE") || normalized.includes("RATE_LIMIT");
2113
2148
  }
2114
2149
  function mapApiCodeToError(code) {
2115
2150
  const normalized = code.toUpperCase();
@@ -2223,6 +2258,43 @@ var AnthropicPromptCompressionStats = class {
2223
2258
  return this.totalOriginalCharacters > 0 ? this.totalCharactersSaved / this.totalOriginalCharacters : 0;
2224
2259
  }
2225
2260
  };
2261
+ var DeferredAnthropicApiPromise = class extends Promise {
2262
+ responseEnvelope;
2263
+ constructor(execute) {
2264
+ super((resolve) => resolve(void 0));
2265
+ this.responseEnvelope = Promise.resolve().then(execute);
2266
+ }
2267
+ then(onfulfilled, onrejected) {
2268
+ return this.responseEnvelope.then((result) => result.data).then(onfulfilled, onrejected);
2269
+ }
2270
+ catch(onrejected) {
2271
+ return this.then(void 0, onrejected);
2272
+ }
2273
+ finally(onfinally) {
2274
+ return this.responseEnvelope.then((result) => result.data).finally(onfinally ?? void 0);
2275
+ }
2276
+ withResponse() {
2277
+ return this.responseEnvelope;
2278
+ }
2279
+ async asResponse() {
2280
+ const result = await this.responseEnvelope;
2281
+ if (!("response" in result)) {
2282
+ throw new TypeError("The wrapped Anthropic result does not expose a raw response");
2283
+ }
2284
+ return result.response;
2285
+ }
2286
+ };
2287
+ async function resolveAnthropicResponseEnvelope(value) {
2288
+ if (isObjectRecord(value) && typeof value.withResponse === "function") {
2289
+ const withResponse = value.withResponse;
2290
+ const result = await withResponse.call(value);
2291
+ if (!isObjectRecord(result) || !("data" in result)) {
2292
+ throw new TypeError("Anthropic create().withResponse() returned an invalid result");
2293
+ }
2294
+ return result;
2295
+ }
2296
+ return { data: await value };
2297
+ }
2226
2298
  var USAGETAP_CORRELATION_HEADER = "x-usage-correlation-id";
2227
2299
  function withSampling(client, options = {}) {
2228
2300
  if (!client?.messages || typeof client.messages.create !== "function" || !options) {
@@ -2235,53 +2307,56 @@ function withSampling(client, options = {}) {
2235
2307
  const localPolicy = typeof policy.rate === "number" ? policy : void 0;
2236
2308
  const usageTap = usageTapClient ?? new UsageTapClient({ apiKey, sampling: localPolicy });
2237
2309
  const originalCreate = client.messages.create.bind(client.messages);
2238
- const create = async (params, requestOptions) => {
2239
- const { usageTap: callContext = {}, ...providerOptions } = requestOptions ?? {};
2240
- const decision = params.stream === true ? Promise.resolve(false) : usageTap.shouldSampleAsync({
2241
- customerId: callContext.customerId,
2242
- feature: callContext.feature,
2243
- input: params
2244
- }, localPolicy);
2245
- const startedAt = Date.now();
2246
- try {
2247
- const response = await originalCreate(
2248
- params,
2249
- Object.keys(providerOptions).length ? providerOptions : void 0
2250
- );
2251
- const selected = await decision;
2252
- if (selected) {
2253
- const record = isObjectRecord(response) ? response : {};
2254
- await usageTap.captureSample({
2255
- customerId: callContext.customerId,
2256
- feature: callContext.feature,
2257
- environment: callContext.environment,
2258
- tags: callContext.tags,
2259
- provider: "anthropic",
2260
- model: readString(record.model) ?? readString(params.model),
2261
- input: params,
2262
- output: response,
2263
- usage: record.usage,
2264
- latencyMs: Date.now() - startedAt
2265
- }).catch(() => void 0);
2266
- }
2267
- return response;
2268
- } catch (error) {
2269
- const selected = await decision;
2270
- if (selected) {
2271
- await usageTap.captureSample({
2272
- customerId: callContext.customerId,
2273
- feature: callContext.feature,
2274
- environment: callContext.environment,
2275
- tags: callContext.tags,
2276
- provider: "anthropic",
2277
- model: readString(params.model),
2278
- input: params,
2279
- latencyMs: Date.now() - startedAt,
2280
- error: error instanceof Error ? { name: error.name, message: error.message } : { message: String(error) }
2281
- }).catch(() => void 0);
2310
+ const create = (params, requestOptions) => {
2311
+ return new DeferredAnthropicApiPromise(async () => {
2312
+ const { usageTap: callContext = {}, ...providerOptions } = requestOptions ?? {};
2313
+ const decision = params.stream === true ? Promise.resolve(false) : usageTap.shouldSampleAsync({
2314
+ customerId: callContext.customerId,
2315
+ feature: callContext.feature,
2316
+ input: params
2317
+ }, localPolicy);
2318
+ const startedAt = Date.now();
2319
+ try {
2320
+ const result = await resolveAnthropicResponseEnvelope(originalCreate(
2321
+ params,
2322
+ Object.keys(providerOptions).length ? providerOptions : void 0
2323
+ ));
2324
+ const response = result.data;
2325
+ const selected = await decision;
2326
+ if (selected) {
2327
+ const record = isObjectRecord(response) ? response : {};
2328
+ await usageTap.captureSample({
2329
+ customerId: callContext.customerId,
2330
+ feature: callContext.feature,
2331
+ environment: callContext.environment,
2332
+ tags: callContext.tags,
2333
+ provider: "anthropic",
2334
+ model: readString(record.model) ?? readString(params.model),
2335
+ input: params,
2336
+ output: response,
2337
+ usage: record.usage,
2338
+ latencyMs: Date.now() - startedAt
2339
+ }).catch(() => void 0);
2340
+ }
2341
+ return result;
2342
+ } catch (error) {
2343
+ const selected = await decision;
2344
+ if (selected) {
2345
+ await usageTap.captureSample({
2346
+ customerId: callContext.customerId,
2347
+ feature: callContext.feature,
2348
+ environment: callContext.environment,
2349
+ tags: callContext.tags,
2350
+ provider: "anthropic",
2351
+ model: readString(params.model),
2352
+ input: params,
2353
+ latencyMs: Date.now() - startedAt,
2354
+ error: error instanceof Error ? { name: error.name, message: error.message } : { message: String(error) }
2355
+ }).catch(() => void 0);
2356
+ }
2357
+ throw error;
2282
2358
  }
2283
- throw error;
2284
- }
2359
+ });
2285
2360
  };
2286
2361
  const messages = new Proxy(client.messages, {
2287
2362
  get(target, prop, receiver) {
@@ -2322,7 +2397,12 @@ function withCompression(client, options = {}) {
2322
2397
  };
2323
2398
  const originalCreate = client.messages.create.bind(client.messages);
2324
2399
  const wrappedCreate = (params, requestOptions) => {
2325
- return compressAnthropicParams(params, usageTap, compression).then((outcome) => originalCreate(outcome.params, requestOptions));
2400
+ return new DeferredAnthropicApiPromise(async () => {
2401
+ const outcome = await compressAnthropicParams(params, usageTap, compression);
2402
+ return resolveAnthropicResponseEnvelope(
2403
+ originalCreate(outcome.params, requestOptions)
2404
+ );
2405
+ });
2326
2406
  };
2327
2407
  const proxiedMessages = new Proxy(client.messages, {
2328
2408
  get(target, prop, receiver) {
@@ -2417,20 +2497,22 @@ function createMessagesProxy(resource, usageTap, defaultContext, applyVendorHint
2417
2497
  withUsage,
2418
2498
  promptCompression
2419
2499
  } = splitUsageOptions(options);
2420
- return invokeMessagesCreate({
2421
- params,
2422
- requestOptions,
2423
- usageContext,
2424
- withUsage,
2425
- promptCompression,
2426
- originalCreate,
2427
- usageTap,
2428
- defaultContext,
2429
- applyVendorHints,
2430
- defaultPromptCompression,
2431
- promptCompressionStats,
2432
- defaultSampling
2433
- });
2500
+ return new DeferredAnthropicApiPromise(
2501
+ () => invokeMessagesCreate({
2502
+ params,
2503
+ requestOptions,
2504
+ usageContext,
2505
+ withUsage,
2506
+ promptCompression,
2507
+ originalCreate,
2508
+ usageTap,
2509
+ defaultContext,
2510
+ applyVendorHints,
2511
+ defaultPromptCompression,
2512
+ promptCompressionStats,
2513
+ defaultSampling
2514
+ })
2515
+ );
2434
2516
  });
2435
2517
  const handler = {
2436
2518
  get(target, prop, receiver) {
@@ -2443,10 +2525,9 @@ function createMessagesProxy(resource, usageTap, defaultContext, applyVendorHint
2443
2525
  return new Proxy(resource, handler);
2444
2526
  }
2445
2527
  async function invokeMessagesCreate(args) {
2446
- const beginRequest = withRuntimeCompressionContext(
2447
- resolveBeginRequest(args.defaultContext, args.usageContext),
2448
- "anthropic",
2449
- String(args.params.model)
2528
+ const beginRequest = resolveBeginRequest(
2529
+ args.defaultContext,
2530
+ args.usageContext
2450
2531
  );
2451
2532
  const begin = await args.usageTap.beginCall(
2452
2533
  beginRequest,
@@ -2477,17 +2558,23 @@ async function invokeMessagesCreate(args) {
2477
2558
  });
2478
2559
  ctx.setUsage(anthropicRequestExecutionMetadata(finalParams));
2479
2560
  const request = attachCorrelationHeader(args.requestOptions, ctx.begin.correlationId);
2480
- const response = await args.originalCreate(finalParams, request);
2561
+ const providerResult = await resolveAnthropicResponseEnvelope(
2562
+ args.originalCreate(finalParams, request)
2563
+ );
2564
+ const response = providerResult.data;
2481
2565
  providerCompleted = true;
2482
2566
  if (isStreamingRequest(finalParams)) {
2483
2567
  ensureAsyncIterable(response, "messages.create");
2484
- return wrapAnthropicStreamForUsageTap(
2485
- response,
2486
- state,
2487
- args.usageTap,
2488
- args.withUsage,
2489
- readString(finalParams.model)
2490
- );
2568
+ return {
2569
+ ...providerResult,
2570
+ data: wrapAnthropicStreamForUsageTap(
2571
+ response,
2572
+ state,
2573
+ args.usageTap,
2574
+ args.withUsage,
2575
+ readString(finalParams.model)
2576
+ )
2577
+ };
2491
2578
  }
2492
2579
  inferAnthropicUsage(response, readString(finalParams.model), ctx);
2493
2580
  await captureMeteredAnthropicSample({
@@ -2500,7 +2587,7 @@ async function invokeMessagesCreate(args) {
2500
2587
  startedAt: sampleStartedAt
2501
2588
  });
2502
2589
  await finalizeCall(state, args.usageTap, args.withUsage);
2503
- return response;
2590
+ return providerResult;
2504
2591
  } catch (error) {
2505
2592
  if (!state.error) {
2506
2593
  state.error = {
@@ -2583,70 +2670,19 @@ async function captureMeteredAnthropicSample({
2583
2670
  }).catch(() => void 0);
2584
2671
  }
2585
2672
  async function compressAnthropicParamsForCall(args) {
2586
- let compression = resolveEffectivePromptCompressionOptions(
2673
+ const compression = resolveEffectivePromptCompressionOptions(
2587
2674
  args.defaultPromptCompression,
2588
2675
  args.callPromptCompression
2589
2676
  );
2590
- const runtimePolicy = args.ctx.begin.data.runtimeCompressionPolicy;
2591
- const policyDriven = !compression && Boolean(runtimePolicy);
2592
- if (policyDriven && runtimePolicy) {
2593
- if (!runtimePolicy.selected) {
2594
- args.ctx.setUsage({
2595
- runtimeCompression: bypassedRuntimeMeasurement(runtimePolicy)
2596
- });
2597
- return args.params;
2598
- }
2599
- compression = anthropicPolicyCompressionOptions(runtimePolicy);
2600
- if (runtimePolicy.mode === "SHADOW") {
2601
- const startedAt2 = Date.now();
2602
- void compressAnthropicParams(
2603
- args.params,
2604
- args.usageTap,
2605
- compression,
2606
- args.withUsage?.signal
2607
- ).then((outcome2) => {
2608
- args.ctx.setUsage({
2609
- runtimeCompression: anthropicRuntimeMeasurement({
2610
- policy: runtimePolicy,
2611
- telemetry: buildPromptCompressionTelemetry(outcome2.segments),
2612
- latencyMs: Date.now() - startedAt2,
2613
- shadow: true,
2614
- originalPayload: args.params,
2615
- resultPayload: outcome2.params
2616
- })
2617
- });
2618
- }).catch(() => {
2619
- args.ctx.setUsage({
2620
- runtimeCompression: failedRuntimeMeasurement(
2621
- runtimePolicy,
2622
- Date.now() - startedAt2
2623
- )
2624
- });
2625
- });
2626
- return args.params;
2627
- }
2628
- }
2629
2677
  if (!compression) {
2630
2678
  return args.params;
2631
2679
  }
2632
- const startedAt = Date.now();
2633
2680
  const outcome = await compressAnthropicParams(
2634
2681
  args.params,
2635
2682
  args.usageTap,
2636
2683
  compression,
2637
2684
  args.withUsage?.signal
2638
2685
  );
2639
- if (policyDriven && runtimePolicy) {
2640
- const runtimeMeasurement = anthropicRuntimeMeasurement({
2641
- policy: runtimePolicy,
2642
- telemetry: buildPromptCompressionTelemetry(outcome.segments),
2643
- latencyMs: Date.now() - startedAt,
2644
- originalPayload: args.params,
2645
- resultPayload: outcome.params
2646
- });
2647
- args.ctx.setUsage({ runtimeCompression: runtimeMeasurement });
2648
- if (runtimeMeasurement.decision !== "compressed") return args.params;
2649
- }
2650
2686
  await recordCompressionOutcome({
2651
2687
  outcome,
2652
2688
  compression,
@@ -2658,76 +2694,6 @@ async function compressAnthropicParamsForCall(args) {
2658
2694
  });
2659
2695
  return outcome.params;
2660
2696
  }
2661
- function anthropicPolicyCompressionOptions(policy) {
2662
- const roles = Object.fromEntries(
2663
- ["system", "user", "tool", "assistant"].filter((role) => policy.snapshot.scope.messageRoles.includes(role)).map((role) => [role, true])
2664
- );
2665
- return {
2666
- provider: "usagetap",
2667
- roles,
2668
- minContextTokens: policy.snapshot.scope.minimumTokens,
2669
- failOpen: true
2670
- };
2671
- }
2672
- function bypassedRuntimeMeasurement(policy) {
2673
- return {
2674
- policyId: policy.policyId,
2675
- policyVersionId: policy.policyVersionId,
2676
- policyVersion: policy.version,
2677
- rolloutMode: policy.mode,
2678
- decision: "bypassed",
2679
- reasonCode: "not_in_rollout_sample",
2680
- methodsAttempted: [],
2681
- methodsApplied: [],
2682
- originalTokens: 0,
2683
- resultTokens: 0,
2684
- savedTokens: 0,
2685
- reductionPercentage: 0,
2686
- compressionLatencyMs: 0,
2687
- compressionComputeCostUsd: 0,
2688
- financialsEstimated: true
2689
- };
2690
- }
2691
- function failedRuntimeMeasurement(policy, latencyMs) {
2692
- return {
2693
- ...bypassedRuntimeMeasurement(policy),
2694
- decision: "fallback",
2695
- reasonCode: "transformation_failed",
2696
- methodsAttempted: ["deterministic"],
2697
- compressionLatencyMs: latencyMs
2698
- };
2699
- }
2700
- function anthropicRuntimeMeasurement(input) {
2701
- const telemetry = input.telemetry;
2702
- const originalTokens = telemetry?.originalTokens ?? estimatePromptTokens(JSON.stringify(input.originalPayload));
2703
- const resultTokens = telemetry?.compressedTokens ?? originalTokens;
2704
- const savedTokens = Math.max(0, telemetry?.savedTokens ?? 0);
2705
- const reductionPercentage = originalTokens > 0 ? savedTokens / originalTokens * 100 : 0;
2706
- const belowMinimumSize = originalTokens < input.policy.snapshot.scope.minimumTokens;
2707
- const latencyExceeded = input.latencyMs > input.policy.snapshot.gates.maximumLatencyMs;
2708
- const belowSavings = savedTokens < input.policy.snapshot.gates.minimumTokensRemoved || reductionPercentage < input.policy.snapshot.gates.minimumReductionPercentage;
2709
- const accepted = !belowMinimumSize && !latencyExceeded && !belowSavings;
2710
- const deepText = input.policy.snapshot.methods.deepText.enabled && !input.policy.snapshot.rollout.deterministicOnly && (input.policy.mode !== "CANARY" || input.policy.snapshot.rollout.deepTextCanaryAllowed);
2711
- const reasonCode = belowMinimumSize ? "below_minimum_size" : latencyExceeded ? "latency_budget_exceeded" : belowSavings ? "below_minimum_savings" : void 0;
2712
- const measurement = {
2713
- policyId: input.policy.policyId,
2714
- policyVersionId: input.policy.policyVersionId,
2715
- policyVersion: input.policy.version,
2716
- rolloutMode: input.policy.mode,
2717
- decision: accepted ? input.shadow ? "bypassed" : "compressed" : latencyExceeded ? "fallback" : "skipped",
2718
- ...reasonCode ? { reasonCode } : {},
2719
- methodsAttempted: ["deterministic", ...deepText ? ["deep_text"] : []],
2720
- methodsApplied: accepted ? ["deterministic"] : [],
2721
- originalTokens,
2722
- resultTokens: accepted ? resultTokens : originalTokens,
2723
- savedTokens: accepted ? savedTokens : 0,
2724
- reductionPercentage: accepted ? reductionPercentage : 0,
2725
- compressionLatencyMs: input.latencyMs,
2726
- compressionComputeCostUsd: 0,
2727
- financialsEstimated: true
2728
- };
2729
- return measurement;
2730
- }
2731
2697
  async function recordCompressionOutcome(args) {
2732
2698
  const telemetry = buildPromptCompressionTelemetry(args.outcome.segments);
2733
2699
  if (!telemetry) {
@@ -3170,10 +3136,6 @@ function resolveBeginRequest(defaults, override) {
3170
3136
  }
3171
3137
  const tags = mergeTags(base.tags, current.tags);
3172
3138
  const begin = { customerId };
3173
- const runtimeCompressionContext = current.runtimeCompressionContext ?? base.runtimeCompressionContext;
3174
- if (runtimeCompressionContext) {
3175
- begin.runtimeCompressionContext = runtimeCompressionContext;
3176
- }
3177
3139
  const requested = current.requested ?? base.requested;
3178
3140
  if (requested) begin.requested = requested;
3179
3141
  const feature = current.feature ?? base.feature;
@@ -3196,8 +3158,6 @@ function resolveBeginRequest(defaults, override) {
3196
3158
  if (customerUserEmail) begin.customerUserEmail = customerUserEmail;
3197
3159
  const stripeCustomerId = current.stripeCustomerId ?? base.stripeCustomerId;
3198
3160
  if (stripeCustomerId) begin.stripeCustomerId = stripeCustomerId;
3199
- const holdUsd = current.holdUsd ?? base.holdUsd;
3200
- if (typeof holdUsd === "number") begin.holdUsd = holdUsd;
3201
3161
  const batch = current.batch ?? base.batch;
3202
3162
  if (typeof batch === "boolean") begin.batch = batch;
3203
3163
  const pricingMode = current.pricingMode ?? base.pricingMode;
@@ -3333,21 +3293,21 @@ function applyAnthropicUsageRecord(usage, usageRecord) {
3333
3293
  if (cacheWriteInputTokens !== void 0) {
3334
3294
  usage.cacheWriteInputTokens = cacheWriteInputTokens;
3335
3295
  }
3296
+ if (isObjectRecord(usageRecord.cache_creation)) {
3297
+ const cacheWrite5m = readNumber(
3298
+ usageRecord.cache_creation.ephemeral_5m_input_tokens
3299
+ );
3300
+ const cacheWrite1h = readNumber(
3301
+ usageRecord.cache_creation.ephemeral_1h_input_tokens
3302
+ );
3303
+ if (cacheWrite5m !== void 0) usage.cacheWrite5mInputTokens = cacheWrite5m;
3304
+ if (cacheWrite1h !== void 0) usage.cacheWrite1hInputTokens = cacheWrite1h;
3305
+ }
3336
3306
  const baseInputTokens = readNumber(usageRecord.input_tokens ?? usageRecord.prompt_tokens);
3337
3307
  if (baseInputTokens !== void 0) {
3338
3308
  usage.inputTokens = baseInputTokens + (cachedInputTokens ?? 0) + (cacheWriteInputTokens ?? 0);
3339
3309
  }
3340
3310
  }
3341
- function withRuntimeCompressionContext(begin, provider, model) {
3342
- return {
3343
- ...begin,
3344
- runtimeCompressionContext: {
3345
- ...begin.runtimeCompressionContext ?? {},
3346
- provider,
3347
- model
3348
- }
3349
- };
3350
- }
3351
3311
  function accumulateAnthropicStreamUsage(chunk, fallbackModel, state) {
3352
3312
  const usage = extractAnthropicUsage(chunk, fallbackModel);
3353
3313
  if (usage) {