mtok-bridge 0.3.0 → 0.3.1
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/package.json +1 -1
- package/src/serve-core.mjs +25 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mtok-bridge",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Serve any model as an OpenAI-compatible API with a key. No payment, no market, runs anywhere node runs. The transport core behind mtok.market's seller relay.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/serve-core.mjs
CHANGED
|
@@ -119,20 +119,36 @@ export function configuredFeeAtomic({ sellerUsdAtomic, feeAddress, feeBps }) {
|
|
|
119
119
|
return (BigInt(sellerUsdAtomic || 0) * bps + 5000n) / 10000n;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
//
|
|
122
|
+
// Tokenizer-independent input estimate, byte-aware with a safety margin.
|
|
123
|
+
//
|
|
124
|
+
// #626: this used to count one token per UTF-8 byte, i.e. a true worst-case
|
|
125
|
+
// bound (a tokenizer cannot emit more text tokens than bytes). That bound is
|
|
126
|
+
// correct and roughly 4x too pessimistic for real text, and the over-estimate
|
|
127
|
+
// is NOT free: boundServe refuses a draw whose estimated input cost alone meets
|
|
128
|
+
// the payment, and that refusal happens AFTER the buyer has paid on chain. A
|
|
129
|
+
// real buyer sending a ~4KB prompt on a budget that comfortably covered it was
|
|
130
|
+
// refused every night for two weeks and auto-disputed, silently.
|
|
131
|
+
//
|
|
132
|
+
// So estimate realistically and keep the margin explicit. BYTES_PER_TOKEN_EST
|
|
133
|
+
// of 3.2 is the English average (~4 bytes/token) with ~25% headroom, and
|
|
134
|
+
// staying in BYTES rather than characters keeps multibyte prompts from reading
|
|
135
|
+
// artificially cheap. The seller's residual exposure when an estimate lands
|
|
136
|
+
// low is bounded: actual usage is metered from the upstream response after the
|
|
137
|
+
// serve, and the output cap is computed from whatever budget the input
|
|
138
|
+
// estimate left, so an under-estimate eats into output headroom rather than
|
|
139
|
+
// running unpriced.
|
|
126
140
|
export const MESSAGE_OVERHEAD_TOKENS = 4;
|
|
141
|
+
export const BYTES_PER_TOKEN_EST = 3.2;
|
|
127
142
|
export function estimateInputTokens(messages) {
|
|
128
143
|
const utf8 = new TextEncoder();
|
|
129
|
-
let
|
|
144
|
+
let bytes = 0;
|
|
145
|
+
let envelope = 3; // reply priming
|
|
130
146
|
for (const m of messages ?? []) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
147
|
+
envelope += MESSAGE_OVERHEAD_TOKENS;
|
|
148
|
+
bytes += utf8.encode(String(m?.role ?? '')).length;
|
|
149
|
+
bytes += utf8.encode(typeof m?.content === 'string' ? m.content : JSON.stringify(m?.content ?? null)).length;
|
|
134
150
|
}
|
|
135
|
-
return
|
|
151
|
+
return envelope + Math.ceil(bytes / BYTES_PER_TOKEN_EST);
|
|
136
152
|
}
|
|
137
153
|
|
|
138
154
|
// Bound a serve against the paid budget in BOTH legs (#495/#460). The relay used
|