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.mjs CHANGED
@@ -554,14 +554,26 @@ function registerModelPricing(modelName, rates) {
554
554
 
555
555
  // src/pricing/calculator.ts
556
556
  function calculateCost(params) {
557
- const rates = getModelPricing(params.model);
557
+ let rates;
558
+ if (params.customRate) {
559
+ const outRate = params.customRate.out ?? params.customRate.output ?? 0;
560
+ rates = {
561
+ inputPer1M: params.customRate.in,
562
+ outputPer1M: outRate,
563
+ reasoningPer1M: params.customRate.reasoning ?? outRate,
564
+ cachedInputPer1M: params.customRate.cached ?? params.customRate.in * 0.15,
565
+ currency: "USD"
566
+ };
567
+ } else {
568
+ rates = getModelPricing(params.model);
569
+ }
558
570
  const inputTokens = params.inputTokens ?? 0;
559
571
  const outputTokens = params.outputTokens ?? 0;
560
572
  const reasoningTokens = params.reasoningTokens ?? 0;
561
573
  const cachedTokens = params.cachedTokens ?? 0;
562
574
  const regularInputTokens = Math.max(0, inputTokens - cachedTokens);
563
575
  const regularInputCost = regularInputTokens / 1e6 * rates.inputPer1M;
564
- const cachedRate = rates.cachedInputPer1M ?? rates.inputPer1M * 0.5;
576
+ const cachedRate = rates.cachedInputPer1M ?? rates.inputPer1M * 0.15;
565
577
  const cachedInputCost = cachedTokens / 1e6 * cachedRate;
566
578
  const inputCostUSD = regularInputCost + cachedInputCost;
567
579
  const outputCostUSD = outputTokens / 1e6 * rates.outputPer1M;
@@ -569,20 +581,27 @@ function calculateCost(params) {
569
581
  const reasoningCostUSD = reasoningTokens / 1e6 * reasoningRate;
570
582
  const standardCacheCost = cachedTokens / 1e6 * rates.inputPer1M;
571
583
  const cachedDiscountUSD = Math.max(0, standardCacheCost - cachedInputCost);
572
- const totalUSD = inputCostUSD + outputCostUSD;
584
+ let totalUSD = inputCostUSD + outputCostUSD;
573
585
  const markup = params.markupMultiplier ?? 1;
574
- const retailUSD = markup !== 1 ? totalUSD * markup : void 0;
586
+ let retailUSD = void 0;
587
+ if (markup !== 1 || params.minimumChargeUSD !== void 0) {
588
+ retailUSD = totalUSD * markup;
589
+ if (params.minimumChargeUSD !== void 0 && retailUSD < params.minimumChargeUSD) {
590
+ retailUSD = params.minimumChargeUSD;
591
+ }
592
+ }
575
593
  return {
576
594
  inputCostUSD: Number(inputCostUSD.toFixed(8)),
577
595
  outputCostUSD: Number(outputCostUSD.toFixed(8)),
578
596
  reasoningCostUSD: reasoningTokens > 0 ? Number(reasoningCostUSD.toFixed(8)) : void 0,
579
597
  cachedDiscountUSD: cachedTokens > 0 ? Number(cachedDiscountUSD.toFixed(8)) : void 0,
580
598
  totalUSD: Number(totalUSD.toFixed(8)),
581
- retailUSD: retailUSD ? Number(retailUSD.toFixed(8)) : void 0,
599
+ retailUSD: retailUSD !== void 0 ? Number(retailUSD.toFixed(8)) : void 0,
582
600
  currency: rates.currency || "USD"
583
601
  };
584
602
  }
585
- function calculateUsageCost(model, usage, markupMultiplier) {
603
+ function calculateUsageCost(model, usage, optionsOrMarkup) {
604
+ const options = typeof optionsOrMarkup === "number" ? { markupMultiplier: optionsOrMarkup } : optionsOrMarkup || {};
586
605
  return calculateCost({
587
606
  model,
588
607
  inputTokens: usage.inputTokens,
@@ -590,7 +609,9 @@ function calculateUsageCost(model, usage, markupMultiplier) {
590
609
  reasoningTokens: usage.reasoningTokens,
591
610
  cachedTokens: usage.cachedTokens,
592
611
  cacheWriteTokens: usage.cacheWriteTokens,
593
- markupMultiplier
612
+ markupMultiplier: options.markupMultiplier,
613
+ minimumChargeUSD: options.minimumChargeUSD,
614
+ customRate: options.customRate
594
615
  });
595
616
  }
596
617
 
@@ -851,7 +872,22 @@ function withBilling(model, options = {}) {
851
872
  const customerId = typeof options.customer === "string" ? options.customer : options.customer?.id || options.customerId;
852
873
  const modelId = model.modelId || "unknown-model";
853
874
  const provider = model.provider?.replace(/^@ai-sdk\//, "") || "ai-sdk";
854
- const handleUsage = (rawUsage) => {
875
+ const maxCostPerCall = options.maxCostPerCallUSD !== void 0 ? options.maxCostPerCallUSD : 0.5;
876
+ const captureOnAbort = options.captureOnAbort !== false;
877
+ const scheduleFlush = () => {
878
+ try {
879
+ const flushPromise = meter.flush();
880
+ if (typeof globalThis !== "undefined") {
881
+ const g = globalThis;
882
+ if (typeof g.after === "function") {
883
+ g.after(() => flushPromise);
884
+ return;
885
+ }
886
+ }
887
+ } catch {
888
+ }
889
+ };
890
+ const handleUsage = (rawUsage, extraMeta) => {
855
891
  if (!rawUsage) return;
856
892
  const inputTokens = rawUsage.promptTokens ?? rawUsage.inputTokens ?? 0;
857
893
  const outputTokens = rawUsage.completionTokens ?? rawUsage.outputTokens ?? 0;
@@ -865,15 +901,19 @@ function withBilling(model, options = {}) {
865
901
  visibleOutputTokens: Math.max(0, outputTokens - reasoningTokens),
866
902
  cachedTokens: cachedTokens > 0 ? cachedTokens : void 0
867
903
  };
868
- const cost = calculateUsageCost(modelId, usage);
869
- if (options.maxCostPerCallUSD && cost.totalUSD > options.maxCostPerCallUSD) {
904
+ const cost = calculateUsageCost(modelId, usage, {
905
+ markupMultiplier: options.pricing?.margin,
906
+ minimumChargeUSD: options.pricing?.minimumChargeUSD,
907
+ customRate: options.rate
908
+ });
909
+ if (maxCostPerCall > 0 && maxCostPerCall !== Infinity && cost.totalUSD > maxCostPerCall) {
870
910
  const budgetEvent = {
871
911
  reason: "cost_per_call_exceeded",
872
- limit: options.maxCostPerCallUSD,
912
+ limit: maxCostPerCall,
873
913
  current: cost.totalUSD,
874
914
  model: modelId,
875
915
  customerId,
876
- message: `[vibezcheck] Circuit Breaker tripped: Call cost ($${cost.totalUSD.toFixed(4)}) exceeded maxCostPerCallUSD threshold ($${options.maxCostPerCallUSD.toFixed(4)}).`
916
+ message: `[vibezcheck] Circuit Breaker tripped: Call cost ($${cost.totalUSD.toFixed(4)}) exceeded budget ceiling ($${maxCostPerCall.toFixed(4)}).`
877
917
  };
878
918
  if (options.onBudgetExceeded) {
879
919
  options.onBudgetExceeded(budgetEvent);
@@ -905,7 +945,11 @@ function withBilling(model, options = {}) {
905
945
  usage,
906
946
  cost,
907
947
  customerId,
908
- metadata: options.metadata
948
+ metadata: {
949
+ ...options.metadata,
950
+ ...extraMeta,
951
+ billingMode: options.billing?.mode || "postpaid"
952
+ }
909
953
  };
910
954
  meter.recordUsage({
911
955
  model: modelId,
@@ -915,11 +959,12 @@ function withBilling(model, options = {}) {
915
959
  reasoningTokens: usage.reasoningTokens,
916
960
  cachedTokens: usage.cachedTokens,
917
961
  customerId,
918
- metadata: options.metadata
962
+ metadata: event.metadata
919
963
  });
920
964
  if (options.onUsage) {
921
965
  options.onUsage(event);
922
966
  }
967
+ scheduleFlush();
923
968
  };
924
969
  const handler = {
925
970
  get(target, prop, receiver) {
@@ -931,12 +976,59 @@ function withBilling(model, options = {}) {
931
976
  return result;
932
977
  }
933
978
  const originalStream = result.stream;
979
+ let streamCompleted = false;
980
+ let accumulatedChars = 0;
981
+ let estimatedInputTokens = 0;
982
+ try {
983
+ if (args[0]?.prompt) {
984
+ const str = typeof args[0].prompt === "string" ? args[0].prompt : JSON.stringify(args[0].prompt);
985
+ estimatedInputTokens = Math.ceil(str.length / 4);
986
+ }
987
+ } catch {
988
+ }
989
+ const abortSignal = args[0]?.abortSignal;
990
+ if (abortSignal && captureOnAbort) {
991
+ abortSignal.addEventListener(
992
+ "abort",
993
+ () => {
994
+ if (!streamCompleted && accumulatedChars > 0) {
995
+ streamCompleted = true;
996
+ const estimatedOutputTokens = Math.ceil(accumulatedChars / 3.8);
997
+ handleUsage(
998
+ {
999
+ inputTokens: estimatedInputTokens,
1000
+ outputTokens: estimatedOutputTokens
1001
+ },
1002
+ { aborted: true, partial: true }
1003
+ );
1004
+ }
1005
+ },
1006
+ { once: true }
1007
+ );
1008
+ }
934
1009
  const transformStream = new TransformStream({
935
1010
  transform(chunk, controller) {
936
1011
  controller.enqueue(chunk);
1012
+ if (chunk.type === "text-delta" && chunk.textDelta) {
1013
+ accumulatedChars += chunk.textDelta.length;
1014
+ }
937
1015
  if (chunk.type === "finish" && chunk.usage) {
1016
+ streamCompleted = true;
938
1017
  handleUsage(chunk.usage);
939
1018
  }
1019
+ },
1020
+ flush() {
1021
+ if (!streamCompleted && captureOnAbort && accumulatedChars > 0) {
1022
+ streamCompleted = true;
1023
+ const estimatedOutputTokens = Math.ceil(accumulatedChars / 3.8);
1024
+ handleUsage(
1025
+ {
1026
+ inputTokens: estimatedInputTokens,
1027
+ outputTokens: estimatedOutputTokens
1028
+ },
1029
+ { aborted: true, partial: true }
1030
+ );
1031
+ }
940
1032
  }
941
1033
  });
942
1034
  return {
@@ -1010,6 +1102,64 @@ function createVibezModel(modelOrId, options = {}) {
1010
1102
  }
1011
1103
  return modelOrId;
1012
1104
  }
1105
+ function createVibezSession(sessionOptions = {}) {
1106
+ const meter = createMeter({
1107
+ apiKey: sessionOptions.stripeApiKey
1108
+ });
1109
+ const customerId = typeof sessionOptions.customer === "string" ? sessionOptions.customer : sessionOptions.customer?.id;
1110
+ return {
1111
+ meter,
1112
+ model: (modelOrId, callOptions = {}) => {
1113
+ return createVibezModel(modelOrId, {
1114
+ customer: sessionOptions.customer,
1115
+ pricing: sessionOptions.pricing,
1116
+ billing: sessionOptions.billing,
1117
+ meter,
1118
+ metadata: {
1119
+ ...sessionOptions.metadata,
1120
+ ...callOptions.metadata
1121
+ },
1122
+ ...callOptions
1123
+ });
1124
+ },
1125
+ trackTool: async (name, { costUSD, metadata }) => {
1126
+ const event = {
1127
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1128
+ model: `tool:${name}`,
1129
+ provider: "tool",
1130
+ usage: {
1131
+ inputTokens: 0,
1132
+ outputTokens: 0,
1133
+ totalTokens: 0
1134
+ },
1135
+ cost: {
1136
+ inputCostUSD: 0,
1137
+ outputCostUSD: costUSD,
1138
+ totalUSD: costUSD,
1139
+ currency: "USD"
1140
+ },
1141
+ customerId,
1142
+ metadata: {
1143
+ ...sessionOptions.metadata,
1144
+ ...metadata,
1145
+ tool: name
1146
+ }
1147
+ };
1148
+ meter.recordUsage({
1149
+ model: `tool:${name}`,
1150
+ provider: "tool",
1151
+ inputTokens: 0,
1152
+ outputTokens: 0,
1153
+ customerId,
1154
+ metadata: event.metadata
1155
+ });
1156
+ await meter.flush();
1157
+ }
1158
+ };
1159
+ }
1160
+ var vibezcheck = Object.assign(createVibezModel, {
1161
+ session: createVibezSession
1162
+ });
1013
1163
 
1014
1164
  // src/customers/manager.ts
1015
1165
  import Stripe2 from "stripe";
@@ -1373,20 +1523,21 @@ var VibezCheckClient = class {
1373
1523
  function createVibezCheck(config = {}) {
1374
1524
  return new VibezCheckClient(config);
1375
1525
  }
1376
- function vibezcheck(firstArg, secondArg) {
1526
+ function vibezcheck2(firstArg, secondArg) {
1377
1527
  if (typeof firstArg === "string" || firstArg && (firstArg.specificationVersion || firstArg.doGenerate || firstArg.doStream)) {
1378
1528
  return createVibezModel(firstArg, secondArg);
1379
1529
  }
1380
1530
  return new VibezCheckClient(firstArg || {});
1381
1531
  }
1382
- vibezcheck.calculateCost = calculateCost;
1383
- vibezcheck.getModelPricing = getModelPricing;
1384
- vibezcheck.registerModelPricing = registerModelPricing;
1385
- vibezcheck.create = createVibezCheck;
1386
- vibezcheck.withBilling = withBilling;
1387
- vibezcheck.createMeter = createMeter;
1532
+ vibezcheck2.calculateCost = calculateCost;
1533
+ vibezcheck2.getModelPricing = getModelPricing;
1534
+ vibezcheck2.registerModelPricing = registerModelPricing;
1535
+ vibezcheck2.create = createVibezCheck;
1536
+ vibezcheck2.withBilling = withBilling;
1537
+ vibezcheck2.createMeter = createMeter;
1538
+ vibezcheck2.session = createVibezSession;
1388
1539
  var vibez = new VibezCheckClient();
1389
- var vibescheck = vibezcheck;
1540
+ var vibescheck = vibezcheck2;
1390
1541
  var vibes = vibez;
1391
1542
  export {
1392
1543
  AnthropicStreamAccumulator,
@@ -1407,6 +1558,7 @@ export {
1407
1558
  createMeter,
1408
1559
  createVibezCheck,
1409
1560
  createVibezModel,
1561
+ createVibezSession,
1410
1562
  detectAndExtractUsage,
1411
1563
  extractAnthropicResponseUsage,
1412
1564
  extractAuthToken,
@@ -1422,7 +1574,7 @@ export {
1422
1574
  vibes,
1423
1575
  vibescheck,
1424
1576
  vibez,
1425
- vibezcheck,
1577
+ vibezcheck2 as vibezcheck,
1426
1578
  withBilling,
1427
1579
  wrapAnthropicStream,
1428
1580
  wrapGeminiStream,