@gabrielsmartin/orbit-sdk 0.2.3 → 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/index.js +159 -6
- package/package.json +20 -35
- package/{src/router.js → router.js} +66 -18
- package/signal.js +105 -0
- package/README.md +0 -202
- package/src/index.js +0 -122
- /package/{src/fingerprint.js → fingerprint.js} +0 -0
package/index.js
CHANGED
|
@@ -1,14 +1,167 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Intelligent AI model routing
|
|
2
|
+
* orbit-ai · v0.3.0
|
|
3
|
+
* Intelligent AI model routing with signal-aware priority bias.
|
|
4
|
+
* Drop in. Save 85%.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
+
* https://orbitai.gtll.app
|
|
6
7
|
* github.com/gtllco/orbit
|
|
8
|
+
* npm: @gabrielsmartin/orbit-sdk
|
|
9
|
+
*
|
|
10
|
+
* 777 · 555 · 333
|
|
7
11
|
*/
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
import { fingerprint } from './fingerprint.js';
|
|
14
|
+
import { route, calculateSavings, MODEL_MATRIX } from './router.js';
|
|
15
|
+
import { applySignalBias, inferSignalFromEvent, formatSignalResponse, SIGNAL_DESCRIPTIONS } from './signal.js';
|
|
16
|
+
|
|
17
|
+
export { fingerprint, route, calculateSavings, MODEL_MATRIX };
|
|
18
|
+
export { applySignalBias, inferSignalFromEvent, formatSignalResponse, SIGNAL_DESCRIPTIONS };
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* OrbitClient — the main class
|
|
22
|
+
* Now with signal-aware routing (777 · 555 · 333)
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* import { OrbitClient } from '@gabrielsmartin/orbit-sdk'
|
|
26
|
+
* const orbit = new OrbitClient()
|
|
27
|
+
*
|
|
28
|
+
* // Without signal — standard 8-axis routing
|
|
29
|
+
* const result = orbit.route("summarize this contract")
|
|
30
|
+
*
|
|
31
|
+
* // With signal — priority-aware routing
|
|
32
|
+
* const result = orbit.route("write the Q1 investor memo", { signal: "777" })
|
|
33
|
+
* // → Claude Sonnet mandatory. This is final form.
|
|
34
|
+
*
|
|
35
|
+
* const result = orbit.route("what's a business model nobody's tried?", { signal: "555" })
|
|
36
|
+
* // → Grok or Claude Sonnet. Destabilize the expected.
|
|
37
|
+
*
|
|
38
|
+
* const result = orbit.route("is this email spam?", { signal: "333" })
|
|
39
|
+
* // → Gemini Flash. Strip cost. Foundation doesn't need premium.
|
|
40
|
+
*/
|
|
41
|
+
export class OrbitClient {
|
|
42
|
+
constructor(config = {}) {
|
|
43
|
+
this.config = {
|
|
44
|
+
cost_tolerance: config.cost_tolerance || 'medium', // 'low' | 'medium' | 'high'
|
|
45
|
+
blocked_models: config.blocked_models || [],
|
|
46
|
+
api_key: config.apiKey || config.api_key || null,
|
|
47
|
+
log: config.log !== false,
|
|
48
|
+
on_route: config.on_route || null,
|
|
49
|
+
// Provider API keys (optional — falls back to env vars)
|
|
50
|
+
anthropic_key: config.anthropic_key || null,
|
|
51
|
+
openai_key: config.openai_key || null,
|
|
52
|
+
google_key: config.google_key || null,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
this._stats = {
|
|
56
|
+
total_queries: 0,
|
|
57
|
+
total_savings: 0,
|
|
58
|
+
model_usage: {},
|
|
59
|
+
signal_usage: { '777': 0, '555': 0, '333': 0, none: 0 },
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Route a query to the optimal model.
|
|
65
|
+
* Signal codes bias routing before model selection.
|
|
66
|
+
*
|
|
67
|
+
* @param {string} text - The query text
|
|
68
|
+
* @param {Object} options - Override options for this query
|
|
69
|
+
* @param {string} [options.signal] - "777" | "555" | "333" | null
|
|
70
|
+
* @param {string} [options.cost_tolerance] - "low" | "medium" | "high"
|
|
71
|
+
* @param {number} [options.estimated_tokens] - Token estimate for cost calc
|
|
72
|
+
* @returns {Object} decision - { model, reason, rule, scores, savings, signal_applied, signal_reason, estimated_cost }
|
|
73
|
+
*/
|
|
74
|
+
route(text, options = {}) {
|
|
75
|
+
// 1. Fingerprint
|
|
76
|
+
const rawScores = fingerprint(text);
|
|
77
|
+
|
|
78
|
+
// 2. Apply cost_tolerance override
|
|
79
|
+
if (options.cost_tolerance) {
|
|
80
|
+
rawScores.cost_tolerance = options.cost_tolerance === 'low' ? 2
|
|
81
|
+
: options.cost_tolerance === 'high' ? 9 : 5;
|
|
82
|
+
}
|
|
10
83
|
|
|
11
|
-
//
|
|
12
|
-
|
|
84
|
+
// 3. Apply signal bias (777 / 555 / 333)
|
|
85
|
+
const signal = options.signal || null;
|
|
86
|
+
const scores = applySignalBias(rawScores, signal);
|
|
87
|
+
|
|
88
|
+
// 4. Route
|
|
89
|
+
const config = { ...this.config, ...options };
|
|
90
|
+
const decision = route(scores, config);
|
|
91
|
+
|
|
92
|
+
// 5. Calculate savings and cost
|
|
93
|
+
const estimatedTokens = options.estimated_tokens || 500;
|
|
94
|
+
const savings = calculateSavings(decision.model, estimatedTokens);
|
|
95
|
+
const estimatedCost = `$${savings.actualCost.toFixed(5)}`;
|
|
96
|
+
|
|
97
|
+
// 6. Format signal metadata
|
|
98
|
+
const signalMeta = formatSignalResponse(scores, decision);
|
|
99
|
+
|
|
100
|
+
const result = {
|
|
101
|
+
model: decision.model,
|
|
102
|
+
reason: decision.reason,
|
|
103
|
+
rule: decision.rule,
|
|
104
|
+
scores: rawScores, // return original scores, not biased
|
|
105
|
+
signal_applied: signalMeta.signal_applied,
|
|
106
|
+
signal_reason: signalMeta.signal_reason || null,
|
|
107
|
+
savings,
|
|
108
|
+
estimated_cost: estimatedCost,
|
|
109
|
+
timestamp: new Date().toISOString(),
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Update stats
|
|
113
|
+
this._stats.total_queries++;
|
|
114
|
+
this._stats.total_savings += savings.savings;
|
|
115
|
+
const modelName = decision.model.name;
|
|
116
|
+
this._stats.model_usage[modelName] = (this._stats.model_usage[modelName] || 0) + 1;
|
|
117
|
+
this._stats.signal_usage[signal || 'none']++;
|
|
118
|
+
|
|
119
|
+
// Log routing decision
|
|
120
|
+
if (this.config.log) {
|
|
121
|
+
const signalTag = signal ? ` [signal:${signal}]` : '';
|
|
122
|
+
console.log(`[ORBIT]${signalTag} → ${decision.model.name} | ${decision.rule} | ${estimatedCost} (saved ${savings.reductionPct}%)`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (this.config.on_route) this.config.on_route(result);
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get cumulative stats for this session — including per-signal breakdown
|
|
131
|
+
*/
|
|
132
|
+
stats() {
|
|
133
|
+
return {
|
|
134
|
+
...this._stats,
|
|
135
|
+
total_savings_formatted: `$${this._stats.total_savings.toFixed(4)}`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Fingerprint a query without routing
|
|
141
|
+
*/
|
|
142
|
+
fingerprint(text) {
|
|
143
|
+
return fingerprint(text);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Apply signal bias to an existing fingerprint
|
|
148
|
+
* Useful for building custom routing logic on top of ORBIT
|
|
149
|
+
*/
|
|
150
|
+
applySignal(fingerprint, signal_code) {
|
|
151
|
+
return applySignalBias(fingerprint, signal_code);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Infer signal from a neural hub event priority
|
|
156
|
+
* coral1 events tagged 777/555/333 auto-translate to signal codes
|
|
157
|
+
*/
|
|
158
|
+
signalFromEvent(eventPriority) {
|
|
159
|
+
return inferSignalFromEvent(eventPriority);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Default singleton client
|
|
165
|
+
*/
|
|
13
166
|
const orbit = new OrbitClient();
|
|
14
167
|
export default orbit;
|
package/package.json
CHANGED
|
@@ -1,49 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gabrielsmartin/orbit-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Intelligent AI model routing
|
|
5
|
-
"
|
|
6
|
-
"
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "Intelligent AI model routing with signal-aware priority bias. 777·555·333.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./index.js",
|
|
7
|
+
"module": "./index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./index.js",
|
|
11
|
+
"default": "./index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
7
14
|
"files": [
|
|
8
|
-
"
|
|
9
|
-
"index.d.ts"
|
|
10
|
-
"src/",
|
|
11
|
-
"README.md"
|
|
15
|
+
"*.js",
|
|
16
|
+
"index.d.ts"
|
|
12
17
|
],
|
|
13
|
-
"scripts": {
|
|
14
|
-
"test": "node test.js"
|
|
15
|
-
},
|
|
16
18
|
"keywords": [
|
|
17
19
|
"ai",
|
|
18
|
-
"llm",
|
|
19
20
|
"routing",
|
|
20
|
-
"
|
|
21
|
-
"anthropic",
|
|
22
|
-
"gemini",
|
|
21
|
+
"llm",
|
|
23
22
|
"orbit",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
23
|
+
"model-selection",
|
|
24
|
+
"anthropic",
|
|
25
|
+
"openai",
|
|
26
|
+
"gemini"
|
|
26
27
|
],
|
|
27
|
-
"author": "Gabriel Martin
|
|
28
|
+
"author": "Gabriel Martin",
|
|
28
29
|
"license": "MIT",
|
|
29
30
|
"repository": {
|
|
30
31
|
"type": "git",
|
|
31
|
-
"url": "https://github.com/gtllco/orbit"
|
|
32
|
-
},
|
|
33
|
-
"homepage": "https://orbit-sdk.base44.app",
|
|
34
|
-
"publishConfig": {
|
|
35
|
-
"registry": "https://registry.npmjs.org",
|
|
36
|
-
"access": "public"
|
|
37
|
-
},
|
|
38
|
-
"module": "index.js",
|
|
39
|
-
"type": "module",
|
|
40
|
-
"exports": {
|
|
41
|
-
".": {
|
|
42
|
-
"import": "./index.js",
|
|
43
|
-
"types": "./index.d.ts"
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
"engines": {
|
|
47
|
-
"node": ">=18.0.0"
|
|
32
|
+
"url": "https://github.com/gtllco/orbit.git"
|
|
48
33
|
}
|
|
49
34
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ORBIT · Selective Model Matching (SMM) Router
|
|
3
|
-
* Routes queries to optimal models based on 8-axis fingerprints
|
|
3
|
+
* Routes queries to optimal models based on 8-axis fingerprints + signal codes
|
|
4
4
|
*
|
|
5
5
|
* Proprietary routing logic — open SDK, closed engine weights
|
|
6
6
|
* 777 · 555 · 333
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
export const MODEL_MATRIX = {
|
|
10
10
|
claude_sonnet: {
|
|
11
|
-
id: 'claude-sonnet-4-
|
|
11
|
+
id: 'claude-sonnet-4-6',
|
|
12
12
|
name: 'Claude Sonnet',
|
|
13
13
|
provider: 'anthropic',
|
|
14
14
|
costPer1M: 15,
|
|
@@ -17,7 +17,7 @@ export const MODEL_MATRIX = {
|
|
|
17
17
|
tier: 'medium',
|
|
18
18
|
},
|
|
19
19
|
claude_haiku: {
|
|
20
|
-
id: 'claude-haiku-
|
|
20
|
+
id: 'claude-haiku-4-5',
|
|
21
21
|
name: 'Claude Haiku',
|
|
22
22
|
provider: 'anthropic',
|
|
23
23
|
costPer1M: 1,
|
|
@@ -64,34 +64,82 @@ export const MODEL_MATRIX = {
|
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
* Core SMM routing logic
|
|
67
|
+
* Core SMM routing logic — Signal-aware
|
|
68
68
|
* Returns the selected model + reasoning
|
|
69
69
|
*
|
|
70
|
-
* @param {Object} scores - 8-axis fingerprint scores
|
|
70
|
+
* @param {Object} scores - 8-axis fingerprint scores (post-signal-bias)
|
|
71
71
|
* @param {Object} config - User config (cost_tolerance override, blocked_models, etc.)
|
|
72
72
|
* @returns {Object} { model, reason, fallback }
|
|
73
73
|
*/
|
|
74
74
|
export function route(scores, config = {}) {
|
|
75
75
|
const {
|
|
76
76
|
complexity, creativity, speed, emotional_weight,
|
|
77
|
-
recency, context_load, domain, cost_tolerance
|
|
77
|
+
recency, context_load, domain, cost_tolerance,
|
|
78
|
+
signal_code, variation_mode
|
|
78
79
|
} = scores;
|
|
79
80
|
|
|
80
81
|
const blocked = config.blocked_models || [];
|
|
81
|
-
const preferLow =
|
|
82
|
-
const preferHigh =
|
|
82
|
+
const preferLow = cost_tolerance <= 3;
|
|
83
|
+
const preferHigh = cost_tolerance >= 8;
|
|
83
84
|
|
|
84
|
-
//
|
|
85
|
+
// ── SIGNAL OVERRIDES (applied before all other rules) ──────────────────────
|
|
86
|
+
|
|
87
|
+
// 777 — Completion Bias: cost_tolerance and complexity already raised by applySignalBias.
|
|
88
|
+
// But explicitly block sub-tier models when signal=777.
|
|
89
|
+
if (signal_code === '777') {
|
|
90
|
+
// Minimum floor: Claude Haiku. Prefer Sonnet if complexity >= 5.
|
|
91
|
+
if (complexity >= 5 && !blocked.includes('claude_sonnet')) {
|
|
92
|
+
return {
|
|
93
|
+
model: MODEL_MATRIX.claude_sonnet,
|
|
94
|
+
reason: `Completion bias (777) — complexity ${complexity}/10 meets threshold. Claude Sonnet mandatory. This output is final form.`,
|
|
95
|
+
rule: 'signal_777_sonnet',
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
// complexity < 5 but still 777: Claude Haiku minimum, no Gemini Flash/GPT-4o Mini
|
|
99
|
+
if (!blocked.includes('claude_haiku')) {
|
|
100
|
+
return {
|
|
101
|
+
model: MODEL_MATRIX.claude_haiku,
|
|
102
|
+
reason: `Completion bias (777) — complexity ${complexity}/10 below Sonnet threshold but 777 enforces Claude Haiku minimum. No sub-tier models on completion events.`,
|
|
103
|
+
rule: 'signal_777_haiku',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 555 — Variation Bias: variation_mode=true, creativity and recency already boosted.
|
|
109
|
+
// Prefer Grok when recency is elevated. Otherwise prefer creative non-default models.
|
|
110
|
+
if (signal_code === '555') {
|
|
111
|
+
if (recency >= 5 && !blocked.includes('grok')) {
|
|
112
|
+
return {
|
|
113
|
+
model: MODEL_MATRIX.grok,
|
|
114
|
+
reason: `Variation bias (555) — recency boosted to ${recency}/10. Grok for live web intelligence and unexpected angles. Destabilize the expected.`,
|
|
115
|
+
rule: 'signal_555_grok',
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (creativity >= 6 && !blocked.includes('claude_sonnet')) {
|
|
119
|
+
return {
|
|
120
|
+
model: MODEL_MATRIX.claude_sonnet,
|
|
121
|
+
reason: `Variation bias (555) — creativity at ${creativity}/10. Claude Sonnet for nuanced, surprising creative output.`,
|
|
122
|
+
rule: 'signal_555_claude',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 333 — Foundation Bias: cost_tolerance dropped to 1 by applySignalBias (unless emotional override).
|
|
128
|
+
// Emotional safety net is handled by ethics rule below — it fires first.
|
|
129
|
+
|
|
130
|
+
// ── CORE ROUTING RULES ─────────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
// Rule 1: ETHICS FIRST — emotional/crisis queries always go to Claude (even on 333)
|
|
85
133
|
if (emotional_weight >= 6) {
|
|
86
134
|
return {
|
|
87
135
|
model: MODEL_MATRIX.claude_sonnet,
|
|
88
|
-
reason:
|
|
136
|
+
reason: `Emotional weight ${emotional_weight}/10 — routing to Claude for ethics-first handling. Never use a cheap model for sensitive content.${signal_code === '333' ? ' (333 foundation bias overridden by emotional safety rule)' : ''}`,
|
|
89
137
|
rule: 'ethics_first',
|
|
90
138
|
};
|
|
91
139
|
}
|
|
92
140
|
|
|
93
141
|
// Rule 2: Realtime / current events → Grok
|
|
94
|
-
if (recency >= 7 && !blocked.includes('grok')) {
|
|
142
|
+
if (recency >= 7 && !blocked.includes('grok') && signal_code !== '777') {
|
|
95
143
|
return {
|
|
96
144
|
model: MODEL_MATRIX.grok,
|
|
97
145
|
reason: `High recency score (${recency}/10) — Grok has live web access for current events and trending topics.`,
|
|
@@ -100,7 +148,7 @@ export function route(scores, config = {}) {
|
|
|
100
148
|
}
|
|
101
149
|
|
|
102
150
|
// Rule 3: Long context load → Claude Sonnet (200k window)
|
|
103
|
-
if (context_load >= 8 && !blocked.includes('claude_sonnet')) {
|
|
151
|
+
if (context_load >= 8 && !blocked.includes('claude_sonnet') && signal_code !== '333') {
|
|
104
152
|
return {
|
|
105
153
|
model: MODEL_MATRIX.claude_sonnet,
|
|
106
154
|
reason: `High context load (${context_load}/10) — Claude's 200k window is the only safe choice.`,
|
|
@@ -117,8 +165,8 @@ export function route(scores, config = {}) {
|
|
|
117
165
|
};
|
|
118
166
|
}
|
|
119
167
|
|
|
120
|
-
// Rule 5: High complexity general → GPT-4o (if cost tolerance allows)
|
|
121
|
-
if (complexity >= 7 && !preferLow && !blocked.includes('gpt4o')) {
|
|
168
|
+
// Rule 5: High complexity general → GPT-4o (if cost tolerance allows and not 777/333)
|
|
169
|
+
if (complexity >= 7 && !preferLow && !blocked.includes('gpt4o') && signal_code !== '777' && signal_code !== '333') {
|
|
122
170
|
return {
|
|
123
171
|
model: MODEL_MATRIX.gpt4o,
|
|
124
172
|
reason: `High complexity (${complexity}/10) — GPT-4o for broad knowledge and structured output.`,
|
|
@@ -126,8 +174,8 @@ export function route(scores, config = {}) {
|
|
|
126
174
|
};
|
|
127
175
|
}
|
|
128
176
|
|
|
129
|
-
// Rule 6: Creative writing → Claude Sonnet
|
|
130
|
-
if (creativity >= 5 && !blocked.includes('claude_sonnet')) {
|
|
177
|
+
// Rule 6: Creative writing → Claude Sonnet (unless 333 forcing minimum)
|
|
178
|
+
if (creativity >= 5 && !blocked.includes('claude_sonnet') && !preferLow) {
|
|
131
179
|
return {
|
|
132
180
|
model: MODEL_MATRIX.claude_sonnet,
|
|
133
181
|
reason: `High creativity score (${creativity}/10) — Claude Sonnet for nuanced creative writing.`,
|
|
@@ -135,11 +183,11 @@ export function route(scores, config = {}) {
|
|
|
135
183
|
};
|
|
136
184
|
}
|
|
137
185
|
|
|
138
|
-
// Rule 7: Cost sensitive OR simple queries → Gemini Flash
|
|
186
|
+
// Rule 7: Cost sensitive OR simple queries OR 333 foundation → Gemini Flash
|
|
139
187
|
if ((preferLow || complexity <= 3) && !blocked.includes('gemini_flash')) {
|
|
140
188
|
return {
|
|
141
189
|
model: MODEL_MATRIX.gemini_flash,
|
|
142
|
-
reason:
|
|
190
|
+
reason: `${signal_code === '333' ? 'Foundation bias (333) — ' : ''}Low complexity (${complexity}/10) — Gemini 2.5 Flash delivers 95% quality at 2% of GPT-4o cost.`,
|
|
143
191
|
rule: 'cost_gemini',
|
|
144
192
|
};
|
|
145
193
|
}
|
package/signal.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ORBIT · Signal Layer — Priority-Aware Routing Bias
|
|
3
|
+
*
|
|
4
|
+
* Signal codes connect the routing layer to the agent network.
|
|
5
|
+
* A 777 event means something is landing — never cut corners.
|
|
6
|
+
* A 555 event means something is shifting — route to variation.
|
|
7
|
+
* A 333 event means ambient/background — route to minimum cost.
|
|
8
|
+
*
|
|
9
|
+
* interval(n) = base / 2^n — Recursive Beat Engine
|
|
10
|
+
* 777 · 555 · 333
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Apply signal bias to a fingerprint before routing.
|
|
15
|
+
* Mutates a COPY of the fingerprint — never the original.
|
|
16
|
+
*
|
|
17
|
+
* @param {Object} fingerprint - 8-axis fingerprint from fingerprint.js
|
|
18
|
+
* @param {string|null} signal_code - "777" | "555" | "333" | null
|
|
19
|
+
* @returns {Object} biased fingerprint + signal metadata
|
|
20
|
+
*/
|
|
21
|
+
export function applySignalBias(fingerprint, signal_code) {
|
|
22
|
+
// No signal = no change
|
|
23
|
+
if (!signal_code || !['777', '555', '333'].includes(signal_code)) {
|
|
24
|
+
return { ...fingerprint, signal_code: null, signal_applied: false };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const f = { ...fingerprint };
|
|
28
|
+
|
|
29
|
+
if (signal_code === '777') {
|
|
30
|
+
// Completion Bias — this output is final form. Never cut corners.
|
|
31
|
+
// Force quality floor: raise cost_tolerance and complexity minimums.
|
|
32
|
+
f.cost_tolerance = Math.max(f.cost_tolerance, 7);
|
|
33
|
+
f.complexity = Math.max(f.complexity, 6);
|
|
34
|
+
// Note: emotional_weight guard is handled in router — Claude always if emotional_weight >= 6 anyway
|
|
35
|
+
f.signal_code = '777';
|
|
36
|
+
f.signal_applied = true;
|
|
37
|
+
f.signal_reason = 'Completion bias — cost floor raised, complexity floor raised. Quality is non-negotiable on 777 events.';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (signal_code === '555') {
|
|
41
|
+
// Variation Bias — something is shifting. Route to surprise.
|
|
42
|
+
// Boost creativity and recency to prefer Grok/Perplexity and non-default models.
|
|
43
|
+
f.creativity = Math.max(f.creativity, 6);
|
|
44
|
+
f.recency = Math.max(f.recency, 5);
|
|
45
|
+
f.variation_mode = true; // router reads this to prefer non-default choices
|
|
46
|
+
f.signal_code = '555';
|
|
47
|
+
f.signal_applied = true;
|
|
48
|
+
f.signal_reason = 'Variation bias — creativity and recency boosted. Routing to destabilize the expected.';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (signal_code === '333') {
|
|
52
|
+
// Foundation Bias — ambient/background. Strip cost aggressively.
|
|
53
|
+
// Exception: emotional_weight >= 7 always upgrades (crisis never gets a cheap model).
|
|
54
|
+
if (f.emotional_weight < 7) {
|
|
55
|
+
f.cost_tolerance = 1; // force minimum cost
|
|
56
|
+
f.complexity = Math.min(f.complexity, 4); // cap complexity perception
|
|
57
|
+
f.signal_code = '333';
|
|
58
|
+
f.signal_applied = true;
|
|
59
|
+
f.signal_reason = 'Foundation bias — cost floor dropped to minimum. Routing to cheapest capable model.';
|
|
60
|
+
} else {
|
|
61
|
+
// Emotional override — even on 333, safety first
|
|
62
|
+
f.signal_code = '333';
|
|
63
|
+
f.signal_applied = true;
|
|
64
|
+
f.signal_reason = 'Foundation bias requested, but emotional_weight >= 7 — safety override active. Routing to Claude.';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return f;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Infer signal code from neural hub event priority.
|
|
73
|
+
* When coral1 fires an AgentEvent, the priority field maps directly to signal codes.
|
|
74
|
+
* This is how the neural hub auto-injects signal into ORBIT routing.
|
|
75
|
+
*
|
|
76
|
+
* @param {string} eventPriority - "777" | "555" | "333" | "444"
|
|
77
|
+
* @returns {string|null} signal_code
|
|
78
|
+
*/
|
|
79
|
+
export function inferSignalFromEvent(eventPriority) {
|
|
80
|
+
const map = { '777': '777', '555': '555', '333': '333' };
|
|
81
|
+
return map[eventPriority] || null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Format signal metadata for API responses.
|
|
86
|
+
*
|
|
87
|
+
* @param {Object} biasedFingerprint - fingerprint after applySignalBias
|
|
88
|
+
* @param {Object} routingDecision - result from route()
|
|
89
|
+
* @returns {Object} signal metadata for API response
|
|
90
|
+
*/
|
|
91
|
+
export function formatSignalResponse(biasedFingerprint, routingDecision) {
|
|
92
|
+
if (!biasedFingerprint.signal_applied) {
|
|
93
|
+
return { signal_applied: null };
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
signal_applied: biasedFingerprint.signal_code,
|
|
97
|
+
signal_reason: biasedFingerprint.signal_reason,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export const SIGNAL_DESCRIPTIONS = {
|
|
102
|
+
'777': 'Completion · Return · Alignment — This output is final form. Quality is mandatory.',
|
|
103
|
+
'555': 'Transformation · Breakthrough — This query is exploratory. Route to variation and surprise.',
|
|
104
|
+
'333': 'Foundation · Breath · Ground — This is ambient. Route to minimum cost. Strip everything.',
|
|
105
|
+
};
|
package/README.md
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
# orbit-ai
|
|
2
|
-
|
|
3
|
-
> Stop blasting every query at GPT-4o. Route intelligently. Save 85%.
|
|
4
|
-
|
|
5
|
-
`orbit-ai` is a drop-in routing layer that reads the fingerprint of every AI query and sends it to the optimal model — automatically, in under 1ms.
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install orbit-ai
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## The problem
|
|
14
|
-
|
|
15
|
-
You're probably doing this:
|
|
16
|
-
|
|
17
|
-
```javascript
|
|
18
|
-
const res = await openai.chat.completions.create({
|
|
19
|
-
model: "gpt-4o", // $30/1M tokens — every single query
|
|
20
|
-
messages
|
|
21
|
-
})
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
GPT-4o costs **30x more per token** than Gemini Flash. For "what's 2+2?" — you're paying Ferrari prices to drive to the mailbox.
|
|
25
|
-
|
|
26
|
-
ORBIT fixes this. One line.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## How it works
|
|
31
|
-
|
|
32
|
-
Every query gets fingerprinted across **8 axes** in under 1ms:
|
|
33
|
-
|
|
34
|
-
| Axis | What it measures |
|
|
35
|
-
|---|---|
|
|
36
|
-
| **Complexity** | Depth of reasoning required |
|
|
37
|
-
| **Creativity** | Open-ended vs deterministic |
|
|
38
|
-
| **Emotional Weight** | Sensitivity — crisis queries always go to Claude |
|
|
39
|
-
| **Recency** | Need for live/current data → Grok |
|
|
40
|
-
| **Context Load** | Window size needed → Claude 200k |
|
|
41
|
-
| **Speed** | Latency sensitivity |
|
|
42
|
-
| **Domain** | Code · Creative · Medical · Legal · General |
|
|
43
|
-
| **Cost Tolerance** | Budget tier (overridable) |
|
|
44
|
-
|
|
45
|
-
Then it routes to the right model. Invisibly.
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## Usage
|
|
50
|
-
|
|
51
|
-
### Zero-config routing decision
|
|
52
|
-
|
|
53
|
-
```javascript
|
|
54
|
-
import orbit from 'orbit-ai'
|
|
55
|
-
|
|
56
|
-
// Get the routing decision
|
|
57
|
-
const decision = orbit.route("write a haiku about recursion")
|
|
58
|
-
|
|
59
|
-
console.log(decision.model.name) // "Claude Sonnet"
|
|
60
|
-
console.log(decision.reason) // "High creativity score (8/10)..."
|
|
61
|
-
console.log(decision.savings) // { savings: 0.007245, reductionPct: 97 }
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### With your own API keys
|
|
65
|
-
|
|
66
|
-
```javascript
|
|
67
|
-
import { OrbitClient } from 'orbit-ai'
|
|
68
|
-
|
|
69
|
-
const orbit = new OrbitClient({
|
|
70
|
-
cost_tolerance: 'low', // 'low' | 'medium' | 'high'
|
|
71
|
-
log: true, // logs routing decisions to console
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
// Route the query
|
|
75
|
-
const { model, reason, savings } = orbit.route("explain blockchain simply")
|
|
76
|
-
// [ORBIT] → Gemini 2.5 Flash | cost_gemini | saved $0.01455 (97% reduction)
|
|
77
|
-
|
|
78
|
-
// Now call the model yourself with your keys
|
|
79
|
-
// model.id = 'gemini-2.5-flash', model.provider = 'google'
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Full pipeline example (with Anthropic SDK)
|
|
83
|
-
|
|
84
|
-
```javascript
|
|
85
|
-
import { OrbitClient } from 'orbit-ai'
|
|
86
|
-
import Anthropic from '@anthropic-ai/sdk'
|
|
87
|
-
import OpenAI from 'openai'
|
|
88
|
-
import { GoogleGenerativeAI } from '@google/generative-ai'
|
|
89
|
-
|
|
90
|
-
const orbit = new OrbitClient({ log: true })
|
|
91
|
-
|
|
92
|
-
async function smartQuery(text) {
|
|
93
|
-
const { model, reason } = orbit.route(text)
|
|
94
|
-
|
|
95
|
-
if (model.provider === 'anthropic') {
|
|
96
|
-
const client = new Anthropic()
|
|
97
|
-
return client.messages.create({
|
|
98
|
-
model: model.id,
|
|
99
|
-
max_tokens: 1024,
|
|
100
|
-
messages: [{ role: 'user', content: text }]
|
|
101
|
-
})
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (model.provider === 'openai') {
|
|
105
|
-
const client = new OpenAI()
|
|
106
|
-
return client.chat.completions.create({
|
|
107
|
-
model: model.id,
|
|
108
|
-
messages: [{ role: 'user', content: text }]
|
|
109
|
-
})
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (model.provider === 'google') {
|
|
113
|
-
const client = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY)
|
|
114
|
-
const genModel = client.getGenerativeModel({ model: model.id })
|
|
115
|
-
return genModel.generateContent(text)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Routes each query to the optimal model
|
|
120
|
-
await smartQuery("write a poem about the ocean") // → Claude Sonnet
|
|
121
|
-
await smartQuery("what's the latest news on AI funding?") // → Grok
|
|
122
|
-
await smartQuery("what is 2+2") // → Gemini Flash
|
|
123
|
-
await smartQuery("I've been feeling really overwhelmed") // → Claude Sonnet (ethics-first)
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### Session stats
|
|
127
|
-
|
|
128
|
-
```javascript
|
|
129
|
-
const stats = orbit.stats()
|
|
130
|
-
console.log(stats.total_savings_formatted) // "$0.2341"
|
|
131
|
-
console.log(stats.model_usage) // { "Claude Sonnet": 4, "Gemini 2.5 Flash": 12, ... }
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Fingerprint only (no routing)
|
|
135
|
-
|
|
136
|
-
```javascript
|
|
137
|
-
import { fingerprint } from 'orbit-ai'
|
|
138
|
-
|
|
139
|
-
const scores = fingerprint("architect a distributed caching system for 10M users")
|
|
140
|
-
// {
|
|
141
|
-
// complexity: 9,
|
|
142
|
-
// creativity: 0,
|
|
143
|
-
// domain: 'code',
|
|
144
|
-
// emotional_weight: 0,
|
|
145
|
-
// recency: 0,
|
|
146
|
-
// context_load: 3,
|
|
147
|
-
// ...
|
|
148
|
-
// }
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
## Model matrix
|
|
154
|
-
|
|
155
|
-
| Model | Provider | Cost/1M | Best for |
|
|
156
|
-
|---|---|---|---|
|
|
157
|
-
| Claude Sonnet | Anthropic | $15 | Complex reasoning · Ethics · Long context |
|
|
158
|
-
| Claude Haiku | Anthropic | $1 | Speed · Summaries · Medium tasks |
|
|
159
|
-
| Gemini 2.5 Flash | Google | $0.50 | High volume · Simple queries · Cost |
|
|
160
|
-
| GPT-4o | OpenAI | $30 | Structured output · Broad knowledge |
|
|
161
|
-
| GPT-4o Mini | OpenAI | $0.30 | Classification · Filler tasks |
|
|
162
|
-
| Grok | xAI | $10 | Trending · Real-time web |
|
|
163
|
-
|
|
164
|
-
---
|
|
165
|
-
|
|
166
|
-
## The math
|
|
167
|
-
|
|
168
|
-
Validated by [RouteLLM (UC Berkeley · ICLR 2025)](https://arxiv.org/abs/2406.18665): intelligent routing achieves **85% cost reduction** while maintaining 95% of quality.
|
|
169
|
-
|
|
170
|
-
For a team running 100k queries/month at GPT-4o:
|
|
171
|
-
- Without ORBIT: **$1,500/month**
|
|
172
|
-
- With ORBIT: **~$225/month**
|
|
173
|
-
- Savings: **$1,275/month · $15,300/year**
|
|
174
|
-
|
|
175
|
-
---
|
|
176
|
-
|
|
177
|
-
## Live demo
|
|
178
|
-
|
|
179
|
-
[orbit-model-flow.base44.app](https://orbit-model-flow.base44.app) — route a real query, see the fingerprint radar, watch the savings counter.
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
## Roadmap
|
|
184
|
-
|
|
185
|
-
- [x] 8-axis fingerprinting engine
|
|
186
|
-
- [x] 6-model routing matrix
|
|
187
|
-
- [x] TypeScript types
|
|
188
|
-
- [ ] Streaming support
|
|
189
|
-
- [ ] Custom model matrix (bring your own models)
|
|
190
|
-
- [ ] Automatic provider failover
|
|
191
|
-
- [ ] Usage analytics dashboard integration
|
|
192
|
-
- [ ] Browser extension
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
|
-
## License
|
|
197
|
-
|
|
198
|
-
MIT · Built by [Gabriel Martin](https://github.com/gabrielsmartin)
|
|
199
|
-
|
|
200
|
-
*"Every model has a gravitational pull. ORBIT decides which one you need."*
|
|
201
|
-
|
|
202
|
-
777 · 555 · 333
|
package/src/index.js
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* orbit-ai · v0.1.0
|
|
3
|
-
* Intelligent AI model routing. Drop in. Save 85%.
|
|
4
|
-
*
|
|
5
|
-
* https://orbit-model-flow.base44.app
|
|
6
|
-
* github.com/gabrielsmartin/orbit
|
|
7
|
-
*
|
|
8
|
-
* 777 · 555 · 333
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { fingerprint } from './fingerprint.js';
|
|
12
|
-
import { route, calculateSavings, MODEL_MATRIX } from './router.js';
|
|
13
|
-
|
|
14
|
-
export { fingerprint, route, calculateSavings, MODEL_MATRIX };
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* OrbitClient — the main class
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* import { OrbitClient } from 'orbit-ai'
|
|
21
|
-
* const orbit = new OrbitClient({ apiKey: 'your-orbit-key' })
|
|
22
|
-
* const result = await orbit.query("explain quantum entanglement simply")
|
|
23
|
-
*/
|
|
24
|
-
export class OrbitClient {
|
|
25
|
-
constructor(config = {}) {
|
|
26
|
-
this.config = {
|
|
27
|
-
cost_tolerance: config.cost_tolerance || 'medium', // 'low' | 'medium' | 'high'
|
|
28
|
-
blocked_models: config.blocked_models || [],
|
|
29
|
-
api_key: config.apiKey || config.api_key || null,
|
|
30
|
-
log: config.log !== false, // log routing decisions by default
|
|
31
|
-
on_route: config.on_route || null, // callback: (decision) => void
|
|
32
|
-
// Provider API keys (optional — falls back to env vars)
|
|
33
|
-
anthropic_key: config.anthropic_key || null,
|
|
34
|
-
openai_key: config.openai_key || null,
|
|
35
|
-
google_key: config.google_key || null,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
this._stats = {
|
|
39
|
-
total_queries: 0,
|
|
40
|
-
total_savings: 0,
|
|
41
|
-
model_usage: {},
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Route a query to the optimal model
|
|
47
|
-
* Returns the routing decision — you call the model yourself with your keys
|
|
48
|
-
*
|
|
49
|
-
* @param {string} text - The query text
|
|
50
|
-
* @param {Object} options - Override options for this query
|
|
51
|
-
* @returns {Object} decision - { model, reason, rule, scores, savings }
|
|
52
|
-
*/
|
|
53
|
-
route(text, options = {}) {
|
|
54
|
-
const scores = fingerprint(text);
|
|
55
|
-
|
|
56
|
-
// Allow per-query cost_tolerance override
|
|
57
|
-
if (options.cost_tolerance) {
|
|
58
|
-
scores.cost_tolerance = options.cost_tolerance === 'low' ? 2
|
|
59
|
-
: options.cost_tolerance === 'high' ? 9 : 5;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const config = { ...this.config, ...options };
|
|
63
|
-
const decision = route(scores, config);
|
|
64
|
-
const savings = calculateSavings(decision.model, options.estimated_tokens || 500);
|
|
65
|
-
|
|
66
|
-
const result = {
|
|
67
|
-
model: decision.model,
|
|
68
|
-
reason: decision.reason,
|
|
69
|
-
rule: decision.rule,
|
|
70
|
-
scores,
|
|
71
|
-
savings,
|
|
72
|
-
timestamp: new Date().toISOString(),
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
// Update stats
|
|
76
|
-
this._stats.total_queries++;
|
|
77
|
-
this._stats.total_savings += savings.savings;
|
|
78
|
-
const modelName = decision.model.name;
|
|
79
|
-
this._stats.model_usage[modelName] = (this._stats.model_usage[modelName] || 0) + 1;
|
|
80
|
-
|
|
81
|
-
// Log routing decision
|
|
82
|
-
if (this.config.log) {
|
|
83
|
-
console.log(`[ORBIT] → ${decision.model.name} | ${decision.rule} | saved $${savings.savings.toFixed(5)} (${savings.reductionPct}% reduction)`);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Fire callback
|
|
87
|
-
if (this.config.on_route) {
|
|
88
|
-
this.config.on_route(result);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return result;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Get cumulative stats for this session
|
|
96
|
-
*/
|
|
97
|
-
stats() {
|
|
98
|
-
return {
|
|
99
|
-
...this._stats,
|
|
100
|
-
total_savings_formatted: `$${this._stats.total_savings.toFixed(4)}`,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Fingerprint a query without routing
|
|
106
|
-
* Useful for debugging or building custom routing logic on top
|
|
107
|
-
*/
|
|
108
|
-
fingerprint(text) {
|
|
109
|
-
return fingerprint(text);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Default singleton client — zero config, ready to use
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* import orbit from 'orbit-ai'
|
|
118
|
-
* const decision = orbit.route("write a haiku about recursion")
|
|
119
|
-
* // → { model: { name: 'Claude Sonnet', ... }, reason: '...', savings: { ... } }
|
|
120
|
-
*/
|
|
121
|
-
const orbit = new OrbitClient();
|
|
122
|
-
export default orbit;
|
|
File without changes
|