freegate 0.6.4 → 0.6.6

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/lib/health.js CHANGED
@@ -8,6 +8,7 @@ const STATE_PATH = path.join(__dirname, '..', 'state.json');
8
8
  let health = {};
9
9
  let circuitBreakers = {};
10
10
  let stats = { totalRequests: 0, successfulRequests: 0, failedRequests: 0, providerUsage: {}, errors: {}, startTime: Date.now(), tokenUsage: {} };
11
+ let lastSelection = null;
11
12
 
12
13
  const MAX_RECENT = 50;
13
14
  let recent = [];
@@ -37,6 +38,17 @@ function loadState() {
37
38
  }
38
39
  }
39
40
 
41
+ function recordSelection(providerKey, modelName, requestedModel) {
42
+ lastSelection = {
43
+ provider: providerKey,
44
+ model: modelName,
45
+ requested: requestedModel,
46
+ at: Date.now(),
47
+ };
48
+ }
49
+
50
+ function getLastSelection() { return lastSelection; }
51
+
40
52
  function saveState() {
41
53
  try {
42
54
  fs.writeFileSync(STATE_PATH, JSON.stringify({ health, circuitBreakers, stats }, null, 2));
@@ -175,5 +187,6 @@ module.exports = {
175
187
  getHealth, getStats,
176
188
  recordRecent, recordRpm, getRecent, getRpm,
177
189
  getDailyUsage, getReliability,
190
+ recordSelection, getLastSelection,
178
191
  _stopTimers,
179
192
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freegate",
3
- "version": "0.6.4",
3
+ "version": "0.6.6",
4
4
  "description": "Free multi-provider LLM gateway with automatic failover. One OpenAI-compatible endpoint routes to 25 free models (Groq, Mistral, Gemini, NIM, OpenRouter, ZAI, Cerebras, DeepSeek). Never pay for LLMs.",
5
5
  "license": "MIT",
6
6
  "bin": {
package/server.js CHANGED
@@ -4,7 +4,7 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const { LRUCache } = require('./lib/cache');
6
6
  const { PROVIDERS, MODEL_MAP, callProvider } = require('./lib/providers');
7
- const { loadState, initHealth, isCircuitOpen, recordSuccess, recordFailure, recordRequest, recordTokens, getHealth, getStats, recordRecent, recordRpm, getRecent, getRpm } = require('./lib/health');
7
+ const { loadState, initHealth, isCircuitOpen, recordSuccess, recordFailure, recordRequest, recordTokens, getHealth, getStats, recordRecent, recordRpm, getRecent, getRpm, recordSelection, getLastSelection } = require('./lib/health');
8
8
  const { checkRateLimit } = require('./lib/rateLimit');
9
9
  const { handleDashboard } = require('./lib/dashboard');
10
10
  const { acquire, stats: poolStats } = require('./lib/pool');
@@ -170,7 +170,7 @@ async function handleChatCompletion(req, res, body) {
170
170
  { type: 'text', text: 'Распознай и извлеки ВЕСЬ текст с изображения (ошибка, код, сообщение). Верни только содержимое, без комментариев. Если это код — верни код как есть.' },
171
171
  ...(Array.isArray(body.messages) ? body.messages.flatMap((m) => (Array.isArray(m.content) ? m.content.filter((c) => c && (c.type === 'image_url' || c.type === 'image' || c.type === 'input_image')).map((c) => {
172
172
  // Normalize any image part to the universal image_url format
173
- const url = c.image_url?.url || c.image?.url || (c.image && typeof c.image === 'string' ? c.image : null) || c.url;
173
+ const url = c.image_url?.url || c.image?.url || c.image?.data || (c.image && typeof c.image === 'string' ? c.image : null) || c.url;
174
174
  return url ? { type: 'image_url', image_url: { url } } : null;
175
175
  }).filter(Boolean) : [])) : []),
176
176
  ],
@@ -339,6 +339,7 @@ async function handleChatCompletion(req, res, body) {
339
339
  recordRequest(key, true);
340
340
  logger.request({ model: requestedModel, provider: key, status: 200, latency: result.latency, stream: isStreaming });
341
341
  recordRecent({ model: requestedModel, provider: key, status: 200, latency: result.latency, cached: false });
342
+ recordSelection(key, provider.model, requestedModel);
342
343
 
343
344
  if (isStreaming && result.stream) {
344
345
  res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' });
@@ -550,6 +551,7 @@ const server = http.createServer(async (req, res) => {
550
551
  cache: cache.stats(),
551
552
  limits,
552
553
  pool: poolStats(),
554
+ last_selection: getLastSelection(),
553
555
  }));
554
556
  return;
555
557
  }