vibezcheck 0.3.0 → 0.4.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/dist/index.js CHANGED
@@ -48,6 +48,7 @@ __export(src_exports, {
48
48
  createMeter: () => createMeter,
49
49
  createVibezCheck: () => createVibezCheck,
50
50
  createVibezModel: () => createVibezModel,
51
+ createVibezSession: () => createVibezSession,
51
52
  detectAndExtractUsage: () => detectAndExtractUsage,
52
53
  extractAnthropicResponseUsage: () => extractAnthropicResponseUsage,
53
54
  extractAuthToken: () => extractAuthToken,
@@ -63,7 +64,7 @@ __export(src_exports, {
63
64
  vibes: () => vibes,
64
65
  vibescheck: () => vibescheck,
65
66
  vibez: () => vibez,
66
- vibezcheck: () => vibezcheck,
67
+ vibezcheck: () => vibezcheck2,
67
68
  withBilling: () => withBilling,
68
69
  wrapAnthropicStream: () => wrapAnthropicStream,
69
70
  wrapGeminiStream: () => wrapGeminiStream,
@@ -620,14 +621,26 @@ function registerModelPricing(modelName, rates) {
620
621
 
621
622
  // src/pricing/calculator.ts
622
623
  function calculateCost(params) {
623
- const rates = getModelPricing(params.model);
624
+ let rates;
625
+ if (params.customRate) {
626
+ const outRate = params.customRate.out ?? params.customRate.output ?? 0;
627
+ rates = {
628
+ inputPer1M: params.customRate.in,
629
+ outputPer1M: outRate,
630
+ reasoningPer1M: params.customRate.reasoning ?? outRate,
631
+ cachedInputPer1M: params.customRate.cached ?? params.customRate.in * 0.15,
632
+ currency: "USD"
633
+ };
634
+ } else {
635
+ rates = getModelPricing(params.model);
636
+ }
624
637
  const inputTokens = params.inputTokens ?? 0;
625
638
  const outputTokens = params.outputTokens ?? 0;
626
639
  const reasoningTokens = params.reasoningTokens ?? 0;
627
640
  const cachedTokens = params.cachedTokens ?? 0;
628
641
  const regularInputTokens = Math.max(0, inputTokens - cachedTokens);
629
642
  const regularInputCost = regularInputTokens / 1e6 * rates.inputPer1M;
630
- const cachedRate = rates.cachedInputPer1M ?? rates.inputPer1M * 0.5;
643
+ const cachedRate = rates.cachedInputPer1M ?? rates.inputPer1M * 0.15;
631
644
  const cachedInputCost = cachedTokens / 1e6 * cachedRate;
632
645
  const inputCostUSD = regularInputCost + cachedInputCost;
633
646
  const outputCostUSD = outputTokens / 1e6 * rates.outputPer1M;
@@ -635,20 +648,27 @@ function calculateCost(params) {
635
648
  const reasoningCostUSD = reasoningTokens / 1e6 * reasoningRate;
636
649
  const standardCacheCost = cachedTokens / 1e6 * rates.inputPer1M;
637
650
  const cachedDiscountUSD = Math.max(0, standardCacheCost - cachedInputCost);
638
- const totalUSD = inputCostUSD + outputCostUSD;
651
+ let totalUSD = inputCostUSD + outputCostUSD;
639
652
  const markup = params.markupMultiplier ?? 1;
640
- const retailUSD = markup !== 1 ? totalUSD * markup : void 0;
653
+ let retailUSD = void 0;
654
+ if (markup !== 1 || params.minimumChargeUSD !== void 0) {
655
+ retailUSD = totalUSD * markup;
656
+ if (params.minimumChargeUSD !== void 0 && retailUSD < params.minimumChargeUSD) {
657
+ retailUSD = params.minimumChargeUSD;
658
+ }
659
+ }
641
660
  return {
642
661
  inputCostUSD: Number(inputCostUSD.toFixed(8)),
643
662
  outputCostUSD: Number(outputCostUSD.toFixed(8)),
644
663
  reasoningCostUSD: reasoningTokens > 0 ? Number(reasoningCostUSD.toFixed(8)) : void 0,
645
664
  cachedDiscountUSD: cachedTokens > 0 ? Number(cachedDiscountUSD.toFixed(8)) : void 0,
646
665
  totalUSD: Number(totalUSD.toFixed(8)),
647
- retailUSD: retailUSD ? Number(retailUSD.toFixed(8)) : void 0,
666
+ retailUSD: retailUSD !== void 0 ? Number(retailUSD.toFixed(8)) : void 0,
648
667
  currency: rates.currency || "USD"
649
668
  };
650
669
  }
651
- function calculateUsageCost(model, usage, markupMultiplier) {
670
+ function calculateUsageCost(model, usage, optionsOrMarkup) {
671
+ const options = typeof optionsOrMarkup === "number" ? { markupMultiplier: optionsOrMarkup } : optionsOrMarkup || {};
652
672
  return calculateCost({
653
673
  model,
654
674
  inputTokens: usage.inputTokens,
@@ -656,7 +676,9 @@ function calculateUsageCost(model, usage, markupMultiplier) {
656
676
  reasoningTokens: usage.reasoningTokens,
657
677
  cachedTokens: usage.cachedTokens,
658
678
  cacheWriteTokens: usage.cacheWriteTokens,
659
- markupMultiplier
679
+ markupMultiplier: options.markupMultiplier,
680
+ minimumChargeUSD: options.minimumChargeUSD,
681
+ customRate: options.customRate
660
682
  });
661
683
  }
662
684
 
@@ -917,7 +939,22 @@ function withBilling(model, options = {}) {
917
939
  const customerId = typeof options.customer === "string" ? options.customer : options.customer?.id || options.customerId;
918
940
  const modelId = model.modelId || "unknown-model";
919
941
  const provider = model.provider?.replace(/^@ai-sdk\//, "") || "ai-sdk";
920
- const handleUsage = (rawUsage) => {
942
+ const maxCostPerCall = options.maxCostPerCallUSD !== void 0 ? options.maxCostPerCallUSD : 0.5;
943
+ const captureOnAbort = options.captureOnAbort !== false;
944
+ const scheduleFlush = () => {
945
+ try {
946
+ const flushPromise = meter.flush();
947
+ if (typeof globalThis !== "undefined") {
948
+ const g = globalThis;
949
+ if (typeof g.after === "function") {
950
+ g.after(() => flushPromise);
951
+ return;
952
+ }
953
+ }
954
+ } catch {
955
+ }
956
+ };
957
+ const handleUsage = (rawUsage, extraMeta) => {
921
958
  if (!rawUsage) return;
922
959
  const inputTokens = rawUsage.promptTokens ?? rawUsage.inputTokens ?? 0;
923
960
  const outputTokens = rawUsage.completionTokens ?? rawUsage.outputTokens ?? 0;
@@ -931,15 +968,19 @@ function withBilling(model, options = {}) {
931
968
  visibleOutputTokens: Math.max(0, outputTokens - reasoningTokens),
932
969
  cachedTokens: cachedTokens > 0 ? cachedTokens : void 0
933
970
  };
934
- const cost = calculateUsageCost(modelId, usage);
935
- if (options.maxCostPerCallUSD && cost.totalUSD > options.maxCostPerCallUSD) {
971
+ const cost = calculateUsageCost(modelId, usage, {
972
+ markupMultiplier: options.pricing?.margin,
973
+ minimumChargeUSD: options.pricing?.minimumChargeUSD,
974
+ customRate: options.rate
975
+ });
976
+ if (maxCostPerCall > 0 && maxCostPerCall !== Infinity && cost.totalUSD > maxCostPerCall) {
936
977
  const budgetEvent = {
937
978
  reason: "cost_per_call_exceeded",
938
- limit: options.maxCostPerCallUSD,
979
+ limit: maxCostPerCall,
939
980
  current: cost.totalUSD,
940
981
  model: modelId,
941
982
  customerId,
942
- message: `[vibezcheck] Circuit Breaker tripped: Call cost ($${cost.totalUSD.toFixed(4)}) exceeded maxCostPerCallUSD threshold ($${options.maxCostPerCallUSD.toFixed(4)}).`
983
+ message: `[vibezcheck] Circuit Breaker tripped: Call cost ($${cost.totalUSD.toFixed(4)}) exceeded budget ceiling ($${maxCostPerCall.toFixed(4)}).`
943
984
  };
944
985
  if (options.onBudgetExceeded) {
945
986
  options.onBudgetExceeded(budgetEvent);
@@ -971,7 +1012,11 @@ function withBilling(model, options = {}) {
971
1012
  usage,
972
1013
  cost,
973
1014
  customerId,
974
- metadata: options.metadata
1015
+ metadata: {
1016
+ ...options.metadata,
1017
+ ...extraMeta,
1018
+ billingMode: options.billing?.mode || "postpaid"
1019
+ }
975
1020
  };
976
1021
  meter.recordUsage({
977
1022
  model: modelId,
@@ -981,11 +1026,12 @@ function withBilling(model, options = {}) {
981
1026
  reasoningTokens: usage.reasoningTokens,
982
1027
  cachedTokens: usage.cachedTokens,
983
1028
  customerId,
984
- metadata: options.metadata
1029
+ metadata: event.metadata
985
1030
  });
986
1031
  if (options.onUsage) {
987
1032
  options.onUsage(event);
988
1033
  }
1034
+ scheduleFlush();
989
1035
  };
990
1036
  const handler = {
991
1037
  get(target, prop, receiver) {
@@ -997,12 +1043,59 @@ function withBilling(model, options = {}) {
997
1043
  return result;
998
1044
  }
999
1045
  const originalStream = result.stream;
1046
+ let streamCompleted = false;
1047
+ let accumulatedChars = 0;
1048
+ let estimatedInputTokens = 0;
1049
+ try {
1050
+ if (args[0]?.prompt) {
1051
+ const str = typeof args[0].prompt === "string" ? args[0].prompt : JSON.stringify(args[0].prompt);
1052
+ estimatedInputTokens = Math.ceil(str.length / 4);
1053
+ }
1054
+ } catch {
1055
+ }
1056
+ const abortSignal = args[0]?.abortSignal;
1057
+ if (abortSignal && captureOnAbort) {
1058
+ abortSignal.addEventListener(
1059
+ "abort",
1060
+ () => {
1061
+ if (!streamCompleted && accumulatedChars > 0) {
1062
+ streamCompleted = true;
1063
+ const estimatedOutputTokens = Math.ceil(accumulatedChars / 3.8);
1064
+ handleUsage(
1065
+ {
1066
+ inputTokens: estimatedInputTokens,
1067
+ outputTokens: estimatedOutputTokens
1068
+ },
1069
+ { aborted: true, partial: true }
1070
+ );
1071
+ }
1072
+ },
1073
+ { once: true }
1074
+ );
1075
+ }
1000
1076
  const transformStream = new TransformStream({
1001
1077
  transform(chunk, controller) {
1002
1078
  controller.enqueue(chunk);
1079
+ if (chunk.type === "text-delta" && chunk.textDelta) {
1080
+ accumulatedChars += chunk.textDelta.length;
1081
+ }
1003
1082
  if (chunk.type === "finish" && chunk.usage) {
1083
+ streamCompleted = true;
1004
1084
  handleUsage(chunk.usage);
1005
1085
  }
1086
+ },
1087
+ flush() {
1088
+ if (!streamCompleted && captureOnAbort && accumulatedChars > 0) {
1089
+ streamCompleted = true;
1090
+ const estimatedOutputTokens = Math.ceil(accumulatedChars / 3.8);
1091
+ handleUsage(
1092
+ {
1093
+ inputTokens: estimatedInputTokens,
1094
+ outputTokens: estimatedOutputTokens
1095
+ },
1096
+ { aborted: true, partial: true }
1097
+ );
1098
+ }
1006
1099
  }
1007
1100
  });
1008
1101
  return {
@@ -1076,6 +1169,64 @@ function createVibezModel(modelOrId, options = {}) {
1076
1169
  }
1077
1170
  return modelOrId;
1078
1171
  }
1172
+ function createVibezSession(sessionOptions = {}) {
1173
+ const meter = createMeter({
1174
+ apiKey: sessionOptions.stripeApiKey
1175
+ });
1176
+ const customerId = typeof sessionOptions.customer === "string" ? sessionOptions.customer : sessionOptions.customer?.id;
1177
+ return {
1178
+ meter,
1179
+ model: (modelOrId, callOptions = {}) => {
1180
+ return createVibezModel(modelOrId, {
1181
+ customer: sessionOptions.customer,
1182
+ pricing: sessionOptions.pricing,
1183
+ billing: sessionOptions.billing,
1184
+ meter,
1185
+ metadata: {
1186
+ ...sessionOptions.metadata,
1187
+ ...callOptions.metadata
1188
+ },
1189
+ ...callOptions
1190
+ });
1191
+ },
1192
+ trackTool: async (name, { costUSD, metadata }) => {
1193
+ const event = {
1194
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1195
+ model: `tool:${name}`,
1196
+ provider: "tool",
1197
+ usage: {
1198
+ inputTokens: 0,
1199
+ outputTokens: 0,
1200
+ totalTokens: 0
1201
+ },
1202
+ cost: {
1203
+ inputCostUSD: 0,
1204
+ outputCostUSD: costUSD,
1205
+ totalUSD: costUSD,
1206
+ currency: "USD"
1207
+ },
1208
+ customerId,
1209
+ metadata: {
1210
+ ...sessionOptions.metadata,
1211
+ ...metadata,
1212
+ tool: name
1213
+ }
1214
+ };
1215
+ meter.recordUsage({
1216
+ model: `tool:${name}`,
1217
+ provider: "tool",
1218
+ inputTokens: 0,
1219
+ outputTokens: 0,
1220
+ customerId,
1221
+ metadata: event.metadata
1222
+ });
1223
+ await meter.flush();
1224
+ }
1225
+ };
1226
+ }
1227
+ var vibezcheck = Object.assign(createVibezModel, {
1228
+ session: createVibezSession
1229
+ });
1079
1230
 
1080
1231
  // src/customers/manager.ts
1081
1232
  var import_stripe2 = __toESM(require("stripe"));
@@ -1439,20 +1590,21 @@ var VibezCheckClient = class {
1439
1590
  function createVibezCheck(config = {}) {
1440
1591
  return new VibezCheckClient(config);
1441
1592
  }
1442
- function vibezcheck(firstArg, secondArg) {
1593
+ function vibezcheck2(firstArg, secondArg) {
1443
1594
  if (typeof firstArg === "string" || firstArg && (firstArg.specificationVersion || firstArg.doGenerate || firstArg.doStream)) {
1444
1595
  return createVibezModel(firstArg, secondArg);
1445
1596
  }
1446
1597
  return new VibezCheckClient(firstArg || {});
1447
1598
  }
1448
- vibezcheck.calculateCost = calculateCost;
1449
- vibezcheck.getModelPricing = getModelPricing;
1450
- vibezcheck.registerModelPricing = registerModelPricing;
1451
- vibezcheck.create = createVibezCheck;
1452
- vibezcheck.withBilling = withBilling;
1453
- vibezcheck.createMeter = createMeter;
1599
+ vibezcheck2.calculateCost = calculateCost;
1600
+ vibezcheck2.getModelPricing = getModelPricing;
1601
+ vibezcheck2.registerModelPricing = registerModelPricing;
1602
+ vibezcheck2.create = createVibezCheck;
1603
+ vibezcheck2.withBilling = withBilling;
1604
+ vibezcheck2.createMeter = createMeter;
1605
+ vibezcheck2.session = createVibezSession;
1454
1606
  var vibez = new VibezCheckClient();
1455
- var vibescheck = vibezcheck;
1607
+ var vibescheck = vibezcheck2;
1456
1608
  var vibes = vibez;
1457
1609
  // Annotate the CommonJS export names for ESM import in node:
1458
1610
  0 && (module.exports = {
@@ -1474,6 +1626,7 @@ var vibes = vibez;
1474
1626
  createMeter,
1475
1627
  createVibezCheck,
1476
1628
  createVibezModel,
1629
+ createVibezSession,
1477
1630
  detectAndExtractUsage,
1478
1631
  extractAnthropicResponseUsage,
1479
1632
  extractAuthToken,