@intelligo-dev/executions 1.0.0-beta.1 → 1.0.0-beta.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/pricing.d.ts CHANGED
@@ -1,159 +1,129 @@
1
1
  /**
2
2
  * Model registry and execution cost accounting.
3
3
  *
4
- * This lives in `executions` rather than beside the provider clients
5
- * because it is not AI code: it is what an execution costs. The
6
- * boundary records actor, workspace, capability, usage and cost
7
- * (ADR-0003), and the price of a token is the last of those.
4
+ * A leaf: no database, no provider SDK. Its one import is
5
+ * `@intelligo-dev/core/registry`, which is itself dependency-free, so
6
+ * `@intelligo-dev/executions/pricing` is something a client bundle can
7
+ * read a display name or a price from without pulling in Drizzle.
8
8
  *
9
- * Deliberately a leaf module no database, no provider SDK, no
10
- * imports at all and reachable as `@intelligo-dev/executions/pricing`
11
- * so a client bundle can read a display name or a price without
12
- * pulling in Drizzle. `@intelligo-dev/ai` re-exports it, so the ids that
13
- * pick a provider and the ids that carry a price stay one list; two
14
- * lists is how a model runs on Gemini and bills at Claude rates.
9
+ * The registry is open: a product registers any model it runs, and
10
+ * `registerModels(DEFAULT_MODELS)` from the composition root registers
11
+ * the shipped catalogue. Nothing self-registers. An id with no price
12
+ * throws at the point where the price is needed, naming the id, rather
13
+ * than billing at a guessed rate.
15
14
  */
