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 +12 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -1
- package/dist/intercept.js +1 -7
- package/dist/preflight.d.ts +39 -0
- package/dist/preflight.js +89 -11
- package/dist/providers.d.ts +26 -0
- package/dist/providers.js +37 -0
- package/package.json +1 -1
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
|
-
|
|
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 = {
|
package/dist/preflight.d.ts
CHANGED
|
@@ -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 =
|
|
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(([
|
|
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
|
+
}
|