mohdel 0.94.0 → 0.96.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.
|
@@ -14,6 +14,19 @@ import { getSpec, setCatalog } from './_catalog.js'
|
|
|
14
14
|
/**
|
|
15
15
|
* Pure cost computation from spec + usage.
|
|
16
16
|
*
|
|
17
|
+
* Each price field (`inputPrice` / `outputPrice` / `thinkingPrice`) is
|
|
18
|
+
* one of:
|
|
19
|
+
*
|
|
20
|
+
* - a `number` — flat per-million rate; or
|
|
21
|
+
* - an object `{">N": number, ..., "default": number}` — tiered.
|
|
22
|
+
* The active rate is the one under the highest `>N` key that the
|
|
23
|
+
* call's `inputTokens` exceeds; falls back to `"default"` when
|
|
24
|
+
* nothing matches. Keys that aren't `">N"` or `"default"` are
|
|
25
|
+
* ignored. `>` is strict — at exactly N, the default is used.
|
|
26
|
+
*
|
|
27
|
+
* `thinkingPrice` is optional and falls back to the resolved
|
|
28
|
+
* `outputPrice` when absent.
|
|
29
|
+
*
|
|
17
30
|
* @param {any} spec Catalog entry (with `inputPrice`/`outputPrice`/`thinkingPrice`),
|
|
18
31
|
* or `undefined`.
|
|
19
32
|
* @param {{inputTokens?: number, outputTokens?: number, thinkingTokens?: number}} usage
|
|
@@ -21,17 +34,50 @@ import { getSpec, setCatalog } from './_catalog.js'
|
|
|
21
34
|
*/
|
|
22
35
|
export function computeCost (spec, usage) {
|
|
23
36
|
if (!spec) return 0
|
|
24
|
-
const ip = spec.inputPrice
|
|
25
|
-
const op = spec.outputPrice
|
|
26
|
-
if (typeof ip !== 'number' || typeof op !== 'number') return 0
|
|
27
37
|
const i = usage.inputTokens ?? 0
|
|
28
38
|
const o = usage.outputTokens ?? 0
|
|
29
39
|
const t = usage.thinkingTokens ?? 0
|
|
30
|
-
const
|
|
31
|
-
const
|
|
40
|
+
const ip = resolveTier(spec.inputPrice, i)
|
|
41
|
+
const op = resolveTier(spec.outputPrice, i)
|
|
42
|
+
if (typeof ip !== 'number' || typeof op !== 'number') return 0
|
|
43
|
+
const tp = resolveTier(spec.thinkingPrice, i)
|
|
44
|
+
const tpFinal = typeof tp === 'number' ? tp : op
|
|
45
|
+
const total = (i * ip + o * op + t * tpFinal) / 1_000_000
|
|
32
46
|
return round(total)
|
|
33
47
|
}
|
|
34
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Resolve a price field against a token count. Scalars pass through;
|
|
51
|
+
* tiered maps return the rate of the highest `>N` key that
|
|
52
|
+
* `tokens` exceeds, falling back to `default`. Returns `null` when
|
|
53
|
+
* the field is absent or malformed — callers decide whether to treat
|
|
54
|
+
* that as "no price" (cost=0) or fall back (thinkingPrice→outputPrice).
|
|
55
|
+
*
|
|
56
|
+
* @param {unknown} price
|
|
57
|
+
* @param {number} tokens
|
|
58
|
+
* @returns {number | null}
|
|
59
|
+
*/
|
|
60
|
+
function resolveTier (price, tokens) {
|
|
61
|
+
if (typeof price === 'number') return price
|
|
62
|
+
if (!price || typeof price !== 'object') return null
|
|
63
|
+
let best = null
|
|
64
|
+
let bestThreshold = -1
|
|
65
|
+
for (const key of Object.keys(price)) {
|
|
66
|
+
if (key === 'default') continue
|
|
67
|
+
const m = /^>(\d+)$/.exec(key)
|
|
68
|
+
if (!m) continue
|
|
69
|
+
const threshold = Number(m[1])
|
|
70
|
+
if (tokens > threshold && threshold > bestThreshold) {
|
|
71
|
+
bestThreshold = threshold
|
|
72
|
+
const v = /** @type {Record<string, unknown>} */ (price)[key]
|
|
73
|
+
if (typeof v === 'number') best = v
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (best != null) return best
|
|
77
|
+
const d = /** @type {Record<string, unknown>} */ (price).default
|
|
78
|
+
return typeof d === 'number' ? d : null
|
|
79
|
+
}
|
|
80
|
+
|
|
35
81
|
/**
|
|
36
82
|
* @param {string} model Fully-qualified `<provider>/<model>`.
|
|
37
83
|
* @param {{inputTokens?: number, outputTokens?: number, thinkingTokens?: number}} usage
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mohdel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.96.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Christophe Le Bars",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"@opentelemetry/exporter-trace-otlp-grpc": "^0.215.0",
|
|
88
88
|
"@opentelemetry/sdk-node": "^0.215.0",
|
|
89
89
|
"chalk": "^5.4.0",
|
|
90
|
-
"mohdel-thin-gate-linux-x64-gnu": "0.
|
|
90
|
+
"mohdel-thin-gate-linux-x64-gnu": "0.96.0"
|
|
91
91
|
},
|
|
92
92
|
"dependencies": {
|
|
93
93
|
"@anthropic-ai/sdk": "^0.91.0",
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
},
|
|
104
104
|
"devDependencies": {
|
|
105
105
|
"lint-staged": "^16.4.0",
|
|
106
|
-
"release-it": "^20.0.
|
|
106
|
+
"release-it": "^20.0.1",
|
|
107
107
|
"standard": "^17.1.2",
|
|
108
108
|
"vitest": "^4.1.5"
|
|
109
109
|
}
|