16
- /**
17
- * Model configuration with display information and cost tracking
18
- *
19
- * 6 models, 3 providers: Google (2), OpenAI (3), Anthropic (1)
20
- */
21
- export declare const MODEL_CONFIGS: {
22
- readonly "google/gemini-2.5-flash": {
23
- readonly provider: "google";
24
- readonly model: "gemini-2.5-flash";
25
- readonly displayName: "Gemini 2.5 Flash";
26
- readonly costPerMInputTokens: 0.3;
27
- readonly costPerMOutputTokens: 2.5;
28
- readonly capabilities: {
29
- readonly thinking: true;
30
- readonly toolCall: true;
31
- readonly vision: true;
32
- readonly webSearch: true;
33
- readonly codeExec: true;
34
- };
35
- };
36
- readonly "google/gemini-2.5-pro": {
37
- readonly provider: "google";
38
- readonly model: "gemini-2.5-pro";
39
- readonly displayName: "Gemini 2.5 Pro";
40
- readonly costPerMInputTokens: 1.25;
41
- readonly costPerMOutputTokens: 10;
42
- readonly capabilities: {
43
- readonly thinking: true;
44
- readonly toolCall: true;
45
- readonly vision: true;
46
- readonly webSearch: true;
47
- readonly codeExec: true;
48
- };
49
- };
50
- readonly "openai/gpt-5-mini": {
51
- readonly provider: "openai";
52
- readonly model: "gpt-5-mini";
53
- readonly displayName: "GPT-5 Mini";
54
- readonly costPerMInputTokens: 0.25;
55
- readonly costPerMOutputTokens: 2;
56
- readonly capabilities: {
57
- readonly thinking: true;
58
- readonly toolCall: true;
59
- readonly vision: true;
60
- readonly webSearch: false;
61
- readonly codeExec: false;
62
- };
63
- };
64
- readonly "openai/gpt-5.4-mini": {
65
- readonly provider: "openai";
66
- readonly model: "gpt-5.4-mini";
67
- readonly displayName: "GPT-5.4 Mini";
68
- readonly costPerMInputTokens: 0.75;
69
- readonly costPerMOutputTokens: 4.5;
70
- readonly capabilities: {
71
- readonly thinking: true;
72
- readonly toolCall: true;
73
- readonly vision: true;
74
- readonly webSearch: true;
75
- readonly codeExec: true;
76
- };
77
- };
78
- readonly "openai/o4-mini": {
79
- readonly provider: "openai";
80
- readonly model: "o4-mini";
81
- readonly displayName: "o4-mini";
82
- readonly costPerMInputTokens: 1.1;
83
- readonly costPerMOutputTokens: 4.4;
84
- readonly capabilities: {
85
- readonly thinking: true;
86
- readonly toolCall: true;
87
- readonly vision: true;
88
- readonly webSearch: true;
89
- readonly codeExec: true;
90
- };
91
- };
92
- readonly "anthropic/claude-sonnet-4-6": {
93
- readonly provider: "anthropic";
94
- readonly model: "claude-sonnet-4-6-20260214";
95
- readonly displayName: "Claude Sonnet 4.6";
96
- readonly costPerMInputTokens: 3;
97
- readonly costPerMOutputTokens: 15;
98
- readonly capabilities: {
99
- readonly thinking: true;
100
- readonly toolCall: true;
101
- readonly vision: true;
102
- readonly webSearch: true;
103
- readonly codeExec: true;
104
- };
105
- };
15
+ import { type CurrencyCode, type Money } from "@intelligo-dev/core/money";
16
+ export type ModelCapabilities = {
17
+ thinking: boolean;
18
+ toolCall: boolean;
19
+ vision: boolean;
20
+ webSearch: boolean;
21
+ codeExec: boolean;
22
+ };
23
+ export type ModelPricing = {
24
+ /** Provider-prefixed id, e.g. `google/gemini-2.5-flash`. */
25
+ id: string;
26
+ provider: string;
27
+ /** The id the provider's own SDK expects, which is often dated. */
28
+ model: string;
29
+ displayName: string;
30
+ /** USD per million input tokens, as the provider quotes it. */
31
+ costPerMInputTokens: number;
32
+ /** USD per million output tokens. */
33
+ costPerMOutputTokens: number;
34
+ /**
35
+ * The ceiling on streamed output used for worst-case pre-request
36
+ * estimation.
37
+ */
38
+ maxOutputTokens: number;
39
+ capabilities: ModelCapabilities;
106
40
  };
107
- export type ModelId = keyof typeof MODEL_CONFIGS;
41
+ /** A provider-prefixed model id; any string, because the registry is open. */
42
+ export type ModelId = string;
43
+ export declare class UnknownModelError extends Error {
44
+ readonly code = "unknown_model";
45
+ readonly modelId: string;
46
+ constructor(modelId: string, registered: readonly string[]);
47
+ }
48
+ /** Register (or replace) one model's price and capabilities. */
49
+ export declare function registerModel(pricing: ModelPricing): void;
50
+ export declare function registerModels(pricings: readonly ModelPricing[]): void;
51
+ export declare function getModelPricing(modelId: string): ModelPricing | undefined;
52
+ export declare function isModelRegistered(modelId: string): boolean;
53
+ export declare function listModels(): readonly ModelPricing[];
54
+ export declare function registeredModelIds(): readonly string[];
55
+ /** For tests composing a fresh root. */
56
+ export declare function clearModels(): void;
108
57
  /**
109
- * Calculate the dollar cost for a given model and token counts.
58
+ * The catalogue the framework ships, as data.
59
+ *
60
+ * Prices are the providers' published USD rates and go stale; a
61
+ * deployment that cares about the third decimal should register its own
62
+ * contracted rates over these.
110
63
  */
111
- export declare function calculateCost(modelId: string, inputTokens: number, outputTokens: number): number;
64
+ export declare const DEFAULT_MODELS: readonly ModelPricing[];
65
+ /** Providers quote in USD; every cost in this module starts there. */
66
+ export declare const PROVIDER_CURRENCY: CurrencyCode;
112
67
  /**
113
- * Default billing margin multiplier applied on top of raw model cost.
114
- * Covers infra, tool overhead, FX volatility, and profit. Tunable per
115
- * deploy via billing_settings.margin_multiplier; this constant is the
116
- * fallback when the DB value is absent.
68
+ * What the provider charges for this call, in USD.
117
69
  *
118
- * INVARIANT 65% gross margin floor (founder contract):
119
- * gross_margin = 1 1/multiplier
120
- * We must keep gross_margin 0.65 across every model in MODEL_CONFIGS,
121
- * which means multiplier 1/0.35 2.857. The current value of 4
122
- * yields 75%, leaving comfortable buffer above the floor for FX moves
123
- * and unexpected provider price hikes. The Vitest assertion in
124
- * models.test.ts pins this — drop below 2.857 at your own risk.
70
+ * A price quoted per million tokens is, per token, that many millionths
71
+ * of a dollar — so the micros are `tokens × price`. The price is scaled
72
+ * to an integer first, because `100 × 1.1` in floating point is
73
+ * `110.00000000000001` and would round up to a micro nobody used.
74
+ * Fractions of a micro round up, which keeps the cheapest models from
75
+ * pricing a real call at nothing.
76
+ *
77
+ * @throws {UnknownModelError} when the id has no registered price.
125
78
  */
126
- export declare const DEFAULT_BILLING_MARGIN = 4;
79
+ export declare function providerCost(modelId: string, inputTokens: number, outputTokens: number): Money;
127
80
  /**
128
- * Default USD→MNT exchange rate fallback. Real value lives in
129
- * billing_settings.usd_to_mnt_rate and is read per request.
81
+ * What a deployment bills in: its currency, what one USD costs in it
82
+ * (micros, so `1_000_000` is a USD deployment and `920_000` a euro one
83
+ * at 0.92), and the margin over provider cost in basis points of a
84
+ * multiplier — `40_000` is 4×.
85
+ *
86
+ * Read per request from `billing_settings`; there is no ambient rate,
87
+ * because a framework that guesses an exchange rate is inventing money.
130
88
  */
131
- export declare const DEFAULT_USD_TO_MNT_RATE = 3450;
89
+ export type BillingRate = {
90
+ currency: CurrencyCode;
91
+ usdRateMicros: number;
92
+ marginBp: number;
93
+ };
132
94
  /**
133
- * Per-model maximum output budget used for worst-case pre-request cost
134
- * estimation in checkQuota. Numbers are conservative — cap on streamed
135
- * output tokens we'd actually let a single chat turn produce.
95
+ * `40_000` bp = provider cost, the fallback margin when a
96
+ * deployment's `billing_settings` row names none.
97
+ *
98
+ * INVARIANT — a 65% gross margin floor:
99
+ * gross_margin = 1 − 1/multiplier
100
+ * Keeping gross_margin ≥ 0.65 means a multiplier ≥ 1/0.35 ≈ 2.857. At
101
+ * 4× this yields 75%, leaving buffer above the floor for FX moves and
102
+ * provider price rises. `pricing.test.ts` pins it.
136
103
  */
137
- export declare const MODEL_OUTPUT_BUDGET: Record<ModelId, number>;
138
- export type ChargedAmount = {
139
- rawCostUsd: number;
140
- chargedMnt: number;
141
- };
104
+ export declare const DEFAULT_MARGIN_BP = 40000;
142
105
  /**
143
- * Convert raw model cost to MNT user-facing charged amount.
106
+ * Provider cost and what the reader is charged for it: cost × margin,
107
+ * converted into the deployment's currency at its own rate.
144
108
  *
145
- * chargedMnt = ceil( rawCostUsd × margin × fxRate )
109
+ * Both steps round up, so a charge is at most two micros over — a
110
+ * millionth of a cent, against a fraction that would otherwise be the
111
+ * deployment's to eat on every request.
146
112
  *
147
- * The rounding is upward so micro-fractions never let a free request
148
- * slip through; over-billing per request is at most 1 MNT.
113
+ * @throws {UnknownModelError} when the id has no registered price.
114
+ * @throws {MoneyError} when a USD deployment passes a rate that is not 1.
149
115
  */
150
- export declare function calculateChargedMnt(modelId: string, inputTokens: number, outputTokens: number, fxRate?: number, margin?: number): ChargedAmount;
116
+ export declare function chargeFor(modelId: string, inputTokens: number, outputTokens: number, rate: BillingRate): {
117
+ providerCost: Money;
118
+ charged: Money;
119
+ };
151
120
  /**
152
- * Worst-case MNT cost estimate for a single chat turn against a given
153
- * model. Used by checkQuota to refuse requests whose ceiling cost would
154
- * exceed remaining balance, before we burn provider tokens. Uses the
155
- * full MODEL_OUTPUT_BUDGET as the output side and a generous 16K input
156
- * budget to cover system prompt + conversation history.
121
+ * The ceiling one turn on this model could charge, for admission:
122
+ * the model's own output limit against a 16K input budget (system
123
+ * prompt plus history). Refusing on the ceiling is what stops a turn
124
+ * that cannot be paid for from burning provider tokens first.
125
+ *
126
+ * @throws {UnknownModelError} when the id has no registered price.
157
127
  */
158
- export declare function estimateWorstCaseChargedMnt(modelId: string, fxRate?: number, margin?: number): number;
128
+ export declare function estimateWorstCaseCharge(modelId: string, rate: BillingRate): Money;
159
129
  //# sourceMappingURL=pricing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwFhB,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,aAAa,CAAC;AAEjD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,CAkBR;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;GAGG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAOvD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,MAAM,GAAE,MAAgC,EACxC,MAAM,GAAE,MAA+B,GACtC,aAAa,CAIf;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAgC,EACxC,MAAM,GAAE,MAA+B,GACtC,MAAM,CAKR"}
1
+ {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,KAAK,EACX,MAAM,2BAA2B,CAAC;AAGnC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,4DAA4D;IAC5D,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,qCAAqC;IACrC,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,iBAAiB,CAAC;CACjC,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,mBAAmB;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBACb,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE;CAS3D;AAID,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAEzD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,GAAG,IAAI,CAEtE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEzE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,wBAAgB,UAAU,IAAI,SAAS,YAAY,EAAE,CAEpD;AAED,wBAAgB,kBAAkB,IAAI,SAAS,MAAM,EAAE,CAEtD;AAED,wCAAwC;AACxC,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAiGjD,CAAC;AASF,sEAAsE;AACtE,eAAO,MAAM,iBAAiB,EAAE,YAA8B,CAAC;AAE/D;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,KAAK,CAWP;AAKD;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,YAAY,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,QAAS,CAAC;AAIxC;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,WAAW,GAChB;IAAE,YAAY,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,KAAK,CAAA;CAAE,CAUzC;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,WAAW,GAChB,KAAK,CAGP"}
package/dist/pricing.js CHANGED
@@ -1,31 +1,70 @@
1
1
  /**
2
2
  * Model registry and execution cost accounting.
3
3
  *
4
- * This lives in `executions` rather than beside the provider clients
5
- * because it is not AI code: it is what an execution costs. The
6
- * boundary records actor, workspace, capability, usage and cost
7
- * (ADR-0003), and the price of a token is the last of those.
4
+ * A leaf: no database, no provider SDK. Its one import is
5
+ * `@intelligo-dev/core/registry`, which is itself dependency-free, so
6
+ * `@intelligo-dev/executions/pricing` is something a client bundle can
7
+ * read a display name or a price from without pulling in Drizzle.
8
8
  *
9
- * Deliberately a leaf module no database, no provider SDK, no
10
- * imports at all and reachable as `@intelligo-dev/executions/pricing`
11
- * so a client bundle can read a display name or a price without
12
- * pulling in Drizzle. `@intelligo-dev/ai` re-exports it, so the ids that
13
- * pick a provider and the ids that carry a price stay one list; two
14
- * lists is how a model runs on Gemini and bills at Claude rates.
9
+ * The registry is open: a product registers any model it runs, and
10
+ * `registerModels(DEFAULT_MODELS)` from the composition root registers
11
+ * the shipped catalogue. Nothing self-registers. An id with no price
12
+ * throws at the point where the price is needed, naming the id, rather
13
+ * than billing at a guessed rate.
15
14
  */
15
+ import { convert, currency, money, } from "@intelligo-dev/core/money";
16
+ import { createRegistry } from "@intelligo-dev/core/registry";
17
+ export class UnknownModelError extends Error {
18
+ constructor(modelId, registered) {
19
+ super(`No price registered for model "${modelId}". ` +
20
+ `Registered: ${registered.length > 0 ? registered.join(", ") : "none"}. ` +
21
+ `Call registerModels(DEFAULT_MODELS) — or your own catalogue — from the composition root.`);
22
+ this.code = "unknown_model";
23
+ this.name = "UnknownModelError";
24
+ this.modelId = modelId;
25
+ }
26
+ }
27
+ const models = createRegistry("executions/model-pricing");
28
+ /** Register (or replace) one model's price and capabilities. */
29
+ export function registerModel(pricing) {
30
+ models.set(pricing.id, pricing);
31
+ }
32
+ export function registerModels(pricings) {
33
+ for (const pricing of pricings)
34
+ registerModel(pricing);
35
+ }
36
+ export function getModelPricing(modelId) {
37
+ return models.get(modelId);
38
+ }
39
+ export function isModelRegistered(modelId) {
40
+ return models.has(modelId);
41
+ }
42
+ export function listModels() {
43
+ return [...models.values()];
44
+ }
45
+ export function registeredModelIds() {
46
+ return [...models.keys()];
47
+ }
48
+ /** For tests composing a fresh root. */
49
+ export function clearModels() {
50
+ models.clear();
51
+ }
16
52
  /**
17
- * Model configuration with display information and cost tracking
53
+ * The catalogue the framework ships, as data.
18
54
  *
19
- * 6 models, 3 providers: Google (2), OpenAI (3), Anthropic (1)
55
+ * Prices are the providers' published USD rates and go stale; a
56
+ * deployment that cares about the third decimal should register its own
57
+ * contracted rates over these.
20
58
  */
21
- export const MODEL_CONFIGS = {
22
- // Google Gemini
23
- "google/gemini-2.5-flash": {
59
+ export const DEFAULT_MODELS = [
60
+ {
61
+ id: "google/gemini-2.5-flash",
24
62
  provider: "google",
25
63
  model: "gemini-2.5-flash",
26
64
  displayName: "Gemini 2.5 Flash",
27
65
  costPerMInputTokens: 0.3,
28
66
  costPerMOutputTokens: 2.5,
67
+ maxOutputTokens: 8000,
29
68
  capabilities: {
30
69
  thinking: true,
31
70
  toolCall: true,
@@ -34,12 +73,14 @@ export const MODEL_CONFIGS = {
34
73
  codeExec: true,
35
74
  },
36
75
  },
37
- "google/gemini-2.5-pro": {
76
+ {
77
+ id: "google/gemini-2.5-pro",
38
78
  provider: "google",
39
79
  model: "gemini-2.5-pro",
40
80
  displayName: "Gemini 2.5 Pro",
41
81
  costPerMInputTokens: 1.25,
42
82
  costPerMOutputTokens: 10,
83
+ maxOutputTokens: 8000,
43
84
  capabilities: {
44
85
  thinking: true,
45
86
  toolCall: true,
@@ -48,13 +89,14 @@ export const MODEL_CONFIGS = {
48
89
  codeExec: true,
49
90
  },
50
91
  },
51
- // OpenAI
52
- "openai/gpt-5-mini": {
92
+ {
93
+ id: "openai/gpt-5-mini",
53
94
  provider: "openai",
54
95
  model: "gpt-5-mini",
55
96
  displayName: "GPT-5 Mini",
56
97
  costPerMInputTokens: 0.25,
57
98
  costPerMOutputTokens: 2.0,
99
+ maxOutputTokens: 8000,
58
100
  capabilities: {
59
101
  thinking: true,
60
102
  toolCall: true,
@@ -63,12 +105,14 @@ export const MODEL_CONFIGS = {
63
105
  codeExec: false,
64
106
  },
65
107
  },
66
- "openai/gpt-5.4-mini": {
108
+ {
109
+ id: "openai/gpt-5.4-mini",
67
110
  provider: "openai",
68
111
  model: "gpt-5.4-mini",
69
112
  displayName: "GPT-5.4 Mini",
70
113
  costPerMInputTokens: 0.75,
71
114
  costPerMOutputTokens: 4.5,
115
+ maxOutputTokens: 8000,
72
116
  capabilities: {
73
117
  thinking: true,
74
118
  toolCall: true,
@@ -77,12 +121,14 @@ export const MODEL_CONFIGS = {
77
121
  codeExec: true,
78
122
  },
79
123
  },
80
- "openai/o4-mini": {
124
+ {
125
+ id: "openai/o4-mini",
81
126
  provider: "openai",
82
127
  model: "o4-mini",
83
128
  displayName: "o4-mini",
84
129
  costPerMInputTokens: 1.1,
85
130
  costPerMOutputTokens: 4.4,
131
+ maxOutputTokens: 8000,
86
132
  capabilities: {
87
133
  thinking: true,
88
134
  toolCall: true,
@@ -91,13 +137,14 @@ export const MODEL_CONFIGS = {
91
137
  codeExec: true,
92
138
  },
93
139
  },
94
- // Anthropic
95
- "anthropic/claude-sonnet-4-6": {
140
+ {
141
+ id: "anthropic/claude-sonnet-4-6",
96
142
  provider: "anthropic",
97
143
  model: "claude-sonnet-4-6-20260214",
98
144
  displayName: "Claude Sonnet 4.6",
99
145
  costPerMInputTokens: 3.0,
100
146
  costPerMOutputTokens: 15.0,
147
+ maxOutputTokens: 8000,
101
148
  capabilities: {
102
149
  thinking: true,
103
150
  toolCall: true,
@@ -106,82 +153,79 @@ export const MODEL_CONFIGS = {
106
153
  codeExec: true,
107
154
  },
108
155
  },
109
- };
156
+ ];
157
+ /** The price of a model, or a loud failure naming the id. */
158
+ function requireModel(modelId) {
159
+ const pricing = models.get(modelId);
160
+ if (!pricing)
161
+ throw new UnknownModelError(modelId, registeredModelIds());
162
+ return pricing;
163
+ }
164
+ /** Providers quote in USD; every cost in this module starts there. */
165
+ export const PROVIDER_CURRENCY = currency("USD");
110
166
  /**
111
- * Calculate the dollar cost for a given model and token counts.
167
+ * What the provider charges for this call, in USD.
168
+ *
169
+ * A price quoted per million tokens is, per token, that many millionths
170
+ * of a dollar — so the micros are `tokens × price`. The price is scaled
171
+ * to an integer first, because `100 × 1.1` in floating point is
172
+ * `110.00000000000001` and would round up to a micro nobody used.
173
+ * Fractions of a micro round up, which keeps the cheapest models from
174
+ * pricing a real call at nothing.
175
+ *
176
+ * @throws {UnknownModelError} when the id has no registered price.
112
177
  */
113
- export function calculateCost(modelId, inputTokens, outputTokens) {
114
- const config = MODEL_CONFIGS[modelId];
115
- if (!config) {
116
- // Loud fallback: an unknown model ID means somewhere upstream is
117
- // shipping a stale string that doesn't match MODEL_CONFIGS. We
118
- // price it at the highest known rate so we don't accidentally give
119
- // away expensive completions for free, but the warning here is the
120
- // contract — silent fallback is how we ended up over-billing every
121
- // free Gemini turn at Claude prices.
122
- console.warn(`[calculateCost] Unknown model "${modelId}" — pricing at worst-case Claude rate ($3/$15 per M). Add it to MODEL_CONFIGS.`);
123
- return (inputTokens / 1000000) * 3.0 + (outputTokens / 1000000) * 15.0;
124
- }
125
- return ((inputTokens / 1000000) * config.costPerMInputTokens +
126
- (outputTokens / 1000000) * config.costPerMOutputTokens);
178
+ export function providerCost(modelId, inputTokens, outputTokens) {
179
+ const config = requireModel(modelId);
180
+ const scaled = (price) => Math.round(price * PRICE_SCALE);
181
+ return money(Math.ceil((inputTokens * scaled(config.costPerMInputTokens) +
182
+ outputTokens * scaled(config.costPerMOutputTokens)) /
183
+ PRICE_SCALE), PROVIDER_CURRENCY);
127
184
  }
185
+ /** Prices carry at most six decimals of a dollar per million tokens. */
186
+ const PRICE_SCALE = 1000000;
128
187
  /**
129
- * Default billing margin multiplier applied on top of raw model cost.
130
- * Covers infra, tool overhead, FX volatility, and profit. Tunable per
131
- * deploy via billing_settings.margin_multiplier; this constant is the
132
- * fallback when the DB value is absent.
188
+ * `40_000` bp = provider cost, the fallback margin when a
189
+ * deployment's `billing_settings` row names none.
133
190
  *
134
- * INVARIANT — 65% gross margin floor (founder contract):
191
+ * INVARIANT — a 65% gross margin floor:
135
192
  * gross_margin = 1 − 1/multiplier
136
- * We must keep gross_margin ≥ 0.65 across every model in MODEL_CONFIGS,
137
- * which means multiplier 1/0.35 2.857. The current value of 4
138
- * yields 75%, leaving comfortable buffer above the floor for FX moves
139
- * and unexpected provider price hikes. The Vitest assertion in
140
- * models.test.ts pins this — drop below 2.857 at your own risk.
193
+ * Keeping gross_margin ≥ 0.65 means a multiplier 1/0.35 ≈ 2.857. At
194
+ * this yields 75%, leaving buffer above the floor for FX moves and
195
+ * provider price rises. `pricing.test.ts` pins it.
141
196
  */
142
- export const DEFAULT_BILLING_MARGIN = 4;
197
+ export const DEFAULT_MARGIN_BP = 40000;
198
+ const BP_PER_MULTIPLE = 10000;
143
199
  /**
144
- * Default USD→MNT exchange rate fallback. Real value lives in
145
- * billing_settings.usd_to_mnt_rate and is read per request.
146
- */
147
- export const DEFAULT_USD_TO_MNT_RATE = 3450;
148
- /**
149
- * Per-model maximum output budget used for worst-case pre-request cost
150
- * estimation in checkQuota. Numbers are conservative — cap on streamed
151
- * output tokens we'd actually let a single chat turn produce.
152
- */
153
- export const MODEL_OUTPUT_BUDGET = {
154
- "google/gemini-2.5-flash": 8000,
155
- "google/gemini-2.5-pro": 8000,
156
- "openai/gpt-5-mini": 8000,
157
- "openai/gpt-5.4-mini": 8000,
158
- "openai/o4-mini": 8000,
159
- "anthropic/claude-sonnet-4-6": 8000,
160
- };
161
- /**
162
- * Convert raw model cost to MNT user-facing charged amount.
200
+ * Provider cost and what the reader is charged for it: cost × margin,
201
+ * converted into the deployment's currency at its own rate.
163
202
  *
164
- * chargedMnt = ceil( rawCostUsd × margin × fxRate )
203
+ * Both steps round up, so a charge is at most two micros over — a
204
+ * millionth of a cent, against a fraction that would otherwise be the
205
+ * deployment's to eat on every request.
165
206
  *
166
- * The rounding is upward so micro-fractions never let a free request
167
- * slip through; over-billing per request is at most 1 MNT.
207
+ * @throws {UnknownModelError} when the id has no registered price.
208
+ * @throws {MoneyError} when a USD deployment passes a rate that is not 1.
168
209
  */
169
- export function calculateChargedMnt(modelId, inputTokens, outputTokens, fxRate = DEFAULT_USD_TO_MNT_RATE, margin = DEFAULT_BILLING_MARGIN) {
170
- const rawCostUsd = calculateCost(modelId, inputTokens, outputTokens);
171
- const chargedMnt = Math.ceil(rawCostUsd * margin * fxRate);
172
- return { rawCostUsd, chargedMnt };
210
+ export function chargeFor(modelId, inputTokens, outputTokens, rate) {
211
+ const cost = providerCost(modelId, inputTokens, outputTokens);
212
+ const withMargin = money(Math.ceil((cost.amount * rate.marginBp) / BP_PER_MULTIPLE), PROVIDER_CURRENCY);
213
+ return {
214
+ providerCost: cost,
215
+ charged: convert(withMargin, rate.currency, rate.usdRateMicros),
216
+ };
173
217
  }
174
218
  /**
175
- * Worst-case MNT cost estimate for a single chat turn against a given
176
- * model. Used by checkQuota to refuse requests whose ceiling cost would
177
- * exceed remaining balance, before we burn provider tokens. Uses the
178
- * full MODEL_OUTPUT_BUDGET as the output side and a generous 16K input
179
- * budget to cover system prompt + conversation history.
219
+ * The ceiling one turn on this model could charge, for admission:
220
+ * the model's own output limit against a 16K input budget (system
221
+ * prompt plus history). Refusing on the ceiling is what stops a turn
222
+ * that cannot be paid for from burning provider tokens first.
223
+ *
224
+ * @throws {UnknownModelError} when the id has no registered price.
180
225
  */
181
- export function estimateWorstCaseChargedMnt(modelId, fxRate = DEFAULT_USD_TO_MNT_RATE, margin = DEFAULT_BILLING_MARGIN) {
182
- const outputBudget = MODEL_OUTPUT_BUDGET[modelId] ?? 8000;
183
- const inputBudget = 16000;
184
- return calculateChargedMnt(modelId, inputBudget, outputBudget, fxRate, margin)
185
- .chargedMnt;
226
+ export function estimateWorstCaseCharge(modelId, rate) {
227
+ const outputBudget = requireModel(modelId).maxOutputTokens;
228
+ return chargeFor(modelId, ESTIMATE_INPUT_BUDGET, outputBudget, rate).charged;
186
229
  }
230
+ const ESTIMATE_INPUT_BUDGET = 16000;
187
231
  //# sourceMappingURL=pricing.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}