@gabrielsmartin/orbit-sdk 0.2.2 → 0.3.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/index.js ADDED
@@ -0,0 +1,167 @@
1
+ /**
2
+ * orbit-ai · v0.3.0
3
+ * Intelligent AI model routing with signal-aware priority bias.
4
+ * Drop in. Save 85%.
5
+ *
6
+ * https://orbitai.gtll.app
7
+ * github.com/gtllco/orbit
8
+ * npm: @gabrielsmartin/orbit-sdk
9
+ *
10
+ * 777 · 555 · 333
11
+ */
12
+
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
+ }
83
+
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
+ */
166
+ const orbit = new OrbitClient();
167
+ export default orbit;
package/package.json CHANGED
@@ -1,53 +1,22 @@
1
1
  {
2
2
  "name": "@gabrielsmartin/orbit-sdk",
3
- "version": "0.2.2",
4
- "description": "Intelligent AI model routing. Drop-in replacement for OpenAI/Anthropic. Routes every query to the optimal model automatically.",
3
+ "version": "0.3.0",
4
+ "description": "Intelligent AI model routing with signal-aware priority bias. 777·555·333.",
5
5
  "type": "module",
6
- "main": "src/index.js",
7
- "types": "src/index.d.ts",
6
+ "main": "./index.js",
7
+ "module": "./index.js",
8
8
  "exports": {
9
9
  ".": {
10
- "import": "./src/index.js",
11
- "types": "./src/index.d.ts"
10
+ "import": "./index.js",
11
+ "default": "./index.js"
12
12
  }
13
13
  },
14
- "files": [
15
- "src",
16
- "README.md"
17
- ],
18
- "scripts": {
19
- "test": "node test.js"
20
- },
21
- "keywords": [
22
- "ai",
23
- "llm",
24
- "routing",
25
- "openai",
26
- "anthropic",
27
- "gemini",
28
- "orbit",
29
- "cost-optimization",
30
- "model-routing",
31
- "selective-model-matching",
32
- "gpt4",
33
- "claude",
34
- "gemini-flash",
35
- "grok",
36
- "ai-infrastructure",
37
- "byok",
38
- "enterprise-ai"
39
- ],
40
- "author": "Gabriel Martin <gabriel@gtll.app>",
14
+ "files": ["*.js", "index.d.ts"],
15
+ "keywords": ["ai", "routing", "llm", "orbit", "model-selection", "anthropic", "openai", "gemini"],
16
+ "author": "Gabriel Martin",
41
17
  "license": "MIT",
42
18
  "repository": {
43
19
  "type": "git",
44
- "url": "git+https://github.com/gtllco/orbit.git"
45
- },
46
- "homepage": "https://orbitai.gtll.app",
47
- "bugs": {
48
- "url": "https://github.com/gtllco/orbit/issues"
49
- },
50
- "engines": {
51
- "node": ">=16"
20
+ "url": "https://github.com/gtllco/orbit.git"
52
21
  }
53
22
  }
@@ -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
@@ -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 = config.cost_tolerance === 'low' || cost_tolerance <= 3;
82
- const preferHigh = config.cost_tolerance === 'high' || cost_tolerance >= 8;
82
+ const preferLow = cost_tolerance <= 3;
83
+ const preferHigh = cost_tolerance >= 8;
83
84
 
