@usagetap/sdk 1.1.0 → 1.2.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 (44) hide show
  1. package/README.md +25 -1
  2. package/dist/adapters/anthropic.cjs +67 -1
  3. package/dist/adapters/anthropic.cjs.map +1 -1
  4. package/dist/adapters/anthropic.d.cts +10 -1
  5. package/dist/adapters/anthropic.d.ts +10 -1
  6. package/dist/adapters/anthropic.mjs +67 -1
  7. package/dist/adapters/anthropic.mjs.map +1 -1
  8. package/dist/adapters/openai.cjs +67 -1
  9. package/dist/adapters/openai.cjs.map +1 -1
  10. package/dist/adapters/openai.d.cts +10 -1
  11. package/dist/adapters/openai.d.ts +10 -1
  12. package/dist/adapters/openai.mjs +67 -1
  13. package/dist/adapters/openai.mjs.map +1 -1
  14. package/dist/adapters/openrouter.cjs.map +1 -1
  15. package/dist/adapters/openrouter.d.cts +1 -1
  16. package/dist/adapters/openrouter.d.ts +1 -1
  17. package/dist/adapters/openrouter.mjs.map +1 -1
  18. package/dist/anthropic/index.cjs +67 -1
  19. package/dist/anthropic/index.cjs.map +1 -1
  20. package/dist/anthropic/index.d.cts +1 -1
  21. package/dist/anthropic/index.d.ts +1 -1
  22. package/dist/anthropic/index.mjs +67 -1
  23. package/dist/anthropic/index.mjs.map +1 -1
  24. package/dist/{client-BA-QlnRq.d.cts → client-EMXt9_fA.d.cts} +77 -8
  25. package/dist/{client-BA-QlnRq.d.ts → client-EMXt9_fA.d.ts} +77 -8
  26. package/dist/express/index.cjs +67 -1
  27. package/dist/express/index.cjs.map +1 -1
  28. package/dist/express/index.d.cts +1 -1
  29. package/dist/express/index.d.ts +1 -1
  30. package/dist/express/index.mjs +67 -1
  31. package/dist/express/index.mjs.map +1 -1
  32. package/dist/index.cjs +217 -22
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +2 -2
  35. package/dist/index.d.ts +2 -2
  36. package/dist/index.mjs +217 -23
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/openai/index.cjs +67 -1
  39. package/dist/openai/index.cjs.map +1 -1
  40. package/dist/openai/index.d.cts +1 -1
  41. package/dist/openai/index.d.ts +1 -1
  42. package/dist/openai/index.mjs +67 -1
  43. package/dist/openai/index.mjs.map +1 -1
  44. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -119,26 +119,32 @@ async function runWithRetry(operation, options, shouldRetry, onSchedule, signal)
119
119
  var DEFAULT_TTC_ENDPOINT = "https://api.thetokencompany.com/v1/compress";
120
120
  var DEFAULT_TTC_MODEL = "bear-2";
121
121
  var DEFAULT_TTC_AGGRESSIVENESS = 0.2;
122
+ var DEFAULT_USAGETAP_COMPRESSION_ENDPOINT = "https://compress.usagetap.com/v1/compress";
123
+ var DEFAULT_USAGETAP_MESSAGES_COMPRESSION_ENDPOINT = "https://compress.usagetap.com/v1/messages/compress";
122
124
  var PROTECTED_TEXT_PATTERN = /<ttc_safe>[\s\S]*?<\/ttc_safe>|<usagetap_safe>[\s\S]*?<\/usagetap_safe>/g;
123
125
  function protectPromptText(text) {
124
126
  return `<ttc_safe>${text}</ttc_safe>`;
125
127
  }
126
128
  var protect = protectPromptText;
127
129
  async function compressPrompt(options) {
130
+ const input = resolvePromptCompressionInput(options);
128
131
  try {
132
+ if (options.provider === "usagetap") {
133
+ return await compressWithUsageTap(options);
134
+ }
129
135
  if (options.provider === "thetokencompany" || options.tokenCompanyApiKey) {
130
136
  return await compressWithTheTokenCompany(options);
131
137
  }
132
138
  if (options.provider === "toon") {
133
- return compressPromptToon(options.input);
139
+ return compressPromptToon(input);
134
140
  }
135
- return compressPromptHeuristic(options.input);
141
+ return compressPromptHeuristic(input);
136
142
  } catch (error) {
137
143
  if (options.failOpen === false) {
138
144
  throw error;
139
145
  }
140
146
  return createPromptCompressionFallback(
141
- options.input,
147
+ input,
142
148
  options.provider ?? (options.tokenCompanyApiKey ? "thetokencompany" : "heuristic"),
143
149
  error
144
150
  );
@@ -172,6 +178,20 @@ function compressPromptToon(input) {
172
178
  "json-minify"
173
179
  ]);
174
180
  }
