@trazum/core 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 +163 -0
- package/dist/advisories.d.ts +23 -0
- package/dist/advisories.d.ts.map +1 -0
- package/dist/advisories.js +376 -0
- package/dist/advisories.js.map +1 -0
- package/dist/aws-sigv4.d.ts +88 -0
- package/dist/aws-sigv4.d.ts.map +1 -0
- package/dist/aws-sigv4.js +117 -0
- package/dist/aws-sigv4.js.map +1 -0
- package/dist/baseline.d.ts +171 -0
- package/dist/baseline.d.ts.map +1 -0
- package/dist/baseline.js +273 -0
- package/dist/baseline.js.map +1 -0
- package/dist/cache.d.ts +26 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +28 -0
- package/dist/cache.js.map +1 -0
- package/dist/changes.d.ts +29 -0
- package/dist/changes.d.ts.map +1 -0
- package/dist/changes.js +142 -0
- package/dist/changes.js.map +1 -0
- package/dist/compare.d.ts +65 -0
- package/dist/compare.d.ts.map +1 -0
- package/dist/compare.js +58 -0
- package/dist/compare.js.map +1 -0
- package/dist/config-schema.d.ts +118 -0
- package/dist/config-schema.d.ts.map +1 -0
- package/dist/config-schema.js +315 -0
- package/dist/config-schema.js.map +1 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +112 -0
- package/dist/config.js.map +1 -0
- package/dist/detect.d.ts +70 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +228 -0
- package/dist/detect.js.map +1 -0
- package/dist/evaluate.d.ts +98 -0
- package/dist/evaluate.d.ts.map +1 -0
- package/dist/evaluate.js +110 -0
- package/dist/evaluate.js.map +1 -0
- package/dist/extract.d.ts +81 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +280 -0
- package/dist/extract.js.map +1 -0
- package/dist/gcp-auth.d.ts +58 -0
- package/dist/gcp-auth.d.ts.map +1 -0
- package/dist/gcp-auth.js +113 -0
- package/dist/gcp-auth.js.map +1 -0
- package/dist/glob.d.ts +49 -0
- package/dist/glob.d.ts.map +1 -0
- package/dist/glob.js +154 -0
- package/dist/glob.js.map +1 -0
- package/dist/host.d.ts +30 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +69 -0
- package/dist/host.js.map +1 -0
- package/dist/i18n/en.d.ts +4 -0
- package/dist/i18n/en.d.ts.map +1 -0
- package/dist/i18n/en.js +168 -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 +168 -0
- package/dist/i18n/es.js.map +1 -0
- package/dist/i18n/index.d.ts +36 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +50 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/types.d.ts +180 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n/types.js +11 -0
- package/dist/i18n/types.js.map +1 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/llm.d.ts +226 -0
- package/dist/llm.d.ts.map +1 -0
- package/dist/llm.js +485 -0
- package/dist/llm.js.map +1 -0
- package/dist/nearest.d.ts +20 -0
- package/dist/nearest.d.ts.map +1 -0
- package/dist/nearest.js +54 -0
- package/dist/nearest.js.map +1 -0
- package/dist/net.d.ts +90 -0
- package/dist/net.d.ts.map +1 -0
- package/dist/net.js +203 -0
- package/dist/net.js.map +1 -0
- package/dist/node.d.ts +32 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +33 -0
- package/dist/node.js.map +1 -0
- package/dist/openrouter.d.ts +25 -0
- package/dist/openrouter.d.ts.map +1 -0
- package/dist/openrouter.js +72 -0
- package/dist/openrouter.js.map +1 -0
- package/dist/optimize.d.ts +38 -0
- package/dist/optimize.d.ts.map +1 -0
- package/dist/optimize.js +183 -0
- package/dist/optimize.js.map +1 -0
- package/dist/otlp.d.ts +91 -0
- package/dist/otlp.d.ts.map +1 -0
- package/dist/otlp.js +102 -0
- package/dist/otlp.js.map +1 -0
- package/dist/phrases.d.ts +169 -0
- package/dist/phrases.d.ts.map +1 -0
- package/dist/phrases.js +939 -0
- package/dist/phrases.js.map +1 -0
- package/dist/pricing-overlay.d.ts +55 -0
- package/dist/pricing-overlay.d.ts.map +1 -0
- package/dist/pricing-overlay.js +241 -0
- package/dist/pricing-overlay.js.map +1 -0
- package/dist/pricing.d.ts +115 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +400 -0
- package/dist/pricing.js.map +1 -0
- package/dist/profile.d.ts +71 -0
- package/dist/profile.d.ts.map +1 -0
- package/dist/profile.js +55 -0
- package/dist/profile.js.map +1 -0
- package/dist/promptfoo.d.ts +58 -0
- package/dist/promptfoo.d.ts.map +1 -0
- package/dist/promptfoo.js +149 -0
- package/dist/promptfoo.js.map +1 -0
- package/dist/prune.d.ts +91 -0
- package/dist/prune.d.ts.map +1 -0
- package/dist/prune.js +110 -0
- package/dist/prune.js.map +1 -0
- package/dist/reorder.d.ts +82 -0
- package/dist/reorder.d.ts.map +1 -0
- package/dist/reorder.js +215 -0
- package/dist/reorder.js.map +1 -0
- package/dist/review.d.ts +54 -0
- package/dist/review.d.ts.map +1 -0
- package/dist/review.js +131 -0
- package/dist/review.js.map +1 -0
- package/dist/rules.d.ts +5 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +279 -0
- package/dist/rules.js.map +1 -0
- package/dist/savings.d.ts +36 -0
- package/dist/savings.d.ts.map +1 -0
- package/dist/savings.js +83 -0
- package/dist/savings.js.map +1 -0
- package/dist/segment.d.ts +8 -0
- package/dist/segment.d.ts.map +1 -0
- package/dist/segment.js +74 -0
- package/dist/segment.js.map +1 -0
- package/dist/shared-prefix.d.ts +63 -0
- package/dist/shared-prefix.d.ts.map +1 -0
- package/dist/shared-prefix.js +151 -0
- package/dist/shared-prefix.js.map +1 -0
- package/dist/similarity.d.ts +13 -0
- package/dist/similarity.d.ts.map +1 -0
- package/dist/similarity.js +30 -0
- package/dist/similarity.js.map +1 -0
- package/dist/structure.d.ts +144 -0
- package/dist/structure.d.ts.map +1 -0
- package/dist/structure.js +455 -0
- package/dist/structure.js.map +1 -0
- package/dist/suggest.d.ts +100 -0
- package/dist/suggest.d.ts.map +1 -0
- package/dist/suggest.js +151 -0
- package/dist/suggest.js.map +1 -0
- package/dist/tokenizer.d.ts +57 -0
- package/dist/tokenizer.d.ts.map +1 -0
- package/dist/tokenizer.js +157 -0
- package/dist/tokenizer.js.map +1 -0
- package/dist/types.d.ts +296 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/walk.d.ts +40 -0
- package/dist/walk.d.ts.map +1 -0
- package/dist/walk.js +95 -0
- package/dist/walk.js.map +1 -0
- package/package.json +56 -0
- package/src/advisories.ts +431 -0
- package/src/aws-sigv4.ts +174 -0
- package/src/baseline.ts +390 -0
- package/src/cache.ts +54 -0
- package/src/changes.ts +158 -0
- package/src/compare.ts +131 -0
- package/src/config-schema.ts +451 -0
- package/src/config.ts +161 -0
- package/src/detect.ts +312 -0
- package/src/evaluate.ts +188 -0
- package/src/extract.ts +336 -0
- package/src/gcp-auth.ts +166 -0
- package/src/glob.ts +160 -0
- package/src/host.ts +90 -0
- package/src/i18n/en.ts +236 -0
- package/src/i18n/es.ts +236 -0
- package/src/i18n/index.ts +68 -0
- package/src/i18n/types.ts +230 -0
- package/src/index.ts +228 -0
- package/src/llm.ts +708 -0
- package/src/nearest.ts +61 -0
- package/src/net.ts +233 -0
- package/src/node.ts +63 -0
- package/src/openrouter.ts +125 -0
- package/src/optimize.ts +228 -0
- package/src/otlp.ts +179 -0
- package/src/phrases.ts +1047 -0
- package/src/pricing-overlay.ts +319 -0
- package/src/pricing.ts +468 -0
- package/src/profile.ts +124 -0
- package/src/promptfoo.ts +213 -0
- package/src/prune.ts +211 -0
- package/src/reorder.ts +307 -0
- package/src/review.ts +180 -0
- package/src/rules.ts +324 -0
- package/src/savings.ts +121 -0
- package/src/segment.ts +106 -0
- package/src/shared-prefix.ts +198 -0
- package/src/similarity.ts +28 -0
- package/src/structure.ts +652 -0
- package/src/suggest.ts +254 -0
- package/src/tokenizer.ts +190 -0
- package/src/types.ts +323 -0
- package/src/walk.ts +117 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 David Muñoz Rey
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @trazum/core
|
|
2
|
+
|
|
3
|
+
Prompt optimiser. Shortens what you send to a model without changing what you
|
|
4
|
+
ask for, and tells you what that is worth per month.
|
|
5
|
+
|
|
6
|
+
**Zero runtime dependencies**, and that is asserted in CI rather than promised.
|
|
7
|
+
This library reads your prompts; every dependency would be someone else's code
|
|
8
|
+
reading them too.
|
|
9
|
+
|
|
10
|
+
Part of [Trazum](https://github.com/Davmunrey/Trazum). For the terminal, see
|
|
11
|
+
[`@trazum/cli`](https://www.npmjs.com/package/@trazum/cli).
|
|
12
|
+
|
|
13
|
+
> [!NOTE]
|
|
14
|
+
> **Not published yet.** The command below will not work today — there is no tag
|
|
15
|
+
> and `npm view` returns 404. Run it from source meanwhile:
|
|
16
|
+
> [github.com/Davmunrey/Trazum](https://github.com/Davmunrey/Trazum#getting-started).
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @trazum/core
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Use
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { optimize } from '@trazum/core';
|
|
26
|
+
|
|
27
|
+
const result = optimize(prompt, {
|
|
28
|
+
level: 'safe', // or 'aggressive' — read the diff
|
|
29
|
+
usage: {
|
|
30
|
+
model: 'claude-opus-5',
|
|
31
|
+
callsPerMonth: 50_000,
|
|
32
|
+
avgOutputTokens: 500,
|
|
33
|
+
cacheHitRate: 0.9,
|
|
34
|
+
batchEligible: false,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
result.optimized; // the shortened prompt
|
|
39
|
+
result.savings.monthlySavingsUsd; // what that is worth
|
|
40
|
+
result.advisories; // usually where the real money is
|
|
41
|
+
result.rules; // what each rule changed, with samples
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The optimisation is **deterministic**: same input, same output, no API key, no
|
|
45
|
+
network call, nothing to pay.
|
|
46
|
+
|
|
47
|
+
## What it does
|
|
48
|
+
|
|
49
|
+
**Trims with deterministic rules** — courtesy, filler, verbose phrasing,
|
|
50
|
+
duplicated paragraphs, decorative separators, shouting in capitals.
|
|
51
|
+
|
|
52
|
+
**Never touches what would break the prompt.** Code fences, inline code, URLs,
|
|
53
|
+
template placeholders (`{{x}}`, `${x}`, `{x}`, `{% %}`) and XML/HTML tags are
|
|
54
|
+
isolated *before* any rule runs. If a rule ever did make one of those disappear,
|
|
55
|
+
that rule is discarded and the rest carry on.
|
|
56
|
+
|
|
57
|
+
**Tells you where the money actually is.** Trimming is usually not it. Read
|
|
58
|
+
`result.advisories` first — they are sorted warnings-first, then by monthly
|
|
59
|
+
saving:
|
|
60
|
+
|
|
61
|
+
| Advisory | What it finds |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `prompt-caching` | Caching is a byte-for-byte prefix match, so a template only caches up to its first placeholder. The saving is computed over the **real** stable prefix. |
|
|
64
|
+
| `cache-prefix-reorder` | Stable instructions stranded *after* the first placeholder never cache. Often the single largest saving available. |
|
|
65
|
+
| `contradictory-instructions` | "Answer in English" three paragraphs above "reply in the customer's own language". A correctness bug that also costs tokens twice. |
|
|
66
|
+
| `redundant-examples` | Few-shot examples that are near-copies of an earlier one. |
|
|
67
|
+
| `restated-output-format` | A schema shown in a code block and then walked again in prose. |
|
|
68
|
+
| `movable-output-schema` | A schema the request could carry as a parameter instead — cheaper *and* stricter, and the one finding that is not a trade-off. Reported, never edited: it changes the call, not the prompt. |
|
|
69
|
+
| `model-downgrade` | A keyword heuristic, not a quality judgement — validate with evaluations before acting on it. |
|
|
70
|
+
| `output-dominated` | You pay more for the answer than the prompt, so shortening it has a ceiling. |
|
|
71
|
+
| `batch-api`, `below-cache-minimum`, `context-window`, `promotional-pricing` | |
|
|
72
|
+
|
|
73
|
+
The last three structural findings are **advisory only**. A contradiction has a
|
|
74
|
+
right answer only you know, and an example that looks redundant may be
|
|
75
|
+
demonstrating a boundary case on purpose. Trazum points; it does not cut.
|
|
76
|
+
|
|
77
|
+
## Comparing two versions
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { comparePrompts, formatSignedUsd } from '@trazum/core';
|
|
81
|
+
|
|
82
|
+
const change = comparePrompts(before, after, { usage });
|
|
83
|
+
|
|
84
|
+
change.tokenDelta; // +37 (grew)
|
|
85
|
+
formatSignedUsd(change.monthlyDeltaUsd); // "+$9.25"
|
|
86
|
+
change.advisories.appeared; // what the edit broke
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Note the sign.** Everything `comparePrompts` returns is `after - before`, so
|
|
90
|
+
**positive means worse** — the opposite of `result.savings`. That is why it lives
|
|
91
|
+
in its own module and why nothing in it is called a saving.
|
|
92
|
+
|
|
93
|
+
## Prices
|
|
94
|
+
|
|
95
|
+
The bundled catalogue is correct as of `PRICING_LAST_REVIEWED` and needs no
|
|
96
|
+
setup. When a published price moves, correct it without upgrading this package:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { catalogueFromOverlay, optimize } from '@trazum/core';
|
|
100
|
+
|
|
101
|
+
const pricing = catalogueFromOverlay(`{
|
|
102
|
+
"lastReviewed": "2027-01-15",
|
|
103
|
+
"models": { "claude-opus-5": { "inputPerMTok": 6 } }
|
|
104
|
+
}`);
|
|
105
|
+
|
|
106
|
+
const result = optimize(prompt, { usage, pricing });
|
|
107
|
+
result.pricingSource; // says which models came from the overlay, and its date
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
A catalogue is a **value**: applying an overlay returns a new one and mutates
|
|
111
|
+
nothing, so your prices never leak into another caller's report.
|
|
112
|
+
|
|
113
|
+
## Two entry points
|
|
114
|
+
|
|
115
|
+
`@trazum/core` imports **no Node builtins** — enforced by a test that walks the
|
|
116
|
+
import graph, because the browser bundles it. Anything that reads the filesystem
|
|
117
|
+
lives on `@trazum/core/node`:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { loadConfig, walkPrompts } from '@trazum/core/node';
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Optional LLM pass
|
|
124
|
+
|
|
125
|
+
For the compression rules cannot do. The result is only accepted if it is
|
|
126
|
+
shorter **and** leaves protected content byte-identical — it never returns
|
|
127
|
+
something worse than where it started.
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import { openAiCompatible, refineWithLlm } from '@trazum/core';
|
|
131
|
+
|
|
132
|
+
const refined = await refineWithLlm(result, openAiCompatible({
|
|
133
|
+
baseUrl: 'https://your-llm/v1',
|
|
134
|
+
apiKey: process.env.LLM_KEY,
|
|
135
|
+
model: 'your-model',
|
|
136
|
+
}));
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Token counts
|
|
140
|
+
|
|
141
|
+
The bundled estimator is a dependency-free heuristic, accurate to about **±15%**
|
|
142
|
+
on ordinary prose, and it compares two versions of the same prompt well — which
|
|
143
|
+
is what it is for. For exact figures, pass a real counter:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import { countTokensAnthropic, withExactTokenCounts } from '@trazum/core';
|
|
147
|
+
|
|
148
|
+
const exact = await withExactTokenCounts(result, countTokensAnthropic({ apiKey }));
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Locales
|
|
152
|
+
|
|
153
|
+
English and Spanish. **A locale changes the report, never the optimisation** —
|
|
154
|
+
the same prompt in any locale produces the same optimised text, the same token
|
|
155
|
+
counts and the same advisory ids. Match on ids, not on prose.
|
|
156
|
+
|
|
157
|
+
## Versioning
|
|
158
|
+
|
|
159
|
+
See [VERSIONING.md](https://github.com/Davmunrey/Trazum/blob/main/VERSIONING.md).
|
|
160
|
+
Rule and advisory **identifiers** are stable across locales and versions on
|
|
161
|
+
purpose; message **text** is copy and gets improved.
|
|
162
|
+
|
|
163
|
+
MIT.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Locale } from './i18n/types.js';
|
|
2
|
+
import type { PricingCatalogue } from './pricing.js';
|
|
3
|
+
import type { Advisory, ModelPricing, TokenCounter, UsageProfile } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Estimates the capability tier the prompt needs.
|
|
6
|
+
*
|
|
7
|
+
* This is a keyword-and-size heuristic, not a judgement about answer quality.
|
|
8
|
+
* Treat it as a hypothesis to validate with your own evaluations before
|
|
9
|
+
* moving down a tier in production.
|
|
10
|
+
*/
|
|
11
|
+
export declare function recommendTier(prompt: string, tokens: number): ModelPricing['tier'];
|
|
12
|
+
export interface AdvisoryOptions {
|
|
13
|
+
/** Reference date, used to decide whether a promotional price is live. */
|
|
14
|
+
on?: Date;
|
|
15
|
+
/** Token counter, so the cache-prefix analysis matches the caller's. */
|
|
16
|
+
count?: TokenCounter;
|
|
17
|
+
locale?: Locale;
|
|
18
|
+
/** Prices to work from. Defaults to the catalogue bundled with this release. */
|
|
19
|
+
pricing?: PricingCatalogue;
|
|
20
|
+
}
|
|
21
|
+
/** Builds the advisories that do not modify the prompt but do move the bill. */
|
|
22
|
+
export declare function buildAdvisories(optimizedPrompt: string, tokensAfter: number, usage: UsageProfile, options?: AdvisoryOptions): Advisory[];
|
|
23
|
+
//# sourceMappingURL=advisories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advisories.d.ts","sourceRoot":"","sources":["../src/advisories.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAG9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAKrD,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAQrF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAclF;AAsDD,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,EAAE,CAAC,EAAE,IAAI,CAAC;IACV,wEAAwE;IACxE,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC5B;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAC7B,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,YAAY,EACnB,OAAO,GAAE,eAAoB,GAC5B,QAAQ,EAAE,CAiUZ"}
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { analyzeCachePrefix } from './cache.js';
|
|
2
|
+
import { getMessages } from './i18n/index.js';
|
|
3
|
+
import { COMPLEX_SIGNALS, SIMPLE_SIGNALS } from './phrases.js';
|
|
4
|
+
import { BUNDLED_CATALOGUE, effectivePricing, modelFrom, multipliersFor } from './pricing.js';
|
|
5
|
+
import { formatUsd } from './savings.js';
|
|
6
|
+
import { analyzeExamples, findContradictions, findMovableSchema, findRestatedFormat } from './structure.js';
|
|
7
|
+
import { estimateTokens } from './tokenizer.js';
|
|
8
|
+
function countSignals(haystack, signals) {
|
|
9
|
+
let count = 0;
|
|
10
|
+
for (const signal of signals)
|
|
11
|
+
if (haystack.includes(signal))
|
|
12
|
+
count++;
|
|
13
|
+
return count;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Estimates the capability tier the prompt needs.
|
|
17
|
+
*
|
|
18
|
+
* This is a keyword-and-size heuristic, not a judgement about answer quality.
|
|
19
|
+
* Treat it as a hypothesis to validate with your own evaluations before
|
|
20
|
+
* moving down a tier in production.
|
|
21
|
+
*/
|
|
22
|
+
export function recommendTier(prompt, tokens) {
|
|
23
|
+
const haystack = prompt.toLowerCase();
|
|
24
|
+
let score = countSignals(haystack, COMPLEX_SIGNALS) * 2 - countSignals(haystack, SIMPLE_SIGNALS) * 2;
|
|
25
|
+
if (tokens > 4000)
|
|
26
|
+
score += 2;
|
|
27
|
+
else if (tokens > 1500)
|
|
28
|
+
score += 1;
|
|
29
|
+
else if (tokens < 300)
|
|
30
|
+
score -= 1;
|
|
31
|
+
if (/```|~~~/.test(prompt))
|
|
32
|
+
score += 1;
|
|
33
|
+
if (score >= 3)
|
|
34
|
+
return 'opus';
|
|
35
|
+
if (score >= 0)
|
|
36
|
+
return 'sonnet';
|
|
37
|
+
return 'haiku';
|
|
38
|
+
}
|
|
39
|
+
const TIER_ORDER = {
|
|
40
|
+
/**
|
|
41
|
+
* Below every real tier, so no tier is ever "less capable than unknown".
|
|
42
|
+
*
|
|
43
|
+
* The value carries the intent rather than the guard below carrying it alone.
|
|
44
|
+
* Set the other way — above everything — the comparison
|
|
45
|
+
* `TIER_ORDER[suggested] < TIER_ORDER['unknown']` is true for every prompt,
|
|
46
|
+
* and the only thing left standing between that and a recommendation is an
|
|
47
|
+
* unrelated provider filter. Mutation testing found exactly that: deleting
|
|
48
|
+
* the guard changed no test result, because a second accident was covering
|
|
49
|
+
* for it. Two accidents in a row is not a design.
|
|
50
|
+
*/
|
|
51
|
+
unknown: Number.NEGATIVE_INFINITY,
|
|
52
|
+
haiku: 0,
|
|
53
|
+
sonnet: 1,
|
|
54
|
+
opus: 2,
|
|
55
|
+
frontier: 3,
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Cheapest model of a capability tier, using today's effective input price.
|
|
59
|
+
*
|
|
60
|
+
* **Within the same provider**, which is a product decision rather than an
|
|
61
|
+
* implementation detail. Dropping from Opus to Sonnet is a one-line change;
|
|
62
|
+
* moving to another vendor is a different API, different behaviour and a
|
|
63
|
+
* migration. This advisory is already caveated as a keyword heuristic rather
|
|
64
|
+
* than a judgement about answer quality, and a keyword heuristic has no business
|
|
65
|
+
* recommending that somebody change supplier.
|
|
66
|
+
*
|
|
67
|
+
* A model with no provider recorded only matches others with none, so an overlay
|
|
68
|
+
* that adds a bare model cannot pull a switch out of thin air.
|
|
69
|
+
*/
|
|
70
|
+
function cheapestInTier(tier, on, pricing, provider) {
|
|
71
|
+
const candidates = pricing.models.filter((m) => m.tier === tier &&
|
|
72
|
+
m.provider === provider &&
|
|
73
|
+
// Not generally available: recommending a model the reader cannot call is
|
|
74
|
+
// worse than recommending nothing.
|
|
75
|
+
m.recommendable !== false);
|
|
76
|
+
if (candidates.length === 0)
|
|
77
|
+
return undefined;
|
|
78
|
+
return candidates.reduce((best, m) => effectivePricing(m, on).inputPerMTok < effectivePricing(best, on).inputPerMTok ? m : best);
|
|
79
|
+
}
|
|
80
|
+
/** Builds the advisories that do not modify the prompt but do move the bill. */
|
|
81
|
+
export function buildAdvisories(optimizedPrompt, tokensAfter, usage, options = {}) {
|
|
82
|
+
const { on = new Date(), count = estimateTokens, locale, pricing = BUNDLED_CATALOGUE } = options;
|
|
83
|
+
const t = getMessages(locale);
|
|
84
|
+
const advisories = [];
|
|
85
|
+
const model = modelFrom(pricing, usage.model);
|
|
86
|
+
const { inputPerMTok, outputPerMTok, promoApplied } = effectivePricing(model, on);
|
|
87
|
+
// Per model, not global. A cache read is ~10% of input on Anthropic and about
|
|
88
|
+
// half on OpenAI; one constant for both overstates an OpenAI caching saving
|
|
89
|
+
// fivefold, which is an invented saving rather than an imprecise one.
|
|
90
|
+
const rates = multipliersFor(model);
|
|
91
|
+
const batchFactor = usage.batchEligible ? (rates.batch ?? 1) : 1;
|
|
92
|
+
const monthlyInputUsd = (tokensAfter / 1_000_000) * inputPerMTok * usage.callsPerMonth * batchFactor;
|
|
93
|
+
const monthlyOutputUsd = (usage.avgOutputTokens / 1_000_000) * outputPerMTok * usage.callsPerMonth * batchFactor;
|
|
94
|
+
// --- Context window ---
|
|
95
|
+
if (tokensAfter > model.contextWindow) {
|
|
96
|
+
advisories.push({
|
|
97
|
+
id: 'context-overflow',
|
|
98
|
+
severity: 'warning',
|
|
99
|
+
...t.advisories.contextOverflow({
|
|
100
|
+
tokens: tokensAfter,
|
|
101
|
+
modelName: model.displayName,
|
|
102
|
+
contextWindow: model.contextWindow,
|
|
103
|
+
}),
|
|
104
|
+
estimatedMonthlyUsd: null,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
// --- Prompt caching ---
|
|
108
|
+
// Caching is a prefix match: in a template with placeholders, only what
|
|
109
|
+
// precedes the first placeholder is cached. Costing the whole prompt would
|
|
110
|
+
// be a lie the moment {{x}} takes a different value between calls.
|
|
111
|
+
const cache = analyzeCachePrefix(optimizedPrompt, count);
|
|
112
|
+
// A provider with no prompt caching gets no caching advice. Without this the
|
|
113
|
+
// zero minimum satisfies `0 >= 0` and Trazum offers a saving that cannot be
|
|
114
|
+
// bought at any price — the exact failure that moving the multipliers onto the
|
|
115
|
+
// model was meant to prevent, reintroduced one field along.
|
|
116
|
+
/**
|
|
117
|
+
* Three ways to have nothing useful to say about caching, and only one of
|
|
118
|
+
* them used to be handled.
|
|
119
|
+
*
|
|
120
|
+
* `none` is a fact: the provider does not cache, so advice would be a saving
|
|
121
|
+
* nobody can buy. `unknown` is the absence of a fact — a catalogue built from
|
|
122
|
+
* a live price feed knows what a model costs and not how it caches — and it
|
|
123
|
+
* has to decline for the opposite reason: not because the answer is no, but
|
|
124
|
+
* because nobody asked anyone. Guessing either way is a number in somebody's
|
|
125
|
+
* budget that came from nowhere.
|
|
126
|
+
*/
|
|
127
|
+
const cachingKnown = model.caching !== 'none' && model.caching !== 'unknown' && model.cacheMinTokens !== null;
|
|
128
|
+
if (usage.callsPerMonth > 1 && cachingKnown) {
|
|
129
|
+
const prefixShare = tokensAfter > 0 ? cache.stablePrefixTokens / tokensAfter : 0;
|
|
130
|
+
const monthlyPrefixUsd = monthlyInputUsd * Math.min(1, prefixShare);
|
|
131
|
+
const hitRate = Math.min(Math.max(usage.cacheHitRate, 0), 1);
|
|
132
|
+
const factor = (1 - hitRate) * rates.cacheWrite5m + hitRate * rates.cacheRead;
|
|
133
|
+
const minTokens = model.cacheMinTokens ?? 0;
|
|
134
|
+
if (cache.stablePrefixTokens >= minTokens) {
|
|
135
|
+
const saving = monthlyPrefixUsd * (1 - factor);
|
|
136
|
+
if (saving > 0) {
|
|
137
|
+
advisories.push({
|
|
138
|
+
id: 'prompt-caching',
|
|
139
|
+
severity: 'opportunity',
|
|
140
|
+
...t.advisories.promptCaching({
|
|
141
|
+
placeholder: cache.firstPlaceholder,
|
|
142
|
+
prefixTokens: cache.stablePrefixTokens,
|
|
143
|
+
totalTokens: tokensAfter,
|
|
144
|
+
minTokens,
|
|
145
|
+
modelName: model.displayName,
|
|
146
|
+
hitRatePct: Math.round(hitRate * 100),
|
|
147
|
+
readPct: Math.round(rates.cacheRead * 100),
|
|
148
|
+
writePct: Math.round(rates.cacheWrite5m * 100),
|
|
149
|
+
explicit: (model.caching ?? 'explicit') === 'explicit',
|
|
150
|
+
}),
|
|
151
|
+
estimatedMonthlyUsd: saving,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
advisories.push({
|
|
156
|
+
id: 'prompt-caching-not-worth-it',
|
|
157
|
+
severity: 'info',
|
|
158
|
+
...t.advisories.promptCachingNotWorthIt(),
|
|
159
|
+
estimatedMonthlyUsd: null,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
advisories.push({
|
|
165
|
+
id: 'below-cache-minimum',
|
|
166
|
+
severity: 'info',
|
|
167
|
+
...t.advisories.belowCacheMinimum({
|
|
168
|
+
modelName: model.displayName,
|
|
169
|
+
minTokens,
|
|
170
|
+
placeholder: cache.firstPlaceholder,
|
|
171
|
+
prefixTokens: cache.stablePrefixTokens,
|
|
172
|
+
totalTokens: tokensAfter,
|
|
173
|
+
mentionLowerMinimum: minTokens > 512,
|
|
174
|
+
}),
|
|
175
|
+
estimatedMonthlyUsd: null,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
// Stable content placed AFTER the first placeholder: never cached today,
|
|
179
|
+
// but moving it in front would make it cacheable.
|
|
180
|
+
if (cache.firstPlaceholder &&
|
|
181
|
+
cache.staticTokensAfter >= 200 &&
|
|
182
|
+
cache.staticTokensAfter >= tokensAfter * 0.3) {
|
|
183
|
+
const movableShare = tokensAfter > 0 ? cache.staticTokensAfter / tokensAfter : 0;
|
|
184
|
+
const saving = monthlyInputUsd * movableShare * Math.max(0, 1 - factor);
|
|
185
|
+
advisories.push({
|
|
186
|
+
id: 'cache-prefix-reorder',
|
|
187
|
+
severity: 'opportunity',
|
|
188
|
+
...t.advisories.cachePrefixReorder({
|
|
189
|
+
staticTokensAfter: cache.staticTokensAfter,
|
|
190
|
+
sharePct: Math.round(movableShare * 100),
|
|
191
|
+
placeholder: cache.firstPlaceholder,
|
|
192
|
+
}),
|
|
193
|
+
estimatedMonthlyUsd: saving > 0 ? saving : null,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// --- Batch API ---
|
|
198
|
+
// `rates.batch === null` means the provider has no batch API at all, which is
|
|
199
|
+
// different from not having said: advising a discount that cannot be bought
|
|
200
|
+
// is worse than staying quiet.
|
|
201
|
+
if (!usage.batchEligible && usage.callsPerMonth > 1 && rates.batch !== null) {
|
|
202
|
+
const saving = (monthlyInputUsd + monthlyOutputUsd) * (1 - rates.batch);
|
|
203
|
+
advisories.push({
|
|
204
|
+
id: 'batch-api',
|
|
205
|
+
severity: 'opportunity',
|
|
206
|
+
...t.advisories.batchApi(),
|
|
207
|
+
estimatedMonthlyUsd: saving,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
// --- Recommended model ---
|
|
211
|
+
const suggestedTier = recommendTier(optimizedPrompt, tokensAfter);
|
|
212
|
+
/**
|
|
213
|
+
* A model whose capability nobody recorded is never told it is overpowered.
|
|
214
|
+
*
|
|
215
|
+
* Part of the condition rather than an early return, which is how the first
|
|
216
|
+
* version of this was wrong: `return advisories` here skipped every advisory
|
|
217
|
+
* *after* the model check — output-dominated, contradictory instructions —
|
|
218
|
+
* none of which has anything to do with what tier the model is. An unknown
|
|
219
|
+
* capability is a reason to say nothing about capability, not a reason to
|
|
220
|
+
* stop reading the prompt.
|
|
221
|
+
*
|
|
222
|
+
* **Deliberately redundant**, and the one surviving mutant in this change.
|
|
223
|
+
* `TIER_ORDER.unknown` is `-Infinity`, so the comparison is already false and
|
|
224
|
+
* deleting this clause changes no behaviour and no test. It stays because the
|
|
225
|
+
* two express the same rule in different places: an ordering that forgets it
|
|
226
|
+
* and a condition that forgets it both have to happen before a model of
|
|
227
|
+
* unrecorded capability is told it is overpowered.
|
|
228
|
+
*/
|
|
229
|
+
if (model.tier !== 'unknown' && TIER_ORDER[suggestedTier] < TIER_ORDER[model.tier]) {
|
|
230
|
+
const candidate = cheapestInTier(suggestedTier, on, pricing, model.provider);
|
|
231
|
+
if (candidate) {
|
|
232
|
+
const candidatePricing = effectivePricing(candidate, on);
|
|
233
|
+
const candidateMonthly = ((tokensAfter / 1_000_000) * candidatePricing.inputPerMTok +
|
|
234
|
+
(usage.avgOutputTokens / 1_000_000) * candidatePricing.outputPerMTok) *
|
|
235
|
+
usage.callsPerMonth *
|
|
236
|
+
(usage.batchEligible ? 0.5 : 1);
|
|
237
|
+
const saving = monthlyInputUsd + monthlyOutputUsd - candidateMonthly;
|
|
238
|
+
if (saving > 0) {
|
|
239
|
+
advisories.push({
|
|
240
|
+
id: 'model-downgrade',
|
|
241
|
+
severity: 'opportunity',
|
|
242
|
+
...t.advisories.modelDowngrade({
|
|
243
|
+
modelName: model.displayName,
|
|
244
|
+
tier: suggestedTier,
|
|
245
|
+
candidateName: candidate.displayName,
|
|
246
|
+
currentUsd: formatUsd(monthlyInputUsd + monthlyOutputUsd),
|
|
247
|
+
candidateUsd: formatUsd(candidateMonthly),
|
|
248
|
+
}),
|
|
249
|
+
estimatedMonthlyUsd: saving,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// --- Where the money actually is ---
|
|
255
|
+
if (monthlyOutputUsd > monthlyInputUsd * 2 && usage.avgOutputTokens > 0) {
|
|
256
|
+
advisories.push({
|
|
257
|
+
id: 'output-dominated',
|
|
258
|
+
severity: 'info',
|
|
259
|
+
...t.advisories.outputDominated({
|
|
260
|
+
outputUsd: formatUsd(monthlyOutputUsd),
|
|
261
|
+
inputUsd: formatUsd(monthlyInputUsd),
|
|
262
|
+
}),
|
|
263
|
+
estimatedMonthlyUsd: null,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
// --- Instructions that fight each other ---
|
|
267
|
+
// Not a saving: a contradiction is a correctness problem that happens to
|
|
268
|
+
// cost tokens, so it carries no dollar figure and sorts on severity instead.
|
|
269
|
+
const contradictions = findContradictions(optimizedPrompt);
|
|
270
|
+
const worst = contradictions[0];
|
|
271
|
+
if (worst) {
|
|
272
|
+
advisories.push({
|
|
273
|
+
id: 'contradictory-instructions',
|
|
274
|
+
severity: 'warning',
|
|
275
|
+
...t.advisories.contradictoryInstructions({
|
|
276
|
+
axis: t.contradictionAxes[worst.axis],
|
|
277
|
+
firstValue: t.contradictionValues[worst.a.value],
|
|
278
|
+
firstSnippet: worst.a.snippet,
|
|
279
|
+
secondValue: t.contradictionValues[worst.b.value],
|
|
280
|
+
secondSnippet: worst.b.snippet,
|
|
281
|
+
otherCount: contradictions.length - 1,
|
|
282
|
+
}),
|
|
283
|
+
estimatedMonthlyUsd: null,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
// --- Few-shot examples that repeat each other ---
|
|
287
|
+
const examples = analyzeExamples(optimizedPrompt, count);
|
|
288
|
+
if (examples.redundant.length > 0 && examples.redundantTokens > 0) {
|
|
289
|
+
const saving = tokensAfter > 0
|
|
290
|
+
? monthlyInputUsd * Math.min(1, examples.redundantTokens / tokensAfter)
|
|
291
|
+
: 0;
|
|
292
|
+
const topSimilarity = Math.max(...examples.redundant.map((r) => r.similarity));
|
|
293
|
+
advisories.push({
|
|
294
|
+
id: 'redundant-examples',
|
|
295
|
+
severity: 'opportunity',
|
|
296
|
+
...t.advisories.redundantExamples({
|
|
297
|
+
redundantCount: examples.redundant.length,
|
|
298
|
+
totalCount: examples.examples.length,
|
|
299
|
+
redundantTokens: examples.redundantTokens,
|
|
300
|
+
topSimilarityPct: Math.round(topSimilarity * 100),
|
|
301
|
+
}),
|
|
302
|
+
estimatedMonthlyUsd: saving > 0 ? saving : null,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
// --- Output format written out twice ---
|
|
306
|
+
const restated = findRestatedFormat(optimizedPrompt, count);
|
|
307
|
+
const movable = findMovableSchema(optimizedPrompt, count);
|
|
308
|
+
if (movable) {
|
|
309
|
+
/**
|
|
310
|
+
* Priced from the tokens, which are real and reproducible, with the
|
|
311
|
+
* uncertainty in the text rather than in the figure.
|
|
312
|
+
*
|
|
313
|
+
* What Trazum knows is how many tokens the block holds; what it cannot know
|
|
314
|
+
* from here is whether the provider accepts a response schema. Withholding
|
|
315
|
+
* the figure for that reason would be the wrong trade — the number is right
|
|
316
|
+
* *if* the move is available, and the advisory says plainly that it does not
|
|
317
|
+
* check. The same posture as `model-downgrade`, which carries a figure and
|
|
318
|
+
* says out loud that it is a keyword heuristic.
|
|
319
|
+
*/
|
|
320
|
+
const saving = tokensAfter > 0 ? monthlyInputUsd * Math.min(1, movable.tokens / tokensAfter) : 0;
|
|
321
|
+
advisories.push({
|
|
322
|
+
id: 'movable-output-schema',
|
|
323
|
+
severity: 'opportunity',
|
|
324
|
+
...t.advisories.movableSchema({
|
|
325
|
+
blocks: movable.blocks,
|
|
326
|
+
tokens: movable.tokens,
|
|
327
|
+
keyList: movable.keys.map((k) => `\`${k}\``).join(', '),
|
|
328
|
+
cue: movable.cue,
|
|
329
|
+
}),
|
|
330
|
+
estimatedMonthlyUsd: saving > 0 ? saving : null,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
if (restated) {
|
|
334
|
+
const saving = tokensAfter > 0
|
|
335
|
+
? monthlyInputUsd * Math.min(1, restated.restatedTokens / tokensAfter)
|
|
336
|
+
: 0;
|
|
337
|
+
advisories.push({
|
|
338
|
+
id: 'restated-output-format',
|
|
339
|
+
severity: 'opportunity',
|
|
340
|
+
...t.advisories.restatedOutputFormat({
|
|
341
|
+
restatedCount: restated.restatedKeys.length,
|
|
342
|
+
totalCount: restated.keys.length,
|
|
343
|
+
restatedTokens: restated.restatedTokens,
|
|
344
|
+
keyList: restated.restatedKeys.map((k) => `\`${k}\``).join(', '),
|
|
345
|
+
}),
|
|
346
|
+
estimatedMonthlyUsd: saving > 0 ? saving : null,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
if (promoApplied && model.promo) {
|
|
350
|
+
advisories.push({
|
|
351
|
+
id: 'promo-pricing',
|
|
352
|
+
severity: 'warning',
|
|
353
|
+
...t.advisories.promoPricing({
|
|
354
|
+
modelName: model.displayName,
|
|
355
|
+
promoInput: model.promo.inputPerMTok,
|
|
356
|
+
promoOutput: model.promo.outputPerMTok,
|
|
357
|
+
until: model.promo.until,
|
|
358
|
+
listInput: model.inputPerMTok,
|
|
359
|
+
listOutput: model.outputPerMTok,
|
|
360
|
+
}),
|
|
361
|
+
estimatedMonthlyUsd: null,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
// Warnings first, then by money. Sorting purely on the dollar figure buried
|
|
365
|
+
// things that are wrong — an overflowing context window, two instructions
|
|
366
|
+
// that contradict each other — underneath a saving of a few dollars, because
|
|
367
|
+
// being wrong carries no price tag.
|
|
368
|
+
const SEVERITY_ORDER = {
|
|
369
|
+
warning: 0,
|
|
370
|
+
opportunity: 1,
|
|
371
|
+
info: 2,
|
|
372
|
+
};
|
|
373
|
+
return advisories.sort((a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity] ||
|
|
374
|
+
(b.estimatedMonthlyUsd ?? 0) - (a.estimatedMonthlyUsd ?? 0));
|
|
375
|
+
}
|
|
376
|
+
//# sourceMappingURL=advisories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advisories.js","sourceRoot":"","sources":["../src/advisories.ts"],"names":[],"mappings":"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"}
|