slash-tokens 1.5.6 → 1.5.7

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/cli.js CHANGED
@@ -208,8 +208,8 @@ var MODELS = {
208
208
  "claude-opus-4.7": { input: 5, output: 25, context: 1e6 },
209
209
  "claude-sonnet": { input: 2, output: 10, context: 1e6 },
210
210
  "claude-haiku": { input: 1, output: 5, context: 200000 },
211
- "grok-4.20": { input: 1.25, output: 2.5, context: 1e6 },
212
- "grok-4-1-fast": { input: 1.25, output: 2.5, context: 1e6 },
211
+ "grok-4.20": { input: 1.25, output: 2.5, context: 1e6, longContextThreshold: 200000, longContextInput: 2.5, longContextOutput: 5 },
212
+ "grok-4-1-fast": { input: 1.25, output: 2.5, context: 1e6, longContextThreshold: 200000, longContextInput: 2.5, longContextOutput: 5 },
213
213
  "gemini-3.1-pro": { input: 2, output: 12, context: 1e6 },
214
214
  "gemini-2.5-flash": { input: 0.3, output: 2.5, context: 1e6 },
215
215
  "gpt-5.4": { input: 2.5, output: 15, context: 1e6 },
@@ -11,5 +11,6 @@ export interface InterceptEvent {
11
11
  routed: boolean;
12
12
  timestamp: string;
13
13
  }
14
+ export declare function normalizeModel(raw: string): string;
14
15
  export declare function onIntercept(handler: (event: InterceptEvent) => void): void;
15
16
  export declare function patchFetch(): void;
package/dist/intercept.js CHANGED
@@ -6,6 +6,7 @@ import { PROVIDER_MODELS } from './providers.js';
6
6
  // (what to put back in the request body)
7
7
  const MODEL_API_NAMES = {
8
8
  'claude-opus': 'claude-opus-5',
9
+ 'claude-opus-4.7': 'claude-opus-4-7',
9
10
  'claude-sonnet': 'claude-sonnet-5',
10
11
  'claude-haiku': 'claude-haiku-4-5-20251001',
11
12
  'gpt-5.4': 'gpt-5.4',
@@ -43,10 +44,20 @@ const AI_ENDPOINTS = [
43
44
  modelExtractor: (body) => body?.model || 'grok-4.20',
44
45
  },
45
46
  ];
46
- // Normalize model names to our pricing table keys
47
- function normalizeModel(raw) {
47
+ // Normalize model names to our pricing table keys.
48
+ // Kept in sync by hand with mcpaas-cf/src/slash-models.ts's normalizeModel
49
+ // (no shared import between the two repos) — fixed 2026-08-23: this copy
50
+ // was missing the opus-4.7 special case and several OpenAI legacy
51
+ // fallbacks the other copy already had, which silently mapped those
52
+ // intercepted calls to generic claude-opus / an unmapped raw string
53
+ // (getModel() returning undefined → $0 reported cost, see slash.ts's
54
+ // DEFAULT_UNKNOWN_MODEL_FACTOR comment for why "unrecognized" defaulting
55
+ // to a falsely-safe-looking value is the dangerous case).
56
+ export function normalizeModel(raw) {
48
57
  const lower = raw.toLowerCase();
49
- // Anthropic
58
+ // Anthropic — 4.7 before generic opus check, same order as slash-models.ts
59
+ if (lower.includes('opus') && (lower.includes('4-7') || lower.includes('4.7')))
60
+ return 'claude-opus-4.7';
50
61
  if (lower.includes('opus'))
51
62
  return 'claude-opus';
52
63
  if (lower.includes('sonnet'))
@@ -63,20 +74,28 @@ function normalizeModel(raw) {
63
74
  return 'gemini-3.1-pro';
64
75
  if (lower.includes('gemini'))
65
76
  return 'gemini-2.5-flash';
66
- // OpenAI
77
+ // OpenAI — current (5.4 family)
67
78
  if (lower.includes('5.4') && lower.includes('nano'))
68
79
  return 'gpt-5.4-nano';
69
80
  if (lower.includes('5.4') && lower.includes('mini'))
70
81
  return 'gpt-5.4-mini';
71
82
  if (lower.includes('5.4'))
72
83
  return 'gpt-5.4';
73
- // Legacy fallbacks
84
+ // OpenAI — legacy model names → map to closest current equivalent
85
+ if (lower.includes('o1-mini') || lower.includes('o1_mini'))
86
+ return 'gpt-5.4-mini';
87
+ if (lower.includes('o1'))
88
+ return 'gpt-5.4';
74
89
  if (lower.includes('4o-mini') || lower.includes('4o_mini'))
75
90
  return 'gpt-5.4-mini';
76
91
  if (lower.includes('4o') || lower.includes('4.1'))
77
92
  return 'gpt-5.4';
78
- if (lower.includes('grok-3'))
79
- return 'grok-4.20';
93
+ if (lower.includes('gpt-4-turbo') || lower.includes('gpt-4-1'))
94
+ return 'gpt-5.4';
95
+ if (lower.includes('gpt-4'))
96
+ return 'gpt-5.4';
97
+ if (lower.includes('gpt-3.5') || lower.includes('gpt-35'))
98
+ return 'gpt-5.4-nano';
80
99
  return raw;
81
100
  }
82
101
  // Extract message content from request body
package/dist/models.d.ts CHANGED
@@ -2,7 +2,14 @@ export interface ModelInfo {
2
2
  input: number;
3
3
  output: number;
4
4
  context: number;
5
+ longContextThreshold?: number;
6
+ longContextInput?: number;
7
+ longContextOutput?: number;
5
8
  }
6
9
  export declare const MODELS: Record<string, ModelInfo>;
7
10
  export declare function getModel(name: string): ModelInfo | undefined;
11
+ export declare function effectiveRate(tokens: number, info: ModelInfo): {
12
+ input: number;
13
+ output: number;
14
+ };
8
15
  export declare function listModels(): string[];
package/dist/models.js CHANGED
@@ -21,8 +21,8 @@ export const MODELS = {
21
21
  'claude-sonnet': { input: 2.00, output: 10.00, context: 1000000 },
22
22
  'claude-haiku': { input: 1.00, output: 5.00, context: 200000 },
23
23
  // xAI
24
- 'grok-4.20': { input: 1.25, output: 2.50, context: 1000000 },
25
- 'grok-4-1-fast': { input: 1.25, output: 2.50, context: 1000000 },
24
+ 'grok-4.20': { input: 1.25, output: 2.50, context: 1000000, longContextThreshold: 200000, longContextInput: 2.50, longContextOutput: 5.00 },
25
+ 'grok-4-1-fast': { input: 1.25, output: 2.50, context: 1000000, longContextThreshold: 200000, longContextInput: 2.50, longContextOutput: 5.00 },
26
26
  // Google
27
27
  'gemini-3.1-pro': { input: 2.00, output: 12.00, context: 1000000 },
28
28
  'gemini-2.5-flash': { input: 0.30, output: 2.50, context: 1000000 },
@@ -34,6 +34,20 @@ export const MODELS = {
34
34
  export function getModel(name) {
35
35
  return MODELS[name] || MODELS[name.toLowerCase()];
36
36
  }
37
+ // Resolve the actual billable rate for a given token count — applies the
38
+ // long-context tier above if the model has one and tokens cross it.
39
+ // preflight()/preflightRoute() should go through this, not read
40
+ // .input/.output directly, or a Grok call over 200K tokens gets silently
41
+ // under-costed at the base rate.
42
+ export function effectiveRate(tokens, info) {
43
+ if (info.longContextThreshold !== undefined && tokens > info.longContextThreshold) {
44
+ return {
45
+ input: info.longContextInput ?? info.input,
46
+ output: info.longContextOutput ?? info.output,
47
+ };
48
+ }
49
+ return { input: info.input, output: info.output };
50
+ }
37
51
  export function listModels() {
38
52
  return Object.keys(MODELS);
39
53
  }
package/dist/preflight.js CHANGED
@@ -1,14 +1,17 @@
1
1
  import { slash } from './slash.js';
2
- import { getModel, MODELS } from './models.js';
2
+ import { getModel, MODELS, effectiveRate } from './models.js';
3
3
  import { PROVIDER_MODELS, providerOf } from './providers.js';
4
4
  import { shouldRoute, isModelAllowed } from './config.js';
5
5
  /**
6
6
  * Compute cost of a prompt of `tokens` tokens on the given ModelInfo.
7
7
  * Uses input-token price only (output is not known at preflight time).
8
- * Rounded to 6 decimals.
8
+ * Rounded to 6 decimals. Goes through effectiveRate() so a long-context
9
+ * model (currently only Grok, over 200K tokens) isn't silently costed at
10
+ * its base rate — fixed 2026-08-23.
9
11
  */
10
12
  function computeCost(tokens, info) {
11
- return Math.round(((tokens / 1000000) * info.input) * 1000000) / 1000000;
13
+ const rate = effectiveRate(tokens, info);
14
+ return Math.round(((tokens / 1000000) * rate.input) * 1000000) / 1000000;
12
15
  }
13
16
  function buildAlternative(model, originalCost, tokens, info) {
14
17
  const altCost = computeCost(tokens, info);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slash-tokens",
3
- "version": "1.5.6",
3
+ "version": "1.5.7",
4
4
  "description": "Token Optimization for Context Engineers. 4.8 KB WASM. Sub-millisecond. Zero dependencies.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",