@gabrielsmartin/orbit-sdk 0.3.0 → 0.3.2
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 +193 -0
- package/index.js +6 -159
- package/package.json +39 -12
- package/src/index.js +167 -0
- package/{router.js → src/router.js} +2 -2
- package/src/signalBias.js +85 -0
- /package/{fingerprint.js → src/fingerprint.js} +0 -0
- /package/{signal.js → src/signal.js} +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
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
|
+
## 🚀 Pro is live
|
|
14
|
+
|
|
15
|
+
**[orbit.gtll.app](https://orbit.gtll.app)** — production routing API with managed keys, usage analytics, and team dashboards.
|
|
16
|
+
|
|
17
|
+
| Plan | Price | What's included |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| **Founding Pro** | $19/mo | API access · 500k routed queries/mo · savings dashboard |
|
|
20
|
+
| **Founding Team** | $99/mo | Unlimited queries · multi-seat · priority support |
|
|
21
|
+
|
|
22
|
+
[→ Get Founding Pro](https://buy.stripe.com/6oE5kF3Yz5Co06s9AB) · [→ Get Founding Team](https://buy.stripe.com/9AQ9AV5GH9SEdss6op)
|
|
23
|
+
|
|
24
|
+
*Founding pricing locks in forever — price goes up at 100 customers.*
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## How it works
|
|
29
|
+
|
|
30
|
+
Every query gets fingerprinted across **9 axes** in under 1ms:
|
|
31
|
+
|
|
32
|
+
| Axis | What it measures |
|
|
33
|
+
|---|---|
|
|
34
|
+
| **Complexity** | Depth of reasoning required |
|
|
35
|
+
| **Creativity** | Open-ended vs deterministic |
|
|
36
|
+
| **Emotional Weight** | Sensitivity — crisis queries always go to Claude |
|
|
37
|
+
| **Recency** | Need for live/current data → Grok |
|
|
38
|
+
| **Context Load** | Window size needed → Claude 200k |
|
|
39
|
+
| **Speed** | Latency sensitivity |
|
|
40
|
+
| **Domain** | Code · Creative · Medical · Legal · General |
|
|
41
|
+
| **Cost Tolerance** | Budget tier (overridable) |
|
|
42
|
+
| **Signal** | Intent code — 777 (completion) · 555 (variation) · 333 (foundation) |
|
|
43
|
+
|
|
44
|
+
Then it routes to the right model. Invisibly.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
### Zero-config routing decision
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
import orbit from 'orbit-ai'
|
|
54
|
+
|
|
55
|
+
const decision = orbit.route("write a haiku about recursion")
|
|
56
|
+
|
|
57
|
+
console.log(decision.model.name) // "Claude Sonnet"
|
|
58
|
+
console.log(decision.reason) // "High creativity score (8/10)..."
|
|
59
|
+
console.log(decision.savings) // { savings: 0.007245, reductionPct: 97 }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### With signal codes (v0.3.0+)
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
import { OrbitClient } from 'orbit-ai'
|
|
66
|
+
|
|
67
|
+
const orbit = new OrbitClient({ log: true })
|
|
68
|
+
|
|
69
|
+
// 777 — completion mode, forces high-capability model
|
|
70
|
+
orbit.route("finalize the architecture doc", { signal: "777" })
|
|
71
|
+
// → Claude Sonnet (floor enforced)
|
|
72
|
+
|
|
73
|
+
// 555 — variation mode, maximizes model diversity
|
|
74
|
+
orbit.route("brainstorm 10 unexpected product names", { signal: "555" })
|
|
75
|
+
// → Grok (variation bias)
|
|
76
|
+
|
|
77
|
+
// 333 — foundation mode, minimizes cost
|
|
78
|
+
orbit.route("summarize this paragraph", { signal: "333" })
|
|
79
|
+
// → Gemini 2.5 Flash
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### With your own API keys
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
import { OrbitClient } from 'orbit-ai'
|
|
86
|
+
|
|
87
|
+
const orbit = new OrbitClient({
|
|
88
|
+
cost_tolerance: 'low', // 'low' | 'medium' | 'high'
|
|
89
|
+
log: true,
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const { model, reason, savings } = orbit.route("explain blockchain simply")
|
|
93
|
+
// [ORBIT] → Gemini 2.5 Flash | saved $0.01455 (97% reduction)
|
|
94
|
+
|
|
95
|
+
// model.id = 'gemini-2.5-flash', model.provider = 'google'
|
|
96
|
+
// Call the model yourself with your keys
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Full pipeline example
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
import { OrbitClient } from 'orbit-ai'
|
|
103
|
+
import Anthropic from '@anthropic-ai/sdk'
|
|
104
|
+
import OpenAI from 'openai'
|
|
105
|
+
import { GoogleGenerativeAI } from '@google/generative-ai'
|
|
106
|
+
|
|
107
|
+
const orbit = new OrbitClient({ log: true })
|
|
108
|
+
|
|
109
|
+
async function smartQuery(text, signal) {
|
|
110
|
+
const { model } = orbit.route(text, { signal })
|
|
111
|
+
|
|
112
|
+
if (model.provider === 'anthropic') {
|
|
113
|
+
const client = new Anthropic()
|
|
114
|
+
return client.messages.create({ model: model.id, max_tokens: 1024, messages: [{ role: 'user', content: text }] })
|
|
115
|
+
}
|
|
116
|
+
if (model.provider === 'openai') {
|
|
117
|
+
const client = new OpenAI()
|
|
118
|
+
return client.chat.completions.create({ model: model.id, messages: [{ role: 'user', content: text }] })
|
|
119
|
+
}
|
|
120
|
+
if (model.provider === 'google') {
|
|
121
|
+
const client = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY)
|
|
122
|
+
return client.getGenerativeModel({ model: model.id }).generateContent(text)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
await smartQuery("write a poem about the ocean") // → Claude Sonnet
|
|
127
|
+
await smartQuery("what's the latest news on AI funding?") // → Grok
|
|
128
|
+
await smartQuery("what is 2+2") // → Gemini Flash
|
|
129
|
+
await smartQuery("I've been feeling really overwhelmed") // → Claude Sonnet (ethics-first)
|
|
130
|
+
await smartQuery("finalize the system design", { signal: "777" }) // → Claude Sonnet (forced)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Session stats
|
|
134
|
+
|
|
135
|
+
```javascript
|
|
136
|
+
const stats = orbit.stats()
|
|
137
|
+
console.log(stats.total_savings_formatted) // "$0.2341"
|
|
138
|
+
console.log(stats.model_usage) // { "Claude Sonnet": 4, "Gemini 2.5 Flash": 12, ... }
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Model matrix
|
|
144
|
+
|
|
145
|
+
| Model | Provider | Cost/1M | Best for |
|
|
146
|
+
|---|---|---|---|
|
|
147
|
+
| Claude Sonnet 3.5 | Anthropic | $15 | Complex reasoning · Ethics · Long context |
|
|
148
|
+
| Claude Haiku | Anthropic | $1 | Speed · Summaries · Medium tasks |
|
|
149
|
+
| Gemini 2.5 Flash | Google | $0.50 | High volume · Simple queries · Cost |
|
|
150
|
+
| GPT-4o | OpenAI | $30 | Structured output · Broad knowledge |
|
|
151
|
+
| GPT-4o Mini | OpenAI | $0.30 | Classification · Filler tasks |
|
|
152
|
+
| Grok | xAI | $10 | Trending · Real-time web |
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## The math
|
|
157
|
+
|
|
158
|
+
Validated by [RouteLLM (UC Berkeley · ICLR 2025)](https://arxiv.org/abs/2406.18665): intelligent routing achieves **85% cost reduction** while maintaining 95% of quality.
|
|
159
|
+
|
|
160
|
+
For a team running 100k queries/month at GPT-4o:
|
|
161
|
+
- Without ORBIT: **$1,500/month**
|
|
162
|
+
- With ORBIT: **~$225/month**
|
|
163
|
+
- Savings: **$1,275/month · $15,300/year**
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Live demo
|
|
168
|
+
|
|
169
|
+
[orbit-model-flow.base44.app](https://orbit-model-flow.base44.app) — route a real query, see the fingerprint radar, watch the savings counter.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Roadmap
|
|
174
|
+
|
|
175
|
+
- [x] 8-axis fingerprinting engine
|
|
176
|
+
- [x] 6-model routing matrix
|
|
177
|
+
- [x] TypeScript types
|
|
178
|
+
- [x] Signal-aware routing (777 · 555 · 333)
|
|
179
|
+
- [ ] Streaming support
|
|
180
|
+
- [ ] Custom model matrix (bring your own models)
|
|
181
|
+
- [ ] Automatic provider failover
|
|
182
|
+
- [ ] Usage analytics dashboard integration
|
|
183
|
+
- [ ] Browser extension
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
MIT · Built by [Gabriel Martin](https://github.com/gabrielsmartin)
|
|
190
|
+
|
|
191
|
+
*"Every model has a gravitational pull. ORBIT decides which one you need."*
|
|
192
|
+
|
|
193
|
+
777 · 555 · 333
|
package/index.js
CHANGED
|
@@ -1,167 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* orbit-
|
|
3
|
-
* Intelligent AI model routing
|
|
4
|
-
* Drop in. Save 85%.
|
|
5
|
-
*
|
|
6
|
-
* https://orbitai.gtll.app
|
|
7
|
-
* github.com/gtllco/orbit
|
|
8
|
-
* npm: @gabrielsmartin/orbit-sdk
|
|
2
|
+
* @gabrielsmartin/orbit-sdk
|
|
3
|
+
* Intelligent AI model routing — routes every query to the optimal model in <1ms
|
|
9
4
|
*
|
|
10
5
|
* 777 · 555 · 333
|
|
6
|
+
* github.com/gtllco/orbit
|
|
11
7
|
*/
|
|
12
8
|
|
|
13
|
-
|
|
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
|
-
}
|
|
9
|
+
export { fingerprint, route, calculateSavings, MODEL_MATRIX, OrbitClient } from './src/index.js';
|
|
83
10
|
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
*/
|
|
11
|
+
// Default export — zero-config instance
|
|
12
|
+
import { OrbitClient } from './src/index.js';
|
|
166
13
|
const orbit = new OrbitClient();
|
|
167
14
|
export default orbit;
|
package/package.json
CHANGED
|
@@ -1,22 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gabrielsmartin/orbit-sdk",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "Intelligent AI model routing with signal
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"description": "Intelligent AI model routing with signal layer. 85% cost savings. 777·555·333",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"index.js",
|
|
9
|
+
"index.d.ts",
|
|
10
|
+
"src/",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"test": "node test.js"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"ai",
|
|
18
|
+
"llm",
|
|
19
|
+
"routing",
|
|
20
|
+
"openai",
|
|
21
|
+
"anthropic",
|
|
22
|
+
"gemini",
|
|
23
|
+
"orbit",
|
|
24
|
+
"cost-optimization",
|
|
25
|
+
"model-routing"
|
|
26
|
+
],
|
|
27
|
+
"author": "Gabriel Martin <admin@gtll.app>",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"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",
|
|
5
39
|
"type": "module",
|
|
6
|
-
"main": "./index.js",
|
|
7
|
-
"module": "./index.js",
|
|
8
40
|
"exports": {
|
|
9
41
|
".": {
|
|
10
42
|
"import": "./index.js",
|
|
11
|
-
"
|
|
43
|
+
"types": "./index.d.ts"
|
|
12
44
|
}
|
|
13
45
|
},
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
"author": "Gabriel Martin",
|
|
17
|
-
"license": "MIT",
|
|
18
|
-
"repository": {
|
|
19
|
-
"type": "git",
|
|
20
|
-
"url": "https://github.com/gtllco/orbit.git"
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18.0.0"
|
|
21
48
|
}
|
|
22
49
|
}
|
package/src/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;
|
|
@@ -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,
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ORBIT Signal Layer — Semantic Intent Routing Bias
|
|
3
|
+
*
|
|
4
|
+
* Signal codes are semantic flags that travel with a query and adjust the routing
|
|
5
|
+
* decision before model selection. They connect ORBIT to the organizational priority
|
|
6
|
+
* layer (the neural hub, event priorities, etc).
|
|
7
|
+
*
|
|
8
|
+
* 777 · 555 · 333
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Apply signal-based routing bias to a fingerprint
|
|
13
|
+
* Modifies the fingerprint scores before model selection happens
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} fingerprint - 8-axis scores from orbitFingerprint()
|
|
16
|
+
* @param {string} signal - '777' | '555' | '333' | null
|
|
17
|
+
* @returns {Object} biased fingerprint
|
|
18
|
+
*/
|
|
19
|
+
export function applySignalBias(fingerprint, signal) {
|
|
20
|
+
if (!signal) return fingerprint;
|
|
21
|
+
|
|
22
|
+
const biased = { ...fingerprint };
|
|
23
|
+
|
|
24
|
+
if (signal === '777') {
|
|
25
|
+
// COMPLETION BIAS
|
|
26
|
+
// 777 = This output is final. Quality floor raised. Never cut corners.
|
|
27
|
+
// - Force high-capability model floor
|
|
28
|
+
// - Never route to sub-tier models (Flash, Mini, Haiku)
|
|
29
|
+
// - If complexity >= 5: Claude Sonnet mandatory
|
|
30
|
+
// - If complexity < 5: Claude Haiku minimum
|
|
31
|
+
// - If emotional_weight >= 7: Claude always (never change this)
|
|
32
|
+
|
|
33
|
+
biased.cost_tolerance = Math.max(biased.cost_tolerance, 7);
|
|
34
|
+
biased.complexity = Math.max(biased.complexity, 5);
|
|
35
|
+
biased.signal_applied = '777';
|
|
36
|
+
biased.signal_reason = 'Completion bias — cost floor raised, quality mandatory';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (signal === '555') {
|
|
40
|
+
// VARIATION BIAS
|
|
41
|
+
// 555 = This query is exploratory. Break the expected pattern. Surprise.
|
|
42
|
+
// - Introduce controlled model diversity
|
|
43
|
+
// - Prefer non-default choices
|
|
44
|
+
// - If creativity >= 5: weight variation higher
|
|
45
|
+
// - If recency >= 6: Perplexity-like model over Claude
|
|
46
|
+
// - If complexity >= 6: allow GPT-4o instead of Claude
|
|
47
|
+
|
|
48
|
+
biased.creativity = Math.max(biased.creativity, 5);
|
|
49
|
+
biased.recency = Math.max(biased.recency, 4);
|
|
50
|
+
biased.variation_mode = true;
|
|
51
|
+
biased.signal_applied = '555';
|
|
52
|
+
biased.signal_reason = 'Variation bias — introduce model diversity, break the pattern';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (signal === '333') {
|
|
56
|
+
// FOUNDATION BIAS
|
|
57
|
+
// 333 = This is ambient/background. Strip to minimum. Cost floor.
|
|
58
|
+
// - Aggressively route to minimum viable model
|
|
59
|
+
// - If emotional_weight < 7: force cost_tolerance to 1 (ignore user config)
|
|
60
|
+
// - If complexity > 5: cap it at 4 (don't overpay)
|
|
61
|
+
// - Exception: emotional_weight >= 7 ALWAYS upgrades to Claude
|
|
62
|
+
// (never route crisis/sensitive to cheap models, even on 333)
|
|
63
|
+
|
|
64
|
+
if (biased.emotional_weight < 7) {
|
|
65
|
+
biased.cost_tolerance = 1; // force minimum cost
|
|
66
|
+
biased.complexity = Math.min(biased.complexity, 4); // cap complexity
|
|
67
|
+
}
|
|
68
|
+
biased.signal_applied = '333';
|
|
69
|
+
biased.signal_reason = 'Foundation bias — cost floor, ambient routing';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return biased;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Create signal explanation for response
|
|
77
|
+
*/
|
|
78
|
+
export function getSignalExplanation(signal) {
|
|
79
|
+
const explanations = {
|
|
80
|
+
'777': 'Completion bias applied — cost floor raised, complexity floor raised. Routed to highest-capability model.',
|
|
81
|
+
'555': 'Variation bias applied — model diversity prioritized. Unexpected routing choice for exploratory output.',
|
|
82
|
+
'333': 'Foundation bias applied — cost floor enforced. Minimum viable model selected for ambient routing.',
|
|
83
|
+
};
|
|
84
|
+
return explanations[signal] || null;
|
|
85
|
+
}
|
|
File without changes
|
|
File without changes
|