@trazum/cli 1.26.0 → 1.27.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
@@ -2,7 +2,7 @@
2
2
  import { readdir, readFile, stat, writeFile } from 'node:fs/promises';
3
3
  import { join, resolve as resolvePath } from 'node:path';
4
4
  import { gunzipSync } from 'node:zlib';
5
- import { applyRewrites, BASELINE_FILENAME, BASELINE_VERSION, breaches, cacheableMinimum, analyzeCachePrefix, billLevers, cacheEconomics, cacheHitRate, comparePrompts, compareToBaseline, computeSavings, countTokensAnthropic, DEFAULT_USAGE, detectFromSource, driversBetween, estimateTokens, evaluate, extractPrompts, findExamples, formatBaseline, formatSignedUsd, formatUsd, getMessages, getModel, hasMarker, LOCALES, MAX_BASELINE_BYTES, moneyIsComparable, mostSpecificMatch, nearestName, optimize, parseBaseline, PHRASE_LANGUAGES, plannedCalls, profilePrompt, profileToCsv, profileUsage, promptId, providerFromEnv, pruneExamples, refineWithLlm, rejectionText, reorderForCache, repriceProfile, reviewAgeDays, reviewExamples, RULES, sharedPrefixes, sharesOf, SOURCE_EXTENSIONS, suggestRewrites, toOtlpMetrics, toPromptfoo, TTL_1H_MS, UNLABELLED, withExactTokenCounts, } from '@trazum/core';
5
+ import { applyRewrites, BASELINE_FILENAME, BASELINE_VERSION, breaches, cacheableMinimum, analyzeCachePrefix, billLevers, cacheEconomics, cacheHitRate, contextPressure, comparePrompts, compareToBaseline, computeSavings, countTokensAnthropic, DEFAULT_USAGE, detectFromSource, driversBetween, estimateTokens, evaluate, extractPrompts, findExamples, formatBaseline, formatSignedUsd, formatUsd, getMessages, getModel, hasMarker, LOCALES, MAX_BASELINE_BYTES, moneyIsComparable, mostSpecificMatch, nearestName, optimize, parseBaseline, PHRASE_LANGUAGES, plannedCalls, profilePrompt, profileToCsv, profileUsage, promptId, providerFromEnv, pruneExamples, refineWithLlm, rejectionText, reorderForCache, repriceProfile, reviewAgeDays, reviewExamples, RULES, sharedPrefixes, sharesOf, SOURCE_EXTENSIONS, suggestRewrites, toOtlpMetrics, toPromptfoo, TTL_1H_MS, UNLABELLED, withExactTokenCounts, } from '@trazum/core';
6
6
  import { cacheDir, cacheStats, cachingProvider, clearCache } from './suggest-cache.js';
7
7
  import { dayOf, formatGap, median, spanDays } from './time.js';
8
8
  // Everything that reads the filesystem, on its own entry point so the web