181
+ async function compressPromptMessages(options) {
182
+ try {
183
+ return await compressMessagesWithUsageTap(options);
184
+ } catch (error) {
185
+ if (options.failOpen === false) {
186
+ throw error;
187
+ }
188
+ return createPromptCompressionFallback(
189
+ options.input,
190
+ options.provider ?? "usagetap",
191
+ error
192
+ );
193
+ }
194
+ }
175
195
  async function compressWithTheTokenCompany(options) {
176
196
  if (!options.tokenCompanyApiKey) {
177
197
  throw new Error(
@@ -184,41 +204,131 @@ async function compressWithTheTokenCompany(options) {
184
204
  "A fetch implementation is required for The Token Company compression"
185
205
  );
186
206
  }
207
+ return compressWithCompatibleRemoteProvider({
208
+ options,
209
+ provider: "thetokencompany",
210
+ endpoint: options.tokenCompanyEndpoint ?? DEFAULT_TTC_ENDPOINT,
211
+ model: options.model ?? options.tokenCompanyModel ?? DEFAULT_TTC_MODEL,
212
+ aggressiveness: options.aggressiveness ?? options.tokenCompanyAggressiveness ?? DEFAULT_TTC_AGGRESSIVENESS,
213
+ apiKey: options.tokenCompanyApiKey,
214
+ appId: options.tokenCompanyAppId,
215
+ providerLabel: "The Token Company"
216
+ });
217
+ }
218
+ async function compressWithUsageTap(options) {
219
+ const fetchCandidate = options.fetchImpl ?? globalThis.fetch;
220
+ if (typeof fetchCandidate !== "function") {
221
+ throw new Error(
222
+ "A fetch implementation is required for UsageTap prompt compression"
223
+ );
224
+ }
225
+ return compressWithCompatibleRemoteProvider({
226
+ options,
227
+ provider: "usagetap",
228
+ endpoint: options.usageTapCompressionEndpoint ?? DEFAULT_USAGETAP_COMPRESSION_ENDPOINT,
229
+ model: options.model ?? options.usageTapCompressionModel ?? options.tokenCompanyModel ?? DEFAULT_TTC_MODEL,
230
+ aggressiveness: options.aggressiveness ?? options.usageTapCompressionAggressiveness ?? options.tokenCompanyAggressiveness ?? DEFAULT_TTC_AGGRESSIVENESS,
231
+ apiKey: options.usageTapCompressionApiKey,
232
+ appId: options.tokenCompanyAppId,
233
+ providerLabel: "UsageTap prompt compression"
234
+ });
235
+ }
236
+ async function compressMessagesWithUsageTap(options) {
237
+ const fetchCandidate = options.fetchImpl ?? globalThis.fetch;
238
+ if (typeof fetchCandidate !== "function") {
239
+ throw new Error(
240
+ "A fetch implementation is required for UsageTap prompt message compression"
241
+ );
242
+ }
243
+ const aggressiveness = options.aggressiveness ?? options.usageTapCompressionAggressiveness ?? DEFAULT_TTC_AGGRESSIVENESS;
244
+ validateAggressiveness(
245
+ aggressiveness,
246
+ "UsageTap prompt message compression"
247
+ );
187
248
  const original = stableStringifyInput(options.input);
188
- const heuristic = compressPromptHeuristic(options.input);
249
+ const headers = {
250
+ "content-type": "application/json"
251
+ };
252
+ if (options.usageTapCompressionApiKey) {
253
+ headers.authorization = `Bearer ${options.usageTapCompressionApiKey}`;
254
+ }
255
+ const response = await fetchCandidate(
256
+ options.usageTapCompressionMessagesEndpoint ?? DEFAULT_USAGETAP_MESSAGES_COMPRESSION_ENDPOINT,
257
+ {
258
+ method: "POST",
259
+ headers,
260
+ body: JSON.stringify({
261
+ ...cloneInputRecord(options.input),
262
+ compression_settings: { aggressiveness }
263
+ }),
264
+ signal: options.signal
265
+ }
266
+ );
267
+ if (!response.ok) {
268
+ throw new Error(
269
+ `UsageTap prompt message compression failed with HTTP ${response.status}`
270
+ );
271
+ }
272
+ const payload = await response.json();
273
+ const compressedInput = payload.compressed_request ?? payload.compressedInput ?? payload.compressed ?? (payload.messages !== void 0 ? { ...cloneInputRecord(options.input), messages: payload.messages } : void 0);
274
+ if (compressedInput === void 0) {
275
+ throw new Error(
276
+ "UsageTap prompt message compression response did not include compressed content"
277
+ );
278
+ }
279
+ const compressed = stableStringifyInput(compressedInput);
280
+ const tokenCounts = normalizeCompatibleTokenCounts(payload);
281
+ return buildResult(
282
+ options.input,
283
+ compressedInput,
284
+ "usagetap",
285
+ original,
286
+ compressed,
287
+ ["usagetap", "messages-endpoint"],
288
+ tokenCounts
289
+ );
290
+ }
291
+ async function compressWithCompatibleRemoteProvider(args) {
292
+ const { options, provider, endpoint, model, aggressiveness, apiKey, appId, providerLabel } = args;
293
+ const fetchCandidate = options.fetchImpl ?? globalThis.fetch;
294
+ const sourceInput = resolvePromptCompressionInput(options);
295
+ const original = stableStringifyInput(sourceInput);
296
+ const heuristic = compressPromptHeuristic(sourceInput);
189
297
  const input = typeof heuristic.compressedInput === "string" ? heuristic.compressedInput : stableStringifyInput(heuristic.compressedInput);
190
- const model = options.tokenCompanyModel ?? DEFAULT_TTC_MODEL;
191
- const aggressiveness = options.tokenCompanyAggressiveness ?? DEFAULT_TTC_AGGRESSIVENESS;
192
- if (typeof aggressiveness !== "number" || !Number.isFinite(aggressiveness) || aggressiveness < 0 || aggressiveness > 1) {
193
- throw new Error("tokenCompanyAggressiveness must be between 0.0 and 1.0");
298
+ if (!isValidAggressiveness(aggressiveness)) {
299
+ throw new Error(`${providerLabel} aggressiveness must be between 0.0 and 1.0`);
300
+ }
301
+ const headers = {
302
+ "content-type": "application/json"
303
+ };
304
+ if (apiKey) {
305
+ headers.authorization = `Bearer ${apiKey}`;
194
306
  }
195
307
  const response = await fetchCandidate(
196
- options.tokenCompanyEndpoint ?? DEFAULT_TTC_ENDPOINT,
308
+ endpoint,
197
309
  {
198
310
  method: "POST",
199
- headers: {
200
- authorization: `Bearer ${options.tokenCompanyApiKey}`,
201
- "content-type": "application/json"
202
- },
311
+ headers,
203
312
  body: JSON.stringify({
204
313
  model,
205
314
  input,
315
+ ...provider === "usagetap" ? { text: input } : {},
206
316
  compression_settings: { aggressiveness },
207
- ...options.tokenCompanyAppId ? { app_id: options.tokenCompanyAppId } : {}
317
+ ...appId ? { app_id: appId } : {}
208
318
  }),
209
319
  signal: options.signal
210
320
  }
211
321
  );
212
322
  if (!response.ok) {
213
323
  throw new Error(
214
- `The Token Company compression failed with HTTP ${response.status}`
324
+ `${providerLabel} failed with HTTP ${response.status}`
215
325
  );
216
326
  }
217
327
  const payload = await response.json();
218
328
  const tokenCompanyResult = normalizeTheTokenCompanyCompressResponse(payload);
219
329
  const compressedInput = payload.compressedInput ?? payload.compressed ?? tokenCompanyResult?.output ?? payload.output ?? payload.text;
220
330
  if (compressedInput === void 0) {
221
- throw new Error("The Token Company response did not include compressed content");
331
+ throw new Error(`${providerLabel} response did not include compressed content`);
222
332
  }
223
333
  const compressed = stableStringifyInput(compressedInput);
224
334
  const tokenCounts = tokenCompanyResult ? {
@@ -227,15 +337,55 @@ async function compressWithTheTokenCompany(options) {
227
337
  savedTokens: tokenCompanyResult.tokens_saved
228
338
  } : void 0;
229
339
  return buildResult(
230
- options.input,
340
+ sourceInput,
231
341
  compressedInput,
232
- "thetokencompany",
342
+ provider,
233
343
  original,
234
344
  compressed,
235
- [...heuristic.techniques, "thetokencompany"],
345
+ [...heuristic.techniques, provider],
236
346
  tokenCounts
237
347
  );
238
348
  }
349
+ function resolvePromptCompressionInput(options) {
350
+ if (options.input !== void 0) {
351
+ return options.input;
352
+ }
353
+ if (options.text !== void 0) {
354
+ return options.text;
355
+ }
356
+ throw new Error("Prompt compression requires input or text");
357
+ }
358
+ function validateAggressiveness(value, label) {
359
+ if (typeof value === "number") {
360
+ if (!isValidAggressiveness(value)) {
361
+ throw new Error(`${label} aggressiveness must be between 0.0 and 1.0`);
362
+ }
363
+ return;
364
+ }
365
+ for (const aggressiveness of Object.values(value)) {
366
+ if (aggressiveness !== void 0 && !isValidAggressiveness(aggressiveness)) {
367
+ throw new Error(`${label} aggressiveness must be between 0.0 and 1.0`);
368
+ }
369
+ }
370
+ }
371
+ function isValidAggressiveness(value) {
372
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
373
+ }
374
+ function cloneInputRecord(input) {
375
+ return input && typeof input === "object" && !Array.isArray(input) ? { ...input } : { input };
376
+ }
377
+ function normalizeCompatibleTokenCounts(data) {
378
+ const inputTokens = typeof data.input_tokens === "number" ? data.input_tokens : data.original_input_tokens;
379
+ const outputTokens = data.output_tokens;
380
+ if (typeof inputTokens !== "number" || typeof outputTokens !== "number") {
381
+ return void 0;
382
+ }
383
+ return {
384
+ originalTokens: inputTokens,
385
+ compressedTokens: outputTokens,
386
+ savedTokens: typeof data.tokens_saved === "number" ? data.tokens_saved : inputTokens - outputTokens
387
+ };
388
+ }
239
389
  function normalizeTheTokenCompanyCompressResponse(data) {
240
390
  if (typeof data.output !== "string" || typeof data.output_tokens !== "number") {
241
391
  return void 0;
@@ -620,7 +770,7 @@ var IDEMPOTENCY_HEADER = "idempotency-key";
620
770
  var SDK_HEADER = "x-usage-sdk";
621
771
  var USER_AGENT = "UsageTapClient";
622
772
  var CANONICAL_MEDIA_TYPE = "application/vnd.usagetap.v1+json";
623
- var SDK_VERSION = "1.1.0" ;
773
+ var SDK_VERSION = "1.2.0" ;
624
774
  var HAS_WINDOW = typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
625
775
  var UsageTapClient = class {
626
776
  apiKey;
@@ -637,9 +787,16 @@ var UsageTapClient = class {
637
787
  autoIdempotency;
638
788
  tokenCompanyApiKey;
639
789
  tokenCompanyEndpoint;
790
+ model;
640
791
  tokenCompanyModel;
792
+ aggressiveness;
641
793
  tokenCompanyAggressiveness;
642
794
  tokenCompanyAppId;
795
+ usageTapCompressionApiKey;
796
+ usageTapCompressionEndpoint;
797
+ usageTapCompressionMessagesEndpoint;
798
+ usageTapCompressionModel;
799
+ usageTapCompressionAggressiveness;
643
800
  constructor(options) {
644
801
  if (!options) {
645
802
  throw new UsageTapError(
@@ -687,9 +844,16 @@ var UsageTapClient = class {
687
844
  this.autoIdempotency = options.autoIdempotency ?? true;
688
845
  this.tokenCompanyApiKey = options.tokenCompanyApiKey;
689
846
  this.tokenCompanyEndpoint = options.tokenCompanyEndpoint;
847
+ this.model = options.model;
690
848
  this.tokenCompanyModel = options.tokenCompanyModel;
849
+ this.aggressiveness = options.aggressiveness;
691
850
  this.tokenCompanyAggressiveness = options.tokenCompanyAggressiveness;
692
851
  this.tokenCompanyAppId = options.tokenCompanyAppId;
852
+ this.usageTapCompressionApiKey = options.usageTapCompressionApiKey ?? options.apiKey;
853
+ this.usageTapCompressionEndpoint = options.usageTapCompressionEndpoint;
854
+ this.usageTapCompressionMessagesEndpoint = options.usageTapCompressionMessagesEndpoint;
855
+ this.usageTapCompressionModel = options.usageTapCompressionModel;
856
+ this.usageTapCompressionAggressiveness = options.usageTapCompressionAggressiveness;
693
857
  }
694
858
  async beginCall(request, options = {}) {
695
859
  const idempotencyKey = request.idempotencyKey ?? request.idempotency ?? (this.autoIdempotency ? this.idempotencyGenerator() : void 0);
@@ -719,11 +883,22 @@ var UsageTapClient = class {
719
883
  "promptCompress requires callId"
720
884
  );
721
885
  }
722
- const result = await this.compressPromptInput(request.input, {
886
+ const requestInput = request.input ?? request.text;
887
+ if (requestInput === void 0) {
888
+ throw new UsageTapError(
889
+ "USAGETAP_BAD_REQUEST",
890
+ "promptCompress requires input or text"
891
+ );
892
+ }
893
+ const result = await this.compressPromptInput(requestInput, {
723
894
  provider: request.provider,
895
+ model: request.model,
724
896
  tokenCompanyModel: request.tokenCompanyModel,
897
+ aggressiveness: request.aggressiveness,
725
898
  tokenCompanyAggressiveness: request.tokenCompanyAggressiveness,
726
899
  tokenCompanyAppId: request.tokenCompanyAppId,
900
+ usageTapCompressionModel: request.usageTapCompressionModel,
901
+ usageTapCompressionAggressiveness: request.usageTapCompressionAggressiveness,
727
902
  signal: options.signal
728
903
  });
729
904
  try {
@@ -738,7 +913,7 @@ var UsageTapClient = class {
738
913
  } catch (error) {
739
914
  return {
740
915
  ...createPromptCompressionFallback(
741
- request.input,
916
+ requestInput,
742
917
  request.provider ?? result.provider,
743
918
  error
744
919
  ),
@@ -752,9 +927,28 @@ var UsageTapClient = class {
752
927
  provider: options.provider,
753
928
  tokenCompanyApiKey: this.tokenCompanyApiKey,
754
929
  tokenCompanyEndpoint: this.tokenCompanyEndpoint,
930
+ model: options.model ?? this.model,
755
931
  tokenCompanyModel: options.tokenCompanyModel ?? this.tokenCompanyModel,
932
+ aggressiveness: options.aggressiveness ?? this.aggressiveness,
756
933
  tokenCompanyAggressiveness: options.tokenCompanyAggressiveness ?? this.tokenCompanyAggressiveness,
757
934
  tokenCompanyAppId: options.tokenCompanyAppId ?? this.tokenCompanyAppId,
935
+ usageTapCompressionApiKey: this.usageTapCompressionApiKey,
936
+ usageTapCompressionEndpoint: this.usageTapCompressionEndpoint,
937
+ usageTapCompressionModel: options.usageTapCompressionModel ?? this.usageTapCompressionModel,
938
+ usageTapCompressionAggressiveness: options.usageTapCompressionAggressiveness ?? this.usageTapCompressionAggressiveness,
939
+ fetchImpl: this.fetchImpl,
940
+ signal: options.signal,
941
+ failOpen: options.failOpen
942
+ });
943
+ }
944
+ async compressPromptMessages(input, options = {}) {
945
+ return compressPromptMessages({
946
+ input,
947
+ provider: options.provider ?? "usagetap",
948
+ usageTapCompressionApiKey: this.usageTapCompressionApiKey,
949
+ usageTapCompressionMessagesEndpoint: this.usageTapCompressionMessagesEndpoint,
950
+ aggressiveness: options.aggressiveness ?? this.aggressiveness,
951
+ usageTapCompressionAggressiveness: options.usageTapCompressionAggressiveness ?? this.usageTapCompressionAggressiveness,
758
952
  fetchImpl: this.fetchImpl,
759
953
  signal: options.signal,
760
954
  failOpen: options.failOpen
@@ -1605,6 +1799,7 @@ exports.UsageTapClient = UsageTapClient;
1605
1799
  exports.UsageTapError = UsageTapError;
1606
1800
  exports.compressPrompt = compressPrompt;
1607
1801
  exports.compressPromptHeuristic = compressPromptHeuristic;
1802
+ exports.compressPromptMessages = compressPromptMessages;
1608
1803
  exports.compressPromptToon = compressPromptToon;
1609
1804
  exports.createIdempotencyKey = createIdempotencyKey;
1610
1805
  exports.estimatePromptTokens = estimatePromptTokens;