84
- // Rule 1: ETHICS FIRST emotional/crisis queries always go to Claude
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: 'Emotional weight detected — routing to Claude for ethics-first handling. Never use a cheap model for sensitive content.',
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: `Low complexity (${complexity}/10) — Gemini 2.5 Flash delivers 95% quality at 2% of GPT-4o cost.`,
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,182 +0,0 @@
1
- # @gabrielsmartin/orbit-sdk
2
-
3
- > Stop blasting every query at GPT-4o. Route intelligently. Save 85%.
4
-
5
- `@gabrielsmartin/orbit-sdk` 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 @gabrielsmartin/orbit-sdk
9
- ```
10
-
11
- **Built by [Gabriel Martin](https://www.linkedin.com/in/gabrielsmartin) · [orbitai.gtll.app](https://orbitai.gtll.app)**
12
-
13
- ---
14
-
15
- ## The problem
16
-
17
- You're probably doing this:
18
-
19
- ```javascript
20
- const res = await openai.chat.completions.create({
21
- model: "gpt-4o", // $30/1M tokens — every single query
22
- messages
23
- });
24
- ```
25
-
26
- You're overpaying by 85%. "Write a haiku" does not need GPT-4o. "What is 2+2?" does not need GPT-4o. Only ~15% of real queries actually require your most expensive model.
27
-
28
- ---
29
-
30
- ## The solution
31
-
32
- ```javascript
33
- import orbit from '@gabrielsmartin/orbit-sdk'
34
-
35
- const decision = orbit.route("write a haiku about recursion")
36
- // → { model: "Claude Sonnet", reason: "High creativity — Claude Sonnet for nuanced generation", savings: { reductionPct: 50 } }
37
-
38
- const decision2 = orbit.route("what is 2+2?")
39
- // → { model: "Gemini 2.5 Flash", reason: "Low complexity — Gemini Flash at $0.50/1M tokens", savings: { reductionPct: 98 } }
40
-
41
- const decision3 = orbit.route("I've been feeling really anxious")
42
- // → { model: "Claude Sonnet", reason: "Emotional weight detected — ethics-first routing. Never a cheap model." }
43
- ```
44
-
45
- ---
46
-
47
- ## How it works
48
-
49
- Every query is fingerprinted across **8 axes** in under 1ms:
50
-
51
- | Axis | What it detects |
52
- |------|----------------|
53
- | `complexity` | Depth of reasoning required |
54
- | `creativity` | Open-ended vs. factual generation |
55
- | `emotional_weight` | Sensitive or crisis content |
56
- | `recency` | Need for real-time / live web data |
57
- | `context_load` | Long-document or multi-turn depth |
58
- | `speed` | Latency sensitivity |
59
- | `domain` | Code, legal, medical, creative, general |
60
- | `cost_tolerance` | Budget flexibility signal |
61
-
62
- The SMM (Selective Model Matching) engine then routes:
63
-
64
- | Signal | → Model | Why |
65
- |--------|---------|-----|
66
- | Emotional weight > 6 | Claude Sonnet | Ethics-first. Always. |
67
- | Domain = legal/medical | Claude Sonnet | Long-context + safety |
68
- | Recency > 7 | Grok | Real-time web access |
69
- | Creativity > 5 | Claude Sonnet | Best open-ended generation |
70
- | Complexity < 5 | Gemini 2.5 Flash | 98% cheaper, 95% quality |
71
- | Trivial query | GPT-4o Mini | 99% cheaper than GPT-4o |
72
-
73
- ---
74
-
75
- ## API
76
-
77
- ```javascript
78
- import orbit, { OrbitClient, fingerprint } from '@gabrielsmartin/orbit-sdk'
79
-
80
- // Route a query — returns routing decision instantly (<1ms)
81
- const result = orbit.route(queryText)
82
- // Returns: { model, reason, savings: { reductionPct, estimatedCost, premiumCost } }
83
-
84
- // Get session stats
85
- const stats = orbit.stats()
86
- // Returns: { queries_routed, total_savings_formatted, breakdown }
87
-
88
- // Custom config
89
- const client = new OrbitClient({
90
- default_model: 'claude_sonnet',
91
- blocked_models: ['gpt4o'],
92
- })
93
-
94
- // Raw fingerprint only
95
- const fp = fingerprint("write a poem about loss")
96
- // Returns all 8 axes as numbers
97
- ```
98
-
99
- ---
100
-
101
- ## Results
102
-
103
- ```
104
- $ node test.js
105
-
106
- [ORBIT] → Claude Sonnet | creative_claude | saved $0.00750 (50% reduction)
107
- [ORBIT] → Gemini 2.5 Flash | cost_gemini | saved $0.01475 (98% reduction)
108
- [ORBIT] → Claude Sonnet | default | saved $0.00750 (50% reduction)
109
-
110
- Session stats: { queries_routed: 3, total_savings_formatted: '$0.0298' }
111
- ```
112
-
113
- Validated by **RouteLLM (UC Berkeley / ICLR 2025)**: intelligent routing achieves **85% cost reduction** while maintaining **95% of GPT-4o quality**.
114
-
115
- ---
116
-
117
- ## ⚡ Hosted API — Live
118
-
119
- The SDK routes decisions **client-side** — no API key, zero latency, works today.
120
-
121
- **Live REST API** — free tier, no auth required:
122
-
123
- ```bash
124
- curl -X POST https://orbit-sdk.base44.app/functions/orbitGateway \
125
- -H "Content-Type: application/json" \
126
- -d '{"query": "write a haiku about recursion"}'
127
- ```
128
-
129
- Response includes `log_id` — pass it back with `feedback: 1|-1|0` on your next call to help train smarter routing:
130
-
131
- ```bash
132
- curl -X POST https://orbit-sdk.base44.app/functions/orbitGateway \
133
- -H "Content-Type: application/json" \
134
- -d '{"query": "next query", "prev_log_id": "<log_id>", "feedback": 1}'
135
- ```
136
-
137
- ---
138
-
139
- ## Pricing
140
-
141
- | Tier | Price | Queries | Features |
142
- |------|-------|---------|----------|
143
- | **Free** | $0/mo | 100/day | SDK + hosted API, routing decisions, cost estimates |
144
- | **Pro** | $19/mo | Unlimited | Everything free + savings dashboard, feedback loop, priority routing |
145
- | **Team** | $99/mo | Unlimited · 5 seats | Everything Pro + team analytics, routing policy editor, audit logs |
146
- | **Enterprise** | Custom | Custom | Custom model matrix, private model support, SLA + **15% savings-share pricing** |
147
-
148
- > 🔒 **BYOK (Bring Your Own Keys)** — ORBIT is a pure routing layer. Your API keys go directly to model providers. We never proxy, store, or touch your data. Enterprise-ready by design.
149
-
150
- **[View pricing →](https://orbitai.gtll.app/pricing)**
151
- **[Join the waitlist →](https://orbitai.gtll.app/#waitlist)**
152
-
153
- Early access: Pro locked at **$9/mo** with access code **`777`**
154
-
155
- ---
156
-
157
- ## Research backing
158
-
159
- - **RouteLLM** — UC Berkeley / ICLR 2025: *"Routing between weak and strong LLMs reduces costs by 85% while maintaining 95% quality."*
160
- - **OpenRouter** ($500M+ valuation) proves the market. ORBIT adds the intelligence layer they're missing.
161
- - **Martian** (Accenture-backed) proves enterprises pay for routing. ORBIT is the frictionless version for everyone else.
162
-
163
- ---
164
-
165
- ## Roadmap
166
-
167
- - [x] v0.1.0 — 8-axis fingerprinting + 6-model routing matrix
168
- - [x] v0.1.1 — Hosted API architecture, waitlist, admin dashboard
169
- - [x] v0.2.0 — Live hosted API + rate limiting (100/day free, unlimited Pro) + OIDC CI/CD publishing
170
- - [x] v0.2.1 — Phase 2 telemetry: every route decision logged to OrbitRouteLog for ML training
171
- - [ ] v0.3.0 — Analytics dashboard + savings tracker
172
- - [ ] v0.4.0 — Feedback-trained routing model (supervised learning on real usage data)
173
- - [ ] v0.5.0 — Chrome extension
174
- - [ ] v1.0.0 — Enterprise API + savings-share pricing model
175
-
176
- ---
177
-
178
- ## License
179
-
180
- MIT © [Gabriel Martin](https://www.linkedin.com/in/gabrielsmartin)
181
-
182
- **[Live demo](https://orbitai.gtll.app) · [GitHub](https://github.com/gtllco/orbit) · [npm](https://www.npmjs.com/package/@gabrielsmartin/orbit-sdk) · [LinkedIn](https://www.linkedin.com/in/gabrielsmartin)**
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
File without changes