slash-tokens 1.3.0 → 1.4.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/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 James Wolfe (wolfejam)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ This project's name, ⚡ mark, and red/gold color scheme ("brand") are not
26
+ covered by the MIT license above and are reserved for the slash-tokens
27
+ project. If you fork, you agree to ship your derivative under your own name
28
+ and colors. Representing your product as "slash-tokens" / "Slash" without
29
+ written consent is not permitted.
package/README.md CHANGED
@@ -1,26 +1,35 @@
1
1
  # /slash-tokens
2
2
 
3
3
  [![CI/CD](https://github.com/Wolfe-Jam/slash-tokens/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/Wolfe-Jam/slash-tokens/actions/workflows/test.yml)
4
- [![npm version](https://img.shields.io/npm/v/slash-tokens.svg)](https://www.npmjs.com/package/slash-tokens)
5
- [![npm downloads](https://img.shields.io/npm/dm/slash-tokens.svg)](https://www.npmjs.com/package/slash-tokens)
6
- [![bundle size](https://img.shields.io/bundlephobia/minzip/slash-tokens)](https://bundlephobia.com/package/slash-tokens)
7
- [![license](https://img.shields.io/npm/l/slash-tokens.svg)](./LICENSE)
4
+ [![npm version](https://img.shields.io/npm/v/slash-tokens?style=flat&color=cb3837)](https://www.npmjs.com/package/slash-tokens)
5
+ [![npm downloads](https://img.shields.io/npm/dm/slash-tokens?style=flat&color=brightgreen)](https://www.npmjs.com/package/slash-tokens)
6
+ [![WASM size](https://img.shields.io/badge/WASM-4.8_KB-blue?style=flat)](https://bundlephobia.com/package/slash-tokens)
7
+ [![license](https://img.shields.io/npm/l/slash-tokens?style=flat)](./LICENSE)
8
8
  [![⭐ Star on GitHub](https://img.shields.io/badge/%E2%AD%90_Star-black?logo=github&logoColor=white)](https://github.com/Wolfe-Jam/slash-tokens)
9
9
 
10
10
  Token Optimization for Context Engineers.
11
11
  For anyone building with LLMs. 4.8 KB WASM. Sub-millisecond. Zero dependencies.
12
12
 
13
- > 🆕 **v1.3 — The Opus 4.7 Edition.** Same-day support for Claude Opus 4.7 with measured token calibration (1.16–1.51x). Plus Gemini proxy fix and benchmark harness for any upstream.
13
+ Know the cost before the call leaves your machine.
14
+
15
+ > 🆕 **v1.4 — The Single-Source-of-Truth Edition.** New `preflightRoute()` matches the Slash proxy exactly — same-provider only, zero routing drift. `PROVIDER_MODELS` is now the single source of truth across the SDK.
16
+ >
17
+ > **v1.3 — The Opus 4.7 Edition.** Same-day support for Claude Opus 4.7 with measured token calibration (1.16–1.51x). Plus Gemini proxy fix and benchmark harness for any upstream.
14
18
 
15
19
  ```bash
16
20
  npm install slash-tokens
17
21
  ```
18
22
 
19
23
  ```js
20
- import { preflight } from 'slash-tokens'
24
+ import { preflight, preflightRoute } from 'slash-tokens'
21
25
 
26
+ // Analysis — all cheaper alternatives across all providers
22
27
  const check = preflight(prompt, 'claude-opus-4.7')
23
28
  // tokens: 47,000 | cost: $0.71 | 11 cheaper options | save 99%
29
+
30
+ // Routing decision — matches Slash proxy behavior (same-provider only)
31
+ const route = preflightRoute(prompt, 'claude-opus-4.7')
32
+ // → { model: 'claude-haiku', cost: 0.14, salvaged: 0.57, ... } or null
24
33
  ```
25
34
 
26
35
  Or one line — every API call optimized pre-call:
@@ -49,4 +58,12 @@ Track savings across all your apps. Free key at [mcpaas.live/slash/setup](https:
49
58
 
50
59
  Full docs, examples, and model pricing at **[GitHub](https://github.com/Wolfe-Jam/slash-tokens)**
51
60
 
52
- [slashtokens.com](https://slashtokens.com) | MIT
61
+ ## License
62
+
63
+ **Code: MIT.** Fork it, ship it, change it, sell it.
64
+
65
+ **Brand: reserved.** The slash-tokens name, ⚡ mark, and red/gold colors stay with the project. If you're building on top of the SDK, ship under your own name and colors — don't represent your app as Slash.
66
+
67
+ ---
68
+
69
+ 🏎️ *Don't go to the Corner Shop in a Ferrari.* · [slashtokens.com](https://slashtokens.com)
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { slash, slashBytes } from './slash.js';
2
- export { preflight } from './preflight.js';
2
+ export { preflight, preflightRoute } from './preflight.js';
3
3
  export type { PreflightResult, Alternative } from './preflight.js';
4
+ export { PROVIDER_MODELS, providerOf } from './providers.js';
4
5
  export { MODELS, listModels } from './models.js';
5
6
  export type { ModelInfo } from './models.js';
6
7
  export { report } from './transact.js';
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  // Core estimation
2
2
  export { slash, slashBytes } from './slash.js';
3
3
  // Pre-flight checks
4
- export { preflight } from './preflight.js';
4
+ export { preflight, preflightRoute } from './preflight.js';
5
+ // Provider groups (shared between preflight + intercept — single source of truth)
6
+ export { PROVIDER_MODELS, providerOf } from './providers.js';
5
7
  // Model intelligence
6
8
  export { MODELS, listModels } from './models.js';
7
9
  // Transaction reporting
package/dist/intercept.js CHANGED
@@ -1,13 +1,7 @@
1
1
  import { slash } from './slash.js';
2
2
  import { getModel } from './models.js';
3
3
  import { shouldRoute, isModelAllowed } from './config.js';
4
- // Provider groups — routing only happens within same provider
5
- const PROVIDER_MODELS = {
6
- 'Anthropic': ['claude-opus', 'claude-sonnet', 'claude-haiku'],
7
- 'OpenAI': ['gpt-5.4', 'gpt-5.4-mini', 'gpt-5.4-nano'],
8
- 'xAI': ['grok-4.20', 'grok-4-1-fast'],
9
- 'Google': ['gemini-3.1-pro', 'gemini-2.5-flash'],
10
- };
4
+ import { PROVIDER_MODELS } from './providers.js';
11
5
  // Reverse lookup: model name → provider model names in the API
12
6
  // (what to put back in the request body)
13
7
  const MODEL_API_NAMES = {
@@ -13,4 +13,43 @@ export interface PreflightResult {
13
13
  utilization: number;
14
14
  options: Alternative[];
15
15
  }
16
+ /**
17
+ * Analysis tool — returns ALL cheaper models across ALL providers.
18
+ *
19
+ * Use this to SHOW developers what their alternatives are, regardless of
20
+ * whether Slash would actually route there. If you want "what will the
21
+ * Slash proxy ACTUALLY route to right now?", use `preflightRoute()`.
22
+ *
23
+ * TEST-NOTE (critical):
24
+ * - `options` is intentionally cross-provider — this is an analysis tool.
25
+ * - `options[0]` is NOT the routing decision. Using it as such is a bug.
26
+ * - See `preflightRoute()` for the actual routing decision that matches
27
+ * the mcpaas-cf proxy's findCheapestRoute semantics.
28
+ * - A test should assert that preflight().options may contain cross-provider
29
+ * entries (e.g. given model='claude-opus', options[0]?.model CAN be 'grok-...').
30
+ */
16
31
  export declare function preflight(content: string, model: string): PreflightResult;
32
+ /**
33
+ * Routing decision — matches mcpaas-cf proxy's `findCheapestRoute` exactly.
34
+ *
35
+ * Returns the single cheapest SAME-PROVIDER alternative that fits the prompt,
36
+ * or null if no cheaper same-provider option exists (or model unknown,
37
+ * or model's provider unknown).
38
+ *
39
+ * This is what you want to display as "what would Slash route to" — it
40
+ * matches the proxy's actual behavior.
41
+ *
42
+ * TEST-NOTE (critical, must never regress):
43
+ * - Same-provider only. `preflightRoute('hello', 'claude-opus')` must NEVER
44
+ * return a model outside Anthropic. Add a test that asserts this for every
45
+ * canonical model in PROVIDER_MODELS.
46
+ * - Returns null when: model unknown, provider unknown, or no cheaper same-
47
+ * provider alternative exists. Null is a valid result ("PASS, no route").
48
+ * - Cheapest SAME-PROVIDER alternative by input price. If two alternatives
49
+ * tie on price (unlikely but possible), returns the first encountered in
50
+ * PROVIDER_MODELS order.
51
+ * - Must agree with intercept.ts findCheapestRoute for identical inputs.
52
+ * Cross-function semantic test: given the same (provider, tokens, model),
53
+ * both functions return the same model name.
54
+ */
55
+ export declare function preflightRoute(content: string, model: string): Alternative | null;
package/dist/preflight.js CHANGED
@@ -1,27 +1,105 @@
1
1
  import { slash } from './slash.js';
2
2
  import { getModel, MODELS } from './models.js';
3
+ import { PROVIDER_MODELS, providerOf } from './providers.js';
4
+ /**
5
+ * Compute cost of a prompt of `tokens` tokens on the given ModelInfo.
6
+ * Uses input-token price only (output is not known at preflight time).
7
+ * Rounded to 6 decimals.
8
+ */
9
+ function computeCost(tokens, info) {
10
+ return Math.round(((tokens / 1000000) * info.input) * 1000000) / 1000000;
11
+ }
12
+ function buildAlternative(model, originalCost, tokens, info) {
13
+ const altCost = computeCost(tokens, info);
14
+ return {
15
+ model,
16
+ cost: altCost,
17
+ salvaged: Math.round((originalCost - altCost) * 1000000) / 1000000,
18
+ salvagePercent: originalCost > 0 ? Math.round(((originalCost - altCost) / originalCost) * 10000) / 100 : 0,
19
+ };
20
+ }
21
+ /**
22
+ * Analysis tool — returns ALL cheaper models across ALL providers.
23
+ *
24
+ * Use this to SHOW developers what their alternatives are, regardless of
25
+ * whether Slash would actually route there. If you want "what will the
26
+ * Slash proxy ACTUALLY route to right now?", use `preflightRoute()`.
27
+ *
28
+ * TEST-NOTE (critical):
29
+ * - `options` is intentionally cross-provider — this is an analysis tool.
30
+ * - `options[0]` is NOT the routing decision. Using it as such is a bug.
31
+ * - See `preflightRoute()` for the actual routing decision that matches
32
+ * the mcpaas-cf proxy's findCheapestRoute semantics.
33
+ * - A test should assert that preflight().options may contain cross-provider
34
+ * entries (e.g. given model='claude-opus', options[0]?.model CAN be 'grok-...').
35
+ */
3
36
  export function preflight(content, model) {
4
37
  const tokens = slash(content);
5
38
  const info = getModel(model);
6
39
  if (!info) {
7
40
  throw new Error(`Unknown model: "${model}". Available: ${Object.keys(MODELS).join(', ')}`);
8
41
  }
9
- const cost = Math.round(((tokens / 1000000) * info.input) * 1000000) / 1000000;
42
+ const cost = computeCost(tokens, info);
10
43
  const fits = tokens <= info.context;
11
44
  const utilization = Math.round((tokens / info.context) * 10000) / 10000;
12
45
  const options = Object.entries(MODELS)
13
46
  .filter(([m]) => m !== model)
14
- .filter(([_, v]) => v.context >= tokens)
15
- .map(([m, v]) => {
16
- const altCost = Math.round(((tokens / 1000000) * v.input) * 1000000) / 1000000;
17
- return {
18
- model: m,
19
- cost: altCost,
20
- salvaged: Math.round((cost - altCost) * 1000000) / 1000000,
21
- salvagePercent: cost > 0 ? Math.round(((cost - altCost) / cost) * 10000) / 100 : 0,
22
- };
23
- })
47
+ .filter(([, v]) => v.context >= tokens)
48
+ .map(([m, v]) => buildAlternative(m, cost, tokens, v))
24
49
  .filter(o => o.salvaged > 0)
25
50
  .sort((a, b) => a.cost - b.cost);
26
51
  return { tokens, cost, fits, model, context: info.context, utilization, options };
27
52
  }
53
+ /**
54
+ * Routing decision — matches mcpaas-cf proxy's `findCheapestRoute` exactly.
55
+ *
56
+ * Returns the single cheapest SAME-PROVIDER alternative that fits the prompt,
57
+ * or null if no cheaper same-provider option exists (or model unknown,
58
+ * or model's provider unknown).
59
+ *
60
+ * This is what you want to display as "what would Slash route to" — it
61
+ * matches the proxy's actual behavior.
62
+ *
63
+ * TEST-NOTE (critical, must never regress):
64
+ * - Same-provider only. `preflightRoute('hello', 'claude-opus')` must NEVER
65
+ * return a model outside Anthropic. Add a test that asserts this for every
66
+ * canonical model in PROVIDER_MODELS.
67
+ * - Returns null when: model unknown, provider unknown, or no cheaper same-
68
+ * provider alternative exists. Null is a valid result ("PASS, no route").
69
+ * - Cheapest SAME-PROVIDER alternative by input price. If two alternatives
70
+ * tie on price (unlikely but possible), returns the first encountered in
71
+ * PROVIDER_MODELS order.
72
+ * - Must agree with intercept.ts findCheapestRoute for identical inputs.
73
+ * Cross-function semantic test: given the same (provider, tokens, model),
74
+ * both functions return the same model name.
75
+ */
76
+ export function preflightRoute(content, model) {
77
+ const tokens = slash(content);
78
+ const info = getModel(model);
79
+ if (!info)
80
+ return null;
81
+ const provider = providerOf(model);
82
+ if (!provider)
83
+ return null;
84
+ const providerModels = PROVIDER_MODELS[provider];
85
+ if (!providerModels)
86
+ return null;
87
+ const originalCost = computeCost(tokens, info);
88
+ let cheapest = null;
89
+ for (const m of providerModels) {
90
+ if (m === model)
91
+ continue;
92
+ const altInfo = getModel(m);
93
+ if (!altInfo)
94
+ continue;
95
+ if (tokens > altInfo.context)
96
+ continue; // doesn't fit
97
+ if (altInfo.input >= info.input)
98
+ continue; // not cheaper
99
+ const alt = buildAlternative(m, originalCost, tokens, altInfo);
100
+ if (!cheapest || alt.cost < cheapest.cost) {
101
+ cheapest = alt;
102
+ }
103
+ }
104
+ return cheapest;
105
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Provider groups — single source of truth.
3
+ *
4
+ * Slash routing is always SAME-PROVIDER. Opus → Haiku, GPT-5.4 → Nano,
5
+ * Grok-4.20 → Fast, Gemini 3.1 Pro → 2.5 Flash. Never cross-provider.
6
+ *
7
+ * This file is the canonical provider mapping. Both `intercept.ts`
8
+ * (runtime fetch patching) and `preflight.ts` (analysis + routing
9
+ * prediction) consume from here so they can never drift.
10
+ *
11
+ * TEST-NOTE: Whenever a new model is added, it MUST appear in exactly one
12
+ * provider group below. A model missing from here will:
13
+ * - Never be a routing target from `findCheapestRoute` / `preflightRoute`
14
+ * - Still appear in `preflight().options` (which is cross-provider analysis)
15
+ * That mismatch is by design — see preflight.ts semantics.
16
+ */
17
+ export declare const PROVIDER_MODELS: Record<string, string[]>;
18
+ /**
19
+ * Identify a model's provider from its canonical key.
20
+ *
21
+ * TEST-NOTE: This function MUST return a non-null provider for every model
22
+ * present in `MODELS` (from models.ts). If `MODELS` adds a model without
23
+ * adding it to `PROVIDER_MODELS`, this returns null and routing is disabled
24
+ * for that model. Silent skip.
25
+ */
26
+ export declare function providerOf(model: string): string | null;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Provider groups — single source of truth.
3
+ *
4
+ * Slash routing is always SAME-PROVIDER. Opus → Haiku, GPT-5.4 → Nano,
5
+ * Grok-4.20 → Fast, Gemini 3.1 Pro → 2.5 Flash. Never cross-provider.
6
+ *
7
+ * This file is the canonical provider mapping. Both `intercept.ts`
8
+ * (runtime fetch patching) and `preflight.ts` (analysis + routing
9
+ * prediction) consume from here so they can never drift.
10
+ *
11
+ * TEST-NOTE: Whenever a new model is added, it MUST appear in exactly one
12
+ * provider group below. A model missing from here will:
13
+ * - Never be a routing target from `findCheapestRoute` / `preflightRoute`
14
+ * - Still appear in `preflight().options` (which is cross-provider analysis)
15
+ * That mismatch is by design — see preflight.ts semantics.
16
+ */
17
+ export const PROVIDER_MODELS = {
18
+ Anthropic: ['claude-opus', 'claude-opus-4.7', 'claude-sonnet', 'claude-haiku'],
19
+ OpenAI: ['gpt-5.4', 'gpt-5.4-mini', 'gpt-5.4-nano'],
20
+ xAI: ['grok-4.20', 'grok-4-1-fast'],
21
+ Google: ['gemini-3.1-pro', 'gemini-2.5-flash'],
22
+ };
23
+ /**
24
+ * Identify a model's provider from its canonical key.
25
+ *
26
+ * TEST-NOTE: This function MUST return a non-null provider for every model
27
+ * present in `MODELS` (from models.ts). If `MODELS` adds a model without
28
+ * adding it to `PROVIDER_MODELS`, this returns null and routing is disabled
29
+ * for that model. Silent skip.
30
+ */
31
+ export function providerOf(model) {
32
+ for (const [provider, models] of Object.entries(PROVIDER_MODELS)) {
33
+ if (models.includes(model))
34
+ return provider;
35
+ }
36
+ return null;
37
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slash-tokens",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
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",