@trazum/cli 1.8.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/LICENSE +21 -0
- package/README.md +134 -0
- package/dist/git.d.ts +81 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +225 -0
- package/dist/git.js.map +1 -0
- package/dist/i18n/en.d.ts +10 -0
- package/dist/i18n/en.d.ts.map +1 -0
- package/dist/i18n/en.js +694 -0
- package/dist/i18n/en.js.map +1 -0
- package/dist/i18n/es.d.ts +4 -0
- package/dist/i18n/es.d.ts.map +1 -0
- package/dist/i18n/es.js +694 -0
- package/dist/i18n/es.js.map +1 -0
- package/dist/i18n/index.d.ts +34 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +46 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/types.d.ts +363 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n/types.js +2 -0
- package/dist/i18n/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2824 -0
- package/dist/index.js.map +1 -0
- package/dist/markdown.d.ts +246 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +492 -0
- package/dist/markdown.js.map +1 -0
- package/dist/suggest-cache.d.ts +119 -0
- package/dist/suggest-cache.d.ts.map +1 -0
- package/dist/suggest-cache.js +225 -0
- package/dist/suggest-cache.js.map +1 -0
- package/package.json +49 -0
- package/src/git.ts +294 -0
- package/src/i18n/en.ts +825 -0
- package/src/i18n/es.ts +838 -0
- package/src/i18n/index.ts +57 -0
- package/src/i18n/types.ts +372 -0
- package/src/index.ts +3873 -0
- package/src/markdown.ts +717 -0
- package/src/suggest-cache.ts +268 -0
package/src/i18n/en.ts
ADDED
|
@@ -0,0 +1,825 @@
|
|
|
1
|
+
import type { CliMessages } from './types.js';
|
|
2
|
+
|
|
3
|
+
/** "(46 days ago)", or nothing when the age is unknown. */
|
|
4
|
+
const ago = (days: number | null): string =>
|
|
5
|
+
days === null ? '' : days === 0 ? ' (today)' : days === 1 ? ' (1 day ago)' : ` (${days} days ago)`;
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* English catalogue — the source of truth.
|
|
10
|
+
*
|
|
11
|
+
* When a message changes here, the other catalogues need the same change.
|
|
12
|
+
* `test/i18n.test.js` in the core enforces the equivalent guarantee for the
|
|
13
|
+
* library's catalogues.
|
|
14
|
+
*/
|
|
15
|
+
export const en: CliMessages = {
|
|
16
|
+
locale: 'en',
|
|
17
|
+
numberLocale: 'en-US',
|
|
18
|
+
|
|
19
|
+
help: (d, bold) => `${bold('trazum')} — cut the cost of your prompts without losing what they ask for.
|
|
20
|
+
|
|
21
|
+
${bold('USAGE')}
|
|
22
|
+
trazum optimize <file|-> [options]
|
|
23
|
+
trazum check <file|dir|-> --max-tokens <n> [options]
|
|
24
|
+
trazum baseline [dir] [options]
|
|
25
|
+
trazum eval <file> --cases <file> [options]
|
|
26
|
+
trazum eval <file> --cases <file> --export promptfoo -o suite.json
|
|
27
|
+
trazum diff <before> <after> [options]
|
|
28
|
+
trazum diff --all <dir> <dir> [options]
|
|
29
|
+
trazum rank <dir> [options]
|
|
30
|
+
trazum doctor [dir] [options]
|
|
31
|
+
trazum blame <file> [options]
|
|
32
|
+
trazum prune <file> --cases <file> --yes
|
|
33
|
+
trazum where [file]
|
|
34
|
+
trazum models
|
|
35
|
+
trazum rules
|
|
36
|
+
|
|
37
|
+
${bold('OPTIONS FOR prune')}
|
|
38
|
+
--cases <file> One input per line, or a JSON array. Required.
|
|
39
|
+
--yes Actually spend the calls. Without it the estimate is
|
|
40
|
+
printed and nothing is called.
|
|
41
|
+
--concurrency <n> Calls in flight at once. Default: 3.
|
|
42
|
+
--json The measurement as data.
|
|
43
|
+
|
|
44
|
+
Removes each few-shot example in turn and measures whether the answers move
|
|
45
|
+
further than the prompt already moves on its own. The bill is
|
|
46
|
+
(2 + examples) x cases, which is why this is the one command that asks first.
|
|
47
|
+
|
|
48
|
+
It reports "no effect on these inputs" and never "delete this": an example may
|
|
49
|
+
exist for a case your inputs do not contain. Nothing is edited.
|
|
50
|
+
|
|
51
|
+
${bold('OPTIONS FOR eval')}
|
|
52
|
+
--cases <file> One input per line, or a JSON array. Required.
|
|
53
|
+
--level <safe|aggressive> Which rewrite to judge. Default: safe.
|
|
54
|
+
--concurrency <n> Calls in flight at once. Default: 3.
|
|
55
|
+
--export promptfoo Write a promptfoo suite instead of running anything:
|
|
56
|
+
both prompts, every case, no API key needed and no
|
|
57
|
+
call made. The assertions are yours — this exists
|
|
58
|
+
for the question agreement cannot answer.
|
|
59
|
+
-o, --out <file> Where to write it. Defaults to stdout.
|
|
60
|
+
|
|
61
|
+
${bold('OPTIONS FOR rank')}
|
|
62
|
+
--level <safe|aggressive> Which rules to count as recoverable. Default: safe.
|
|
63
|
+
--model, --calls, Price the recoverable tokens, as in optimize.
|
|
64
|
+
--output-tokens, --batch
|
|
65
|
+
--prompt <name> Which marked prompt to take from each source file.
|
|
66
|
+
--markdown-out <file> Also write the ranking as Markdown, for a CI job
|
|
67
|
+
summary or a pull request comment.
|
|
68
|
+
--json The ranking as data.
|
|
69
|
+
|
|
70
|
+
There is no score. Prompts are ordered by what the rules would actually
|
|
71
|
+
recover, measured by running them; the other columns explain that position.
|
|
72
|
+
|
|
73
|
+
${bold('OPTIONS FOR doctor')}
|
|
74
|
+
--level <safe|aggressive> Which rules to count. Default: safe.
|
|
75
|
+
--model, --calls, Price the findings, as in optimize.
|
|
76
|
+
--output-tokens, --batch
|
|
77
|
+
--prompt <name> Which marked prompt to take from each source file.
|
|
78
|
+
--otlp-out <file> Write the survey as OpenTelemetry metrics (OTLP/HTTP
|
|
79
|
+
JSON). Trazum writes the file; your pipeline sends it.
|
|
80
|
+
--json The survey as data.
|
|
81
|
+
|
|
82
|
+
Surveys a whole workspace: which prompts nothing is watching, which are already
|
|
83
|
+
over budget, and what the advisories add up to across all of them. Every finding
|
|
84
|
+
is one trazum optimize raises on that prompt on its own, so any line can be
|
|
85
|
+
checked against a single file. There is no score.
|
|
86
|
+
|
|
87
|
+
It exits 0 even when it finds things. trazum check is the gate.
|
|
88
|
+
|
|
89
|
+
${bold('OPTIONS FOR blame')}
|
|
90
|
+
--limit <n> Revisions to walk. Default: 20, maximum 500.
|
|
91
|
+
--prompt <name> Track one marked prompt inside a source file, so a
|
|
92
|
+
refactor of the imports is not read as growth.
|
|
93
|
+
--model, --calls, Price the movement, exactly as in optimize.
|
|
94
|
+
--output-tokens, --batch
|
|
95
|
+
--markdown-out <file> Also write the history as Markdown, for a CI job
|
|
96
|
+
summary or a pull request comment.
|
|
97
|
+
--json The history as data.
|
|
98
|
+
|
|
99
|
+
Paths are taken literally after "--": trazum blame -- --odd-name.txt
|
|
100
|
+
|
|
101
|
+
${bold('OPTIONS FOR optimize')}
|
|
102
|
+
--level <safe|aggressive> How hard the rules push. Default: safe.
|
|
103
|
+
--model <id> Model used to price the prompt. Default: ${d.model}.
|
|
104
|
+
--calls <n> Calls per month. Default: ${d.callsPerMonth}.
|
|
105
|
+
--output-tokens <n> Average output tokens. Default: ${d.avgOutputTokens}.
|
|
106
|
+
--cache-hit-rate <0-1> Estimated cache hit rate. Default: ${d.cacheHitRate}.
|
|
107
|
+
--batch The work tolerates latency (Batch API, 50% off).
|
|
108
|
+
--disable <id,id> Turn off specific rules (see "trazum rules").
|
|
109
|
+
--suggest Ask the LLM for phrase-level rewrites and list them
|
|
110
|
+
with what each saves. Changes nothing on its own —
|
|
111
|
+
every proposal is checked against your prompt first
|
|
112
|
+
and dropped if it does not survive.
|
|
113
|
+
--apply-suggestions Take them. Only with --suggest; alone it is an error
|
|
114
|
+
rather than a flag that runs and does nothing.
|
|
115
|
+
--cache-suggestions Answer --suggest from a local cache when the same
|
|
116
|
+
prompt was asked about before, instead of paying for
|
|
117
|
+
the call again. Off by default: a hit is what the
|
|
118
|
+
model said last time, and that should be a choice.
|
|
119
|
+
Kept in $XDG_CACHE_HOME/trazum, 0600, for 7 days.
|
|
120
|
+
--reorder Move stable instructions ahead of the first placeholder,
|
|
121
|
+
so prompt caching can reach them. This MOVES text rather
|
|
122
|
+
than deleting it: read the diff and decide whether the
|
|
123
|
+
order mattered. Refuses on any block that refers
|
|
124
|
+
backwards ("the text above"), and says which phrase.
|
|
125
|
+
--llm Add a pass through the LLM configured by environment.
|
|
126
|
+
--exact-tokens Count tokens with the official API instead of the heuristic.
|
|
127
|
+
--tokens-only Report the token saving and no money at all. The
|
|
128
|
+
default inside Claude Code, Codex or Cursor, where
|
|
129
|
+
a subscription means there is no bill to reduce.
|
|
130
|
+
--cost Show the money even there — the host says where
|
|
131
|
+
Trazum runs, not where your prompt goes.
|
|
132
|
+
--prompt <name> Which marked prompt to optimise, when a source file
|
|
133
|
+
holds more than one. See "trazum where".
|
|
134
|
+
--diff Show the line-by-line diff.
|
|
135
|
+
--json Dump the full report as JSON.
|
|
136
|
+
--locale <${d.locales.join('|')}> Language of the report. Default: the system language.
|
|
137
|
+
-o, --out <file> Write the optimised prompt to a file.
|
|
138
|
+
-h, --help This help.
|
|
139
|
+
--clear-suggestion-cache Empty the --cache-suggestions cache and say how much
|
|
140
|
+
went. An errand rather than a mode: it needs no
|
|
141
|
+
command and reads no config.
|
|
142
|
+
|
|
143
|
+
${bold('OPTIONS FOR check')}
|
|
144
|
+
--max-tokens <n> Input token budget. Required unless a config budget covers the file.
|
|
145
|
+
--level <safe|aggressive> Level used to work out whether the optimised prompt would fit.
|
|
146
|
+
--exact-tokens Exact count (needs ANTHROPIC_API_KEY).
|
|
147
|
+
--json Result as JSON.
|
|
148
|
+
--markdown-out <file> Also write the report as Markdown, for a CI job summary
|
|
149
|
+
or a pull request comment.
|
|
150
|
+
--baseline Gate on the recorded cost baseline. On by default whenever
|
|
151
|
+
the config declares one, so CI needs no argument; the useful
|
|
152
|
+
spelling is --no-baseline, which skips it for one run.
|
|
153
|
+
|
|
154
|
+
Built for CI: exits with code 1 when the prompt busts the budget, so a
|
|
155
|
+
template that grows unchecked breaks the build instead of the bill.
|
|
156
|
+
|
|
157
|
+
${bold('OPTIONS FOR baseline')}
|
|
158
|
+
Records what the prompts in a directory cost right now, to a file you commit.
|
|
159
|
+
Then "check" fails the build when the repository drifts past it — the question
|
|
160
|
+
budgets cannot answer, because a repository at 95% of every budget passes
|
|
161
|
+
forever while a pull request adds four hundred tokens across a dozen files.
|
|
162
|
+
|
|
163
|
+
-o, --out <file> Where to write it. Default: the config's baseline.path,
|
|
164
|
+
or trazum.baseline.json.
|
|
165
|
+
--model, --calls, --output-tokens, --cache-hit-rate, --batch
|
|
166
|
+
The scenario the monthly figure is recorded under. It is
|
|
167
|
+
recorded so a later comparison can say whether the money is
|
|
168
|
+
comparable — the gate itself is in tokens, so a repriced
|
|
169
|
+
model never fails a build on its own.
|
|
170
|
+
--exact-tokens Exact counts (needs ANTHROPIC_API_KEY).
|
|
171
|
+
--json Result as JSON.
|
|
172
|
+
|
|
173
|
+
It never fails. Recording is not a verdict, and a command that could fail while
|
|
174
|
+
writing the thing you would fix the failure with is a loop.
|
|
175
|
+
|
|
176
|
+
Given a directory it checks every prompt inside it against the "budgets"
|
|
177
|
+
patterns in ${bold('trazum.config.json')} — one CI step for a whole repository of
|
|
178
|
+
prompts. A file no pattern covers is listed as unbudgeted rather than
|
|
179
|
+
skipped quietly, and a run where nothing at all was budgeted is an error:
|
|
180
|
+
"0 failures" from a check that measured nothing is the most misleading
|
|
181
|
+
thing this tool could tell you.
|
|
182
|
+
|
|
183
|
+
${bold('OPTIONS FOR eval')}
|
|
184
|
+
--cases <file> Inputs to test, one per line or a JSON array. Required.
|
|
185
|
+
--level <safe|aggressive> Level to optimise with before comparing.
|
|
186
|
+
--concurrency <n> Cases in flight at once. Default: 3.
|
|
187
|
+
--json Result as JSON.
|
|
188
|
+
|
|
189
|
+
Runs both prompt versions over your cases and reports whether the
|
|
190
|
+
optimisation changed the answers. Costs THREE provider calls per case: the
|
|
191
|
+
original twice, to measure the model's own run-to-run variance, and the
|
|
192
|
+
optimised once. That baseline is the yardstick — without it, a divergence
|
|
193
|
+
figure means nothing. Exits with code 1 when the answers genuinely diverge.
|
|
194
|
+
|
|
195
|
+
${bold('OPTIONS FOR diff')}
|
|
196
|
+
--max-growth <n> Fail if the prompt grew by more than n tokens.
|
|
197
|
+
--all Compare two directories of prompts, paired by relative
|
|
198
|
+
path. Prompts on only one side are named, never
|
|
199
|
+
counted: a deletion is a question, not a saving.
|
|
200
|
+
--max-growth then applies per prompt, not to the
|
|
201
|
+
total, so one prompt doubling cannot hide behind
|
|
202
|
+
another shrinking.
|
|
203
|
+
--optimized Measure what the rules would leave, not what is written.
|
|
204
|
+
--level <safe|aggressive> Level used for the rule and advisory findings.
|
|
205
|
+
--model <id> Model used to price the change.
|
|
206
|
+
--calls <n> Calls per month, for the cost figure.
|
|
207
|
+
--json Result as JSON.
|
|
208
|
+
--markdown-out <file> Also write the report as Markdown, for a CI job summary
|
|
209
|
+
or a pull request comment.
|
|
210
|
+
|
|
211
|
+
Compares two versions of a prompt: how the token count moved, what that
|
|
212
|
+
costs, which advisories the edit introduced or resolved. Every figure is a
|
|
213
|
+
delta and positive means worse. It reports and exits 0 unless --max-growth
|
|
214
|
+
is given: deciding that growth is unacceptable is your call, not ours.
|
|
215
|
+
|
|
216
|
+
${bold('trazum where')}
|
|
217
|
+
Says which provider a file's prompts are actually sent to, and how it knows —
|
|
218
|
+
an SDK import, a base URL, a quoted model id, or "model=" on a trazum:prompt
|
|
219
|
+
marker. Every answer names the line it came from.
|
|
220
|
+
|
|
221
|
+
It refuses when a file names two providers rather than picking one. Two
|
|
222
|
+
answers is not a weaker version of one answer, and picking silently is how
|
|
223
|
+
somebody budgets against the wrong provider for a month.
|
|
224
|
+
|
|
225
|
+
A base URL beats the SDK it was pointed at: Moonshot, DeepSeek, xAI and Groq
|
|
226
|
+
are all called through the OpenAI SDK with a different base_url, so treating
|
|
227
|
+
that as a contradiction would refuse to price an ordinary client.
|
|
228
|
+
|
|
229
|
+
With no file, it reports only which tool Trazum is running inside — and warns
|
|
230
|
+
when that tool bills by subscription, because a monthly saving is arithmetic
|
|
231
|
+
about tokens there, not money you get back.
|
|
232
|
+
|
|
233
|
+
${bold('CONFIG FILE')}
|
|
234
|
+
${bold('trazum.config.json')}, found by walking up from the working directory and
|
|
235
|
+
stopping at the repository root. Every key is optional:
|
|
236
|
+
|
|
237
|
+
level, locale, disable, maxGrowth, extensions
|
|
238
|
+
usage { model, callsPerMonth, avgOutputTokens, cacheHitRate, batchEligible }
|
|
239
|
+
budgets { "prompts/**": 2000, "prompts/system.txt": 4000 }
|
|
240
|
+
baseline { "path": "trazum.baseline.json", "maxGrowthTokens": 0, "maxGrowthPct": 5 }
|
|
241
|
+
pricing "./prices.json" — local price corrections, see below
|
|
242
|
+
|
|
243
|
+
Flags beat the config; the config beats the defaults. Budgets resolve to the
|
|
244
|
+
most specific matching pattern — most literal characters wins. A boolean the
|
|
245
|
+
config switched on comes back off with --no-<flag>, e.g. --no-batch.
|
|
246
|
+
|
|
247
|
+
${bold('budgets')} is a ceiling; ${bold('baseline')} is a gate. One asks whether a file fits,
|
|
248
|
+
the other whether the repository got worse than the commit somebody recorded
|
|
249
|
+
with "trazum baseline". A repository at 95% of every budget passes forever
|
|
250
|
+
while a pull request adds four hundred tokens across a dozen files. With
|
|
251
|
+
baseline in the config, "check" on a directory reads it and gates on it — no
|
|
252
|
+
flag, because a gate you have to remember to pass an argument to runs in the
|
|
253
|
+
author's terminal and not in CI. Thresholds are in tokens, never dollars: a
|
|
254
|
+
repriced model would otherwise fail a build for a change nobody made.
|
|
255
|
+
|
|
256
|
+
A config that will not validate is an error, including an unknown key. A
|
|
257
|
+
lenient parser would silently restore defaults, and for a budget the default
|
|
258
|
+
is "no budget" — a green build for a prompt nobody measured.
|
|
259
|
+
|
|
260
|
+
--config <file> Use this config instead of searching for one.
|
|
261
|
+
|
|
262
|
+
${bold('PRICES')}
|
|
263
|
+
Prices change on someone else's schedule, so correcting one does not require
|
|
264
|
+
upgrading Trazum. A pricing overlay is a JSON file layered over the bundled
|
|
265
|
+
catalogue:
|
|
266
|
+
|
|
267
|
+
{ "lastReviewed": "2027-01-15",
|
|
268
|
+
"models": { "claude-opus-5": { "inputPerMTok": 6 } } }
|
|
269
|
+
|
|
270
|
+
Only the fields you name change. A model the bundled catalogue does not have
|
|
271
|
+
must be complete, because a half-defined model would price at nothing and
|
|
272
|
+
report a saving that is not there. "promo": null withdraws a promotion.
|
|
273
|
+
|
|
274
|
+
Every report says when overlaid prices were used and which models they cover:
|
|
275
|
+
a figure from the bundled catalogue and a figure from your JSON file otherwise
|
|
276
|
+
look identical.
|
|
277
|
+
|
|
278
|
+
--pricing <file> Use this overlay, ahead of the config's own.
|
|
279
|
+
--pricing-live Take prices from OpenRouter instead of the bundled
|
|
280
|
+
table: today's figures for hundreds of models across
|
|
281
|
+
dozens of providers. Opt-in, because it is a network
|
|
282
|
+
call — the deterministic core never makes one.
|
|
283
|
+
A --pricing file wins over this.
|
|
284
|
+
|
|
285
|
+
What that source does not publish is whether a model
|
|
286
|
+
has prompt caching or the minimum prefix it caches
|
|
287
|
+
at. Models it adds therefore get no caching advice
|
|
288
|
+
at all, rather than a guess: claiming caching works
|
|
289
|
+
would offer a saving nobody can buy, and claiming it
|
|
290
|
+
does not would hide the largest saving there is.
|
|
291
|
+
|
|
292
|
+
${bold('OPTIONAL LLM')}
|
|
293
|
+
The core is deterministic and free. --llm adds a semantic compression pass
|
|
294
|
+
using whichever provider you configure by environment:
|
|
295
|
+
|
|
296
|
+
TRAZUM_LLM_PROVIDER openai | anthropic (default: openai)
|
|
297
|
+
TRAZUM_LLM_BASE_URL https://your-llm/v1
|
|
298
|
+
TRAZUM_LLM_API_KEY your key
|
|
299
|
+
TRAZUM_LLM_MODEL model identifier
|
|
300
|
+
|
|
301
|
+
The LLM's answer is only accepted when it is shorter and leaves code, URLs
|
|
302
|
+
and template placeholders untouched.
|
|
303
|
+
|
|
304
|
+
${bold('LANGUAGE')}
|
|
305
|
+
The report language follows --locale, then TRAZUM_LOCALE, then LANG, and last
|
|
306
|
+
the config file — so a project can set the language its CI logs read in
|
|
307
|
+
without overriding the language of whoever is at the keyboard. It changes the
|
|
308
|
+
report only: the same prompt always optimises the same way.
|
|
309
|
+
|
|
310
|
+
${bold('EXAMPLES')}
|
|
311
|
+
trazum optimize prompt.txt --calls 50000 --diff
|
|
312
|
+
cat prompt.md | trazum optimize - --level aggressive --json
|
|
313
|
+
trazum optimize prompt.txt --reorder --diff
|
|
314
|
+
trazum optimize prompt.txt --llm -o prompt.optimised.txt
|
|
315
|
+
trazum eval prompt.txt --cases cases.txt --level aggressive
|
|
316
|
+
trazum diff prompts/system.txt prompts/system.new.txt --max-growth 10
|
|
317
|
+
trazum check prompts/
|
|
318
|
+
`,
|
|
319
|
+
|
|
320
|
+
cache: {
|
|
321
|
+
cleared: (entries: number, bytes: number, dir: string) =>
|
|
322
|
+
entries === 0
|
|
323
|
+
? `No cached suggestions to remove (${dir}).`
|
|
324
|
+
: `Removed ${entries} cached ${entries === 1 ? 'answer' : 'answers'} (${(bytes / 1024).toFixed(1)} KB) from ${dir}.`,
|
|
325
|
+
used: (hits: number, misses: number) =>
|
|
326
|
+
`Suggestions: ${hits} from cache, ${misses} asked. Cached answers are what the model said last time; --clear-suggestion-cache to start over.`,
|
|
327
|
+
},
|
|
328
|
+
|
|
329
|
+
errors: {
|
|
330
|
+
livePricingFailed: (url: string, detail: string) =>
|
|
331
|
+
`Could not load live prices from ${url}: ${detail}. The bundled prices are still there — drop --pricing-live to use them.`,
|
|
332
|
+
optionNeedsValue: (name) => `Option --${name} needs a value.`,
|
|
333
|
+
mustBeNonNegative: (name, raw) =>
|
|
334
|
+
`--${name} must be a non-negative number (received: "${raw}").`,
|
|
335
|
+
badLevel: (received) => `--level must be "safe" or "aggressive" (received: "${received}").`,
|
|
336
|
+
unknownRuleInDisable: (id) => `Unknown rule in --disable: "${id}". Full list: trazum rules`,
|
|
337
|
+
unknownCommand: (command) => `Unknown command: "${command}". Try "trazum --help".`,
|
|
338
|
+
missingInputFile: () => 'Missing input file. Use "-" to read from standard input.',
|
|
339
|
+
applyNeedsSuggest: () =>
|
|
340
|
+
'--apply-suggestions has nothing to apply without --suggest. On its own it would have '
|
|
341
|
+
+ 'run silently and changed nothing, which is not an answer.',
|
|
342
|
+
llmNotConfigured: () =>
|
|
343
|
+
'You asked for --llm but no provider is configured.\n' +
|
|
344
|
+
'Set TRAZUM_LLM_BASE_URL and TRAZUM_LLM_MODEL (OpenAI-compatible endpoint),\n' +
|
|
345
|
+
'or TRAZUM_LLM_PROVIDER=anthropic with TRAZUM_LLM_API_KEY.',
|
|
346
|
+
exactTokensNeedsKey: () => '--exact-tokens needs ANTHROPIC_API_KEY in the environment.',
|
|
347
|
+
checkNeedsMaxTokens: () => 'trazum check needs --max-tokens <n>.',
|
|
348
|
+
evalNeedsCases: () => 'trazum eval needs --cases <file>.',
|
|
349
|
+
unknownExportFormat: (received, allowed) =>
|
|
350
|
+
`Unknown export format "${received}". Available: ${allowed}.`,
|
|
351
|
+
evalNoCases: (path) => `No cases found in "${path}".`,
|
|
352
|
+
unknownFlag: (name, allowed) =>
|
|
353
|
+
`Unknown option --${name}. This command accepts: ${allowed}.`,
|
|
354
|
+
unknownFlagDidYouMean: (name, suggestion) =>
|
|
355
|
+
`Unknown option --${name}. Did you mean --${suggestion}?`,
|
|
356
|
+
diffNeedsTwoFiles: () => 'trazum diff needs two files: trazum diff <before> <after>.',
|
|
357
|
+
cannotNegate: (name) => `--no-${name} makes no sense: --${name} takes a value.`,
|
|
358
|
+
noPromptsFound: (directory, extensions) =>
|
|
359
|
+
`No prompt files under "${directory}". Looked for: ${extensions}.`,
|
|
360
|
+
noBudgetsApply: (directory, configFile) =>
|
|
361
|
+
`No budget covers anything under "${directory}". Add one to ${configFile} under "budgets", or pass --max-tokens. ` +
|
|
362
|
+
'Reporting "0 failures" for files nobody measured would be worse than this error.',
|
|
363
|
+
baselineMissing: (path) =>
|
|
364
|
+
`The config declares a baseline at "${path}" and it is not there. Record one with "trazum baseline" and commit it. This is an error rather than a skipped check: a gate the config asked for and could not run is not a pass.`,
|
|
365
|
+
baselineTooBig: (path, limit) =>
|
|
366
|
+
`"${path}" is over the ${limit}-byte limit for a baseline. Something other than a baseline is at that path.`,
|
|
367
|
+
errorLabel: () => 'Error',
|
|
368
|
+
},
|
|
369
|
+
|
|
370
|
+
report: {
|
|
371
|
+
inputTokens: () => 'Input tokens',
|
|
372
|
+
estimated: (offFamily) =>
|
|
373
|
+
offFamily === null
|
|
374
|
+
? ' (estimated, ±15%)'
|
|
375
|
+
: ` (estimated — the counter is calibrated on Claude, not ${offFamily})`,
|
|
376
|
+
exactCount: () => ' (exact count)',
|
|
377
|
+
rulesApplied: () => 'Rules applied',
|
|
378
|
+
nothingToTrim: () => ' No rule found anything to trim.',
|
|
379
|
+
// Printed only when nothing fired, which is exactly when the reader would
|
|
380
|
+
// otherwise conclude their prompt is already efficient. Stated rather than
|
|
381
|
+
// detected: guessing the prompt's language is one more thing to get wrong,
|
|
382
|
+
// and naming the coverage cannot be wrong.
|
|
383
|
+
dictionaryCoverage: (languages) =>
|
|
384
|
+
` The phrase dictionaries cover ${languages}. A prompt in another language `
|
|
385
|
+
+ 'is not necessarily efficient — it may just be one Trazum cannot read yet.',
|
|
386
|
+
levelAggressive: () => '[aggressive]',
|
|
387
|
+
levelSafe: () => '[safe]',
|
|
388
|
+
ruleHits: (hits, tokensSaved) => `(${hits}×, ~${tokensSaved} tokens)`,
|
|
389
|
+
moreChanges: (count) => `+${count} more not shown`,
|
|
390
|
+
llmPass: () => 'LLM pass',
|
|
391
|
+
examplesReview: () => 'Examples the model considers redundant',
|
|
392
|
+
examplesReviewNote: (provider, model, count) =>
|
|
393
|
+
`${count} examples reviewed by ${provider}/${model}. A suggestion to read, not a change made.`,
|
|
394
|
+
exampleRedundant: (redundant, keep) =>
|
|
395
|
+
`Example ${redundant.map((i) => i + 1).join(', ')} repeats example ${keep + 1}`,
|
|
396
|
+
llmApplied: (provider, model, before, after) =>
|
|
397
|
+
`applied via ${provider}/${model}: ${before} → ${after} tokens`,
|
|
398
|
+
llmRejected: (reason) => `rejected: ${reason}`,
|
|
399
|
+
costWith: (modelName) => `Cost with ${modelName}`,
|
|
400
|
+
usageLine: (calls, outputTokens, batch) =>
|
|
401
|
+
`${calls} calls/month · ${outputTokens} output tokens per call${batch ? ' · Batch API' : ''}`,
|
|
402
|
+
perMonthSaving: (saving, pct) => `saving ${saving}/month (${pct}%)`,
|
|
403
|
+
beyondShortening: () => 'Beyond shortening the prompt',
|
|
404
|
+
biggestLever: () => 'Start here:',
|
|
405
|
+
biggestLeverDetail: (title, amount, times) =>
|
|
406
|
+
// The title keeps its case: lowercasing it turned "Claude Opus 5" into
|
|
407
|
+
// "claude opus 5", which is a product name mangled to fit a sentence.
|
|
408
|
+
`"${title}" — ${amount}/month` +
|
|
409
|
+
(times !== null && times >= 2 ? `, ${times}× what the rules saved.` : '.'),
|
|
410
|
+
perMonthSuffix: (amount) => ` ~${amount}/month`,
|
|
411
|
+
diff: () => 'Diff',
|
|
412
|
+
tokensOnlyHeading: (host) => `What this buys on ${host}`,
|
|
413
|
+
tokensOnlyWhy: (host) =>
|
|
414
|
+
`${host} bills by subscription, so there is no bill to reduce and no monthly figure to print.`,
|
|
415
|
+
tokensOnlyAsked: () => 'Costs hidden because you asked for tokens only.',
|
|
416
|
+
// `tokens` arrives already formatted for the locale, so the singular is
|
|
417
|
+
// decided on the string rather than on a number that is no longer here.
|
|
418
|
+
tokensSaved: (tokens) => `${tokens} token${tokens === '1' ? '' : 's'} back, every call.`,
|
|
419
|
+
windowUse: (before, after, model, window) =>
|
|
420
|
+
`Context window: ${before} → ${after} of ${model}'s ${window} tokens — room the conversation gets instead.`,
|
|
421
|
+
tokensOnlyCost: () => 'Pass --cost if this prompt is bound for a metered API.',
|
|
422
|
+
pricingOverlaid: (models, lastReviewed) =>
|
|
423
|
+
`Prices for ${models} came from a local overlay reviewed ${lastReviewed}, not from the bundled catalogue.`,
|
|
424
|
+
reorderHeading: () => 'Reordered for caching',
|
|
425
|
+
reorderMoved: (blocks, tokens) =>
|
|
426
|
+
`Moved ${blocks} ${blocks === 1 ? 'block' : 'blocks'} (~${tokens} tokens) ahead of the first placeholder.`,
|
|
427
|
+
reorderPrefix: (before, after) => `Cacheable prefix ${before} → ${after} tokens.`,
|
|
428
|
+
reorderDeclined: (count) =>
|
|
429
|
+
count === 1 ? 'Left 1 block where it was:' : `Left ${count} blocks where they were:`,
|
|
430
|
+
reorderDeclinedRef: (phrase, excerpt) => `refers back ("${phrase}"): ${excerpt}`,
|
|
431
|
+
reorderDeclinedAfter: (excerpt) => `after a block that had to stay: ${excerpt}`,
|
|
432
|
+
reorderDeclinedScript: (script) =>
|
|
433
|
+
`this prompt is written in ${script}, and Trazum has no backward-reference phrases ` +
|
|
434
|
+
`for it. It cannot tell "summarise the text above" from an instruction that is safe ` +
|
|
435
|
+
`to move, so it moved nothing. Adding a language is adding an array to phrases.ts.`,
|
|
436
|
+
reorderDeclinedMore: (count) => `…and ${count} more, in the output file.`,
|
|
437
|
+
reorderPiped: (moved, tokens, declined) => {
|
|
438
|
+
const head =
|
|
439
|
+
moved === 0
|
|
440
|
+
? 'nothing could safely move'
|
|
441
|
+
: `moved ${moved} ${moved === 1 ? 'block' : 'blocks'} (~${tokens} tokens) into the cacheable prefix`;
|
|
442
|
+
const tail =
|
|
443
|
+
declined === 0 ? '' : `; ${declined} ${declined === 1 ? 'block' : 'blocks'} left in place`;
|
|
444
|
+
return `trazum: ${head}${tail}. Run without redirecting output for the reasons.`;
|
|
445
|
+
},
|
|
446
|
+
reorderNothing: () => 'Nothing could safely move.',
|
|
447
|
+
suggestHeading: () => 'Suggested rewrites',
|
|
448
|
+
suggestOffered: (count, tokens) =>
|
|
449
|
+
`${count} ${count === 1 ? 'phrase' : 'phrases'} could say the same in ~${tokens} fewer tokens:`,
|
|
450
|
+
suggestApplied: (count, tokens) =>
|
|
451
|
+
`Applied ${count} ${count === 1 ? 'rewrite' : 'rewrites'} (~${tokens} tokens). Read the diff.`,
|
|
452
|
+
suggestNothing: (provider, model) =>
|
|
453
|
+
`${provider} (${model}) found nothing worth rewriting that the rules had not already taken.`,
|
|
454
|
+
suggestRejected: (count) =>
|
|
455
|
+
`${count} ${count === 1 ? 'proposal' : 'proposals'} did not survive checking against your prompt.`,
|
|
456
|
+
suggestRemoved: () => '(removed)',
|
|
457
|
+
suggestHowToApply: () => 'Nothing was changed. Add --apply-suggestions to take them.',
|
|
458
|
+
reorderReview: () =>
|
|
459
|
+
'Read the diff: this moved text rather than deleting it, so the question is whether the order mattered.',
|
|
460
|
+
diffTooLarge: (lines, max) =>
|
|
461
|
+
` Diff skipped: ${lines} lines is past the ${max}-line limit, and aligning them would cost more memory than the answer is worth.`,
|
|
462
|
+
wroteTo: (path) => `Optimised prompt written to ${path}`,
|
|
463
|
+
},
|
|
464
|
+
|
|
465
|
+
where: {
|
|
466
|
+
hostHeading: () => 'Running inside',
|
|
467
|
+
subscription: (host) =>
|
|
468
|
+
`${host} bills by subscription, not by the token. A monthly saving below is arithmetic about tokens, not money you get back — what you gain is context window and rate-limit headroom.`,
|
|
469
|
+
noTarget: () => 'Pass a source file to see which provider its prompts are sent to.',
|
|
470
|
+
sourceHeading: (path) => `Prompts in ${path} go to`,
|
|
471
|
+
conflict: () => 'Cannot tell: the file names more than one provider.',
|
|
472
|
+
conflictFallback: () =>
|
|
473
|
+
'Nothing was assumed. Set "usage.model" in trazum.config.json, or pass --model.',
|
|
474
|
+
nothingFound: () => 'Nothing in this file says which provider it calls.',
|
|
475
|
+
providerOnly: () => ' (provider only — nothing named a model)',
|
|
476
|
+
evidenceLine: (line, kind, detail) => `line ${line} ${kind}: ${detail}`,
|
|
477
|
+
pricedAs: () => 'Priced as',
|
|
478
|
+
fromConfig: () => '(from trazum.config.json)',
|
|
479
|
+
fromDetection: () => '(read from the source)',
|
|
480
|
+
fromProviderDefault: (provider) =>
|
|
481
|
+
`(${provider} was read from the source; nothing named a model, so this is theirs)`,
|
|
482
|
+
fromDefault: () => '(the built-in default — nothing said otherwise)',
|
|
483
|
+
},
|
|
484
|
+
|
|
485
|
+
pricing: {
|
|
486
|
+
liveLoaded: (added: number, refreshed: number, skipped: number) =>
|
|
487
|
+
`Live prices: ${refreshed} refreshed, ${added} models added, ${skipped} skipped for having no usable price or context window. Caching minimums are not published by this source, so caching advice is withheld for the added models.`,
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
models: {
|
|
491
|
+
title: () => 'Models and pricing',
|
|
492
|
+
unit: () => ' (USD per million tokens)',
|
|
493
|
+
reviewedOn: (date, days) =>
|
|
494
|
+
` Table reviewed on ${date}${ago(days)}. Verify before budgeting.`,
|
|
495
|
+
columns: {
|
|
496
|
+
model: 'model',
|
|
497
|
+
input: 'input',
|
|
498
|
+
output: 'output',
|
|
499
|
+
context: 'context',
|
|
500
|
+
cacheMin: 'cache min.',
|
|
501
|
+
},
|
|
502
|
+
promoNote: () => ' Prices in brackets are the price once the promotion ends.',
|
|
503
|
+
cacheNote: () =>
|
|
504
|
+
' Cache: reading costs 10% of input; writing, 125% (5 min) or 200% (1 h).',
|
|
505
|
+
batchNote: () => ' Batch API: 50% off input and output.',
|
|
506
|
+
},
|
|
507
|
+
|
|
508
|
+
rank: {
|
|
509
|
+
heading: (root, count) =>
|
|
510
|
+
`${count} ${count === 1 ? 'prompt' : 'prompts'} under ${root}, most recoverable first`,
|
|
511
|
+
subheading: (model, calls) => `Priced on ${model} at ${calls} calls a month.`,
|
|
512
|
+
columns: {
|
|
513
|
+
recoverable: 'Recover',
|
|
514
|
+
tokensBack: 'Tokens',
|
|
515
|
+
tokens: 'Size',
|
|
516
|
+
density: 'Tok/sen',
|
|
517
|
+
notes: 'Prompt',
|
|
518
|
+
},
|
|
519
|
+
noteExamples: (count, tokens) => `${count} examples, ~${tokens} tokens`,
|
|
520
|
+
noteFormat: (tokens) => `~${tokens} tokens restating the output format`,
|
|
521
|
+
noteProtected: (pct) => `${pct}% is code or URLs, which cannot be trimmed`,
|
|
522
|
+
skipped: (count) =>
|
|
523
|
+
`Skipped ${count} source ${count === 1 ? 'file' : 'files'} with no \`// trazum:prompt\` marker — `
|
|
524
|
+
+ 'their prompts are not in this ranking.',
|
|
525
|
+
densityNote: () =>
|
|
526
|
+
'Tok/sen is tokens per sentence: verbosity independent of length. There is no score — every column is a measurement you can check against the file.',
|
|
527
|
+
recoverableNote: () =>
|
|
528
|
+
'Recover is what the deterministic rules would take at this level, priced by the usage profile, with the token count beside it — a saving of one token is twenty-five cents and no work worth doing. It is measured by running the rules, not by a formula.',
|
|
529
|
+
},
|
|
530
|
+
|
|
531
|
+
blame: {
|
|
532
|
+
heading: (path, revisions) =>
|
|
533
|
+
`${path} — ${revisions} ${revisions === 1 ? 'revision' : 'revisions'}`,
|
|
534
|
+
notARepository: () =>
|
|
535
|
+
'blame reads a file\'s history from git, and this directory is not inside a repository.',
|
|
536
|
+
outsideRepository: (path) =>
|
|
537
|
+
`${path} is outside the repository, so there is no history to read.`,
|
|
538
|
+
noHistory: (path) => `git has no commits touching ${path}.`,
|
|
539
|
+
gitMissing: () => 'git is not on PATH, and blame has nothing to read the history from.',
|
|
540
|
+
columns: { when: 'Date', tokens: 'Tokens', change: 'Change', who: 'Author', commit: 'Commit' },
|
|
541
|
+
net: (first, last, delta, pct) =>
|
|
542
|
+
`Net across this history: ${first} → ${last} tokens (${delta}, ${pct}).`,
|
|
543
|
+
netCost: (amount, model, calls) =>
|
|
544
|
+
`That movement is ${amount} a month on ${model} at ${calls} calls.`,
|
|
545
|
+
biggestRise: () => 'Biggest single increase',
|
|
546
|
+
biggestRiseDetail: (tokens, author, subject, sha) =>
|
|
547
|
+
`+${tokens} tokens — ${author}, "${subject}" (${sha})`,
|
|
548
|
+
addedAt: () => 'added',
|
|
549
|
+
goneAt: () => 'not present',
|
|
550
|
+
truncated: (shown) =>
|
|
551
|
+
`Showing the most recent ${shown}. Pass --limit for more.`,
|
|
552
|
+
followedRename: (from) => `Followed a rename: earlier revisions are ${from}.`,
|
|
553
|
+
estimateNote: () =>
|
|
554
|
+
'Token counts are estimates (±15%). The trend is the point; the absolute figures are not.',
|
|
555
|
+
},
|
|
556
|
+
|
|
557
|
+
languages: {
|
|
558
|
+
and: 'and',
|
|
559
|
+
en: 'English',
|
|
560
|
+
es: 'Spanish',
|
|
561
|
+
fr: 'French',
|
|
562
|
+
de: 'German',
|
|
563
|
+
pt: 'Portuguese',
|
|
564
|
+
it: 'Italian',
|
|
565
|
+
nl: 'Dutch',
|
|
566
|
+
},
|
|
567
|
+
|
|
568
|
+
rules: {
|
|
569
|
+
title: () => 'Available rules',
|
|
570
|
+
disableHint: () => ' Turn off the ones you do not want with --disable id1,id2',
|
|
571
|
+
},
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
doctor: {
|
|
575
|
+
heading: (root, prompts) =>
|
|
576
|
+
`${root} — ${prompts} ${prompts === 1 ? 'prompt' : 'prompts'}`,
|
|
577
|
+
subheading: (model, calls) => `Priced on ${model} at ${calls} calls a month.`,
|
|
578
|
+
pricesReviewed: (date, days) => `Prices reviewed ${date}${ago(days)}.`,
|
|
579
|
+
budgetsHeading: () => 'Budgets',
|
|
580
|
+
everyPromptBudgeted: (count) =>
|
|
581
|
+
count === 1
|
|
582
|
+
? 'The prompt has a budget and is inside it.'
|
|
583
|
+
: `All ${count} prompts have a budget and are inside it.`,
|
|
584
|
+
unbudgeted: (count, total) =>
|
|
585
|
+
`${count} of ${total} ${count === 1 ? 'prompt has' : 'prompts have'} no budget, so nothing is watching ${count === 1 ? 'it' : 'them'}`,
|
|
586
|
+
overBudget: (count) =>
|
|
587
|
+
count === 1
|
|
588
|
+
? '1 prompt is already over its budget — trazum check would fail on it'
|
|
589
|
+
: `${count} prompts are already over their budget — trazum check would fail on them`,
|
|
590
|
+
andMore: (count) => `and ${count} more`,
|
|
591
|
+
findingsHeading: () => 'What it would be worth fixing',
|
|
592
|
+
acrossPrompts: (count) => `${count} ${count === 1 ? 'prompt' : 'prompts'}`,
|
|
593
|
+
findingsNote: () =>
|
|
594
|
+
'Each line is the same advisory trazum optimize raises on those prompts, summed. '
|
|
595
|
+
+ 'Run it on any one of them to see the figure on its own.',
|
|
596
|
+
notAGate: () =>
|
|
597
|
+
'Nothing here fails a build. trazum check is the gate; this is the survey — the '
|
|
598
|
+
+ 'model recommendation is a keyword heuristic, and a build gated on one teaches '
|
|
599
|
+
+ 'people to re-run until green.',
|
|
600
|
+
|
|
601
|
+
sharedPrefixHeading: () => 'Preambles that could share a cache entry and do not',
|
|
602
|
+
sharedPrefixGroup: (count, tokens, drift) =>
|
|
603
|
+
`${count} prompts open with the same ${tokens}-token preamble, `
|
|
604
|
+
+ (drift === 'whitespace'
|
|
605
|
+
? 'differing only in whitespace'
|
|
606
|
+
: 'differing in wording, capitalisation or punctuation'),
|
|
607
|
+
sharedPrefixFix: (drift) =>
|
|
608
|
+
drift === 'whitespace'
|
|
609
|
+
? 'A formatter fixes this: the text already agrees, only the spacing does not.'
|
|
610
|
+
: 'Someone has to pick one wording — the text itself differs, not just its spacing.',
|
|
611
|
+
sharedPrefixNoFigure: () =>
|
|
612
|
+
'No figure is attached, deliberately. Caching matches bytes, so these prompts hold '
|
|
613
|
+
+ 'one cache entry each instead of one between them — but what that costs depends on '
|
|
614
|
+
+ 'how the calls are spread across the group, and Trazum applies a single '
|
|
615
|
+
+ '--cache-hit-rate to every prompt. Pricing it would mean inventing your traffic.',
|
|
616
|
+
},
|
|
617
|
+
|
|
618
|
+
prune: {
|
|
619
|
+
needsExamples: () =>
|
|
620
|
+
'This prompt has fewer than two few-shot examples, so there is nothing to compare.',
|
|
621
|
+
estimate: (examples, cases, calls) =>
|
|
622
|
+
`${examples} examples × ${cases} cases: ${calls} provider calls `
|
|
623
|
+
+ `(2 baselines per case, then one per example removed).`,
|
|
624
|
+
needsConsent: () =>
|
|
625
|
+
'Nothing was called. Add --yes to spend it. This is the only command that asks, '
|
|
626
|
+
+ 'because it is the only one whose bill grows with the length of your prompt.',
|
|
627
|
+
heading: (model) => `What each example is doing, measured on ${model}`,
|
|
628
|
+
selfAgreement: (pct) =>
|
|
629
|
+
`The prompt agrees with itself ${pct} of the time. That is the yardstick: a removal `
|
|
630
|
+
+ 'that moves the answer less than this moved nothing attributable to the example.',
|
|
631
|
+
line: (n, tokens, pct) => `example ${n} — ${tokens} tokens, ${pct} agreement without it`,
|
|
632
|
+
verdictNeeded: () => 'needed here',
|
|
633
|
+
verdictRecoverable: () => 'no effect on these inputs',
|
|
634
|
+
verdictUnknown: () => 'inconclusive',
|
|
635
|
+
recoverable: (tokens) =>
|
|
636
|
+
`${tokens} tokens sit in examples whose removal changed nothing measurable here.`,
|
|
637
|
+
caveat: () =>
|
|
638
|
+
'Which is not the same as "delete them". An example may exist for a case these '
|
|
639
|
+
+ 'inputs do not contain — the boundary condition somebody hit in production and '
|
|
640
|
+
+ 'added a demonstration for. This measures the inputs you gave it, and only you '
|
|
641
|
+
+ 'know whether they cover what matters. Nothing was edited.',
|
|
642
|
+
},
|
|
643
|
+
|
|
644
|
+
eval: {
|
|
645
|
+
nothingToCompare: () =>
|
|
646
|
+
'The rules changed nothing in this prompt, so there is nothing to compare. Try --level aggressive.',
|
|
647
|
+
starting: (cases, calls, model) =>
|
|
648
|
+
`Running ${cases} cases through ${model}: ${calls} calls (the original twice per case, to measure its own variance, and the optimised once).`,
|
|
649
|
+
heading: () => 'Agreement',
|
|
650
|
+
selfAgreement: (pct) => `${pct} the original prompt with itself ${'\u2190'} the yardstick`,
|
|
651
|
+
crossAgreement: (pct) => `${pct} the optimised prompt with the original`,
|
|
652
|
+
verdict: (kind) =>
|
|
653
|
+
({
|
|
654
|
+
indistinguishable: {
|
|
655
|
+
label: 'Indistinguishable',
|
|
656
|
+
detail: 'Every answer matched. On this set the optimisation changed nothing.',
|
|
657
|
+
},
|
|
658
|
+
'within-noise': {
|
|
659
|
+
label: 'Within the model own noise',
|
|
660
|
+
detail:
|
|
661
|
+
'The optimised prompt disagrees with the original about as often as the original disagrees with itself, so the difference is not attributable to the rewrite. Widen the set before trusting this.',
|
|
662
|
+
},
|
|
663
|
+
diverges: {
|
|
664
|
+
label: 'Diverges',
|
|
665
|
+
detail:
|
|
666
|
+
'The model is consistent with itself and markedly less so with the rewrite, so the optimisation changed what the prompt asks for. Read the cases below and the diff before shipping this.',
|
|
667
|
+
},
|
|
668
|
+
inconclusive: {
|
|
669
|
+
label: 'Inconclusive',
|
|
670
|
+
detail:
|
|
671
|
+
'The original prompt does not agree with itself often enough to judge anything against. Lower the temperature, or the task may simply be too open-ended for this test.',
|
|
672
|
+
},
|
|
673
|
+
})[kind],
|
|
674
|
+
mostChanged: () => 'Cases that changed most',
|
|
675
|
+
caseAgreement: (cross, self) => `${cross} agreement with the original (which self-agreed ${self})`,
|
|
676
|
+
exportWarnings: (count) =>
|
|
677
|
+
`${count} ${count === 1 ? 'thing' : 'things'} to know before you trust the run:`,
|
|
678
|
+
exportWrote: (path, cases, assertions) =>
|
|
679
|
+
`Wrote ${path}: two prompts, ${cases} ${cases === 1 ? 'case' : 'cases'}, ` +
|
|
680
|
+
`${assertions === 0 ? 'no assertions' : `${assertions} assertion${assertions === 1 ? '' : 's'} (the prompt asks for JSON)`}. ` +
|
|
681
|
+
`Add yours, then run: npx promptfoo eval -c ${path}`,
|
|
682
|
+
callsMade: (count) => `${count} provider calls made.`,
|
|
683
|
+
},
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
diff: {
|
|
687
|
+
heading: (before, after) => `${before} → ${after}`,
|
|
688
|
+
measuringOptimised: () =>
|
|
689
|
+
'Measuring what the rules would leave, not what is written.',
|
|
690
|
+
monthly: (delta, calls, model) =>
|
|
691
|
+
`${delta}/month at ${calls} calls with ${model}`,
|
|
692
|
+
advisoriesAppeared: () => 'New problems',
|
|
693
|
+
advisoriesResolved: () => 'Resolved',
|
|
694
|
+
rulesNewlyFiring: () => 'Rules that now find something:',
|
|
695
|
+
rulesNoLongerFiring: () => 'Rules that no longer find anything:',
|
|
696
|
+
overLimit: (delta, max) =>
|
|
697
|
+
`Grew by ${delta} tokens, past the limit of ${max}.`,
|
|
698
|
+
someOverLimit: (count, max) =>
|
|
699
|
+
`${count} ${count === 1 ? 'prompt grew' : 'prompts grew'} past the per-prompt limit of ${max} tokens:`,
|
|
700
|
+
allSubheading: (prompts) =>
|
|
701
|
+
`${prompts} ${prompts === 1 ? 'prompt' : 'prompts'} on both sides.`,
|
|
702
|
+
allTotal: (delta, prompts) =>
|
|
703
|
+
`${delta} tokens across ${prompts} ${prompts === 1 ? 'prompt' : 'prompts'}`,
|
|
704
|
+
signConvention: () =>
|
|
705
|
+
'Every figure is after minus before, so positive means worse — the opposite of the rest of Trazum.',
|
|
706
|
+
onlyBefore: () => 'only before',
|
|
707
|
+
onlyAfter: () => 'only after ',
|
|
708
|
+
onlyOneSideNote: () =>
|
|
709
|
+
'Not counted in the totals. A prompt that vanished is a question, not a saving.',
|
|
710
|
+
},
|
|
711
|
+
|
|
712
|
+
markdown: {
|
|
713
|
+
checkHeading: (target) => `Trazum — token budgets for ${target}`,
|
|
714
|
+
baselineGrew: (delta, pct) => `This branch adds ${delta} tokens (${pct}) to the prompts here`,
|
|
715
|
+
baselineShrank: (delta, pct) => `This branch removes ${delta} tokens (${pct}) from the prompts here`,
|
|
716
|
+
baselineUnchanged: () => 'No change against the recorded baseline',
|
|
717
|
+
baselineOverLimit: (limits) => `over the limit of ${limits}`,
|
|
718
|
+
baselineLimitTokens: (limit) => `${limit} tokens`,
|
|
719
|
+
baselineLimitPct: (limit) => `${limit}%`,
|
|
720
|
+
baselineColumnBefore: () => 'Baseline',
|
|
721
|
+
baselineColumnAfter: () => 'Now',
|
|
722
|
+
baselineMoney: (before, after, delta) => `Monthly cost **${before} \u2192 ${after}** (${delta})`,
|
|
723
|
+
baselineMoneyIncomparable: () =>
|
|
724
|
+
'The scenario or the price list moved since the baseline was recorded, so the two monthly figures are not the same measurement and are not subtracted here. The token comparison above is unaffected.',
|
|
725
|
+
baselineReRecord: (command, path) =>
|
|
726
|
+
`If this growth is intended, re-record with \`${command}\` and commit \`${path}\`.`,
|
|
727
|
+
diffHeading: (before, after) => `Trazum — ${before} → ${after}`,
|
|
728
|
+
rankHeading: (root, count) =>
|
|
729
|
+
`Trazum — what to fix first in ${root} (${count} ${count === 1 ? "prompt" : "prompts"})`,
|
|
730
|
+
blameHeading: (path) => `Trazum — token history for ${path}`,
|
|
731
|
+
rankLevel: (level) => `Measured at rule level \`${level}\`.`,
|
|
732
|
+
columnFile: () => 'Prompt',
|
|
733
|
+
columnTokens: () => 'Tokens',
|
|
734
|
+
columnBudget: () => 'Budget',
|
|
735
|
+
columnMetric: () => 'Metric',
|
|
736
|
+
columnChange: () => 'Change',
|
|
737
|
+
allWithin: (budgeted) =>
|
|
738
|
+
budgeted === 1
|
|
739
|
+
? 'The prompt is within budget.'
|
|
740
|
+
: `All ${budgeted} budgeted prompts are within budget.`,
|
|
741
|
+
overBudget: (failures, budgeted) => `${failures} of ${budgeted} over budget`,
|
|
742
|
+
noBudget: () => '—',
|
|
743
|
+
unbudgetedNote: (count) =>
|
|
744
|
+
count === 1
|
|
745
|
+
? '1 prompt is not covered by any budget pattern, so nothing is watching it.'
|
|
746
|
+
: `${count} prompts are not covered by any budget pattern, so nothing is watching them.`,
|
|
747
|
+
whatWouldHelp: () => 'What would help',
|
|
748
|
+
wouldFit: (level, optimizedTokens) =>
|
|
749
|
+
`optimising at \`${level}\` would land at ~${optimizedTokens} tokens, which fits`,
|
|
750
|
+
stillTooBig: (optimizedTokens) =>
|
|
751
|
+
`even optimised it does not fit (~${optimizedTokens} tokens): content has to be cut by hand`,
|
|
752
|
+
truncated: () =>
|
|
753
|
+
'Stopped early: the directory is larger than the walk limit, so this is not the whole picture.',
|
|
754
|
+
footer: (source, level) => `Token counts ${source} · rule level \`${level}\``,
|
|
755
|
+
pricingOverlaid: (count, lastReviewed) =>
|
|
756
|
+
`Prices for ${count} ${count === 1 ? 'model' : 'models'} came from a local overlay reviewed ${lastReviewed}.`,
|
|
757
|
+
sourceEstimated: () => 'estimated, ±15%',
|
|
758
|
+
sourceExact: () => 'counted exactly',
|
|
759
|
+
measuringOptimised: () =>
|
|
760
|
+
'Measuring what the rules would leave, not what is written in the file.',
|
|
761
|
+
metricTokens: (before, after) => `Input tokens (${before} → ${after})`,
|
|
762
|
+
metricMonthly: (calls, model) => `Cost per month at ${calls} calls with ${model}`,
|
|
763
|
+
deltaConvention: () =>
|
|
764
|
+
'Every figure is a delta: after minus before, so <strong>positive means worse</strong>. ' +
|
|
765
|
+
'This is the opposite of the rest of Trazum, where every figure is a saving.',
|
|
766
|
+
advisoriesAppeared: () => 'Problems this edit introduced',
|
|
767
|
+
advisoriesResolved: () => 'Problems this edit resolved',
|
|
768
|
+
rulesNewlyFiring: () => 'Rules that now find something',
|
|
769
|
+
rulesNoLongerFiring: () => 'Rules that no longer find anything',
|
|
770
|
+
collapsedNote: () => 'nothing over budget, expand for the numbers',
|
|
771
|
+
trimNotice: () =>
|
|
772
|
+
'_Trimmed to fit a comment. The full report is in the workflow run summary._',
|
|
773
|
+
commentTitle: () => 'Trazum',
|
|
774
|
+
},
|
|
775
|
+
|
|
776
|
+
check: {
|
|
777
|
+
okLabel: () => 'OK',
|
|
778
|
+
embeddedHeading: (path, count) =>
|
|
779
|
+
`${path} — ${count} marked ${count === 1 ? 'prompt' : 'prompts'}`,
|
|
780
|
+
declinedHeading: (count) =>
|
|
781
|
+
`${count} ${count === 1 ? 'marker' : 'markers'} could not be read:`,
|
|
782
|
+
declinedAt: (line, detail) => `line ${line}: ${detail}`,
|
|
783
|
+
failedLabel: () => 'FAILED',
|
|
784
|
+
ok: (tokens, budget) => `${tokens} tokens, within the budget of ${budget}.`,
|
|
785
|
+
failed: (tokens, budget) => `${tokens} tokens busts the budget of ${budget}.`,
|
|
786
|
+
wouldFit: (level, optimizedTokens) =>
|
|
787
|
+
` Optimised with "trazum optimize --level ${level}" it would land at ~${optimizedTokens} tokens and fit.`,
|
|
788
|
+
stillTooBig: (optimizedTokens) =>
|
|
789
|
+
` Even optimised it does not fit (~${optimizedTokens} tokens): content has to be cut by hand.`,
|
|
790
|
+
directoryHeading: (directory, files) =>
|
|
791
|
+
`${directory} — ${files} ${files === 1 ? 'prompt' : 'prompts'}`,
|
|
792
|
+
directorySummary: (failures, files) =>
|
|
793
|
+
failures === 0
|
|
794
|
+
? `All ${files} within budget.`
|
|
795
|
+
: `${failures} of ${files} over budget.`,
|
|
796
|
+
noBudget: () => '(no budget)',
|
|
797
|
+
walkTruncated: () =>
|
|
798
|
+
'Stopped early: the directory is larger than the walk limit, so this is not the whole picture.',
|
|
799
|
+
exactCountsCost: (files) =>
|
|
800
|
+
`Counting ${files} ${files === 1 ? 'file' : 'files'} through the API, one call each. This takes a moment.`,
|
|
801
|
+
},
|
|
802
|
+
baseline: {
|
|
803
|
+
recorded: (path, files, tokens) =>
|
|
804
|
+
`Recorded ${files} prompts, ${tokens} tokens, to ${path}. Commit it — the gate compares the tree against what is committed.`,
|
|
805
|
+
recordedMoney: (monthly, model, calls) =>
|
|
806
|
+
`That is ${monthly} per month with ${model} at ${calls} calls. Reported, not gated on: thresholds are in tokens, so a repriced model never fails a build on its own.`,
|
|
807
|
+
heading: () => 'Against the baseline',
|
|
808
|
+
unchanged: (tokens) => `unchanged at ${tokens} tokens`,
|
|
809
|
+
grew: (delta, pct, tokens) => `grew by ${delta} tokens (${pct}) to ${tokens}`,
|
|
810
|
+
shrank: (delta, pct, tokens) => `shrank by ${delta} tokens (${pct}) to ${tokens}`,
|
|
811
|
+
entry: (path, before, after, delta) => `${path} ${before} \u2192 ${after} (${delta})`,
|
|
812
|
+
addedHeading: (count) => `New since the baseline (${count})`,
|
|
813
|
+
removedHeading: (count) => `Gone since the baseline (${count})`,
|
|
814
|
+
grownHeading: (count) => `Grew (${count})`,
|
|
815
|
+
breachTokens: (actual, limit) => `growth of ${actual} tokens is over the limit of ${limit}`,
|
|
816
|
+
breachPct: (actual, limit) => `growth of ${actual} is over the limit of ${limit}`,
|
|
817
|
+
reRecord: (path) =>
|
|
818
|
+
`If the growth is intended, re-record with "trazum baseline" and commit ${path}.`,
|
|
819
|
+
money: (before, after, delta) => `Monthly cost ${before} \u2192 ${after} (${delta})`,
|
|
820
|
+
moneyIncomparableScenario: () =>
|
|
821
|
+
'The usage scenario changed since the baseline was recorded, so the two monthly figures are not the same measurement. The token comparison is unaffected.',
|
|
822
|
+
moneyIncomparablePricing: (was, now) =>
|
|
823
|
+
`Prices were reviewed ${was} when the baseline was recorded and ${now} now, so the monthly figures are not the same measurement. The token comparison is unaffected.`,
|
|
824
|
+
},
|
|
825
|
+
};
|