llm-usage-metrics 0.1.9 → 0.1.11

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
@@ -1729,7 +1729,11 @@ var litellm_model_map_default = {
1729
1729
  "claude-sonnet-4.6": "claude-sonnet-4.6",
1730
1730
  "claude-sonnet-4-6": "claude-sonnet-4.6",
1731
1731
  "anthropic/claude-sonnet-4.6": "claude-sonnet-4.6",
1732
- "anthropic.claude-sonnet-4-6": "claude-sonnet-4.6"
1732
+ "anthropic.claude-sonnet-4-6": "claude-sonnet-4.6",
1733
+ "gpt-5.3-codex": "gpt-5.2-codex"
1734
+ },
1735
+ notes: {
1736
+ "gpt-5.3-codex": "Temporary fallback to gpt-5.2-codex until upstream publishes direct gpt-5.3-codex token pricing"
1733
1737
  },
1734
1738
  preferredPricingKeyByCanonicalModel: {
1735
1739
  "kimi-k2.5": "moonshot/kimi-k2.5",
@@ -2766,7 +2770,6 @@ function renderReportHeader(options) {
2766
2770
 
2767
2771
  // src/render/terminal-table.ts
2768
2772
  import pc4 from "picocolors";
2769
- import { table } from "table";
2770
2773
 
2771
2774
  // src/render/terminal-style-policy.ts
2772
2775
  import pc3 from "picocolors";
@@ -2781,6 +2784,9 @@ var defaultTerminalStylePalette = {
2781
2784
  dim: pc3.dim
2782
2785
  };
2783
2786
  var passthroughStyler = (text) => text;
2787
+ function styleCellLines(cell, styler) {
2788
+ return cell.split("\n").map((line) => line.length === 0 ? "" : styler(line)).join("\n");
2789
+ }
2784
2790
  var sourceStylePolicies = /* @__PURE__ */ new Map([
2785
2791
  ["pi", (palette) => palette.cyan],
2786
2792
  ["codex", (palette) => palette.magenta],
@@ -2797,23 +2803,23 @@ var rowTypeStylePolicies = {
2797
2803
  period_source: (cells, palette) => {
2798
2804
  const styledCells = [...cells];
2799
2805
  const costColumnIndex = styledCells.length - 1;
2800
- styledCells[costColumnIndex] = palette.yellow(styledCells[costColumnIndex]);
2806
+ styledCells[costColumnIndex] = styleCellLines(styledCells[costColumnIndex], palette.yellow);
2801
2807
  return styledCells;
2802
2808
  },
2803
2809
  period_combined: (cells, palette) => cells.map((cell, cellIndex) => {
2804
2810
  if (cellIndex === 1) {
2805
- return palette.bold(palette.yellow(cell));
2811
+ return styleCellLines(cell, (line) => palette.bold(palette.yellow(line)));
2806
2812
  }
2807
- return palette.dim(cell);
2813
+ return styleCellLines(cell, palette.dim);
2808
2814
  }),
2809
2815
  grand_total: (cells, palette) => cells.map((cell, cellIndex) => {
2810
2816
  if (cellIndex === 0) {
2811
- return palette.bold(palette.white(cell));
2817
+ return styleCellLines(cell, (line) => palette.bold(palette.white(line)));
2812
2818
  }
2813
2819
  if (cellIndex === 1) {
2814
- return palette.bold(palette.green(cell));
2820
+ return styleCellLines(cell, (line) => palette.bold(palette.green(line)));
2815
2821
  }
2816
- return palette.bold(cell);
2822
+ return styleCellLines(cell, palette.bold);
2817
2823
  })
2818
2824
  };
2819
2825
  function applyRowTypeStyle(rowType, cells, palette = defaultTerminalStylePalette) {
@@ -2824,8 +2830,8 @@ function applyBaseCellStyle(cells, palette, sourceStyler) {
2824
2830
  return [...cells];
2825
2831
  }
2826
2832
  const styledCells = [...cells];
2827
- styledCells[0] = palette.white(styledCells[0]);
2828
- styledCells[1] = sourceStyler(styledCells[1]);
2833
+ styledCells[0] = styleCellLines(styledCells[0], palette.white);
2834
+ styledCells[1] = styleCellLines(styledCells[1], sourceStyler);
2829
2835
  return styledCells;
2830
2836
  }
2831
2837
  function colorizeUsageBodyRows(bodyRows, rows, options) {
@@ -2840,66 +2846,291 @@ function colorizeUsageBodyRows(bodyRows, rows, options) {
2840
2846
  });
2841
2847
  }
2842
2848
 
2843
- // src/render/terminal-table.ts
2844
- var modelsColumnIndex = 2;
2845
- var roundedBorders = {
2846
- topBody: "\u2500",
2847
- topJoin: "\u252C",
2848
- topLeft: "\u256D",
2849
- topRight: "\u256E",
2850
- bottomBody: "\u2500",
2851
- bottomJoin: "\u2534",
2852
- bottomLeft: "\u2570",
2853
- bottomRight: "\u256F",
2854
- bodyLeft: "\u2502",
2855
- bodyRight: "\u2502",
2856
- bodyJoin: "\u2502",
2857
- headerJoin: "\u252C",
2858
- joinBody: "\u2500",
2859
- joinLeft: "\u251C",
2860
- joinRight: "\u2524",
2861
- joinJoin: "\u253C",
2862
- joinMiddleDown: "\u252C",
2863
- joinMiddleUp: "\u2534",
2864
- joinMiddleLeft: "\u2524",
2865
- joinMiddleRight: "\u251C"
2866
- };
2867
- function shouldDrawHorizontalLine(index, rowCount, usageRows) {
2868
- if (index === 0 || index === 1 || index === rowCount) {
2849
+ // src/render/table-text-layout.ts
2850
+ var ansiEscapePattern = new RegExp(String.raw`\u001B\[[0-9;]*m`, "gu");
2851
+ var combiningMarkPattern = /\p{Mark}/u;
2852
+ var extendedPictographicPattern = /\p{Extended_Pictographic}/u;
2853
+ var emojiPresentationPattern = /\p{Emoji_Presentation}/u;
2854
+ var regionalIndicatorPattern = /\p{Regional_Indicator}/u;
2855
+ var graphemeSegmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
2856
+ function normalizeLineBreaks(value) {
2857
+ return value.replace(/\r\n?/gu, "\n");
2858
+ }
2859
+ function stripAnsi(value) {
2860
+ return value.replaceAll(ansiEscapePattern, "");
2861
+ }
2862
+ function isControlCodePoint(codePoint) {
2863
+ return codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
2864
+ }
2865
+ function isZeroWidthCodePoint(codePoint) {
2866
+ return codePoint === 8203 || codePoint === 8205 || codePoint === 8288 || codePoint === 65279 || codePoint >= 65024 && codePoint <= 65039;
2867
+ }
2868
+ function isFullWidthCodePoint(codePoint) {
2869
+ if (Number.isNaN(codePoint)) {
2870
+ return false;
2871
+ }
2872
+ if (codePoint >= 4352 && (codePoint <= 4447 || codePoint === 9001 || codePoint === 9002 || codePoint >= 11904 && codePoint <= 12871 && codePoint !== 12351 || codePoint >= 12880 && codePoint <= 19903 || codePoint >= 19968 && codePoint <= 42182 || codePoint >= 43360 && codePoint <= 43388 || codePoint >= 44032 && codePoint <= 55203 || codePoint >= 63744 && codePoint <= 64255 || codePoint >= 65040 && codePoint <= 65049 || codePoint >= 65072 && codePoint <= 65131 || codePoint >= 65281 && codePoint <= 65376 || codePoint >= 65504 && codePoint <= 65510 || codePoint >= 110592 && codePoint <= 110593 || codePoint >= 127488 && codePoint <= 127569 || codePoint >= 131072 && codePoint <= 262141)) {
2873
+ return true;
2874
+ }
2875
+ return false;
2876
+ }
2877
+ function codePointDisplayWidth(character) {
2878
+ const codePoint = character.codePointAt(0);
2879
+ if (codePoint === void 0) {
2880
+ return 0;
2881
+ }
2882
+ if (isControlCodePoint(codePoint) || isZeroWidthCodePoint(codePoint)) {
2883
+ return 0;
2884
+ }
2885
+ if (combiningMarkPattern.test(character)) {
2886
+ return 0;
2887
+ }
2888
+ if (isFullWidthCodePoint(codePoint)) {
2889
+ return 2;
2890
+ }
2891
+ return 1;
2892
+ }
2893
+ function segmentGraphemes(value) {
2894
+ return Array.from(graphemeSegmenter.segment(value), (segment) => segment.segment);
2895
+ }
2896
+ function isEmojiGrapheme(grapheme) {
2897
+ if (emojiPresentationPattern.test(grapheme)) {
2898
+ return true;
2899
+ }
2900
+ if (regionalIndicatorPattern.test(grapheme)) {
2901
+ return true;
2902
+ }
2903
+ if (grapheme.includes("\u20E3")) {
2904
+ return true;
2905
+ }
2906
+ if (grapheme.includes("\uFE0F")) {
2869
2907
  return true;
2870
2908
  }
2871
- const previousRow = usageRows[index - 2];
2872
- const nextRow = usageRows[index - 1];
2909
+ return grapheme.includes("\u200D") && extendedPictographicPattern.test(grapheme);
2910
+ }
2911
+ function graphemeDisplayWidth(grapheme) {
2912
+ if (isEmojiGrapheme(grapheme)) {
2913
+ return 2;
2914
+ }
2915
+ let width = 0;
2916
+ for (const character of grapheme) {
2917
+ width = Math.max(width, codePointDisplayWidth(character));
2918
+ }
2919
+ return width;
2920
+ }
2921
+ function visibleWidth(value) {
2922
+ let width = 0;
2923
+ for (const grapheme of segmentGraphemes(stripAnsi(value))) {
2924
+ width += graphemeDisplayWidth(grapheme);
2925
+ }
2926
+ return width;
2927
+ }
2928
+ function splitCellLines(value) {
2929
+ return normalizeLineBreaks(value).split("\n");
2930
+ }
2931
+ function sliceByVisibleWidth(value, maxWidth) {
2932
+ if (maxWidth <= 0) {
2933
+ return "";
2934
+ }
2935
+ let width = 0;
2936
+ let endOffset = 0;
2937
+ for (const grapheme of segmentGraphemes(value)) {
2938
+ const graphemeWidth = graphemeDisplayWidth(grapheme);
2939
+ if (width + graphemeWidth > maxWidth) {
2940
+ break;
2941
+ }
2942
+ width += graphemeWidth;
2943
+ endOffset += grapheme.length;
2944
+ }
2945
+ return value.slice(0, endOffset);
2946
+ }
2947
+ function getFirstGrapheme(value) {
2948
+ for (const grapheme of segmentGraphemes(value)) {
2949
+ return grapheme;
2950
+ }
2951
+ return "";
2952
+ }
2953
+ function wrapPlainLine(line, width) {
2954
+ if (visibleWidth(line) <= width) {
2955
+ return [line];
2956
+ }
2957
+ const wrappedLines = [];
2958
+ let remaining = line;
2959
+ while (visibleWidth(remaining) > width) {
2960
+ const slice = sliceByVisibleWidth(remaining, width + 1);
2961
+ const breakIndex = slice.lastIndexOf(" ");
2962
+ if (breakIndex > 0) {
2963
+ wrappedLines.push(remaining.slice(0, breakIndex));
2964
+ remaining = remaining.slice(breakIndex + 1);
2965
+ continue;
2966
+ }
2967
+ const chunk = sliceByVisibleWidth(remaining, width);
2968
+ if (chunk.length > 0) {
2969
+ wrappedLines.push(chunk);
2970
+ remaining = remaining.slice(chunk.length);
2971
+ continue;
2972
+ }
2973
+ const firstCharacter = getFirstGrapheme(remaining);
2974
+ wrappedLines.push(firstCharacter);
2975
+ remaining = remaining.slice(firstCharacter.length);
2976
+ }
2977
+ wrappedLines.push(remaining);
2978
+ return wrappedLines;
2979
+ }
2980
+ function wrapTableColumn(rows, options) {
2981
+ if (options.width <= 0) {
2982
+ throw new RangeError("wrapTableColumn width must be greater than 0");
2983
+ }
2984
+ return rows.map((row) => {
2985
+ const wrappedRow = [...row];
2986
+ const cell = wrappedRow[options.columnIndex] ?? "";
2987
+ const wrappedLines = splitCellLines(cell).flatMap((line) => wrapPlainLine(line, options.width));
2988
+ wrappedRow[options.columnIndex] = wrappedLines.join("\n");
2989
+ return wrappedRow;
2990
+ });
2991
+ }
2992
+
2993
+ // src/render/unicode-table.ts
2994
+ function getColumnAlignment(columnIndex, modelsColumnIndex2) {
2995
+ if (columnIndex <= modelsColumnIndex2) {
2996
+ return "left";
2997
+ }
2998
+ return "right";
2999
+ }
3000
+ function getVerticalAlignment(columnIndex, tableLayout, modelsColumnIndex2) {
3001
+ if (columnIndex === modelsColumnIndex2) {
3002
+ return "top";
3003
+ }
3004
+ return tableLayout === "per_model_columns" ? "top" : "middle";
3005
+ }
3006
+ function alignCellLine(value, width, alignment2) {
3007
+ const padding = Math.max(0, width - visibleWidth(value));
3008
+ if (alignment2 === "right") {
3009
+ return `${" ".repeat(padding)}${value}`;
3010
+ }
3011
+ return `${value}${" ".repeat(padding)}`;
3012
+ }
3013
+ function padCellLines(lines, rowHeight, verticalAlignment) {
3014
+ const missingLineCount = rowHeight - lines.length;
3015
+ if (missingLineCount <= 0) {
3016
+ return lines;
3017
+ }
3018
+ if (verticalAlignment === "top") {
3019
+ return [...lines, ...Array.from({ length: missingLineCount }, () => "")];
3020
+ }
3021
+ const topPadding = Math.floor(missingLineCount / 2);
3022
+ const bottomPadding = missingLineCount - topPadding;
3023
+ return [
3024
+ ...Array.from({ length: topPadding }, () => ""),
3025
+ ...lines,
3026
+ ...Array.from({ length: bottomPadding }, () => "")
3027
+ ];
3028
+ }
3029
+ function toRenderableRowLines(row, options) {
3030
+ const cellLines = row.map((cell) => splitCellLines(cell));
3031
+ const rowHeight = cellLines.reduce((max, lines) => Math.max(max, lines.length), 1);
3032
+ const paddedAlignedColumns = cellLines.map((lines, columnIndex) => {
3033
+ const verticalAlignment = getVerticalAlignment(
3034
+ columnIndex,
3035
+ options.tableLayout,
3036
+ options.modelsColumnIndex
3037
+ );
3038
+ const alignedLines = padCellLines(lines, rowHeight, verticalAlignment);
3039
+ const horizontalAlignment = getColumnAlignment(columnIndex, options.modelsColumnIndex);
3040
+ return alignedLines.map(
3041
+ (line) => alignCellLine(line, options.widths[columnIndex], horizontalAlignment)
3042
+ );
3043
+ });
3044
+ return Array.from({ length: rowHeight }, (_, lineIndex) => {
3045
+ const lineCells = paddedAlignedColumns.map((columnLines) => columnLines[lineIndex]);
3046
+ return `\u2502 ${lineCells.join(" \u2502 ")} \u2502`;
3047
+ });
3048
+ }
3049
+ function buildBorderLine(widths, chars) {
3050
+ const segments = widths.map((width) => "\u2500".repeat(width + 2));
3051
+ return `${chars.left}${segments.join(chars.join)}${chars.right}`;
3052
+ }
3053
+ function shouldDrawBodySeparator(index, usageRows) {
3054
+ if (index < 0 || index >= usageRows.length - 1) {
3055
+ return false;
3056
+ }
3057
+ const previousRow = usageRows[index];
3058
+ const nextRow = usageRows[index + 1];
2873
3059
  return previousRow.rowType === "period_combined" || nextRow.rowType === "grand_total" || previousRow.periodKey !== nextRow.periodKey;
2874
3060
  }
2875
- function createTableConfig(tableLayout, usageRows) {
2876
- const rowVerticalAlignment = tableLayout === "per_model_columns" ? "top" : "middle";
2877
- return {
2878
- border: roundedBorders,
2879
- drawHorizontalLine: (index, rowCount) => shouldDrawHorizontalLine(index, rowCount, usageRows),
2880
- columnDefault: {
2881
- paddingLeft: 1,
2882
- paddingRight: 1,
2883
- verticalAlignment: "top"
2884
- },
2885
- columns: {
2886
- 0: { alignment: "left", verticalAlignment: rowVerticalAlignment },
2887
- 1: { alignment: "left", verticalAlignment: rowVerticalAlignment },
2888
- [modelsColumnIndex]: {
2889
- alignment: "left",
2890
- width: 32,
2891
- wrapWord: true
2892
- },
2893
- 3: { alignment: "right", verticalAlignment: rowVerticalAlignment },
2894
- 4: { alignment: "right", verticalAlignment: rowVerticalAlignment },
2895
- 5: { alignment: "right", verticalAlignment: rowVerticalAlignment },
2896
- 6: { alignment: "right", verticalAlignment: rowVerticalAlignment },
2897
- 7: { alignment: "right", verticalAlignment: rowVerticalAlignment },
2898
- 8: { alignment: "right", verticalAlignment: rowVerticalAlignment },
2899
- 9: { alignment: "right", verticalAlignment: rowVerticalAlignment }
3061
+ function computeColumnWidths(measureRows, options) {
3062
+ const columnCount = measureRows[0]?.length ?? 0;
3063
+ const widths = Array.from({ length: columnCount }, () => 0);
3064
+ for (const row of measureRows) {
3065
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex += 1) {
3066
+ for (const line of splitCellLines(row[columnIndex])) {
3067
+ widths[columnIndex] = Math.max(widths[columnIndex], visibleWidth(line));
3068
+ }
2900
3069
  }
2901
- };
3070
+ }
3071
+ widths[options.modelsColumnIndex] = options.modelsColumnWidth;
3072
+ return widths;
2902
3073
  }
3074
+ function renderUnicodeTable(options) {
3075
+ const measureRows = [options.measureHeaderCells, ...options.measureBodyRows];
3076
+ const widths = computeColumnWidths(measureRows, {
3077
+ modelsColumnIndex: options.modelsColumnIndex,
3078
+ modelsColumnWidth: options.modelsColumnWidth
3079
+ });
3080
+ const renderedLines = [];
3081
+ renderedLines.push(
3082
+ buildBorderLine(widths, {
3083
+ left: "\u256D",
3084
+ join: "\u252C",
3085
+ right: "\u256E"
3086
+ })
3087
+ );
3088
+ renderedLines.push(
3089
+ ...toRenderableRowLines(options.headerCells, {
3090
+ widths,
3091
+ tableLayout: "per_model_columns",
3092
+ modelsColumnIndex: options.modelsColumnIndex
3093
+ })
3094
+ );
3095
+ renderedLines.push(
3096
+ buildBorderLine(widths, {
3097
+ left: "\u251C",
3098
+ join: "\u253C",
3099
+ right: "\u2524"
3100
+ })
3101
+ );
3102
+ options.bodyRows.forEach((row, rowIndex) => {
3103
+ renderedLines.push(
3104
+ ...toRenderableRowLines(row, {
3105
+ widths,
3106
+ tableLayout: options.tableLayout,
3107
+ modelsColumnIndex: options.modelsColumnIndex
3108
+ })
3109
+ );
3110
+ if (rowIndex < options.bodyRows.length - 1 && shouldDrawBodySeparator(rowIndex, options.usageRows)) {
3111
+ renderedLines.push(
3112
+ buildBorderLine(widths, {
3113
+ left: "\u251C",
3114
+ join: "\u253C",
3115
+ right: "\u2524"
3116
+ })
3117
+ );
3118
+ }
3119
+ });
3120
+ renderedLines.push(
3121
+ buildBorderLine(widths, {
3122
+ left: "\u2570",
3123
+ join: "\u2534",
3124
+ right: "\u256F"
3125
+ })
3126
+ );
3127
+ return `${renderedLines.join("\n")}
3128
+ `;
3129
+ }
3130
+
3131
+ // src/render/terminal-table.ts
3132
+ var modelsColumnIndex = 2;
3133
+ var modelsColumnWidth = 32;
2903
3134
  function shouldUseColorByDefault() {
2904
3135
  if (process.env.NO_COLOR !== void 0) {
2905
3136
  return false;
@@ -2921,9 +3152,21 @@ function renderTerminalTable(rows, options = {}) {
2921
3152
  const useColor = options.useColor ?? shouldUseColorByDefault();
2922
3153
  const tableLayout = options.tableLayout ?? "compact";
2923
3154
  const uncoloredBodyRows = toUsageTableCells(rows, { layout: tableLayout });
2924
- const bodyRows = colorizeUsageBodyRows(uncoloredBodyRows, rows, { useColor });
2925
- const displayRows = [colorizeHeader(useColor), ...bodyRows];
2926
- return table(displayRows, createTableConfig(tableLayout, rows));
3155
+ const wrappedBodyRows = wrapTableColumn(uncoloredBodyRows, {
3156
+ columnIndex: modelsColumnIndex,
3157
+ width: modelsColumnWidth
3158
+ });
3159
+ const bodyRows = colorizeUsageBodyRows(wrappedBodyRows, rows, { useColor });
3160
+ return renderUnicodeTable({
3161
+ headerCells: colorizeHeader(useColor),
3162
+ bodyRows,
3163
+ measureHeaderCells: usageTableHeaders,
3164
+ measureBodyRows: wrappedBodyRows,
3165
+ usageRows: rows,
3166
+ tableLayout,
3167
+ modelsColumnIndex,
3168
+ modelsColumnWidth
3169
+ });
2927
3170
  }
2928
3171
 
2929
3172
  // src/render/render-usage-report.ts