opencode-pollinations-plugin 5.8.4-beta.14 → 5.8.4-beta.16
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 +4 -2
- package/dist/server/commands.js +9 -19
- package/dist/server/generate-config.d.ts +29 -1
- package/dist/server/generate-config.js +91 -201
- package/dist/server/proxy.js +8 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,9 +10,11 @@
|
|
|
10
10
|
|
|
11
11
|
<div align="center">
|
|
12
12
|
|
|
13
|
-

|
|
14
14
|

|
|
15
|
-

|
|
16
|
+
|
|
17
|
+
[📜 View Changelog](./CHANGELOG.md) | [🛣️ Roadmap](./ROADMAP.md)
|
|
16
18
|
|
|
17
19
|
</div>
|
|
18
20
|
|
package/dist/server/commands.js
CHANGED
|
@@ -303,15 +303,15 @@ async function handleConnectCommand(args) {
|
|
|
303
303
|
// 1. Universal Validation (No Syntax Check) - Functional Check
|
|
304
304
|
emitStatusToast('info', 'Vérification de la clé...', 'Pollinations Config');
|
|
305
305
|
try {
|
|
306
|
-
const models = await generatePollinationsConfig(key
|
|
307
|
-
// 2. Check if we got
|
|
308
|
-
const
|
|
309
|
-
if (
|
|
306
|
+
const models = await generatePollinationsConfig(key);
|
|
307
|
+
// 2. Check if we got real models (not just connect placeholder)
|
|
308
|
+
const realModels = models.filter(m => m.id !== 'connect');
|
|
309
|
+
if (realModels.length > 0) {
|
|
310
310
|
// SUCCESS
|
|
311
311
|
saveConfig({ apiKey: key }); // Don't force mode 'pro'. Let user decide.
|
|
312
312
|
const masked = key.substring(0, 6) + '...';
|
|
313
313
|
// Count Paid Only models found
|
|
314
|
-
const diamondCount =
|
|
314
|
+
const diamondCount = realModels.filter(m => m.name.includes('💎')).length;
|
|
315
315
|
// CHECK RESTRICTIONS: Strict Check (Usage + Profile + Balance)
|
|
316
316
|
let forcedModeMsg = "";
|
|
317
317
|
let isLimited = false;
|
|
@@ -336,10 +336,10 @@ async function handleConnectCommand(args) {
|
|
|
336
336
|
else {
|
|
337
337
|
saveConfig({ apiKey: key, keyHasAccessToProfile: true }); // Let user keep current mode or default
|
|
338
338
|
}
|
|
339
|
-
emitStatusToast('success', `Clé Valide! (${
|
|
339
|
+
emitStatusToast('success', `Clé Valide! (${realModels.length} modèles débloqués)`, 'Pollinations Config');
|
|
340
340
|
return {
|
|
341
341
|
handled: true,
|
|
342
|
-
response: `✅ **Connexion Réussie!**\n- Clé: \`${masked}\`\n- Modèles Débloqués: ${
|
|
342
|
+
response: `✅ **Connexion Réussie!**\n- Clé: \`${masked}\`\n- Modèles Débloqués: ${realModels.length} (dont ${diamondCount} 💎 Paid)${forcedModeMsg}`
|
|
343
343
|
};
|
|
344
344
|
}
|
|
345
345
|
else {
|
|
@@ -351,18 +351,8 @@ async function handleConnectCommand(args) {
|
|
|
351
351
|
// Wait, generate-config falls back to providing a list containing "[Enter] GPT-4o (Fallback)" if fetch failed.
|
|
352
352
|
// So we need to detect if it's a "REAL" fetch or a "FALLBACK" fetch.
|
|
353
353
|
// The fallback models have `variants: {}` usually, but real ones might too.
|
|
354
|
-
//
|
|
355
|
-
|
|
356
|
-
// Or just check if the returned models work?
|
|
357
|
-
// Simplest: If `generatePollinationsConfig` returns any model starting with `enter/` that includes "(Fallback)" in name, we assume failure?
|
|
358
|
-
// "GPT-4o (Fallback)" is the name.
|
|
359
|
-
const isFallback = models.some(m => m.name.includes('(Fallback)') && m.id.startsWith('enter/'));
|
|
360
|
-
if (isFallback) {
|
|
361
|
-
throw new Error("Clé rejetée par l'API (Accès refusé ou invalide).");
|
|
362
|
-
}
|
|
363
|
-
// If we are here, we got no enter models, or empty list?
|
|
364
|
-
// If key is valid but has no access?
|
|
365
|
-
throw new Error("Aucun modèle Enterprise détecté pour cette clé.");
|
|
354
|
+
// v6.0: No fallback prefix check needed. If models is empty (only connect), key is invalid.
|
|
355
|
+
throw new Error("Aucun modèle détecté pour cette clé. Clé invalide ou expirée.");
|
|
366
356
|
}
|
|
367
357
|
}
|
|
368
358
|
catch (e) {
|
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate-config.ts - v6.0 Simplified
|
|
3
|
+
*
|
|
4
|
+
* Single endpoint: gen.pollinations.ai/text/models
|
|
5
|
+
* No more Free tier, no cache ETag, no prefixes
|
|
6
|
+
*/
|
|
7
|
+
export interface PollinationsModel {
|
|
8
|
+
name: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
type?: string;
|
|
11
|
+
tools?: boolean;
|
|
12
|
+
reasoning?: boolean;
|
|
13
|
+
context?: number;
|
|
14
|
+
context_window?: number;
|
|
15
|
+
input_modalities?: string[];
|
|
16
|
+
output_modalities?: string[];
|
|
17
|
+
paid_only?: boolean;
|
|
18
|
+
vision?: boolean;
|
|
19
|
+
audio?: boolean;
|
|
20
|
+
pricing?: {
|
|
21
|
+
promptTextTokens?: number;
|
|
22
|
+
completionTextTokens?: number;
|
|
23
|
+
promptImageTokens?: number;
|
|
24
|
+
promptAudioTokens?: number;
|
|
25
|
+
completionAudioTokens?: number;
|
|
26
|
+
};
|
|
27
|
+
[key: string]: any;
|
|
28
|
+
}
|
|
1
29
|
interface OpenCodeModel {
|
|
2
30
|
id: string;
|
|
3
31
|
name: string;
|
|
@@ -12,5 +40,5 @@ interface OpenCodeModel {
|
|
|
12
40
|
};
|
|
13
41
|
tool_call?: boolean;
|
|
14
42
|
}
|
|
15
|
-
export declare function generatePollinationsConfig(forceApiKey?: string
|
|
43
|
+
export declare function generatePollinationsConfig(forceApiKey?: string): Promise<OpenCodeModel[]>;
|
|
16
44
|
export {};
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate-config.ts - v6.0 Simplified
|
|
3
|
+
*
|
|
4
|
+
* Single endpoint: gen.pollinations.ai/text/models
|
|
5
|
+
* No more Free tier, no cache ETag, no prefixes
|
|
6
|
+
*/
|
|
1
7
|
import * as https from 'https';
|
|
2
8
|
import * as fs from 'fs';
|
|
3
|
-
import * as os from 'os';
|
|
4
|
-
import * as path from 'path';
|
|
5
9
|
import { loadConfig } from './config.js';
|
|
6
|
-
const HOMEDIR = os.homedir();
|
|
7
|
-
const CONFIG_DIR_POLLI = path.join(HOMEDIR, '.pollinations');
|
|
8
|
-
const CACHE_FILE = path.join(CONFIG_DIR_POLLI, 'models-cache.json');
|
|
9
|
-
// --- CONSTANTS ---
|
|
10
|
-
// Seed from models-seed.ts
|
|
11
|
-
import { FREE_MODELS_SEED } from './models-seed.js';
|
|
12
10
|
// --- LOGGING ---
|
|
13
11
|
const LOG_FILE = '/tmp/opencode_pollinations_config.log';
|
|
14
12
|
function log(msg) {
|
|
@@ -16,44 +14,28 @@ function log(msg) {
|
|
|
16
14
|
const ts = new Date().toISOString();
|
|
17
15
|
if (!fs.existsSync(LOG_FILE))
|
|
18
16
|
fs.writeFileSync(LOG_FILE, '');
|
|
19
|
-
fs.appendFileSync(LOG_FILE, `[ConfigGen] ${ts} ${msg}\n`);
|
|
17
|
+
fs.appendFileSync(LOG_FILE, `[ConfigGen v6.0] ${ts} ${msg}\n`);
|
|
20
18
|
}
|
|
21
19
|
catch (e) { }
|
|
22
20
|
}
|
|
23
21
|
// --- NETWORK HELPER ---
|
|
24
|
-
function fetchHead(url) {
|
|
25
|
-
return new Promise((resolve) => {
|
|
26
|
-
// Use Node.js native https check for minimal overhead
|
|
27
|
-
const req = https.request(url, { method: 'HEAD', timeout: 5000 }, (res) => {
|
|
28
|
-
resolve(res.headers['etag'] || null);
|
|
29
|
-
});
|
|
30
|
-
req.on('error', () => resolve(null));
|
|
31
|
-
req.on('timeout', () => { req.destroy(); resolve(null); });
|
|
32
|
-
req.end();
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
22
|
function fetchJson(url, headers = {}) {
|
|
36
23
|
return new Promise((resolve, reject) => {
|
|
37
24
|
const finalHeaders = {
|
|
38
25
|
...headers,
|
|
39
|
-
'User-Agent': 'Mozilla/5.0 (compatible; OpenCode/
|
|
26
|
+
'User-Agent': 'Mozilla/5.0 (compatible; OpenCode-Pollinations/6.0; +https://opencode.ai)'
|
|
40
27
|
};
|
|
41
28
|
const req = https.get(url, { headers: finalHeaders }, (res) => {
|
|
42
|
-
const etag = res.headers['etag'];
|
|
43
29
|
let data = '';
|
|
44
30
|
res.on('data', chunk => data += chunk);
|
|
45
31
|
res.on('end', () => {
|
|
46
32
|
try {
|
|
47
33
|
const json = JSON.parse(data);
|
|
48
|
-
// HACK: Attach ETag to the object to pass it up
|
|
49
|
-
if (etag && typeof json === 'object') {
|
|
50
|
-
Object.defineProperty(json, '_etag', { value: etag, enumerable: false, writable: true });
|
|
51
|
-
}
|
|
52
34
|
resolve(json);
|
|
53
35
|
}
|
|
54
36
|
catch (e) {
|
|
55
37
|
log(`JSON Parse Error for ${url}: ${e}`);
|
|
56
|
-
resolve([]);
|
|
38
|
+
resolve([]);
|
|
57
39
|
}
|
|
58
40
|
});
|
|
59
41
|
});
|
|
@@ -67,218 +49,126 @@ function fetchJson(url, headers = {}) {
|
|
|
67
49
|
});
|
|
68
50
|
});
|
|
69
51
|
}
|
|
70
|
-
function loadCache() {
|
|
71
|
-
try {
|
|
72
|
-
if (fs.existsSync(CACHE_FILE)) {
|
|
73
|
-
const content = fs.readFileSync(CACHE_FILE, 'utf-8');
|
|
74
|
-
return JSON.parse(content);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
catch (e) {
|
|
78
|
-
log(`Error loading cache: ${e}`);
|
|
79
|
-
}
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
function saveCache(models, etag) {
|
|
83
|
-
try {
|
|
84
|
-
const data = {
|
|
85
|
-
timestamp: Date.now(),
|
|
86
|
-
etag: etag,
|
|
87
|
-
models: models
|
|
88
|
-
};
|
|
89
|
-
if (!fs.existsSync(CONFIG_DIR_POLLI))
|
|
90
|
-
fs.mkdirSync(CONFIG_DIR_POLLI, { recursive: true });
|
|
91
|
-
fs.writeFileSync(CACHE_FILE, JSON.stringify(data, null, 2));
|
|
92
|
-
}
|
|
93
|
-
catch (e) {
|
|
94
|
-
log(`Error saving cache: ${e}`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
52
|
// --- GENERATOR LOGIC ---
|
|
98
|
-
export async function generatePollinationsConfig(forceApiKey
|
|
53
|
+
export async function generatePollinationsConfig(forceApiKey) {
|
|
99
54
|
const config = loadConfig();
|
|
100
55
|
const modelsOutput = [];
|
|
101
|
-
log(`Starting Configuration (v5.8.4-Debug-Tools)...`);
|
|
102
56
|
const effectiveKey = forceApiKey || config.apiKey;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (remoteEtag && remoteEtag !== cache.etag) {
|
|
117
|
-
log(`Update Detected! (Remote: ${remoteEtag} != Local: ${cache.etag}). Forcing refresh.`);
|
|
118
|
-
shouldFetch = true;
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
log('Cache is clean (ETag match). No refresh needed.');
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
catch (e) {
|
|
125
|
-
log(`Smart Refresh check failed: ${e}. Ignoring.`);
|
|
126
|
-
}
|
|
57
|
+
log(`Starting Configuration v6.0...`);
|
|
58
|
+
log(`API Key present: ${!!effectiveKey}`);
|
|
59
|
+
// 1. ALWAYS add "connect" placeholder model
|
|
60
|
+
modelsOutput.push({
|
|
61
|
+
id: 'connect',
|
|
62
|
+
name: '🔑 Connect your Pollinations Account',
|
|
63
|
+
modalities: { input: ['text'], output: ['text'] },
|
|
64
|
+
tool_call: false
|
|
65
|
+
});
|
|
66
|
+
// 2. If no API key, return only connect placeholder
|
|
67
|
+
if (!effectiveKey || effectiveKey.length < 5 || effectiveKey === 'dummy') {
|
|
68
|
+
log('No API key configured. Returning connect placeholder only.');
|
|
69
|
+
return modelsOutput;
|
|
127
70
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
catch (e) {
|
|
144
|
-
log(`Fetch failed: ${e}.`);
|
|
145
|
-
isOffline = true;
|
|
146
|
-
// Fallback Logic
|
|
147
|
-
if (cache && cache.models.length > 0) {
|
|
148
|
-
log('Using cached models (Offline).');
|
|
149
|
-
freeModelsList = cache.models;
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
log('Using DEFAULT SEED models (Offline + No Cache).');
|
|
153
|
-
freeModelsList = FREE_MODELS_SEED;
|
|
71
|
+
// 3. Fetch models from Enterprise endpoint
|
|
72
|
+
try {
|
|
73
|
+
log('Fetching models from gen.pollinations.ai/text/models...');
|
|
74
|
+
const rawList = await fetchJson('https://gen.pollinations.ai/text/models', {
|
|
75
|
+
'Authorization': `Bearer ${effectiveKey}`
|
|
76
|
+
});
|
|
77
|
+
const modelsList = Array.isArray(rawList) ? rawList : (rawList.data || []);
|
|
78
|
+
log(`Received ${modelsList.length} models from API`);
|
|
79
|
+
modelsList.forEach((m) => {
|
|
80
|
+
// Skip models without tools support (except nomnom - special handling)
|
|
81
|
+
if (m.tools === false && m.name !== 'nomnom') {
|
|
82
|
+
log(`Skipping ${m.name} (no tools)`);
|
|
83
|
+
return;
|
|
154
84
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
log(
|
|
159
|
-
|
|
85
|
+
const mapped = mapModel(m);
|
|
86
|
+
modelsOutput.push(mapped);
|
|
87
|
+
});
|
|
88
|
+
log(`Total models registered: ${modelsOutput.length}`);
|
|
89
|
+
log(`Model IDs: ${modelsOutput.map(m => m.id).join(', ')}`);
|
|
160
90
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
//
|
|
164
|
-
// If we use cache because it's valid (Skipped fetch), we don't tag (Offline).
|
|
165
|
-
const suffix = isOffline ? ' (Offline)' : '';
|
|
166
|
-
const mapped = mapModel(m, 'free-', `[Free] `, suffix);
|
|
167
|
-
modelsOutput.push(mapped);
|
|
168
|
-
});
|
|
169
|
-
// 2. ENTERPRISE UNIVERSE
|
|
170
|
-
if (effectiveKey && effectiveKey.length > 5 && effectiveKey !== 'dummy') {
|
|
171
|
-
try {
|
|
172
|
-
const enterListRaw = await fetchJson('https://gen.pollinations.ai/text/models', {
|
|
173
|
-
'Authorization': `Bearer ${effectiveKey}`
|
|
174
|
-
});
|
|
175
|
-
const enterList = Array.isArray(enterListRaw) ? enterListRaw : (enterListRaw.data || []);
|
|
176
|
-
enterList.forEach((m) => {
|
|
177
|
-
if (m.tools === false)
|
|
178
|
-
return;
|
|
179
|
-
const mapped = mapModel(m, 'enter-', '[Enter] ');
|
|
180
|
-
modelsOutput.push(mapped);
|
|
181
|
-
});
|
|
182
|
-
log(`Total models (Free+Pro): ${modelsOutput.length}`);
|
|
183
|
-
log(`Generated IDs: ${modelsOutput.map(m => m.id).join(', ')}`);
|
|
184
|
-
}
|
|
185
|
-
catch (e) {
|
|
186
|
-
log(`Error fetching Enterprise models: ${e}`);
|
|
187
|
-
if (forceStrict)
|
|
188
|
-
throw e;
|
|
189
|
-
// STRICT: No Fallback for Enterprise. If API is down, we have 0 Enter models.
|
|
190
|
-
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
log(`Error fetching models: ${e.message}`);
|
|
93
|
+
// Return connect placeholder only on error
|
|
191
94
|
}
|
|
192
95
|
return modelsOutput;
|
|
193
96
|
}
|
|
194
97
|
// --- UTILS ---
|
|
195
98
|
function getCapabilityIcons(raw) {
|
|
196
99
|
const icons = [];
|
|
197
|
-
|
|
100
|
+
// Vision: check both input_modalities and legacy vision flag
|
|
101
|
+
if (raw.input_modalities?.includes('image') || raw.vision === true) {
|
|
198
102
|
icons.push('👁️');
|
|
199
|
-
|
|
103
|
+
}
|
|
104
|
+
// Audio input
|
|
105
|
+
if (raw.input_modalities?.includes('audio') || raw.audio === true) {
|
|
200
106
|
icons.push('🎙️');
|
|
201
|
-
|
|
107
|
+
}
|
|
108
|
+
// Audio output
|
|
109
|
+
if (raw.output_modalities?.includes('audio')) {
|
|
202
110
|
icons.push('🔊');
|
|
203
|
-
|
|
111
|
+
}
|
|
112
|
+
// Reasoning
|
|
113
|
+
if (raw.reasoning === true) {
|
|
204
114
|
icons.push('🧠');
|
|
205
|
-
|
|
115
|
+
}
|
|
116
|
+
// Search capability
|
|
117
|
+
if (raw.description?.toLowerCase().includes('search') || raw.name?.includes('search')) {
|
|
206
118
|
icons.push('🔍');
|
|
207
|
-
|
|
208
|
-
|
|
119
|
+
}
|
|
120
|
+
// Tools
|
|
121
|
+
if (raw.tools === true) {
|
|
122
|
+
icons.push('🛠️');
|
|
123
|
+
}
|
|
124
|
+
// Paid only
|
|
125
|
+
if (raw.paid_only === true) {
|
|
126
|
+
icons.push('💎');
|
|
127
|
+
}
|
|
209
128
|
return icons.length > 0 ? ` ${icons.join('')}` : '';
|
|
210
129
|
}
|
|
211
|
-
function formatName(id
|
|
212
|
-
let clean = id.replace(
|
|
130
|
+
function formatName(id) {
|
|
131
|
+
let clean = id.replace(/-/g, ' ');
|
|
213
132
|
clean = clean.replace(/\b\w/g, l => l.toUpperCase());
|
|
214
|
-
if (!censored)
|
|
215
|
-
clean += " (Uncensored)";
|
|
216
133
|
return clean;
|
|
217
134
|
}
|
|
218
|
-
function mapModel(raw
|
|
219
|
-
const rawId = raw.
|
|
220
|
-
|
|
135
|
+
function mapModel(raw) {
|
|
136
|
+
const rawId = raw.name;
|
|
137
|
+
// Build display name
|
|
221
138
|
let baseName = raw.description;
|
|
222
139
|
if (!baseName || baseName === rawId) {
|
|
223
|
-
baseName = formatName(rawId
|
|
140
|
+
baseName = formatName(rawId);
|
|
224
141
|
}
|
|
142
|
+
// Truncate after first " - "
|
|
225
143
|
if (baseName && baseName.includes(' - ')) {
|
|
226
144
|
baseName = baseName.split(' - ')[0].trim();
|
|
227
145
|
}
|
|
228
|
-
let namePrefixFinal = namePrefix;
|
|
229
|
-
if (raw.paid_only) {
|
|
230
|
-
namePrefixFinal = namePrefix.replace('[Enter]', '[💎 Paid]');
|
|
231
|
-
}
|
|
232
146
|
const capabilityIcons = getCapabilityIcons(raw);
|
|
233
|
-
const finalName = `${
|
|
147
|
+
const finalName = `${baseName}${capabilityIcons}`;
|
|
148
|
+
// Determine modalities for OpenCode
|
|
149
|
+
const inputMods = raw.input_modalities || ['text'];
|
|
150
|
+
const outputMods = raw.output_modalities || ['text'];
|
|
234
151
|
const modelObj = {
|
|
235
|
-
id:
|
|
152
|
+
id: rawId, // No prefix! Direct model ID
|
|
236
153
|
name: finalName,
|
|
237
|
-
// object: 'model',
|
|
238
|
-
// variants: {}, // POTENTIAL SCHEMA VIOLATION
|
|
239
154
|
modalities: {
|
|
240
|
-
input:
|
|
241
|
-
output:
|
|
155
|
+
input: inputMods,
|
|
156
|
+
output: outputMods
|
|
242
157
|
},
|
|
243
|
-
tool_call:
|
|
158
|
+
tool_call: raw.tools === true && rawId !== 'nomnom' // NomNom: no tools
|
|
244
159
|
};
|
|
245
|
-
//
|
|
246
|
-
/*
|
|
247
|
-
if (raw.reasoning === true || rawId.includes('thinking') || rawId.includes('reasoning')) {
|
|
248
|
-
modelObj.variants = { ...modelObj.variants, high_reasoning: { options: { reasoningEffort: "high", budgetTokens: 16000 } } };
|
|
249
|
-
}
|
|
250
|
-
if (rawId.includes('gemini') && !rawId.includes('fast')) {
|
|
251
|
-
if (!modelObj.variants.high_reasoning && (rawId === 'gemini' || rawId === 'gemini-large')) {
|
|
252
|
-
modelObj.variants.high_reasoning = { options: { reasoningEffort: "high", budgetTokens: 16000 } };
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
if (rawId.includes('claude') || rawId.includes('mistral') || rawId.includes('llama')) {
|
|
256
|
-
modelObj.variants.safe_tokens = { options: { maxTokens: 8000 } };
|
|
257
|
-
}
|
|
258
|
-
*/
|
|
160
|
+
// Model-specific limits
|
|
259
161
|
if (rawId.includes('nova')) {
|
|
260
|
-
|
|
261
|
-
modelObj.limit = { output: 8000, context: 128000 };
|
|
262
|
-
}
|
|
263
|
-
if (rawId.includes('nomnom') || rawId.includes('scrape')) {
|
|
264
|
-
modelObj.limit = { output: 2048, context: 32768 };
|
|
265
|
-
}
|
|
266
|
-
if (rawId.includes('chicky') || rawId.includes('mistral')) {
|
|
267
|
-
modelObj.limit = { output: 4096, context: 8192 };
|
|
268
|
-
modelObj.options = { ...modelObj.options, maxTokens: 4096 };
|
|
269
|
-
log(`[LimitConfig] Applied strict limit to ${fullId}: output=4096, context=8192`);
|
|
270
|
-
}
|
|
271
|
-
/*
|
|
272
|
-
if (rawId.includes('fast') || rawId.includes('flash')) {
|
|
273
|
-
if (!rawId.includes('gemini')) {
|
|
274
|
-
modelObj.variants.speed = { options: { thinking: { disabled: true } } };
|
|
275
|
-
}
|
|
162
|
+
modelObj.limit = { output: 8000, context: 128000 };
|
|
276
163
|
}
|
|
277
|
-
|
|
164
|
+
if (rawId === 'nomnom') {
|
|
165
|
+
modelObj.limit = { output: 2048, context: 32768 };
|
|
166
|
+
modelObj.tool_call = false; // NomNom is a router, no external tools
|
|
278
167
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
168
|
+
if (rawId.includes('chicky') || rawId.includes('mistral')) {
|
|
169
|
+
modelObj.limit = { output: 4096, context: 8192 };
|
|
170
|
+
modelObj.options = { maxTokens: 4096 };
|
|
282
171
|
}
|
|
172
|
+
log(`[Mapped] ${modelObj.id} → ${modelObj.name} | tools=${modelObj.tool_call} | modalities=${JSON.stringify(modelObj.modalities)}`);
|
|
283
173
|
return modelObj;
|
|
284
174
|
}
|
package/dist/server/proxy.js
CHANGED
|
@@ -478,6 +478,14 @@ export async function handleChatCompletion(req, res, bodyRaw) {
|
|
|
478
478
|
log(`[Proxy] Gemini Logic: Tools=${proxyBody.tools ? proxyBody.tools.length : 'REMOVED'}, Stops NOT Injected.`);
|
|
479
479
|
}
|
|
480
480
|
}
|
|
481
|
+
// B5. BEDROCK TOKEN LIMIT FIX
|
|
482
|
+
if (actualModel.includes("chicky") || actualModel.includes("mistral")) {
|
|
483
|
+
// Force max_tokens if not present or too high (Bedrock outputs usually max 4k, context 8k+ but strict check)
|
|
484
|
+
if (!proxyBody.max_tokens || proxyBody.max_tokens > 4096) {
|
|
485
|
+
proxyBody.max_tokens = 4096;
|
|
486
|
+
log(`[Proxy] Enforcing max_tokens=4096 for ${actualModel} (Bedrock Limit)`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
481
489
|
// C. GEMINI ID BACKTRACKING & SIGNATURE
|
|
482
490
|
if ((actualModel.includes("gemini") || actualModel === "nomnom") && proxyBody.messages) {
|
|
483
491
|
const lastMsg = proxyBody.messages[proxyBody.messages.length - 1];
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-pollinations-plugin",
|
|
3
3
|
"displayName": "Pollinations AI (V5.6)",
|
|
4
|
-
"version": "5.8.4-beta.
|
|
4
|
+
"version": "5.8.4-beta.16",
|
|
5
5
|
"description": "Native Pollinations.ai Provider Plugin for OpenCode",
|
|
6
6
|
"publisher": "pollinations",
|
|
7
7
|
"repository": {
|
|
@@ -55,4 +55,4 @@
|
|
|
55
55
|
"@types/node": "^20.0.0",
|
|
56
56
|
"typescript": "^5.0.0"
|
|
57
57
|
}
|
|
58
|
-
}
|
|
58
|
+
}
|