opencode-pollinations-plugin 5.6.0-beta.0 → 5.6.0-beta.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/dist/index.js +5 -1
- package/dist/server/commands.js +18 -66
- package/dist/server/generate-config.js +5 -5
- package/dist/server/quota.js +5 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,6 +6,8 @@ import { handleChatCompletion } from './server/proxy.js';
|
|
|
6
6
|
import { createToastHooks, setGlobalClient } from './server/toast.js';
|
|
7
7
|
import { createStatusHooks } from './server/status.js';
|
|
8
8
|
import { createCommandHooks } from './server/commands.js';
|
|
9
|
+
import { createRequire } from 'module';
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
9
11
|
const LOG_FILE = '/tmp/opencode_pollinations_v4.log';
|
|
10
12
|
function log(msg) {
|
|
11
13
|
try {
|
|
@@ -94,9 +96,11 @@ export const PollinationsPlugin = async (ctx) => {
|
|
|
94
96
|
}
|
|
95
97
|
if (!config.provider)
|
|
96
98
|
config.provider = {};
|
|
99
|
+
// Dynamic Provider Name
|
|
100
|
+
const version = require('../../package.json').version;
|
|
97
101
|
config.provider['pollinations'] = {
|
|
98
102
|
id: 'pollinations',
|
|
99
|
-
name:
|
|
103
|
+
name: `Pollinations AI (v${version})`,
|
|
100
104
|
options: { baseURL: localBaseUrl },
|
|
101
105
|
models: modelsObj
|
|
102
106
|
};
|
package/dist/server/commands.js
CHANGED
|
@@ -3,36 +3,6 @@ import { getQuotaStatus } from './quota.js';
|
|
|
3
3
|
import { emitStatusToast } from './toast.js';
|
|
4
4
|
import { getDetailedUsage } from './pollinations-api.js';
|
|
5
5
|
import { generatePollinationsConfig } from './generate-config.js';
|
|
6
|
-
import * as https from 'https';
|
|
7
|
-
function checkEndpoint(ep, key) {
|
|
8
|
-
return new Promise((resolve) => {
|
|
9
|
-
const req = https.request({
|
|
10
|
-
hostname: 'gen.pollinations.ai',
|
|
11
|
-
path: ep,
|
|
12
|
-
method: 'GET',
|
|
13
|
-
headers: { 'Authorization': `Bearer ${key}` }
|
|
14
|
-
}, (res) => {
|
|
15
|
-
if (res.statusCode === 200)
|
|
16
|
-
resolve({ ok: true });
|
|
17
|
-
else
|
|
18
|
-
resolve({ ok: false, status: res.statusCode });
|
|
19
|
-
});
|
|
20
|
-
req.on('error', (e) => resolve({ ok: false, status: e.message || 'Error' }));
|
|
21
|
-
req.setTimeout(10000, () => req.destroy()); // 10s Timeout
|
|
22
|
-
req.end();
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
async function checkKeyPermissions(key) {
|
|
26
|
-
// SEQUENTIAL CHECK (Avoid Rate Limits on Key Verification)
|
|
27
|
-
const endpoints = ['/account/profile', '/account/balance', '/account/usage'];
|
|
28
|
-
for (const ep of endpoints) {
|
|
29
|
-
const res = await checkEndpoint(ep, key);
|
|
30
|
-
if (!res.ok) {
|
|
31
|
-
return { ok: false, reason: `${ep} (${res.status})` };
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return { ok: true };
|
|
35
|
-
}
|
|
36
6
|
// === CONSTANTS & PRICING ===
|
|
37
7
|
const TIER_LIMITS = {
|
|
38
8
|
spore: { pollen: 1, emoji: '🦠' },
|
|
@@ -151,17 +121,9 @@ function handleModeCommand(args) {
|
|
|
151
121
|
error: `Mode invalide: ${mode}. Valeurs: manual, alwaysfree, pro`
|
|
152
122
|
};
|
|
153
123
|
}
|
|
154
|
-
const currentConfig = loadConfig();
|
|
155
|
-
// RESTRICTED KEY LOGIC: Block Managed Modes if key is limited
|
|
156
|
-
if (currentConfig.keyHasAccessToProfile === false && (mode === 'alwaysfree' || mode === 'pro')) {
|
|
157
|
-
return {
|
|
158
|
-
handled: true,
|
|
159
|
-
error: `❌ **Mode Refusé**: Votre clé API est "Limitée" (Pas d'accès Profile/Usage).\n\nLes modes gérés (Pro/AlwaysFree) nécessitent un accès au Quota pour fonctionner.\nRestez en mode **Manual** ou utilisez une clé avec permissions complètes.`
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
124
|
saveConfig({ mode: mode });
|
|
163
|
-
const
|
|
164
|
-
if (
|
|
125
|
+
const config = loadConfig();
|
|
126
|
+
if (config.gui.status !== 'none') {
|
|
165
127
|
emitStatusToast('success', `Mode changé vers: ${mode}`, 'Pollinations Config');
|
|
166
128
|
}
|
|
167
129
|
return {
|
|
@@ -266,45 +228,34 @@ async function handleConnectCommand(args) {
|
|
|
266
228
|
// SUCCESS
|
|
267
229
|
saveConfig({ apiKey: key }); // Don't force mode 'pro'. Let user decide.
|
|
268
230
|
const masked = key.substring(0, 6) + '...';
|
|
269
|
-
//
|
|
231
|
+
// Count Paid Only models found
|
|
270
232
|
const diamondCount = enterpriseModels.filter(m => m.name.includes('💎')).length;
|
|
271
|
-
// CHECK RESTRICTIONS: Strict Check (Usage + Profile + Balance)
|
|
272
|
-
let forcedModeMsg = "";
|
|
273
|
-
let isLimited = false;
|
|
274
|
-
let limitReason = "";
|
|
275
|
-
try {
|
|
276
|
-
// Strict Probe: Must be able to read ALL accounting data
|
|
277
|
-
const check = await checkKeyPermissions(key);
|
|
278
|
-
if (!check.ok) {
|
|
279
|
-
isLimited = true;
|
|
280
|
-
limitReason = check.reason || "Unknown";
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
catch (e) {
|
|
284
|
-
isLimited = true;
|
|
285
|
-
limitReason = e.message;
|
|
286
|
-
}
|
|
287
|
-
// If Limited -> FORCE MANUAL
|
|
288
|
-
if (isLimited) {
|
|
289
|
-
saveConfig({ apiKey: key, mode: 'manual', keyHasAccessToProfile: false });
|
|
290
|
-
forcedModeMsg = `\n⚠️ **Clé Limitée** (Echec: ${limitReason}) -> Mode **MANUAL** forcé.\n*Requis pour mode Auto: Profile, Balance & Usage.*`;
|
|
291
|
-
}
|
|
292
|
-
else {
|
|
293
|
-
saveConfig({ apiKey: key, keyHasAccessToProfile: true }); // Let user keep current mode or default
|
|
294
|
-
}
|
|
295
233
|
emitStatusToast('success', `Clé Valide! (${enterpriseModels.length} modèles Pro débloqués)`, 'Pollinations Config');
|
|
296
234
|
return {
|
|
297
235
|
handled: true,
|
|
298
|
-
response: `✅ **Connexion Réussie!**\n- Clé: \`${masked}\`\n- Modèles Débloqués: ${enterpriseModels.length} (dont ${diamondCount} 💎 Paid)
|
|
236
|
+
response: `✅ **Connexion Réussie!**\n- Clé: \`${masked}\`\n- Mode: **PRO** (Activé)\n- Modèles Débloqués: ${enterpriseModels.length} (dont ${diamondCount} 💎 Paid)`
|
|
299
237
|
};
|
|
300
238
|
}
|
|
301
239
|
else {
|
|
302
240
|
// FAILURE (Valid JSON but no Enterprise models - likely Invalid Key or Free plan only?)
|
|
241
|
+
// If key is invalid, generatePollinationsConfig usually returns fallback free models BUT
|
|
242
|
+
// we specifically checked 'enter/'. If 0 enterprise models found for a *provided* key, it's suspicious.
|
|
243
|
+
// Actually config generator returns Free models + Enter models if key works.
|
|
244
|
+
// If key is BAD, fetchJson throws/logs error, and returns fallbacks (Enter GPT-4o Fallback).
|
|
245
|
+
// Wait, generate-config falls back to providing a list containing "[Enter] GPT-4o (Fallback)" if fetch failed.
|
|
246
|
+
// So we need to detect if it's a "REAL" fetch or a "FALLBACK" fetch.
|
|
247
|
+
// The fallback models have `variants: {}` usually, but real ones might too.
|
|
248
|
+
// A better check: The fallback list is hardcoded in generate-config.ts catch block.
|
|
249
|
+
// Let's modify generate-config to return EMPTY list on error?
|
|
250
|
+
// Or just check if the returned models work?
|
|
251
|
+
// Simplest: If `generatePollinationsConfig` returns any model starting with `enter/` that includes "(Fallback)" in name, we assume failure?
|
|
252
|
+
// "GPT-4o (Fallback)" is the name.
|
|
303
253
|
const isFallback = models.some(m => m.name.includes('(Fallback)') && m.id.startsWith('enter/'));
|
|
304
254
|
if (isFallback) {
|
|
305
255
|
throw new Error("Clé rejetée par l'API (Accès refusé ou invalide).");
|
|
306
256
|
}
|
|
307
257
|
// If we are here, we got no enter models, or empty list?
|
|
258
|
+
// If key is valid but has no access?
|
|
308
259
|
throw new Error("Aucun modèle Enterprise détecté pour cette clé.");
|
|
309
260
|
}
|
|
310
261
|
}
|
|
@@ -328,6 +279,7 @@ function handleConfigCommand(args) {
|
|
|
328
279
|
};
|
|
329
280
|
}
|
|
330
281
|
if (key === 'toast_verbosity' && value) {
|
|
282
|
+
// BACKWARD COMPAT (Maps to Status GUI)
|
|
331
283
|
if (!['none', 'alert', 'all'].includes(value)) {
|
|
332
284
|
return { handled: true, error: 'Valeurs: none, alert, all' };
|
|
333
285
|
}
|
|
@@ -85,11 +85,11 @@ export async function generatePollinationsConfig(forceApiKey, forceStrict = fals
|
|
|
85
85
|
log(`[ConfigGen] Force-injecting free/gemini.`);
|
|
86
86
|
modelsOutput.push({ id: "free/gemini", name: "[Free] Gemini Flash (Force)", object: "model", variants: {} });
|
|
87
87
|
}
|
|
88
|
-
// ALIAS for
|
|
89
|
-
const hasGeminiAlias = modelsOutput.find(m => m.id === 'pollinations/free/gemini');
|
|
90
|
-
if (!hasGeminiAlias) {
|
|
91
|
-
|
|
92
|
-
}
|
|
88
|
+
// ALIAS Removed for Clean Config
|
|
89
|
+
// const hasGeminiAlias = modelsOutput.find(m => m.id === 'pollinations/free/gemini');
|
|
90
|
+
// if (!hasGeminiAlias) {
|
|
91
|
+
// modelsOutput.push({ id: "pollinations/free/gemini", name: "[Free] Gemini Flash (Alias)", object: "model", variants: {} });
|
|
92
|
+
// }
|
|
93
93
|
// 2. ENTERPRISE UNIVERSE
|
|
94
94
|
if (effectiveKey && effectiveKey.length > 5 && effectiveKey !== 'dummy') {
|
|
95
95
|
try {
|
package/dist/server/quota.js
CHANGED
|
@@ -45,11 +45,11 @@ export async function getQuotaStatus(forceRefresh = false) {
|
|
|
45
45
|
try {
|
|
46
46
|
logQuota("Fetching Quota Data...");
|
|
47
47
|
// Fetch parallèle using HTTPS helper
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
const [profileRes, balanceRes, usageRes] = await Promise.all([
|
|
49
|
+
fetchAPI('/account/profile', config.apiKey),
|
|
50
|
+
fetchAPI('/account/balance', config.apiKey),
|
|
51
|
+
fetchAPI('/account/usage', config.apiKey)
|
|
52
|
+
]);
|
|
53
53
|
logQuota(`Fetch Success. Tier: ${profileRes.tier}, Balance: ${balanceRes.balance}`);
|
|
54
54
|
const profile = profileRes;
|
|
55
55
|
const balance = balanceRes.balance;
|
package/package.json
CHANGED