omnigate-ai 1.0.1 → 1.0.3
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 +56 -5
- package/package.json +1 -1
- package/public/app.js +34 -0
- package/public/index.html +21 -8
- package/server.js +42 -2
package/README.md
CHANGED
|
@@ -32,15 +32,66 @@ You will be greeted by a beautiful, glassmorphic UI where you can:
|
|
|
32
32
|
|
|
33
33
|
## 🛠️ Integrating with VS Code / AI Agents
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
### Continue Extension (VS Code)
|
|
36
|
+
|
|
37
|
+
Replace your `~/.continue/config.yaml` with the following:
|
|
38
|
+
|
|
39
|
+
```yaml
|
|
40
|
+
name: OmniGate Local Config
|
|
41
|
+
version: 1.0.0
|
|
42
|
+
schema: v1
|
|
43
|
+
|
|
44
|
+
models:
|
|
45
|
+
- name: DeepSeek (via OmniGate)
|
|
46
|
+
provider: openai
|
|
47
|
+
model: deepseek-v4-pro
|
|
48
|
+
apiBase: http://localhost:8080/v1/
|
|
49
|
+
apiKey: your-gateway-secret-key
|
|
50
|
+
roles:
|
|
51
|
+
- chat
|
|
52
|
+
- edit
|
|
53
|
+
- apply
|
|
54
|
+
requestOptions:
|
|
55
|
+
headers:
|
|
56
|
+
X-Gateway-Key: your-gateway-secret-key
|
|
57
|
+
X-Gateway-User-ID: your-name
|
|
58
|
+
X-Gateway-Project-ID: your-project-name
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
> **Important:** Continue v2.0+ requires `name` (not `title`), `roles`, and the top-level `schema: v1` field. Without these, you'll see a "config error" in the VS Code status bar.
|
|
62
|
+
|
|
63
|
+
### Roo Code / Cline / Other Agents
|
|
36
64
|
|
|
37
|
-
1.
|
|
38
|
-
2. Set the **
|
|
39
|
-
3. Set the **
|
|
40
|
-
4. Set the **API Key** to your **Gateway Secret Key** (the one you created in the dashboard, *not* your real OpenAI key).
|
|
65
|
+
1. Set the **Provider** to `OpenAI Compatible`.
|
|
66
|
+
2. Set the **Base URL** to `http://localhost:8080/v1`.
|
|
67
|
+
3. Set the **API Key** to your **Gateway Secret Key** (the one you created in the dashboard, *not* your real OpenAI key).
|
|
41
68
|
|
|
42
69
|
Now, start coding! OmniGate AI will silently intercept the requests, inject your real API key, forward it to the provider, and track your tokens on the dashboard.
|
|
43
70
|
|
|
71
|
+
## 🤖 Routing Your Custom AI Apps (Python & Node.js)
|
|
72
|
+
|
|
73
|
+
Are you building your own AI apps? You can easily route them through OmniGate AI to track their token usage too! Just change the base URL in your official OpenAI SDK to point to your local proxy.
|
|
74
|
+
|
|
75
|
+
**Python Example:**
|
|
76
|
+
```python
|
|
77
|
+
from openai import OpenAI
|
|
78
|
+
|
|
79
|
+
client = OpenAI(
|
|
80
|
+
base_url="http://localhost:8080/v1", # Point to your proxy
|
|
81
|
+
api_key="your-gateway-secret-key" # Use your local secret
|
|
82
|
+
)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Node.js Example:**
|
|
86
|
+
```javascript
|
|
87
|
+
import OpenAI from 'openai';
|
|
88
|
+
|
|
89
|
+
const openai = new OpenAI({
|
|
90
|
+
baseURL: "http://localhost:8080/v1", // Point to your proxy
|
|
91
|
+
apiKey: "your-gateway-secret-key" // Use your local secret
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
44
95
|
## ✨ Features
|
|
45
96
|
|
|
46
97
|
- **🔒 100% Local Privacy:** Your real API keys are saved locally. Cloud-based AI tools never see them.
|
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -151,6 +151,40 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
151
151
|
console.error("Stream parse error:", err);
|
|
152
152
|
}
|
|
153
153
|
};
|
|
154
|
+
|
|
155
|
+
evtSource.addEventListener('clear_telemetry', () => {
|
|
156
|
+
// Reset state
|
|
157
|
+
totalTokens = 0;
|
|
158
|
+
totalInputTokens = 0;
|
|
159
|
+
totalOutputTokens = 0;
|
|
160
|
+
totalCost = 0.0;
|
|
161
|
+
totalRequests = 0;
|
|
162
|
+
requestTimestamps.length = 0;
|
|
163
|
+
|
|
164
|
+
// Clear DOM
|
|
165
|
+
tbody.innerHTML = '';
|
|
166
|
+
elTotalTokens.textContent = '0';
|
|
167
|
+
elInputTokens.textContent = '0';
|
|
168
|
+
elOutputTokens.textContent = '0';
|
|
169
|
+
elTotalCost.textContent = '$0.000';
|
|
170
|
+
elAvgCost.textContent = '$0.000';
|
|
171
|
+
elTotalRequests.textContent = '0';
|
|
172
|
+
|
|
173
|
+
updateGauges();
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ==========================================
|
|
178
|
+
// Reset Data Button
|
|
179
|
+
// ==========================================
|
|
180
|
+
const btnResetData = document.getElementById('btn-reset-data');
|
|
181
|
+
if (btnResetData) {
|
|
182
|
+
btnResetData.addEventListener('click', () => {
|
|
183
|
+
if (confirm('Are you sure you want to clear all telemetry history?')) {
|
|
184
|
+
fetch('/api/telemetry', { method: 'DELETE' })
|
|
185
|
+
.catch(err => console.error('Failed to clear telemetry:', err));
|
|
186
|
+
}
|
|
187
|
+
});
|
|
154
188
|
}
|
|
155
189
|
|
|
156
190
|
// ==========================================
|
package/public/index.html
CHANGED
|
@@ -27,9 +27,14 @@
|
|
|
27
27
|
<span style="font-size:0.7rem;color:var(--text-dim);font-weight:400;display:block;margin-top:0.1rem;">Privacy-First API Gateway · Token Cost Tracker</span>
|
|
28
28
|
</div>
|
|
29
29
|
</div>
|
|
30
|
-
<div class="
|
|
31
|
-
<
|
|
32
|
-
|
|
30
|
+
<div class="header-actions" style="display: flex; gap: 1rem; align-items: center;">
|
|
31
|
+
<button id="btn-reset-data" class="btn-secondary" style="padding: 0.4rem 0.8rem; font-size: 0.8rem; border-color: rgba(255,8,68,0.5); color: #ffb199; background: rgba(255,8,68,0.1); border-radius: 50px;">
|
|
32
|
+
⟲ Reset Data
|
|
33
|
+
</button>
|
|
34
|
+
<div class="status-indicator">
|
|
35
|
+
<span class="pulse-dot"></span>
|
|
36
|
+
<span>Gateway Connected</span>
|
|
37
|
+
</div>
|
|
33
38
|
</div>
|
|
34
39
|
</header>
|
|
35
40
|
|
|
@@ -202,17 +207,25 @@
|
|
|
202
207
|
<p>Add this model block to your <code>~/.continue/config.yaml</code> config file:</p>
|
|
203
208
|
<div class="code-container">
|
|
204
209
|
<button class="copy-btn" onclick="copySnippet('continue-code', this)">Copy</button>
|
|
205
|
-
<pre id="continue-code">
|
|
210
|
+
<pre id="continue-code">name: OmniGate Local Config
|
|
211
|
+
version: 1.0.0
|
|
212
|
+
schema: v1
|
|
213
|
+
|
|
214
|
+
models:
|
|
206
215
|
- name: DeepSeek (via OmniGate)
|
|
207
216
|
provider: openai
|
|
208
217
|
model: deepseek-v4-pro
|
|
209
218
|
apiBase: http://localhost:8080/v1/
|
|
210
|
-
apiKey:
|
|
219
|
+
apiKey: your-gateway-secret-key
|
|
220
|
+
roles:
|
|
221
|
+
- chat
|
|
222
|
+
- edit
|
|
223
|
+
- apply
|
|
211
224
|
requestOptions:
|
|
212
225
|
headers:
|
|
213
|
-
X-Gateway-Key:
|
|
214
|
-
X-Gateway-User-ID: developer-
|
|
215
|
-
X-Gateway-Project-ID: vscode-project-
|
|
226
|
+
X-Gateway-Key: your-gateway-secret-key
|
|
227
|
+
X-Gateway-User-ID: developer-name
|
|
228
|
+
X-Gateway-Project-ID: vscode-project-name</pre>
|
|
216
229
|
</div>
|
|
217
230
|
</div>
|
|
218
231
|
|
package/server.js
CHANGED
|
@@ -84,6 +84,12 @@ app.get('/api/telemetry', (req, res) => {
|
|
|
84
84
|
res.json(telemetryHistory);
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
+
app.delete('/api/telemetry', (req, res) => {
|
|
88
|
+
telemetryHistory.length = 0;
|
|
89
|
+
telemetryEmitter.emit('clear_telemetry', { status: 'cleared' });
|
|
90
|
+
res.json({ status: 'success', message: 'Telemetry history cleared' });
|
|
91
|
+
});
|
|
92
|
+
|
|
87
93
|
app.get('/api/telemetry/stream', (req, res) => {
|
|
88
94
|
res.setHeader('Content-Type', 'text/event-stream');
|
|
89
95
|
res.setHeader('Cache-Control', 'no-cache');
|
|
@@ -150,7 +156,14 @@ app.use((req, res, next) => {
|
|
|
150
156
|
return next();
|
|
151
157
|
}
|
|
152
158
|
|
|
153
|
-
|
|
159
|
+
let incomingGatewayKey = req.headers['x-gateway-key'] || '';
|
|
160
|
+
if (!incomingGatewayKey && req.headers.authorization) {
|
|
161
|
+
const authHeader = req.headers.authorization;
|
|
162
|
+
if (authHeader.startsWith('Bearer ')) {
|
|
163
|
+
incomingGatewayKey = authHeader.slice(7);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
154
167
|
const expectedKey = activeConfig.agencyGatewayKey || '';
|
|
155
168
|
|
|
156
169
|
const incomingBuffer = Buffer.from(incomingGatewayKey);
|
|
@@ -564,11 +577,38 @@ app.post('/v1/messages', async (req, res) => {
|
|
|
564
577
|
}
|
|
565
578
|
});
|
|
566
579
|
|
|
580
|
+
// 4. OpenAI Models Proxy Handler
|
|
581
|
+
app.get('/v1/models', (req, res) => {
|
|
582
|
+
res.json({
|
|
583
|
+
object: 'list',
|
|
584
|
+
data: [
|
|
585
|
+
{
|
|
586
|
+
id: 'deepseek-v4-pro',
|
|
587
|
+
object: 'model',
|
|
588
|
+
created: Date.now(),
|
|
589
|
+
owned_by: 'OmniGate'
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
id: 'gpt-4o',
|
|
593
|
+
object: 'model',
|
|
594
|
+
created: Date.now(),
|
|
595
|
+
owned_by: 'OmniGate'
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
id: 'gpt-3.5-turbo',
|
|
599
|
+
object: 'model',
|
|
600
|
+
created: Date.now(),
|
|
601
|
+
owned_by: 'OmniGate'
|
|
602
|
+
}
|
|
603
|
+
]
|
|
604
|
+
});
|
|
605
|
+
});
|
|
606
|
+
|
|
567
607
|
// Catch-all route to reject unsupported endpoints
|
|
568
608
|
app.use((req, res) => {
|
|
569
609
|
res.status(404).json({
|
|
570
610
|
error: {
|
|
571
|
-
message: `The endpoint ${req.method} ${req.path} is not supported by OmniGate AI gateway. Only /v1/chat/completions (OpenAI) and /v1/messages (Anthropic) are valid proxy routes.`,
|
|
611
|
+
message: `The endpoint ${req.method} ${req.path} is not supported by OmniGate AI gateway. Only /v1/chat/completions (OpenAI), /v1/models, and /v1/messages (Anthropic) are valid proxy routes.`,
|
|
572
612
|
type: 'gateway_route_error',
|
|
573
613
|
code: 'unsupported_route'
|
|
574
614
|
}
|