@relayplane/proxy 1.1.0 → 1.1.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.
Files changed (38) hide show
  1. package/README.md +120 -221
  2. package/dist/__tests__/model-suggestions.test.d.ts +2 -0
  3. package/dist/__tests__/model-suggestions.test.d.ts.map +1 -0
  4. package/dist/__tests__/model-suggestions.test.js +67 -0
  5. package/dist/__tests__/model-suggestions.test.js.map +1 -0
  6. package/dist/__tests__/routing-aliases.test.d.ts +2 -0
  7. package/dist/__tests__/routing-aliases.test.d.ts.map +1 -0
  8. package/dist/__tests__/routing-aliases.test.js +81 -0
  9. package/dist/__tests__/routing-aliases.test.js.map +1 -0
  10. package/dist/cli.d.ts +36 -0
  11. package/dist/cli.d.ts.map +1 -0
  12. package/dist/cli.js +304 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/config.d.ts +80 -0
  15. package/dist/config.d.ts.map +1 -0
  16. package/dist/config.js +208 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/index.d.ts +27 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +60 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/standalone-proxy.d.ts +101 -0
  23. package/dist/standalone-proxy.d.ts.map +1 -0
  24. package/dist/standalone-proxy.js +2524 -0
  25. package/dist/standalone-proxy.js.map +1 -0
  26. package/dist/swarm-client.d.ts +87 -0
  27. package/dist/swarm-client.d.ts.map +1 -0
  28. package/dist/swarm-client.js +205 -0
  29. package/dist/swarm-client.js.map +1 -0
  30. package/dist/telemetry.d.ts +127 -0
  31. package/dist/telemetry.d.ts.map +1 -0
  32. package/dist/telemetry.js +426 -0
  33. package/dist/telemetry.js.map +1 -0
  34. package/dist/utils/model-suggestions.d.ts +28 -0
  35. package/dist/utils/model-suggestions.d.ts.map +1 -0
  36. package/dist/utils/model-suggestions.js +50 -0
  37. package/dist/utils/model-suggestions.js.map +1 -0
  38. package/package.json +35 -29
