@trazum/cli 1.50.3 → 1.50.5
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/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +40 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +40 -0
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/types.d.ts +27 -0
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/index.js +121 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/i18n/en.ts +50 -0
- package/src/i18n/es.ts +50 -0
- package/src/i18n/types.ts +18 -0
- package/src/index.ts +172 -0
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { open, readdir, readFile, stat, writeFile } from 'node:fs/promises';
|
|
|
4
4
|
import { dirname, join, resolve as resolvePath } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { gunzipSync } from 'node:zlib';
|
|
7
|
-
import { applyRewrites, BASELINE_FILENAME, BASELINE_VERSION, breaches, cacheableMinimum, analyzeCachePrefix, billLevers, bucketedCacheEconomics, bucketedProfile, buildHistory, buildPlan, connectorFor, CONNECTORS, normalizeAnthropicUsage, normalizeOpenAIUsage, bucketsFromRecords, evaluateWatch, firedKey, pruneRecords, recordsFromBuckets, storeInventory, storedReportFrom, verifyPlan, cacheEconomics, cacheHitRate, contextPressure, comparePrompts, compareToBaseline, computeSavings, countTokensAnthropic, DEFAULT_USAGE, budgetPositions, conform, FAILURE_POLICIES, detectFromSource, matchLocale, parsePlanDocument, waiverDay, waiverHistory, proposeInit, MIN_RATE_DAYS, parseConfig, coverageDrift, driversBetween, explainGateFailure, assignSources, fleetRollup, labelCoverage, measuredUsage, gateMargin, GATE_MARGIN_TIGHT, 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';
|
|
7
|
+
import { applyRewrites, BASELINE_FILENAME, BASELINE_VERSION, breaches, cacheableMinimum, analyzeCachePrefix, billLevers, bucketedCacheEconomics, bucketedProfile, buildHistory, buildPlan, connectorFor, CONNECTORS, normalizeAnthropicUsage, normalizeOpenAIUsage, bucketsFromRecords, evaluateWatch, firedKey, pruneRecords, recordsFromBuckets, storeInventory, storedReportFrom, verifyPlan, cacheEconomics, cacheHitRate, contextPressure, comparePrompts, compareToBaseline, computeSavings, countTokensAnthropic, DEFAULT_USAGE, budgetPositions, conform, outcomeReport, rankPerOutcome, FAILURE_POLICIES, detectFromSource, matchLocale, parsePlanDocument, waiverDay, waiverHistory, proposeInit, MIN_RATE_DAYS, parseConfig, coverageDrift, driversBetween, explainGateFailure, assignSources, fleetRollup, labelCoverage, measuredUsage, gateMargin, GATE_MARGIN_TIGHT, 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';
|
|
8
8
|
import { cacheDir, cacheStats, cachingProvider, clearCache } from './suggest-cache.js';
|
|
9
9
|
import { dayOf, formatGap, median, spanDays } from './time.js';
|
|
10
10
|
// Everything that reads the filesystem, on its own entry point so the web
|
|
@@ -3587,6 +3587,7 @@ async function commandProfile(args, config, configDir, pricing, t) {
|
|
|
3587
3587
|
can(cov.label > 0, t.profile.dryRunLabels(share(cov.label)));
|
|
3588
3588
|
can(cov.ts > 0, t.profile.dryRunClock(share(cov.ts)));
|
|
3589
3589
|
can(cov.session > 0, t.profile.dryRunSessions(share(cov.session)));
|
|
3590
|
+
can(cov.outcome > 0, t.profile.dryRunOutcomes(share(cov.outcome)));
|
|
3590
3591
|
can(cov.stopReason > 0, t.profile.dryRunStopReason(share(cov.stopReason)));
|
|
3591
3592
|
// "No cache traffic" is not a missing field: the split can only exist on
|
|
3592
3593
|
// records that wrote, and a log that never wrote has nothing to record.
|
|
@@ -5209,6 +5210,117 @@ async function commandProfile(args, config, configDir, pricing, t) {
|
|
|
5209
5210
|
* section at all, because a paragraph of things that are fine is the
|
|
5210
5211
|
* paragraph readers learn to skip.
|
|
5211
5212
|
*/
|
|
5213
|
+
/**
|
|
5214
|
+
* Outcomes — the counterpart, where somebody recorded one.
|
|
5215
|
+
*
|
|
5216
|
+
* Printed above the coverage section rather than below it, because when this
|
|
5217
|
+
* section is present it is the most valuable thing on the page: every other
|
|
5218
|
+
* figure in this report is a cost, and this is the only one that says what
|
|
5219
|
+
* the money bought.
|
|
5220
|
+
*
|
|
5221
|
+
* Silent when nothing recorded an outcome. The coverage section below
|
|
5222
|
+
* already names the missing field and what it would unlock, and printing an
|
|
5223
|
+
* empty Outcomes heading above it would be the same sentence twice.
|
|
5224
|
+
*/
|
|
5225
|
+
{
|
|
5226
|
+
const outcomes = outcomeReport(report.outcomeTally, config.outcomes ?? null);
|
|
5227
|
+
if (outcomes.coverage.recorded > 0) {
|
|
5228
|
+
console.log();
|
|
5229
|
+
console.log(c.bold(t.profile.outcomeHeading()));
|
|
5230
|
+
const col = t.profile.outcomeColumns;
|
|
5231
|
+
const rows = [...outcomes.slices, ...outcomes.undeclared].map((slice) => ({
|
|
5232
|
+
value: slice.value,
|
|
5233
|
+
verdict: slice.verdict === 'success'
|
|
5234
|
+
? t.profile.verdictSuccess()
|
|
5235
|
+
: slice.verdict === 'undeclared'
|
|
5236
|
+
? t.profile.verdictUndeclared()
|
|
5237
|
+
: t.profile.verdictOther(),
|
|
5238
|
+
calls: n(slice.calls),
|
|
5239
|
+
spend: formatUsd(slice.usd),
|
|
5240
|
+
}));
|
|
5241
|
+
const w = {
|
|
5242
|
+
value: Math.max(...rows.map((r) => r.value.length), col.outcome.length),
|
|
5243
|
+
verdict: Math.max(...rows.map((r) => r.verdict.length), 0),
|
|
5244
|
+
calls: Math.max(...rows.map((r) => r.calls.length), col.calls.length),
|
|
5245
|
+
spend: Math.max(...rows.map((r) => r.spend.length), col.spend.length),
|
|
5246
|
+
};
|
|
5247
|
+
console.log(c.dim(` ${col.outcome.padEnd(w.value)} ${''.padEnd(w.verdict)} ` +
|
|
5248
|
+
`${col.calls.padStart(w.calls)} ${col.spend.padStart(w.spend)}`));
|
|
5249
|
+
for (const row of rows) {
|
|
5250
|
+
const tint = row.verdict === t.profile.verdictUndeclared()
|
|
5251
|
+
? c.yellow
|
|
5252
|
+
: row.verdict === t.profile.verdictSuccess()
|
|
5253
|
+
? c.green
|
|
5254
|
+
: c.dim;
|
|
5255
|
+
console.log(` ${row.value.padEnd(w.value)} ${tint(row.verdict.padEnd(w.verdict))} ` +
|
|
5256
|
+
`${row.calls.padStart(w.calls)} ${row.spend.padStart(w.spend)}`);
|
|
5257
|
+
}
|
|
5258
|
+
console.log();
|
|
5259
|
+
if (outcomes.successShareOfRecordedUsd !== null) {
|
|
5260
|
+
const declaredUsd = outcomes.slices.reduce((sum, slice) => sum + slice.usd, 0);
|
|
5261
|
+
console.log(` ${wrap(t.profile.outcomeRate(pct(outcomes.successShareOfRecordedUsd), formatUsd(declaredUsd)), 74, ' ')}`);
|
|
5262
|
+
}
|
|
5263
|
+
else if (outcomes.noRate !== null) {
|
|
5264
|
+
console.log(` ${c.dim(wrap(t.profile.outcomeNoRate(outcomes.noRate), 74, ' '))}`);
|
|
5265
|
+
}
|
|
5266
|
+
// What the rate does not cover, every time it is printed. A rate over a
|
|
5267
|
+
// twelfth of the bill is a rate about a twelfth of the bill.
|
|
5268
|
+
if (outcomes.coverage.unrecordedUsd > 0 && report.total.totalUsd > 0) {
|
|
5269
|
+
console.log(` ${c.yellow('!')} ${wrap(t.profile.outcomeUnrecorded(pct(outcomes.coverage.unrecordedUsd / report.total.totalUsd), formatUsd(outcomes.coverage.unrecordedUsd)), 74, ' ')}`);
|
|
5270
|
+
}
|
|
5271
|
+
/**
|
|
5272
|
+
* What an outcome costs, per workload — the finding a total cannot make.
|
|
5273
|
+
*
|
|
5274
|
+
* Printed only when at least one workload has enough recorded outcomes
|
|
5275
|
+
* to say something, and every row that cannot state a figure says which
|
|
5276
|
+
* of the five reasons applies rather than showing a blank.
|
|
5277
|
+
*/
|
|
5278
|
+
const ranking = rankPerOutcome(report.outcomeTallyByLabel.map((entry) => ({
|
|
5279
|
+
key: entry.label,
|
|
5280
|
+
calls: entry.calls,
|
|
5281
|
+
totalUsd: entry.totalUsd,
|
|
5282
|
+
tally: entry.tally,
|
|
5283
|
+
})), config.outcomes ?? null);
|
|
5284
|
+
if (ranking.byCall.length > 0) {
|
|
5285
|
+
console.log();
|
|
5286
|
+
console.log(c.bold(t.profile.perOutcomeHeading()));
|
|
5287
|
+
const pcol = t.profile.perOutcomeColumns;
|
|
5288
|
+
const prows = ranking.byCall.map((slice) => ({
|
|
5289
|
+
key: slice.key,
|
|
5290
|
+
perCall: formatUsd(slice.usdPerCall),
|
|
5291
|
+
perOutcome: slice.per.usdPerSuccess !== null
|
|
5292
|
+
? formatUsd(slice.per.usdPerSuccess)
|
|
5293
|
+
: t.profile.perOutcomeWithheld(slice.per.withheld ?? 'no-vocabulary', n(slice.per.successes), pct(slice.per.coverage)),
|
|
5294
|
+
recorded: pct(slice.per.coverage),
|
|
5295
|
+
}));
|
|
5296
|
+
const pw = {
|
|
5297
|
+
key: Math.max(...prows.map((r) => r.key.length), pcol.workload.length),
|
|
5298
|
+
perCall: Math.max(...prows.map((r) => r.perCall.length), pcol.perCall.length),
|
|
5299
|
+
perOutcome: Math.max(...prows.map((r) => r.perOutcome.length), pcol.perOutcome.length),
|
|
5300
|
+
recorded: Math.max(...prows.map((r) => r.recorded.length), pcol.recorded.length),
|
|
5301
|
+
};
|
|
5302
|
+
console.log(c.dim(` ${pcol.workload.padEnd(pw.key)} ${pcol.perCall.padStart(pw.perCall)} ` +
|
|
5303
|
+
`${pcol.perOutcome.padStart(pw.perOutcome)} ${pcol.recorded.padStart(pw.recorded)}`));
|
|
5304
|
+
for (const row of prows) {
|
|
5305
|
+
console.log(` ${row.key.padEnd(pw.key)} ${row.perCall.padStart(pw.perCall)} ` +
|
|
5306
|
+
`${row.perOutcome.padStart(pw.perOutcome)} ${c.dim(row.recorded.padStart(pw.recorded))}`);
|
|
5307
|
+
}
|
|
5308
|
+
console.log();
|
|
5309
|
+
console.log(` ${c.dim(wrap(t.profile.perOutcomeNumerator(), 74, ' '))}`);
|
|
5310
|
+
// The disagreement between the two orders, which is itself the finding.
|
|
5311
|
+
if (ranking.disagreements.length > 0) {
|
|
5312
|
+
console.log();
|
|
5313
|
+
console.log(` ${c.dim(wrap(t.profile.perOutcomeBothOrders(), 74, ' '))}`);
|
|
5314
|
+
for (const d of ranking.disagreements) {
|
|
5315
|
+
console.log(` ${c.yellow('→')} ${wrap(t.profile.perOutcomeDisagreement(d.slice.key, n(d.callRank + 1), n(d.outcomeRank + 1)), 74, ' ')}`);
|
|
5316
|
+
}
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5319
|
+
if (outcomes.undeclared.length > 0) {
|
|
5320
|
+
console.log(` ${c.yellow('!')} ${wrap(t.profile.outcomeUndeclared(outcomes.undeclared.map((s) => s.value).join(', ')), 74, ' ')}`);
|
|
5321
|
+
}
|
|
5322
|
+
}
|
|
5323
|
+
}
|
|
5212
5324
|
const coverage = report.fieldCoverage;
|
|
5213
5325
|
if (coverage.parsed > 0) {
|
|
5214
5326
|
const missing = [];
|
|
@@ -5219,6 +5331,14 @@ async function commandProfile(args, config, configDir, pricing, t) {
|
|
|
5219
5331
|
if (coverage.session < coverage.parsed) {
|
|
5220
5332
|
missing.push(t.profile.needsSession(partial(coverage.session)));
|
|
5221
5333
|
}
|
|
5334
|
+
/**
|
|
5335
|
+
* Listed first among the missing when it is missing entirely, because it
|
|
5336
|
+
* is the one field that changes what every other figure here *means*. The
|
|
5337
|
+
* rest sharpen a cost; this one gives it a counterpart.
|
|
5338
|
+
*/
|
|
5339
|
+
if (coverage.outcome < coverage.parsed) {
|
|
5340
|
+
missing.push(t.profile.needsOutcome(partial(coverage.outcome)));
|
|
5341
|
+
}
|
|
5222
5342
|
if (coverage.ts < coverage.parsed) {
|
|
5223
5343
|
missing.push(t.profile.needsTs(partial(coverage.ts)));
|
|
5224
5344
|
}
|