@@ -1660,6 +1660,12 @@ async function commandProfile(args, config, pricing, t) {
1660
1660
  * got a report with no answer in it, and has no way to tell a typo from a
1661
1661
  * model this comparison had nothing to say about.
1662
1662
  */
1663
+ /**
1664
+ * The largest call against each model's window, computed once here so the
1665
+ * terminal, the JSON and the markdown state the same ratio — the
1666
+ * denominator lives in the (possibly overlaid) catalogue.
1667
+ */
1668
+ const pressures = contextPressure(report, pricing);
1663
1669
  const whatIfModel = stringFlag(args, 'what-if');
1664
1670
  const whatIf = whatIfModel !== undefined ? repriceProfile(report, whatIfModel, pricing) : null;
1665
1671
  if (whatIfModel !== undefined && whatIf === null) {
@@ -1899,6 +1905,7 @@ async function commandProfile(args, config, pricing, t) {
1899
1905
  // handed over, so the summary in a pull request cannot disagree
1900
1906
  // with the terminal about what a move would cost.
1901
1907
  ...(whatIf !== null ? { whatIf } : {}),
1908
+ pressure: pressures,
1902
1909
  // The comparison, when there was one — the same figures and the same
1903
1910
  // drivers the terminal printed, never re-derived here.
1904
1911
  ...(previous !== null
@@ -1994,6 +2001,10 @@ async function commandProfile(args, config, pricing, t) {
1994
2001
  },
1995
2002
  }
1996
2003
  : {}),
2004
+ // How close each slice's largest call is to its model's window —
2005
+ // derived like `cache` and `levers`, so a dashboard need not
2006
+ // re-derive a ratio whose denominator lives in the catalogue.
2007
+ contextPressure: pressures,
1997
2008
  // Present only when --what-if was passed. `sameTokensAssumed` rides
1998
2009
  // along inside it so a consumer cannot print the dollar figure
1999
2010
  // without the caveat being in the same object.
@@ -2697,6 +2708,52 @@ async function commandProfile(args, config, pricing, t) {
2697
2708
  }
2698
2709
  }
2699
2710
  }
2711
+ /**
2712
+ * How close the largest call is to the model's ceiling.
2713
+ *
2714
+ * The failure a bill cannot show: input grows turn by turn or document by
2715
+ * document, costs nothing extra to grow, and then one call crosses the
2716
+ * context window and the API refuses it. Loud from 85% — close enough
2717
+ * that the next retrieval bump or long conversation plausibly crosses —
2718
+ * and quiet above half, so the reader sees it coming either way. No
2719
+ * prediction of *when*: a straight line through two points is a guess
2720
+ * wearing arithmetic's clothes.
2721
+ */
2722
+ {
2723
+ if (pressures.length > 0) {
2724
+ console.log();
2725
+ console.log(c.bold(t.profile.pressureHeading()));
2726
+ for (const row of pressures.slice(0, 3)) {
2727
+ const label = row.label === UNLABELLED ? t.profile.unlabelled() : row.label;
2728
+ const line = t.profile.pressureLine(label, row.modelName, n(row.maxCallInputTokens), n(row.contextWindow), pct(row.share));
2729
+ console.log();
2730
+ if (row.share >= 0.85) {
2731
+ console.log(` ${c.yellow('!')} ${c.bold(wrap(line, 74, ' '))}`);
2732
+ console.log(` ${c.dim(wrap(t.profile.pressureAdvice(), 74, ' '))}`);
2733
+ }
2734
+ else {
2735
+ console.log(` ${c.dim(wrap(line, 74, ' '))}`);
2736
+ }
2737
+ }
2738
+ }
2739
+ }
2740
+ /**
2741
+ * The mix moving inside one log — the drift `--against` needs a second log
2742
+ * to see. Spoken only past fifteen points, a presentation threshold stated
2743
+ * in the copy; the data states exact shares and the JSON carries them all.
2744
+ */
2745
+ if (report.modelMixDrift !== null) {
2746
+ const moved = report.modelMixDrift.models.filter((m) => Math.abs(m.lastShare - m.firstShare) >= 0.15);
2747
+ if (moved.length > 0) {
2748
+ console.log();
2749
+ console.log(c.bold(t.profile.mixDriftHeading()));
2750
+ for (const m of moved.slice(0, 3)) {
2751
+ console.log();
2752
+ console.log(` ${c.yellow('!')} ${c.bold(wrap(t.profile.mixDriftLine(m.model, pct(m.firstShare), pct(m.lastShare), n(report.modelMixDrift.firstDays), n(report.modelMixDrift.lastDays), formatUsd(m.lastUsd)), 74, ' '))}`);
2753
+ }
2754
+ console.log(` ${c.dim(wrap(t.profile.mixDriftNote(), 74, ' '))}`);
2755
+ }
2756
+ }
2700
2757
  /**
2701
2758
  * The same request, sent again a moment later.
2702
2759
  *