@@ -0,0 +1,426 @@
1
+ "use strict";
2
+ /**
3
+ * RelayPlane Proxy Telemetry
4
+ *
5
+ * Anonymized telemetry collection for improving model routing.
6
+ *
7
+ * What we collect (exact schema):
8
+ * - device_id: anonymous random ID
9
+ * - task_type: inferred from token patterns, NOT prompt content
10
+ * - model: which model was used
11
+ * - tokens_in/out: token counts
12
+ * - latency_ms: response time
13
+ * - success: whether request succeeded
14
+ * - cost_usd: estimated cost
15
+ *
16
+ * What we NEVER collect:
17
+ * - Prompts or responses
18
+ * - File paths or contents
19
+ * - Anything that could identify you or your project
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ var desc = Object.getOwnPropertyDescriptor(m, k);
26
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
27
+ desc = { enumerable: true, get: function() { return m[k]; } };
28
+ }
29
+ Object.defineProperty(o, k2, desc);
30
+ }) : (function(o, m, k, k2) {
31
+ if (k2 === undefined) k2 = k;
32
+ o[k2] = m[k];
33
+ }));
34
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
35
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
36
+ }) : function(o, v) {
37
+ o["default"] = v;
38
+ });
39
+ var __importStar = (this && this.__importStar) || (function () {
40
+ var ownKeys = function(o) {
41
+ ownKeys = Object.getOwnPropertyNames || function (o) {
42
+ var ar = [];
43
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
44
+ return ar;
45
+ };
46
+ return ownKeys(o);
47
+ };
48
+ return function (mod) {
49
+ if (mod && mod.__esModule) return mod;
50
+ var result = {};
51
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
52
+ __setModuleDefault(result, mod);
53
+ return result;
54
+ };
55
+ })();
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ exports.inferTaskType = inferTaskType;
58
+ exports.estimateCost = estimateCost;
59
+ exports.setAuditMode = setAuditMode;
60
+ exports.isAuditMode = isAuditMode;
61
+ exports.setOfflineMode = setOfflineMode;
62
+ exports.isOfflineMode = isOfflineMode;
63
+ exports.getAuditBuffer = getAuditBuffer;
64
+ exports.clearAuditBuffer = clearAuditBuffer;
65
+ exports.recordTelemetry = recordTelemetry;
66
+ exports.getLocalTelemetry = getLocalTelemetry;
67
+ exports.getTelemetryStats = getTelemetryStats;
68
+ exports.clearTelemetry = clearTelemetry;
69
+ exports.getTelemetryPath = getTelemetryPath;
70
+ exports.queueForUpload = queueForUpload;
71
+ exports.flushTelemetryToCloud = flushTelemetryToCloud;
72
+ exports.stopUploadTimer = stopUploadTimer;
73
+ exports.getPendingUploadCount = getPendingUploadCount;
74
+ exports.printTelemetryDisclosure = printTelemetryDisclosure;
75
+ const fs = __importStar(require("fs"));
76
+ const path = __importStar(require("path"));
77
+ const config_js_1 = require("./config.js");
78
+ /**
79
+ * Local telemetry store using SQLite (via Ledger)
80
+ */
81
+ const TELEMETRY_FILE = path.join((0, config_js_1.getConfigDir)(), 'telemetry.jsonl');
82
+ // In-memory buffer for audit mode
83
+ let auditBuffer = [];
84
+ let auditMode = false;
85
+ let offlineMode = false;
86
+ /**
87
+ * Task type inference based on token patterns
88
+ * This infers task type from request characteristics, NOT from prompt content
89
+ */
90
+ function inferTaskType(inputTokens, outputTokens, model, hasTools = false) {
91
+ // Simple heuristics based on token patterns
92
+ const ratio = outputTokens / Math.max(inputTokens, 1);
93
+ if (hasTools) {
94
+ return 'tool_use';
95
+ }
96
+ if (inputTokens > 10000) {
97
+ return 'long_context';
98
+ }
99
+ if (ratio > 5) {
100
+ return 'generation';
101
+ }
102
+ if (ratio < 0.3 && outputTokens < 100) {
103
+ return 'classification';
104
+ }
105
+ if (inputTokens < 500 && outputTokens < 500) {
106
+ return 'quick_task';
107
+ }
108
+ if (inputTokens > 2000 && outputTokens > 500) {
109
+ return 'code_review';
110
+ }
111
+ if (outputTokens > 1000) {
112
+ return 'content_generation';
113
+ }
114
+ return 'general';
115
+ }
116
+ /**
117
+ * Estimate cost based on model and token counts
118
+ * Pricing as of 2024 (USD per 1M tokens)
119
+ */
120
+ const MODEL_PRICING = {
121
+ // Anthropic
122
+ 'claude-opus-4-20250514': { input: 15.0, output: 75.0 },
123
+ 'claude-sonnet-4-20250514': { input: 3.0, output: 15.0 },
124
+ 'claude-3-5-sonnet-20241022': { input: 3.0, output: 15.0 },
125
+ 'claude-3-5-sonnet-20240620': { input: 3.0, output: 15.0 },
126
+ 'claude-3-5-haiku-20241022': { input: 0.8, output: 4.0 },
127
+ 'claude-3-opus-20240229': { input: 15.0, output: 75.0 },
128
+ 'claude-3-sonnet-20240229': { input: 3.0, output: 15.0 },
129
+ 'claude-3-haiku-20240307': { input: 0.25, output: 1.25 },
130
+ // OpenAI
131
+ 'gpt-4o': { input: 2.5, output: 10.0 },
132
+ 'gpt-4o-mini': { input: 0.15, output: 0.60 },
133
+ 'gpt-4-turbo': { input: 10.0, output: 30.0 },
134
+ 'gpt-4': { input: 30.0, output: 60.0 },
135
+ 'gpt-3.5-turbo': { input: 0.5, output: 1.5 },
136
+ // Default for unknown models
137
+ 'default': { input: 1.0, output: 3.0 },
138
+ };
139
+ function estimateCost(model, inputTokens, outputTokens) {
140
+ const pricing = MODEL_PRICING[model] || MODEL_PRICING['default'];
141
+ const inputCost = (inputTokens / 1_000_000) * pricing.input;
142
+ const outputCost = (outputTokens / 1_000_000) * pricing.output;
143
+ return Math.round((inputCost + outputCost) * 10000) / 10000; // Round to 4 decimal places
144
+ }
145
+ /**
146
+ * Set audit mode - shows telemetry payload before sending
147
+ */
148
+ function setAuditMode(enabled) {
149
+ auditMode = enabled;
150
+ }
151
+ /**
152
+ * Check if audit mode is enabled
153
+ */
154
+ function isAuditMode() {
155
+ return auditMode;
156
+ }
157
+ /**
158
+ * Set offline mode - disables all network calls except LLM
159
+ */
160
+ function setOfflineMode(enabled) {
161
+ offlineMode = enabled;
162
+ }
163
+ /**
164
+ * Check if offline mode is enabled
165
+ */
166
+ function isOfflineMode() {
167
+ return offlineMode;
168
+ }
169
+ /**
170
+ * Get pending audit events
171
+ */
172
+ function getAuditBuffer() {
173
+ return [...auditBuffer];
174
+ }
175
+ /**
176
+ * Clear audit buffer
177
+ */
178
+ function clearAuditBuffer() {
179
+ auditBuffer = [];
180
+ }
181
+ /**
182
+ * Record a telemetry event
183
+ */
184
+ function recordTelemetry(event) {
185
+ if (!(0, config_js_1.isTelemetryEnabled)() && !auditMode) {
186
+ return; // Telemetry disabled and not in audit mode
187
+ }
188
+ const fullEvent = {
189
+ ...event,
190
+ device_id: (0, config_js_1.getDeviceId)(),
191
+ timestamp: new Date().toISOString(),
192
+ };
193
+ if (auditMode) {
194
+ // In audit mode, buffer events and print them
195
+ auditBuffer.push(fullEvent);
196
+ console.log('\n📊 [TELEMETRY AUDIT] The following data would be collected:');
197
+ console.log(JSON.stringify(fullEvent, null, 2));
198
+ console.log('');
199
+ return;
200
+ }
201
+ if (!(0, config_js_1.isTelemetryEnabled)()) {
202
+ return;
203
+ }
204
+ // Store locally (append to JSONL file)
205
+ try {
206
+ const configDir = (0, config_js_1.getConfigDir)();
207
+ if (!fs.existsSync(configDir)) {
208
+ fs.mkdirSync(configDir, { recursive: true });
209
+ }
210
+ fs.appendFileSync(TELEMETRY_FILE, JSON.stringify(fullEvent) + '\n');
211
+ }
212
+ catch (err) {
213
+ // Silently fail - telemetry should never break the proxy
214
+ }
215
+ // Queue for cloud upload (if not offline)
216
+ queueForUpload(fullEvent);
217
+ }
218
+ /**
219
+ * Get local telemetry data
220
+ */
221
+ function getLocalTelemetry() {
222
+ try {
223
+ if (!fs.existsSync(TELEMETRY_FILE)) {
224
+ return [];
225
+ }
226
+ const data = fs.readFileSync(TELEMETRY_FILE, 'utf-8');
227
+ return data
228
+ .split('\n')
229
+ .filter(line => line.trim())
230
+ .map(line => JSON.parse(line));
231
+ }
232
+ catch (err) {
233
+ return [];
234
+ }
235
+ }
236
+ /**
237
+ * Get telemetry stats summary
238
+ */
239
+ function getTelemetryStats() {
240
+ const events = getLocalTelemetry();
241
+ const byModel = {};
242
+ const byTaskType = {};
243
+ let totalCost = 0;
244
+ let successCount = 0;
245
+ for (const event of events) {
246
+ totalCost += event.cost_usd;
247
+ if (event.success)
248
+ successCount++;
249
+ if (!byModel[event.model]) {
250
+ byModel[event.model] = { count: 0, cost: 0 };
251
+ }
252
+ byModel[event.model].count++;
253
+ byModel[event.model].cost += event.cost_usd;
254
+ if (!byTaskType[event.task_type]) {
255
+ byTaskType[event.task_type] = { count: 0, cost: 0 };
256
+ }
257
+ byTaskType[event.task_type].count++;
258
+ byTaskType[event.task_type].cost += event.cost_usd;
259
+ }
260
+ return {
261
+ totalEvents: events.length,
262
+ totalCost: Math.round(totalCost * 100) / 100,
263
+ byModel,
264
+ byTaskType,
265
+ successRate: events.length > 0 ? successCount / events.length : 0,
266
+ };
267
+ }
268
+ /**
269
+ * Clear all local telemetry data
270
+ */
271
+ function clearTelemetry() {
272
+ try {
273
+ if (fs.existsSync(TELEMETRY_FILE)) {
274
+ fs.unlinkSync(TELEMETRY_FILE);
275
+ }
276
+ }
277
+ catch (err) {
278
+ // Silently fail
279
+ }
280
+ }
281
+ /**
282
+ * Get telemetry file path
283
+ */
284
+ function getTelemetryPath() {
285
+ return TELEMETRY_FILE;
286
+ }
287
+ // ============================================
288
+ // CLOUD TELEMETRY UPLOAD
289
+ // ============================================
290
+ const BRAIN_API_URL = process.env.RELAYPLANE_API_URL || 'https://api.relayplane.com';
291
+ const UPLOAD_BATCH_SIZE = 50;
292
+ const UPLOAD_INTERVAL_MS = 60000; // 1 minute
293
+ let uploadQueue = [];
294
+ let uploadTimer = null;
295
+ /**
296
+ * Queue an event for cloud upload
297
+ */
298
+ function queueForUpload(event) {
299
+ if (offlineMode)
300
+ return;
301
+ uploadQueue.push(event);
302
+ // Flush if batch is full
303
+ if (uploadQueue.length >= UPLOAD_BATCH_SIZE) {
304
+ flushTelemetryToCloud().catch(err => {
305
+ console.error('[Telemetry] Failed to flush batch:', err);
306
+ });
307
+ }
308
+ // Start periodic flush timer if not running
309
+ if (!uploadTimer) {
310
+ uploadTimer = setInterval(() => {
311
+ flushTelemetryToCloud().catch(err => {
312
+ console.error('[Telemetry] Periodic flush failed:', err);
313
+ });
314
+ }, UPLOAD_INTERVAL_MS);
315
+ }
316
+ }
317
+ /**
318
+ * Flush queued telemetry to cloud
319
+ */
320
+ async function flushTelemetryToCloud() {
321
+ if (offlineMode || uploadQueue.length === 0)
322
+ return;
323
+ const apiKey = getApiKey();
324
+ if (!apiKey) {
325
+ // No API key, can't upload
326
+ return;
327
+ }
328
+ const batch = uploadQueue.splice(0, UPLOAD_BATCH_SIZE);
329
+ try {
330
+ const response = await fetch(`${BRAIN_API_URL}/v1/telemetry`, {
331
+ method: 'POST',
332
+ headers: {
333
+ 'Content-Type': 'application/json',
334
+ 'Authorization': `Bearer ${apiKey}`,
335
+ },
336
+ body: JSON.stringify({
337
+ schemaVersion: '1.0',
338
+ events: batch,
339
+ }),
340
+ });
341
+ if (!response.ok) {
342
+ // Re-queue failed events
343
+ uploadQueue.unshift(...batch);
344
+ throw new Error(`Upload failed: ${response.status} ${response.statusText}`);
345
+ }
346
+ const result = await response.json();
347
+ if (result.success) {
348
+ // Successfully uploaded
349
+ }
350
+ else {
351
+ // Partial failure - log but continue
352
+ console.warn('[Telemetry] Partial upload failure:', result.errors);
353
+ }
354
+ }
355
+ catch (err) {
356
+ // Network error - re-queue events
357
+ uploadQueue.unshift(...batch);
358
+ throw err;
359
+ }
360
+ }
361
+ /**
362
+ * Get configured API key
363
+ */
364
+ function getApiKey() {
365
+ try {
366
+ const configPath = path.join((0, config_js_1.getConfigDir)(), 'config.json');
367
+ if (fs.existsSync(configPath)) {
368
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
369
+ return config.apiKey || null;
370
+ }
371
+ }
372
+ catch (err) {
373
+ // Ignore config read errors
374
+ }
375
+ return process.env.RELAYPLANE_API_KEY || null;
376
+ }
377
+ /**
378
+ * Stop upload timer (for cleanup)
379
+ */
380
+ function stopUploadTimer() {
381
+ if (uploadTimer) {
382
+ clearInterval(uploadTimer);
383
+ uploadTimer = null;
384
+ }
385
+ }
386
+ /**
387
+ * Get number of events pending upload
388
+ */
389
+ function getPendingUploadCount() {
390
+ return uploadQueue.length;
391
+ }
392
+ /**
393
+ * Print telemetry disclosure message
394
+ */
395
+ function printTelemetryDisclosure() {
396
+ console.log(`
397
+ ╭─────────────────────────────────────────────────────────────────────╮
398
+ │ 📊 TELEMETRY DISCLOSURE │
399
+ ╰─────────────────────────────────────────────────────────────────────╯
400
+
401
+ RelayPlane collects anonymous telemetry to improve model routing.
402
+
403
+ What we collect:
404
+ • Anonymous device ID (random, not fingerprintable)
405
+ • Task type (inferred from token patterns, NOT your prompts)
406
+ • Model used, token counts, latency, success/failure
407
+ • Estimated cost
408
+
409
+ What we NEVER collect:
410
+ • Your prompts or model responses
411
+ • File paths or contents
412
+ • Anything that could identify you or your project
413
+
414
+ How to verify:
415
+ • Run with --audit to see exact payloads before they're sent
416
+ • Run with --offline to disable all telemetry transmission
417
+ • Full source code: https://github.com/RelayPlane/proxy
418
+
419
+ To opt out completely:
420
+ $ relayplane-proxy telemetry off
421
+
422
+ Learn more: https://relayplane.com/privacy
423
+
424
+ `);
425
+ }
426
+ //# sourceMappingURL=telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Model suggestion utilities for improved error messages
3
+ *
4
+ * Uses Levenshtein distance to suggest similar model names when a
5
+ * requested model doesn't exist.
6
+ */
7
+ /**
8
+ * Suggest similar models based on Levenshtein distance
9
+ *
10
+ * @param requested - The model name that was requested but not found
11
+ * @param available - List of available/valid model names
12
+ * @param max - Maximum number of suggestions to return (default: 3)
13
+ * @returns Array of suggested model names, sorted by similarity
14
+ */
15
+ export declare function suggestModels(requested: string, available: string[], max?: number): string[];
16
+ /**
17
+ * Build an error response for model-not-found errors with suggestions
18
+ *
19
+ * @param requestedModel - The model name that was requested
20
+ * @param availableModels - List of available model names
21
+ * @returns Error response object with suggestions
22
+ */
23
+ export declare function buildModelNotFoundError(requestedModel: string, availableModels: string[]): {
24
+ error: string;
25
+ suggestions?: string[];
26
+ hint?: string;
27
+ };
28
+ //# sourceMappingURL=model-suggestions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-suggestions.d.ts","sourceRoot":"","sources":["../../src/utils/model-suggestions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EAAE,EACnB,GAAG,SAAI,GACN,MAAM,EAAE,CAYV;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,MAAM,EAAE,GACxB;IACD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAiBA"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ /**
3
+ * Model suggestion utilities for improved error messages
4
+ *
5
+ * Uses Levenshtein distance to suggest similar model names when a
6
+ * requested model doesn't exist.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.suggestModels = suggestModels;
10
+ exports.buildModelNotFoundError = buildModelNotFoundError;
11
+ const fastest_levenshtein_1 = require("fastest-levenshtein");
12
+ /**
13
+ * Suggest similar models based on Levenshtein distance
14
+ *
15
+ * @param requested - The model name that was requested but not found
16
+ * @param available - List of available/valid model names
17
+ * @param max - Maximum number of suggestions to return (default: 3)
18
+ * @returns Array of suggested model names, sorted by similarity
19
+ */
20
+ function suggestModels(requested, available, max = 3) {
21
+ const requestedLower = requested.toLowerCase();
22
+ return available
23
+ .map((model) => ({
24
+ model,
25
+ dist: (0, fastest_levenshtein_1.distance)(requestedLower, model.toLowerCase()),
26
+ }))
27
+ .filter(({ dist }) => dist <= 4) // Within 4 edits
28
+ .sort((a, b) => a.dist - b.dist)
29
+ .slice(0, max)
30
+ .map(({ model }) => model);
31
+ }
32
+ /**
33
+ * Build an error response for model-not-found errors with suggestions
34
+ *
35
+ * @param requestedModel - The model name that was requested
36
+ * @param availableModels - List of available model names
37
+ * @returns Error response object with suggestions
38
+ */
39
+ function buildModelNotFoundError(requestedModel, availableModels) {
40
+ const suggestions = suggestModels(requestedModel, availableModels);
41
+ const response = {
42
+ error: `Model '${requestedModel}' does not exist`,
43
+ };
44
+ if (suggestions.length > 0) {
45
+ response.suggestions = suggestions;
46
+ response.hint = `Did you mean '${suggestions[0]}'?`;
47
+ }
48
+ return response;
49
+ }
50
+ //# sourceMappingURL=model-suggestions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-suggestions.js","sourceRoot":"","sources":["../../src/utils/model-suggestions.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAYH,sCAgBC;AASD,0DAwBC;AA3DD,6DAA+C;AAE/C;;;;;;;GAOG;AACH,SAAgB,aAAa,CAC3B,SAAiB,EACjB,SAAmB,EACnB,GAAG,GAAG,CAAC;IAEP,MAAM,cAAc,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IAE/C,OAAO,SAAS;SACb,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACf,KAAK;QACL,IAAI,EAAE,IAAA,8BAAQ,EAAC,cAAc,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;KACpD,CAAC,CAAC;SACF,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,iBAAiB;SACjD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;SAC/B,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;SACb,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,uBAAuB,CACrC,cAAsB,EACtB,eAAyB;IAMzB,MAAM,WAAW,GAAG,aAAa,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;IAEnE,MAAM,QAAQ,GAIV;QACF,KAAK,EAAE,UAAU,cAAc,kBAAkB;KAClD,CAAC;IAEF,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,QAAQ,CAAC,WAAW,GAAG,WAAW,CAAC;QACnC,QAAQ,CAAC,IAAI,GAAG,iBAAiB,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;IACtD,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
package/package.json CHANGED
@@ -1,52 +1,58 @@
1
1
  {
2
2
  "name": "@relayplane/proxy",
3
- "version": "1.1.0",
4
- "description": "RelayPlane Local LLM Proxy - Route requests through multiple providers",
5
- "type": "module",
6
- "main": "dist/server.js",
7
- "types": "dist/server.d.ts",
3
+ "version": "1.1.2",
4
+ "description": "RelayPlane proxy server - intelligent AI model routing with observability",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
8
7
  "bin": {
9
- "relayplane-proxy": "dist/server.js"
8
+ "relayplane-proxy": "dist/cli.js"
10
9
  },
11
10
  "scripts": {
12
11
  "build": "tsc",
13
12
  "dev": "tsc --watch",
14
- "start": "node dist/server.js",
13
+ "start": "node dist/cli.js",
15
14
  "test": "vitest run",
16
15
  "test:watch": "vitest",
17
- "type-check": "tsc --noEmit",
18
- "clean": "rm -rf dist"
16
+ "prepublishOnly": "npm run build"
19
17
  },
20
18
  "keywords": [
21
- "proxy",
19
+ "relayplane",
20
+ "ai",
22
21
  "llm",
23
- "openai",
22
+ "proxy",
23
+ "routing",
24
24
  "anthropic",
25
- "ai",
26
- "relayplane"
25
+ "openai",
26
+ "gemini",
27
+ "openclaw",
28
+ "observability",
29
+ "agent-ops"
27
30
  ],
28
31
  "author": "RelayPlane",
29
32
  "license": "MIT",
30
- "homepage": "https://relayplane.com",
33
+ "dependencies": {
34
+ "@relayplane/core": "^0.1.1",
35
+ "fastest-levenshtein": "^1.0.16"
36
+ },
37
+ "optionalDependencies": {
38
+ "@relayplane/auth-gate": "^0.1.0",
39
+ "@relayplane/explainability": "^0.1.0",
40
+ "@relayplane/ledger": "^0.1.0",
41
+ "@relayplane/policy-engine": "^0.1.0",
42
+ "@relayplane/routing-engine": "^0.1.0"
43
+ },
44
+ "devDependencies": {
45
+ "typescript": "^5.3.3",
46
+ "vitest": "^1.1.0"
47
+ },
31
48
  "engines": {
32
- "node": ">=18.0.0"
49
+ "node": ">=18"
33
50
  },
34
51
  "publishConfig": {
35
- "access": "public",
36
- "registry": "https://registry.npmjs.org/"
52
+ "access": "public"
37
53
  },
38
54
  "files": [
39
55
  "dist",
40
- "README.md",
41
- "LICENSE"
42
- ],
43
- "dependencies": {
44
- "node-fetch": "^2.7.0"
45
- },
46
- "devDependencies": {
47
- "@types/node": "^20.10.0",
48
- "@types/node-fetch": "^2.6.11",
49
- "typescript": "^5.3.3",
50
- "vitest": "^1.1.0"
51
- }
56
+ "README.md"
57
+ ]
52
58
  }