opencode-pollinations-plugin 5.4.8 → 5.4.9
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/server/generate-config.js +26 -1
- package/dist/server/proxy.js +37 -0
- package/package.json +1 -1
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import * as https from 'https';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import * as path from 'path';
|
|
3
5
|
import { loadConfig } from './config.js';
|
|
6
|
+
const HOMEDIR = os.homedir();
|
|
7
|
+
const CONFIG_DIR_POLLI = path.join(HOMEDIR, '.pollinations');
|
|
8
|
+
const CONFIG_FILE = path.join(CONFIG_DIR_POLLI, 'config.json');
|
|
4
9
|
// --- LOGGING ---
|
|
5
10
|
const LOG_FILE = '/tmp/opencode_pollinations_config.log';
|
|
6
11
|
function log(msg) {
|
|
@@ -92,18 +97,34 @@ export async function generatePollinationsConfig(forceApiKey) {
|
|
|
92
97
|
'Authorization': `Bearer ${effectiveKey}`
|
|
93
98
|
});
|
|
94
99
|
const enterList = Array.isArray(enterListRaw) ? enterListRaw : (enterListRaw.data || []);
|
|
100
|
+
const paidModels = [];
|
|
95
101
|
enterList.forEach((m) => {
|
|
96
102
|
if (m.tools === false)
|
|
97
103
|
return;
|
|
98
104
|
const mapped = mapModel(m, 'enter/', '[Enter] ');
|
|
99
105
|
modelsOutput.push(mapped);
|
|
106
|
+
if (m.paid_only) {
|
|
107
|
+
paidModels.push(mapped.id.replace('enter/', '')); // Store bare ID "gemini-large"
|
|
108
|
+
}
|
|
100
109
|
});
|
|
101
110
|
log(`Total models (Free+Pro): ${modelsOutput.length}`);
|
|
111
|
+
// Save Paid Models List for Proxy
|
|
112
|
+
try {
|
|
113
|
+
const paidListPath = path.join(config.gui ? path.dirname(CONFIG_FILE) : '/tmp', 'pollinations-paid-models.json');
|
|
114
|
+
// Ensure dir exists (re-use config dir logic from config.ts if possible, or just assume it exists since config loaded)
|
|
115
|
+
if (fs.existsSync(path.dirname(paidListPath))) {
|
|
116
|
+
fs.writeFileSync(paidListPath, JSON.stringify(paidModels));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
log(`Error saving paid models list: ${e}`);
|
|
121
|
+
}
|
|
102
122
|
}
|
|
103
123
|
catch (e) {
|
|
104
124
|
log(`Error fetching Enterprise models: ${e}`);
|
|
105
125
|
// Fallback Robust for Enterprise (User has Key but discovery failed)
|
|
106
126
|
modelsOutput.push({ id: "enter/gpt-4o", name: "[Enter] GPT-4o (Fallback)", object: "model", variants: {} });
|
|
127
|
+
// ...
|
|
107
128
|
modelsOutput.push({ id: "enter/claude-3-5-sonnet", name: "[Enter] Claude 3.5 Sonnet (Fallback)", object: "model", variants: {} });
|
|
108
129
|
modelsOutput.push({ id: "enter/deepseek-reasoner", name: "[Enter] DeepSeek R1 (Fallback)", object: "model", variants: {} });
|
|
109
130
|
}
|
|
@@ -123,7 +144,11 @@ function mapModel(raw, prefix, namePrefix) {
|
|
|
123
144
|
if (baseName && baseName.includes(' - ')) {
|
|
124
145
|
baseName = baseName.split(' - ')[0].trim();
|
|
125
146
|
}
|
|
126
|
-
|
|
147
|
+
let namePrefixFinal = namePrefix;
|
|
148
|
+
if (raw.paid_only) {
|
|
149
|
+
namePrefixFinal = namePrefix.replace('[Enter]', '[💎 Paid]');
|
|
150
|
+
}
|
|
151
|
+
const finalName = `${namePrefixFinal}${baseName}`;
|
|
127
152
|
const modelObj = {
|
|
128
153
|
id: fullId,
|
|
129
154
|
name: finalName,
|
package/dist/server/proxy.js
CHANGED
|
@@ -220,6 +220,43 @@ export async function handleChatCompletion(req, res, bodyRaw) {
|
|
|
220
220
|
isEnterprise = false;
|
|
221
221
|
actualModel = actualModel.replace('free/', '');
|
|
222
222
|
}
|
|
223
|
+
// A.1 PAID MODEL ENFORCEMENT (V5.5 Strategy)
|
|
224
|
+
// Check dynamic list saved by generate-config.ts
|
|
225
|
+
if (isEnterprise) {
|
|
226
|
+
try {
|
|
227
|
+
const paidListPath = path.join(config.gui ? path.dirname(path.join(process.env.HOME || '/tmp', '.config/opencode/pollinations-signature.json')) : '/tmp', 'pollinations-paid-models.json');
|
|
228
|
+
// Wait, logic above for config path is messy. Let's use standard path logic:
|
|
229
|
+
// config.ts uses ~/.pollinations/config.json usually.
|
|
230
|
+
// generate-config uses path.join(config.gui ? path.dirname(CONFIG_FILE) : '/tmp')
|
|
231
|
+
// Let's rely on standard ~/.pollinations location if possible, or try both.
|
|
232
|
+
const homedir = process.env.HOME || '/tmp';
|
|
233
|
+
const standardPaidPath = path.join(homedir, '.pollinations', 'pollinations-paid-models.json');
|
|
234
|
+
if (fs.existsSync(standardPaidPath)) {
|
|
235
|
+
const paidModels = JSON.parse(fs.readFileSync(standardPaidPath, 'utf-8'));
|
|
236
|
+
if (paidModels.includes(actualModel)) {
|
|
237
|
+
// IT IS A PAID ONLY MODEL.
|
|
238
|
+
// STRICT CHECK: Wallet > 0 required. (Not just Tier)
|
|
239
|
+
if (quota.walletBalance <= 0.001) { // Floating point safety
|
|
240
|
+
log(`[SafetyNet] Paid Only Model (${actualModel}) requested but Wallet is Empty ($${quota.walletBalance}). BLOCKING.`);
|
|
241
|
+
// Immediate Block or Fallback?
|
|
242
|
+
// Text says: "💎 Paid Only models require purchased pollen only"
|
|
243
|
+
// Blocking is safer/clearer than falling back to a free model which might not be what the user expects for a "Pro" feature?
|
|
244
|
+
// Actually, Fallback to Free is usually better for UX if configured, BUT for specific "Paid Only" requests, the user explicitly chose a powerful model.
|
|
245
|
+
// Falling back to Mistral might be confusing if they asked for Gemini-Large.
|
|
246
|
+
// BUT we are failing gracefully.
|
|
247
|
+
// Let's Fallback to Free Default and Warn.
|
|
248
|
+
actualModel = config.fallbacks.free.main.replace('free/', '');
|
|
249
|
+
isEnterprise = false;
|
|
250
|
+
isFallbackActive = true;
|
|
251
|
+
fallbackReason = "Paid Only Model requires purchased credits";
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
catch (e) {
|
|
257
|
+
log(`[Proxy] Error checking paid models: ${e}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
223
260
|
// B. SAFETY NETS (The Core V5 Logic)
|
|
224
261
|
if (config.mode === 'alwaysfree') {
|
|
225
262
|
if (isEnterprise) {
|
package/package.json
CHANGED