slash-tokens 1.3.0 → 1.4.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.
package/README.md CHANGED
@@ -17,10 +17,15 @@ npm install slash-tokens
17
17
  ```
18
18
 
19
19
  ```js
20
- import { preflight } from 'slash-tokens'
20
+ import { preflight, preflightRoute } from 'slash-tokens'
21
21
 
22
+ // Analysis — all cheaper alternatives across all providers
22
23
  const check = preflight(prompt, 'claude-opus-4.7')
23
24
  // tokens: 47,000 | cost: $0.71 | 11 cheaper options | save 99%
25
+
26
+ // Routing decision — matches Slash proxy behavior (same-provider only)
27
+ const route = preflightRoute(prompt, 'claude-opus-4.7')
28
+ // → { model: 'claude-haiku', cost: 0.14, salvaged: 0.57, ... } or null
24
29
  ```
25
30
 
26
31
  Or one line — every API call optimized pre-call:
@@ -49,4 +54,10 @@ Track savings across all your apps. Free key at [mcpaas.live/slash/setup](https:
49
54
 
50
55
  Full docs, examples, and model pricing at **[GitHub](https://github.com/Wolfe-Jam/slash-tokens)**
51
56
 
57
+ ## Brand
58
+
59
+ By using the SDK, you agree not to use the ⚡slash-tokens brand or colors for your app without written consent. Violators will get a takedown request issued immediately.
60
+
61
+ ## License
62
+
52
63
  [slashtokens.com](https://slashtokens.com) | MIT
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.0",
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",