@trazum/core 1.35.0 → 1.36.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/README.md +12 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/measured-profile.d.ts +126 -0
- package/dist/measured-profile.d.ts.map +1 -0
- package/dist/measured-profile.js +114 -0
- package/dist/measured-profile.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/measured-profile.ts +198 -0
package/README.md
CHANGED
|
@@ -69,6 +69,18 @@ The last three structural findings are **advisory only**. A contradiction has a
|
|
|
69
69
|
right answer only you know, and an example that looks redundant may be
|
|
70
70
|
demonstrating a boundary case on purpose. Trazum points; it does not cut.
|
|
71
71
|
|
|
72
|
+
## Measured usage
|
|
73
|
+
|
|
74
|
+
`measuredUsage(report, label)` turns one label's slice of a `profileUsage()`
|
|
75
|
+
report into the `UsageProfile` that `optimize()` multiplies by — the real call
|
|
76
|
+
count, output size and cache-read share instead of typed guesses — with the
|
|
77
|
+
provenance attached: the span, the scaling factor when a month was derived
|
|
78
|
+
(never under seven days of data), the chosen model's share when the label ran
|
|
79
|
+
on several, and whether output was ever recorded. `labelCoverage(report,
|
|
80
|
+
labels)` names both mismatches between a config's label→prompt map and the
|
|
81
|
+
log: prompts mapped to labels with no traffic, and labels carrying money with
|
|
82
|
+
no prompt mapped.
|
|
83
|
+
|
|
72
84
|
## Comparing two versions
|
|
73
85
|
|
|
74
86
|
```ts
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export { driversBetween } from './against.js';
|
|
|
11
11
|
export type { AgainstDriver } from './against.js';
|
|
12
12
|
export { coverageDrift, COVERAGE_FIELDS, COVERAGE_DRIFT_MIN } from './coverage-drift.js';
|
|
13
13
|
export { explainGateFailure, gateMargin, GATE_MARGIN_TIGHT } from './gate-explain.js';
|
|
14
|
+
export { measuredUsage, labelCoverage, MIN_SCALE_DAYS, SCALE_TO_DAYS } from './measured-profile.js';
|
|
15
|
+
export type { MeasuredUsage, LabelCoverage } from './measured-profile.js';
|
|
14
16
|
export type { GateExplanation } from './gate-explain.js';
|
|
15
17
|
export type { CoverageDrift, CoverageField } from './coverage-drift.js';
|
|
16
18
|
export { createInputShapeTracker, inputShapes } from './input-shape.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export { PROFILE_CSV_COLUMNS, PROFILE_CSV_DAY_COLUMNS, PROFILE_CSV_HOUR_COLUMNS,
|
|
|
16
16
|
export { driversBetween } from './against.js';
|
|
17
17
|
export { coverageDrift, COVERAGE_FIELDS, COVERAGE_DRIFT_MIN } from './coverage-drift.js';
|
|
18
18
|
export { explainGateFailure, gateMargin, GATE_MARGIN_TIGHT } from './gate-explain.js';
|
|
19
|
+
export { measuredUsage, labelCoverage, MIN_SCALE_DAYS, SCALE_TO_DAYS } from './measured-profile.js';
|
|
19
20
|
// The same tokens at another model's rates — arithmetic, not advice, and it
|
|
20
21
|
// refuses to price a call the target could not have accepted. See reprice.ts.
|
|
21
22
|
// The shape of a call's input — the half of the bill a total could only name.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EACL,UAAU,EACV,cAAc,EACd,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,QAAQ,GACT,MAAM,YAAY,CAAC;AAWpB,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAClF,gFAAgF;AAChF,4EAA4E;AAC5E,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEtF,2EAA2E;AAC3E,+EAA+E;AAC/E,8EAA8E;AAC9E,0EAA0E;AAC1E,yCAAyC;AACzC,4EAA4E;AAC5E,qDAAqD;AACrD,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,EACxB,6BAA6B,EAC7B,YAAY,GACb,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The usage profile `optimize` multiplies by, taken from a log instead of
|
|
3
|
+
* from somebody's typing.
|
|
4
|
+
*
|
|
5
|
+
* `optimize` prices a prompt change as `token delta × callsPerMonth`, with
|
|
6
|
+
* `avgOutputTokens` and `cacheHitRate` shaping the rest. Those three numbers
|
|
7
|
+
* are typed into a config file by a human who is guessing, and the two values
|
|
8
|
+
* most often typed are `1000` and whatever the README's example used. A usage
|
|
9
|
+
* log sitting in the same repository knows all three exactly.
|
|
10
|
+
*
|
|
11
|
+
* **What this module does not do is turn an estimate into a fact.** The token
|
|
12
|
+
* delta stays an estimate with its ±10% band; what stops being a guess is
|
|
13
|
+
* everything it is multiplied by. That distinction has to survive into the
|
|
14
|
+
* rendering, which is why `MeasuredUsage` carries the provenance of each
|
|
15
|
+
* figure rather than only the figures.
|
|
16
|
+
*
|
|
17
|
+
* The hardest decision here is the call count. A month's saving from a log
|
|
18
|
+
* covering three days is a forecast wearing arithmetic's clothes, and this
|
|
19
|
+
* repository refuses those. So the scaling has a floor, it is stated whenever
|
|
20
|
+
* it happens, and under the floor the tool reports the period it measured and
|
|
21
|
+
* declines the multiplication rather than performing it quietly.
|
|
22
|
+
*/
|
|
23
|
+
import type { UsageProfileReport } from './usage.js';
|
|
24
|
+
import type { UsageProfile } from './types.js';
|
|
25
|
+
/**
|
|
26
|
+
* The shortest span that may be scaled to a month, in days.
|
|
27
|
+
*
|
|
28
|
+
* A full week, because the week is the cycle traffic actually has: weekdays
|
|
29
|
+
* against weekends is the one periodicity nearly every workload shows, and a
|
|
30
|
+
* span shorter than one cycle scaled up multiplies whichever part of the
|
|
31
|
+
* cycle it happened to catch. Three weekdays scaled to a month is not a
|
|
32
|
+
* monthly figure, it is a Tuesday with a multiplier.
|
|
33
|
+
*
|
|
34
|
+
* Above the floor this is still a *rate*, not a prediction: "at the rate this
|
|
35
|
+
* log measured" is arithmetic about the past, and every rendering says so.
|
|
36
|
+
*/
|
|
37
|
+
export declare const MIN_SCALE_DAYS = 7;
|
|
38
|
+
/** Days in the month this scales to. Stated rather than hidden in a constant. */
|
|
39
|
+
export declare const SCALE_TO_DAYS = 30;
|
|
40
|
+
export interface MeasuredUsage {
|
|
41
|
+
/** Ready to hand to `optimize`. Every field below is measured, not typed. */
|
|
42
|
+
profile: UsageProfile;
|
|
43
|
+
/** Calls the log actually recorded for this slice. Never scaled. */
|
|
44
|
+
calls: number;
|
|
45
|
+
/** What those calls actually cost. The measured half of any comparison. */
|
|
46
|
+
spentUsd: number;
|
|
47
|
+
/**
|
|
48
|
+
* The period the calls fall in, in days, or null when no call carried a
|
|
49
|
+
* clock. Null is why `scaled` can be null with calls above the floor.
|
|
50
|
+
*/
|
|
51
|
+
spanDays: number | null;
|
|
52
|
+
/**
|
|
53
|
+
* How `callsPerMonth` was reached, or **null when it was not scaled at
|
|
54
|
+
* all** — in which case `profile.callsPerMonth` is the raw measured count
|
|
55
|
+
* over whatever period the log covers, and the rendering must say so
|
|
56
|
+
* rather than printing it under a "per month" heading.
|
|
57
|
+
*/
|
|
58
|
+
scaled: {
|
|
59
|
+
fromDays: number;
|
|
60
|
+
factor: number;
|
|
61
|
+
} | null;
|
|
62
|
+
/**
|
|
63
|
+
* The share of input tokens served from cache, 0–1.
|
|
64
|
+
*
|
|
65
|
+
* `UsageProfile.cacheHitRate` is documented as the fraction of *calls* that
|
|
66
|
+
* reuse the prefix; what a log can measure is the fraction of input
|
|
67
|
+
* *tokens* that were cache reads. Those are the same number only when every
|
|
68
|
+
* call is the same size. It is handed over as the better of two
|
|
69
|
+
* approximations — a measured token share beats a typed call share — and
|
|
70
|
+
* named honestly here so no rendering can call it something it is not.
|
|
71
|
+
*/
|
|
72
|
+
cacheReadShare: number;
|
|
73
|
+
/**
|
|
74
|
+
* The model carrying the most spend in this slice, and how many models the
|
|
75
|
+
* slice used at all. Above one, the single model handed to `optimize` is a
|
|
76
|
+
* simplification and the rendering says which share it covers.
|
|
77
|
+
*/
|
|
78
|
+
models: {
|
|
79
|
+
chosen: string;
|
|
80
|
+
count: number;
|
|
81
|
+
chosenShareOfSpend: number;
|
|
82
|
+
};
|
|
83
|
+
/** True when no call in the slice recorded any output tokens. */
|
|
84
|
+
outputUnmeasured: boolean;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Derives the usage profile for one label from a measured report.
|
|
88
|
+
*
|
|
89
|
+
* Returns `null` when the label carries no priced calls — a slice with no
|
|
90
|
+
* measured traffic has nothing to hand over, and inventing a zero-call
|
|
91
|
+
* profile would produce a $0 saving that reads as "this change is worthless"
|
|
92
|
+
* rather than "nothing here was measured".
|
|
93
|
+
*/
|
|
94
|
+
export declare function measuredUsage(report: UsageProfileReport, label: string, options?: {
|
|
95
|
+
batchEligible?: boolean;
|
|
96
|
+
}): MeasuredUsage | null;
|
|
97
|
+
/**
|
|
98
|
+
* Every label the report priced, with the prompt file the config maps to it —
|
|
99
|
+
* and, deliberately, both kinds of mismatch.
|
|
100
|
+
*
|
|
101
|
+
* The two failures this surfaces are the ones a person cannot see from either
|
|
102
|
+
* side alone: a prompt file mapped to a label that no longer appears in the
|
|
103
|
+
* log (renamed, retired, or a typo that has been silently doing nothing), and
|
|
104
|
+
* a label carrying real money with no prompt file mapped at all (the workload
|
|
105
|
+
* nobody can optimise because nobody said where it lives).
|
|
106
|
+
*/
|
|
107
|
+
export interface LabelCoverage {
|
|
108
|
+
/** Labels with both traffic and a mapped prompt file. */
|
|
109
|
+
joined: {
|
|
110
|
+
label: string;
|
|
111
|
+
promptPath: string;
|
|
112
|
+
spentUsd: number;
|
|
113
|
+
}[];
|
|
114
|
+
/** Mapped prompt files whose label has no priced traffic in this log. */
|
|
115
|
+
mappedWithoutTraffic: {
|
|
116
|
+
label: string;
|
|
117
|
+
promptPath: string;
|
|
118
|
+
}[];
|
|
119
|
+
/** Labels with priced traffic and no prompt file mapped, dearest first. */
|
|
120
|
+
trafficWithoutPrompt: {
|
|
121
|
+
label: string;
|
|
122
|
+
spentUsd: number;
|
|
123
|
+
}[];
|
|
124
|
+
}
|
|
125
|
+
export declare function labelCoverage(report: UsageProfileReport, labels: Record<string, string>): LabelCoverage;
|
|
126
|
+
//# sourceMappingURL=measured-profile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measured-profile.d.ts","sourceRoot":"","sources":["../src/measured-profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,iFAAiF;AACjF,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,OAAO,EAAE,YAAY,CAAC;IACtB,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;;;OAKG;IACH,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACpD;;;;;;;;;OASG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE,iEAAiE;IACjE,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,kBAAkB,EAC1B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAO,GACxC,aAAa,GAAG,IAAI,CAuDtB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAClE,yEAAyE;IACzE,oBAAoB,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9D,2EAA2E;IAC3E,oBAAoB,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC7D;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,aAAa,CAsBf"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The usage profile `optimize` multiplies by, taken from a log instead of
|
|
3
|
+
* from somebody's typing.
|
|
4
|
+
*
|
|
5
|
+
* `optimize` prices a prompt change as `token delta × callsPerMonth`, with
|
|
6
|
+
* `avgOutputTokens` and `cacheHitRate` shaping the rest. Those three numbers
|
|
7
|
+
* are typed into a config file by a human who is guessing, and the two values
|
|
8
|
+
* most often typed are `1000` and whatever the README's example used. A usage
|
|
9
|
+
* log sitting in the same repository knows all three exactly.
|
|
10
|
+
*
|
|
11
|
+
* **What this module does not do is turn an estimate into a fact.** The token
|
|
12
|
+
* delta stays an estimate with its ±10% band; what stops being a guess is
|
|
13
|
+
* everything it is multiplied by. That distinction has to survive into the
|
|
14
|
+
* rendering, which is why `MeasuredUsage` carries the provenance of each
|
|
15
|
+
* figure rather than only the figures.
|
|
16
|
+
*
|
|
17
|
+
* The hardest decision here is the call count. A month's saving from a log
|
|
18
|
+
* covering three days is a forecast wearing arithmetic's clothes, and this
|
|
19
|
+
* repository refuses those. So the scaling has a floor, it is stated whenever
|
|
20
|
+
* it happens, and under the floor the tool reports the period it measured and
|
|
21
|
+
* declines the multiplication rather than performing it quietly.
|
|
22
|
+
*/
|
|
23
|
+
import { UNLABELLED } from './usage.js';
|
|
24
|
+
/**
|
|
25
|
+
* The shortest span that may be scaled to a month, in days.
|
|
26
|
+
*
|
|
27
|
+
* A full week, because the week is the cycle traffic actually has: weekdays
|
|
28
|
+
* against weekends is the one periodicity nearly every workload shows, and a
|
|
29
|
+
* span shorter than one cycle scaled up multiplies whichever part of the
|
|
30
|
+
* cycle it happened to catch. Three weekdays scaled to a month is not a
|
|
31
|
+
* monthly figure, it is a Tuesday with a multiplier.
|
|
32
|
+
*
|
|
33
|
+
* Above the floor this is still a *rate*, not a prediction: "at the rate this
|
|
34
|
+
* log measured" is arithmetic about the past, and every rendering says so.
|
|
35
|
+
*/
|
|
36
|
+
export const MIN_SCALE_DAYS = 7;
|
|
37
|
+
/** Days in the month this scales to. Stated rather than hidden in a constant. */
|
|
38
|
+
export const SCALE_TO_DAYS = 30;
|
|
39
|
+
/**
|
|
40
|
+
* Derives the usage profile for one label from a measured report.
|
|
41
|
+
*
|
|
42
|
+
* Returns `null` when the label carries no priced calls — a slice with no
|
|
43
|
+
* measured traffic has nothing to hand over, and inventing a zero-call
|
|
44
|
+
* profile would produce a $0 saving that reads as "this change is worthless"
|
|
45
|
+
* rather than "nothing here was measured".
|
|
46
|
+
*/
|
|
47
|
+
export function measuredUsage(report, label, options = {}) {
|
|
48
|
+
const slices = report.byLabelAndModel.filter((row) => row.label === label);
|
|
49
|
+
if (slices.length === 0)
|
|
50
|
+
return null;
|
|
51
|
+
const calls = slices.reduce((sum, row) => sum + row.breakdown.calls, 0);
|
|
52
|
+
if (calls === 0)
|
|
53
|
+
return null;
|
|
54
|
+
const spentUsd = slices.reduce((sum, row) => sum + row.breakdown.totalUsd, 0);
|
|
55
|
+
const outputTokens = slices.reduce((sum, row) => sum + row.breakdown.outputTokens, 0);
|
|
56
|
+
const inputTokens = slices.reduce((sum, row) => sum + row.breakdown.inputTokens, 0);
|
|
57
|
+
const cacheReadTokens = slices.reduce((sum, row) => sum + row.breakdown.cacheReadTokens, 0);
|
|
58
|
+
// The model carrying the most spend. Ties break on the larger call count, so
|
|
59
|
+
// the answer is stable rather than dependent on map ordering.
|
|
60
|
+
const ranked = [...slices].sort((a, b) => b.breakdown.totalUsd - a.breakdown.totalUsd || b.breakdown.calls - a.breakdown.calls);
|
|
61
|
+
const chosen = ranked[0];
|
|
62
|
+
const chosenShareOfSpend = spentUsd > 0 ? chosen.breakdown.totalUsd / spentUsd : 0;
|
|
63
|
+
/**
|
|
64
|
+
* The span of *this slice*, not of the whole log. A label active for three
|
|
65
|
+
* days of a thirty-day log has a three-day rate, and using the log's span
|
|
66
|
+
* would divide its calls across weeks it never ran in.
|
|
67
|
+
*/
|
|
68
|
+
const spanDays = report.span === null ? null : (report.span.toMs - report.span.fromMs) / 86_400_000;
|
|
69
|
+
const scaled = spanDays !== null && spanDays >= MIN_SCALE_DAYS
|
|
70
|
+
? { fromDays: spanDays, factor: SCALE_TO_DAYS / spanDays }
|
|
71
|
+
: null;
|
|
72
|
+
const readShare = inputTokens + cacheReadTokens > 0 ? cacheReadTokens / (inputTokens + cacheReadTokens) : 0;
|
|
73
|
+
return {
|
|
74
|
+
profile: {
|
|
75
|
+
model: chosen.model,
|
|
76
|
+
// Scaled when the span earns it, the raw measured count otherwise. The
|
|
77
|
+
// caller must read `scaled` before printing this under any heading that
|
|
78
|
+
// says "month".
|
|
79
|
+
callsPerMonth: scaled === null ? calls : Math.round(calls * scaled.factor),
|
|
80
|
+
avgOutputTokens: Math.round(outputTokens / calls),
|
|
81
|
+
cacheHitRate: readShare,
|
|
82
|
+
batchEligible: options.batchEligible ?? false,
|
|
83
|
+
},
|
|
84
|
+
calls,
|
|
85
|
+
spentUsd,
|
|
86
|
+
spanDays,
|
|
87
|
+
scaled,
|
|
88
|
+
cacheReadShare: readShare,
|
|
89
|
+
models: { chosen: chosen.model, count: slices.length, chosenShareOfSpend },
|
|
90
|
+
outputUnmeasured: outputTokens === 0,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export function labelCoverage(report, labels) {
|
|
94
|
+
const spendByLabel = new Map(report.byLabel.map((row) => [row.label, row.breakdown.totalUsd]));
|
|
95
|
+
const joined = [];
|
|
96
|
+
const mappedWithoutTraffic = [];
|
|
97
|
+
for (const [label, promptPath] of Object.entries(labels)) {
|
|
98
|
+
const spentUsd = spendByLabel.get(label);
|
|
99
|
+
if (spentUsd === undefined)
|
|
100
|
+
mappedWithoutTraffic.push({ label, promptPath });
|
|
101
|
+
else
|
|
102
|
+
joined.push({ label, promptPath, spentUsd });
|
|
103
|
+
}
|
|
104
|
+
const trafficWithoutPrompt = report.byLabel
|
|
105
|
+
// The unlabelled bucket is not a workload somebody forgot to map; it is
|
|
106
|
+
// calls that carry no label at all, which `fieldCoverage` already reports.
|
|
107
|
+
.filter((row) => row.label !== UNLABELLED && labels[row.label] === undefined)
|
|
108
|
+
.map((row) => ({ label: row.label, spentUsd: row.breakdown.totalUsd }))
|
|
109
|
+
.sort((a, b) => b.spentUsd - a.spentUsd);
|
|
110
|
+
joined.sort((a, b) => b.spentUsd - a.spentUsd);
|
|
111
|
+
mappedWithoutTraffic.sort((a, b) => a.label.localeCompare(b.label));
|
|
112
|
+
return { joined, mappedWithoutTraffic, trafficWithoutPrompt };
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=measured-profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measured-profile.js","sourceRoot":"","sources":["../src/measured-profile.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trazum/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.36.0",
|
|
4
4
|
"description": "Trazum core: priced advisories for LLM prompts (caching, model tier, batching, schemas), plus deterministic trimming, token counting and pricing.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "David Mu\u00f1oz Rey",
|
package/src/index.ts
CHANGED
|
@@ -42,6 +42,8 @@ export { driversBetween } from './against.js';
|
|
|
42
42
|
export type { AgainstDriver } from './against.js';
|
|
43
43
|
export { coverageDrift, COVERAGE_FIELDS, COVERAGE_DRIFT_MIN } from './coverage-drift.js';
|
|
44
44
|
export { explainGateFailure, gateMargin, GATE_MARGIN_TIGHT } from './gate-explain.js';
|
|
45
|
+
export { measuredUsage, labelCoverage, MIN_SCALE_DAYS, SCALE_TO_DAYS } from './measured-profile.js';
|
|
46
|
+
export type { MeasuredUsage, LabelCoverage } from './measured-profile.js';
|
|
45
47
|
export type { GateExplanation } from './gate-explain.js';
|
|
46
48
|
export type { CoverageDrift, CoverageField } from './coverage-drift.js';
|
|
47
49
|
// The same tokens at another model's rates — arithmetic, not advice, and it
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The usage profile `optimize` multiplies by, taken from a log instead of
|
|
3
|
+
* from somebody's typing.
|
|
4
|
+
*
|
|
5
|
+
* `optimize` prices a prompt change as `token delta × callsPerMonth`, with
|
|
6
|
+
* `avgOutputTokens` and `cacheHitRate` shaping the rest. Those three numbers
|
|
7
|
+
* are typed into a config file by a human who is guessing, and the two values
|
|
8
|
+
* most often typed are `1000` and whatever the README's example used. A usage
|
|
9
|
+
* log sitting in the same repository knows all three exactly.
|
|
10
|
+
*
|
|
11
|
+
* **What this module does not do is turn an estimate into a fact.** The token
|
|
12
|
+
* delta stays an estimate with its ±10% band; what stops being a guess is
|
|
13
|
+
* everything it is multiplied by. That distinction has to survive into the
|
|
14
|
+
* rendering, which is why `MeasuredUsage` carries the provenance of each
|
|
15
|
+
* figure rather than only the figures.
|
|
16
|
+
*
|
|
17
|
+
* The hardest decision here is the call count. A month's saving from a log
|
|
18
|
+
* covering three days is a forecast wearing arithmetic's clothes, and this
|
|
19
|
+
* repository refuses those. So the scaling has a floor, it is stated whenever
|
|
20
|
+
* it happens, and under the floor the tool reports the period it measured and
|
|
21
|
+
* declines the multiplication rather than performing it quietly.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { UNLABELLED } from './usage.js';
|
|
25
|
+
import type { UsageProfileReport } from './usage.js';
|
|
26
|
+
import type { UsageProfile } from './types.js';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The shortest span that may be scaled to a month, in days.
|
|
30
|
+
*
|
|
31
|
+
* A full week, because the week is the cycle traffic actually has: weekdays
|
|
32
|
+
* against weekends is the one periodicity nearly every workload shows, and a
|
|
33
|
+
* span shorter than one cycle scaled up multiplies whichever part of the
|
|
34
|
+
* cycle it happened to catch. Three weekdays scaled to a month is not a
|
|
35
|
+
* monthly figure, it is a Tuesday with a multiplier.
|
|
36
|
+
*
|
|
37
|
+
* Above the floor this is still a *rate*, not a prediction: "at the rate this
|
|
38
|
+
* log measured" is arithmetic about the past, and every rendering says so.
|
|
39
|
+
*/
|
|
40
|
+
export const MIN_SCALE_DAYS = 7;
|
|
41
|
+
|
|
42
|
+
/** Days in the month this scales to. Stated rather than hidden in a constant. */
|
|
43
|
+
export const SCALE_TO_DAYS = 30;
|
|
44
|
+
|
|
45
|
+
export interface MeasuredUsage {
|
|
46
|
+
/** Ready to hand to `optimize`. Every field below is measured, not typed. */
|
|
47
|
+
profile: UsageProfile;
|
|
48
|
+
/** Calls the log actually recorded for this slice. Never scaled. */
|
|
49
|
+
calls: number;
|
|
50
|
+
/** What those calls actually cost. The measured half of any comparison. */
|
|
51
|
+
spentUsd: number;
|
|
52
|
+
/**
|
|
53
|
+
* The period the calls fall in, in days, or null when no call carried a
|
|
54
|
+
* clock. Null is why `scaled` can be null with calls above the floor.
|
|
55
|
+
*/
|
|
56
|
+
spanDays: number | null;
|
|
57
|
+
/**
|
|
58
|
+
* How `callsPerMonth` was reached, or **null when it was not scaled at
|
|
59
|
+
* all** — in which case `profile.callsPerMonth` is the raw measured count
|
|
60
|
+
* over whatever period the log covers, and the rendering must say so
|
|
61
|
+
* rather than printing it under a "per month" heading.
|
|
62
|
+
*/
|
|
63
|
+
scaled: { fromDays: number; factor: number } | null;
|
|
64
|
+
/**
|
|
65
|
+
* The share of input tokens served from cache, 0–1.
|
|
66
|
+
*
|
|
67
|
+
* `UsageProfile.cacheHitRate` is documented as the fraction of *calls* that
|
|
68
|
+
* reuse the prefix; what a log can measure is the fraction of input
|
|
69
|
+
* *tokens* that were cache reads. Those are the same number only when every
|
|
70
|
+
* call is the same size. It is handed over as the better of two
|
|
71
|
+
* approximations — a measured token share beats a typed call share — and
|
|
72
|
+
* named honestly here so no rendering can call it something it is not.
|
|
73
|
+
*/
|
|
74
|
+
cacheReadShare: number;
|
|
75
|
+
/**
|
|
76
|
+
* The model carrying the most spend in this slice, and how many models the
|
|
77
|
+
* slice used at all. Above one, the single model handed to `optimize` is a
|
|
78
|
+
* simplification and the rendering says which share it covers.
|
|
79
|
+
*/
|
|
80
|
+
models: { chosen: string; count: number; chosenShareOfSpend: number };
|
|
81
|
+
/** True when no call in the slice recorded any output tokens. */
|
|
82
|
+
outputUnmeasured: boolean;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Derives the usage profile for one label from a measured report.
|
|
87
|
+
*
|
|
88
|
+
* Returns `null` when the label carries no priced calls — a slice with no
|
|
89
|
+
* measured traffic has nothing to hand over, and inventing a zero-call
|
|
90
|
+
* profile would produce a $0 saving that reads as "this change is worthless"
|
|
91
|
+
* rather than "nothing here was measured".
|
|
92
|
+
*/
|
|
93
|
+
export function measuredUsage(
|
|
94
|
+
report: UsageProfileReport,
|
|
95
|
+
label: string,
|
|
96
|
+
options: { batchEligible?: boolean } = {},
|
|
97
|
+
): MeasuredUsage | null {
|
|
98
|
+
const slices = report.byLabelAndModel.filter((row) => row.label === label);
|
|
99
|
+
if (slices.length === 0) return null;
|
|
100
|
+
|
|
101
|
+
const calls = slices.reduce((sum, row) => sum + row.breakdown.calls, 0);
|
|
102
|
+
if (calls === 0) return null;
|
|
103
|
+
|
|
104
|
+
const spentUsd = slices.reduce((sum, row) => sum + row.breakdown.totalUsd, 0);
|
|
105
|
+
const outputTokens = slices.reduce((sum, row) => sum + row.breakdown.outputTokens, 0);
|
|
106
|
+
const inputTokens = slices.reduce((sum, row) => sum + row.breakdown.inputTokens, 0);
|
|
107
|
+
const cacheReadTokens = slices.reduce((sum, row) => sum + row.breakdown.cacheReadTokens, 0);
|
|
108
|
+
|
|
109
|
+
// The model carrying the most spend. Ties break on the larger call count, so
|
|
110
|
+
// the answer is stable rather than dependent on map ordering.
|
|
111
|
+
const ranked = [...slices].sort(
|
|
112
|
+
(a, b) => b.breakdown.totalUsd - a.breakdown.totalUsd || b.breakdown.calls - a.breakdown.calls,
|
|
113
|
+
);
|
|
114
|
+
const chosen = ranked[0]!;
|
|
115
|
+
const chosenShareOfSpend = spentUsd > 0 ? chosen.breakdown.totalUsd / spentUsd : 0;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* The span of *this slice*, not of the whole log. A label active for three
|
|
119
|
+
* days of a thirty-day log has a three-day rate, and using the log's span
|
|
120
|
+
* would divide its calls across weeks it never ran in.
|
|
121
|
+
*/
|
|
122
|
+
const spanDays =
|
|
123
|
+
report.span === null ? null : (report.span.toMs - report.span.fromMs) / 86_400_000;
|
|
124
|
+
|
|
125
|
+
const scaled =
|
|
126
|
+
spanDays !== null && spanDays >= MIN_SCALE_DAYS
|
|
127
|
+
? { fromDays: spanDays, factor: SCALE_TO_DAYS / spanDays }
|
|
128
|
+
: null;
|
|
129
|
+
|
|
130
|
+
const readShare =
|
|
131
|
+
inputTokens + cacheReadTokens > 0 ? cacheReadTokens / (inputTokens + cacheReadTokens) : 0;
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
profile: {
|
|
135
|
+
model: chosen.model,
|
|
136
|
+
// Scaled when the span earns it, the raw measured count otherwise. The
|
|
137
|
+
// caller must read `scaled` before printing this under any heading that
|
|
138
|
+
// says "month".
|
|
139
|
+
callsPerMonth: scaled === null ? calls : Math.round(calls * scaled.factor),
|
|
140
|
+
avgOutputTokens: Math.round(outputTokens / calls),
|
|
141
|
+
cacheHitRate: readShare,
|
|
142
|
+
batchEligible: options.batchEligible ?? false,
|
|
143
|
+
},
|
|
144
|
+
calls,
|
|
145
|
+
spentUsd,
|
|
146
|
+
spanDays,
|
|
147
|
+
scaled,
|
|
148
|
+
cacheReadShare: readShare,
|
|
149
|
+
models: { chosen: chosen.model, count: slices.length, chosenShareOfSpend },
|
|
150
|
+
outputUnmeasured: outputTokens === 0,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Every label the report priced, with the prompt file the config maps to it —
|
|
156
|
+
* and, deliberately, both kinds of mismatch.
|
|
157
|
+
*
|
|
158
|
+
* The two failures this surfaces are the ones a person cannot see from either
|
|
159
|
+
* side alone: a prompt file mapped to a label that no longer appears in the
|
|
160
|
+
* log (renamed, retired, or a typo that has been silently doing nothing), and
|
|
161
|
+
* a label carrying real money with no prompt file mapped at all (the workload
|
|
162
|
+
* nobody can optimise because nobody said where it lives).
|
|
163
|
+
*/
|
|
164
|
+
export interface LabelCoverage {
|
|
165
|
+
/** Labels with both traffic and a mapped prompt file. */
|
|
166
|
+
joined: { label: string; promptPath: string; spentUsd: number }[];
|
|
167
|
+
/** Mapped prompt files whose label has no priced traffic in this log. */
|
|
168
|
+
mappedWithoutTraffic: { label: string; promptPath: string }[];
|
|
169
|
+
/** Labels with priced traffic and no prompt file mapped, dearest first. */
|
|
170
|
+
trafficWithoutPrompt: { label: string; spentUsd: number }[];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function labelCoverage(
|
|
174
|
+
report: UsageProfileReport,
|
|
175
|
+
labels: Record<string, string>,
|
|
176
|
+
): LabelCoverage {
|
|
177
|
+
const spendByLabel = new Map(report.byLabel.map((row) => [row.label, row.breakdown.totalUsd]));
|
|
178
|
+
|
|
179
|
+
const joined: LabelCoverage['joined'] = [];
|
|
180
|
+
const mappedWithoutTraffic: LabelCoverage['mappedWithoutTraffic'] = [];
|
|
181
|
+
for (const [label, promptPath] of Object.entries(labels)) {
|
|
182
|
+
const spentUsd = spendByLabel.get(label);
|
|
183
|
+
if (spentUsd === undefined) mappedWithoutTraffic.push({ label, promptPath });
|
|
184
|
+
else joined.push({ label, promptPath, spentUsd });
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const trafficWithoutPrompt = report.byLabel
|
|
188
|
+
// The unlabelled bucket is not a workload somebody forgot to map; it is
|
|
189
|
+
// calls that carry no label at all, which `fieldCoverage` already reports.
|
|
190
|
+
.filter((row) => row.label !== UNLABELLED && labels[row.label] === undefined)
|
|
191
|
+
.map((row) => ({ label: row.label, spentUsd: row.breakdown.totalUsd }))
|
|
192
|
+
.sort((a, b) => b.spentUsd - a.spentUsd);
|
|
193
|
+
|
|
194
|
+
joined.sort((a, b) => b.spentUsd - a.spentUsd);
|
|
195
|
+
mappedWithoutTraffic.sort((a, b) => a.label.localeCompare(b.label));
|
|
196
|
+
|
|
197
|
+
return { joined, mappedWithoutTraffic, trafficWithoutPrompt };
|
|
198
|
+
}
|