opencode-pollinations-plugin 6.4.2 → 6.4.4
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/commands.js +7 -1
- package/dist/server/config.d.ts +2 -0
- package/dist/server/config.js +1 -0
- package/dist/server/generate-config.js +4 -4
- package/dist/server/models/worker.js +8 -7
- package/dist/server/proxy.js +7 -1
- package/dist/server/quota.d.ts +6 -0
- package/dist/server/quota.js +48 -1
- package/dist/tools/pollinations/polli_config.js +4 -1
- package/package.json +1 -1
package/dist/server/commands.js
CHANGED
|
@@ -656,6 +656,7 @@ ${t('commands.config.table_divider')}
|
|
|
656
656
|
| **costThreshold**| \`${config.costThreshold ?? 0.15} 🌻\` | ${t('commands.config.costThreshold_role')} | \`/poll config costThreshold <X>\` |
|
|
657
657
|
| **cost_estimator**| \`${config.costEstimator ?? true}\` | ${t('commands.config.cost_estimator_role')} | \`/poll config cost_estimator <true/false>\` |
|
|
658
658
|
| **refillOverride**| \`${config.refillOverride ?? 'auto (déduit)'}\` | Quest Pollen refill horaire | \`/poll config refillOverride <0.01/0.15/0.4/0.8/10>\` |
|
|
659
|
+
| **questStashInFreeMode**| \`${config.questStashInFreeMode ?? true}\` | Compte le stash dans alwaysfree | \`/poll config questStashInFreeMode <true/false>\` |
|
|
659
660
|
| **fallbacks.free.main** | \`${config.fallbacks?.free?.main || 'free/mistral'}\` | ${t('commands.config.fallback_main_role')} | \`/poll fallback <main> <agent>\` |
|
|
660
661
|
| **fallbacks.free.agent** | \`${config.fallbacks?.free?.agent || 'free/openai-fast'}\`| ${t('commands.config.fallback_agent_role')} | \`/poll fallback <main> <agent>\` |
|
|
661
662
|
| **fallbacks.enter.agent** | \`${config.fallbacks?.enter?.agent || 'free/openai-fast'}\`| ${t('commands.config.fallback_enter_role')} | *${t('commands.config.managed_auto')}* |
|
|
@@ -764,9 +765,14 @@ ${t('commands.config.table_divider')}
|
|
|
764
765
|
saveConfig({ refillOverride: override });
|
|
765
766
|
return { handled: true, response: `✅ refillOverride = ${override} 🌻/h` };
|
|
766
767
|
}
|
|
768
|
+
if (key === 'questStashInFreeMode' && value) {
|
|
769
|
+
const enabled = value === 'true';
|
|
770
|
+
saveConfig({ questStashInFreeMode: enabled });
|
|
771
|
+
return { handled: true, response: `✅ questStashInFreeMode = ${enabled}${enabled ? ' (le stash Quest compte comme free)' : ' (seul le refill horaire compte)'}` };
|
|
772
|
+
}
|
|
767
773
|
return {
|
|
768
774
|
handled: true,
|
|
769
|
-
error: `Clé inconnue: ${key}. Clés: status_gui, logs_gui, threshold_tier, threshold_wallet, status_bar, cost_estimator, enablePaidTools, costThreshold, costConfirmationRequired, refillOverride, lang`
|
|
775
|
+
error: `Clé inconnue: ${key}. Clés: status_gui, logs_gui, threshold_tier, threshold_wallet, status_bar, cost_estimator, enablePaidTools, costThreshold, costConfirmationRequired, refillOverride, questStashInFreeMode, lang`
|
|
770
776
|
};
|
|
771
777
|
}
|
|
772
778
|
function handleHelpCommand() {
|
package/dist/server/config.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export interface PollinationsConfigV5 {
|
|
|
29
29
|
statusBar: boolean;
|
|
30
30
|
costEstimator: boolean;
|
|
31
31
|
refillOverride?: number;
|
|
32
|
+
questStashInFreeMode?: boolean;
|
|
32
33
|
lang?: string;
|
|
33
34
|
}
|
|
34
35
|
export declare function loadConfig(): PollinationsConfigV5;
|
|
@@ -60,6 +61,7 @@ export declare function saveConfig(updates: Partial<PollinationsConfigV5>): {
|
|
|
60
61
|
statusBar: boolean;
|
|
61
62
|
costEstimator: boolean;
|
|
62
63
|
refillOverride?: number;
|
|
64
|
+
questStashInFreeMode?: boolean;
|
|
63
65
|
lang?: string;
|
|
64
66
|
};
|
|
65
67
|
export declare function saveKeyToAuthJson(key: string): boolean;
|
package/dist/server/config.js
CHANGED
|
@@ -82,6 +82,7 @@ const DEFAULT_CONFIG_V5 = {
|
|
|
82
82
|
keyHasAccessToProfile: true, // Default true for legacy keys
|
|
83
83
|
statusBar: true,
|
|
84
84
|
costEstimator: true, // Show cost estimates by default
|
|
85
|
+
questStashInFreeMode: true, // Count quest stash as free in alwaysfree
|
|
85
86
|
lang: 'en', // Default language is English
|
|
86
87
|
};
|
|
87
88
|
import { log as logSystem } from './logger.js';
|
|
@@ -87,12 +87,12 @@ export async function generatePollinationsConfig(forceApiKey, forceStrict = fals
|
|
|
87
87
|
const enterList = ModelRegistry.list('text');
|
|
88
88
|
const paidModels = [];
|
|
89
89
|
enterList.forEach((m) => {
|
|
90
|
-
if (m.tools ===
|
|
91
|
-
return; //
|
|
90
|
+
if (m.tools !== true || m.community === true)
|
|
91
|
+
return; // Exclude non-tool and community models
|
|
92
92
|
const mapped = mapModel(m, 'enter/', '');
|
|
93
93
|
modelsOutput.push(mapped);
|
|
94
94
|
if (m.paid_only) {
|
|
95
|
-
paidModels.push(mapped.id.replace('enter/', ''));
|
|
95
|
+
paidModels.push(mapped.id.replace('enter/', ''));
|
|
96
96
|
}
|
|
97
97
|
});
|
|
98
98
|
log(`Total models (Free+Pro): ${modelsOutput.length}`);
|
|
@@ -207,7 +207,7 @@ function mapModel(raw, prefix, namePrefix) {
|
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
// 2. REASONING VARIANTS — format @ai-sdk/openai-compatible: { reasoningEffort: "level" }
|
|
210
|
-
if (raw.reasoning === true || rawId.includes('thinking') || rawId.includes('reasoning')) {
|
|
210
|
+
if (raw.reasoning === true || raw.capabilities?.includes('reasoning') || rawId.includes('thinking') || rawId.includes('reasoning')) {
|
|
211
211
|
modelObj.variants = {
|
|
212
212
|
...modelObj.variants,
|
|
213
213
|
low: { reasoningEffort: 'low' },
|
|
@@ -58,12 +58,11 @@ export class ToolRegistryWorker {
|
|
|
58
58
|
videoTable += `| Modèle | Source I/O | Audio | 1 pollen ≈ | Specs |\n`;
|
|
59
59
|
videoTable += `|--------|------------|-------|------------|-------|\n`;
|
|
60
60
|
for (const m of videoModels) {
|
|
61
|
-
// Estimation pour une vidéo moyenne de 6 secondes
|
|
62
61
|
const cost = estimateVideoCost(m.name, 6);
|
|
63
62
|
const price = cost ? `${per1pollen(cost)} vidéos` : 'inconnu';
|
|
64
|
-
// durationRange et aspectRatios arrivent du fetcher (ou fallback)
|
|
65
63
|
const specs = `${m.durationRange ? m.durationRange.join('-') + 's' : '?s'} / ${m.aspectRatios ? m.aspectRatios.length : '?'} ratios`;
|
|
66
|
-
const
|
|
64
|
+
const isCommunity = m.community === true || m.name.includes('/');
|
|
65
|
+
const badge = isCommunity ? '[👥]' : (m.paid_only ? '[💎 Paid]' : '[🌿 Free]');
|
|
67
66
|
videoTable += `| \`${m.name}\` ${badge} | ${m.supportsI2X ? 'T2V/I2V' : 'T2V'} | ${m.output_modalities?.includes('audio') || m.name === 'grok-video' ? '✅' : '❌'} | ${price} | ${specs} |\n`;
|
|
68
67
|
}
|
|
69
68
|
if (!polliGenVideoTool.description.includes('**🎬 Modèles Vidéo Détectés')) {
|
|
@@ -84,7 +83,8 @@ export class ToolRegistryWorker {
|
|
|
84
83
|
for (const m of imageModels.slice(0, 20)) {
|
|
85
84
|
const cost = estimateImageCost(m.name);
|
|
86
85
|
const price = cost ? `${per1pollen(cost)} images` : 'inconnu';
|
|
87
|
-
const
|
|
86
|
+
const isCommunity = m.community === true || m.name.includes('/');
|
|
87
|
+
const badge = isCommunity ? '[👥]' : (m.paid_only ? '[💎 Paid]' : '[🌿 Free]');
|
|
88
88
|
imageTable += `| \`${m.name}\` ${badge} | ${m.supportsI2X ? '✅' : '❌'} | Standard | ${price} |\n`;
|
|
89
89
|
}
|
|
90
90
|
if (imageModels.length > 20) {
|
|
@@ -105,9 +105,9 @@ export class ToolRegistryWorker {
|
|
|
105
105
|
audioTable += `| Modèle | Durée max | Qualité |\n`;
|
|
106
106
|
audioTable += `|--------|-----------|---------|\n`;
|
|
107
107
|
for (const m of audioModels) {
|
|
108
|
-
const
|
|
108
|
+
const isCommunity = m.community === true || m.name.includes('/');
|
|
109
|
+
const badge = isCommunity ? '[👥]' : (m.paid_only ? '[💎 Paid]' : '[🌿 Free]');
|
|
109
110
|
const duration = m.durationRange ? `${m.durationRange.join('-')}s` : 'Standard';
|
|
110
|
-
// STT Whispers or TTS or Music
|
|
111
111
|
audioTable += `| \`${m.name}\` ${badge} | ${duration} | Standard |\n`;
|
|
112
112
|
}
|
|
113
113
|
if (!polliGenAudioTool.description.includes('**🎵 Modèles Audio/Music Détectés')) {
|
|
@@ -138,7 +138,8 @@ export class ToolRegistryWorker {
|
|
|
138
138
|
searchTable += `| Modèle | Description / Specs |\n`;
|
|
139
139
|
searchTable += `|--------|---------------------|\n`;
|
|
140
140
|
for (const m of searchModels) {
|
|
141
|
-
const
|
|
141
|
+
const isCommunity = m.community === true || m.name.includes('/');
|
|
142
|
+
const badge = isCommunity ? '[👥]' : (m.paid_only ? '[💎 Paid]' : '[🌿 Free]');
|
|
142
143
|
// Clean markdown piping conflicts
|
|
143
144
|
let cleanDesc = m.description.replace(/\|/g, '-');
|
|
144
145
|
// Adding "Specialized" hint
|
package/dist/server/proxy.js
CHANGED
|
@@ -446,7 +446,13 @@ export async function handleChatCompletion(req, res, bodyRaw) {
|
|
|
446
446
|
fallbackReason = t('proxy.warnings.quota_unreachable_msg');
|
|
447
447
|
}
|
|
448
448
|
else {
|
|
449
|
-
const
|
|
449
|
+
const effectiveFree = config.questStashInFreeMode !== false
|
|
450
|
+
? quota.tierRemaining + (quota.questStash || 0)
|
|
451
|
+
: quota.tierRemaining;
|
|
452
|
+
const effectiveLimit = config.questStashInFreeMode !== false
|
|
453
|
+
? quota.tierLimit + (quota.questStash || 0)
|
|
454
|
+
: quota.tierLimit;
|
|
455
|
+
const tierRatio = effectiveLimit > 0 ? (effectiveFree / effectiveLimit) : 0;
|
|
450
456
|
if (tierRatio <= (config.thresholds.tier / 100)) {
|
|
451
457
|
log(`[SafetyNet] AlwaysFree Mode: Tier (${(tierRatio * 100).toFixed(1)}%) <= Threshold (${config.thresholds.tier}%). Switching.`);
|
|
452
458
|
emitStatusToast('warning', t('proxy.warnings.tier_limit_title', { threshold: config.thresholds.tier }), 'AlwaysFree Mode');
|
package/dist/server/quota.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export interface QuotaStatus {
|
|
|
3
3
|
tierRemaining: number;
|
|
4
4
|
tierUsed: number;
|
|
5
5
|
tierLimit: number;
|
|
6
|
+
questStash: number;
|
|
6
7
|
walletBalance: number;
|
|
7
8
|
nextResetAt: Date;
|
|
8
9
|
timeUntilReset: number;
|
|
@@ -16,3 +17,8 @@ export interface QuotaStatus {
|
|
|
16
17
|
export declare function fetchUsageForPeriod(apiKey: string, lastReset: Date): Promise<DetailedUsageEntry[]>;
|
|
17
18
|
export declare function getQuotaStatus(forceRefresh?: boolean): Promise<QuotaStatus>;
|
|
18
19
|
export declare function formatQuotaForToast(quota: QuotaStatus): string;
|
|
20
|
+
export declare function fetchQuestStash(apiKey: string): Promise<{
|
|
21
|
+
questStash: number;
|
|
22
|
+
claimedQuestTier: number;
|
|
23
|
+
tierConsumedSinceClaim: number;
|
|
24
|
+
}>;
|
package/dist/server/quota.js
CHANGED
|
@@ -4,6 +4,9 @@ import { loadConfig } from './config.js';
|
|
|
4
4
|
const CACHE_TTL = 30000;
|
|
5
5
|
let cachedQuota = null;
|
|
6
6
|
let lastQuotaFetch = 0;
|
|
7
|
+
const STASH_CACHE_TTL = 5 * 60 * 1000; // 5 min — le stash Quest change rarement
|
|
8
|
+
let cachedStash = null;
|
|
9
|
+
let lastStashFetch = 0;
|
|
7
10
|
const ONE_HOUR_MS = 60 * 60 * 1000;
|
|
8
11
|
const KNOWN_REFILLS = [
|
|
9
12
|
{ pollen: 0, emoji: '👤', label: 'anonymous' },
|
|
@@ -177,10 +180,21 @@ export async function getQuotaStatus(forceRefresh = false) {
|
|
|
177
180
|
const tierNeedsAlert = tierLimit > 0 && tierAlertPercent <= config.thresholds.tier;
|
|
178
181
|
const walletNeedsAlert = cleanWalletBalance > 0 && cleanWalletBalance < (config.thresholds.wallet || 0.5);
|
|
179
182
|
logQuota(`Fetch Success. Allowance: ${allowance}, Paid: ${cleanWalletBalance}, Total: ${totalBalance}`);
|
|
183
|
+
// Fetch quest stash (cached 5 min)
|
|
184
|
+
const nowStash = Date.now();
|
|
185
|
+
if (!cachedStash || (nowStash - lastStashFetch) > STASH_CACHE_TTL) {
|
|
186
|
+
try {
|
|
187
|
+
cachedStash = await fetchQuestStash(config.apiKey);
|
|
188
|
+
lastStashFetch = nowStash;
|
|
189
|
+
}
|
|
190
|
+
catch { /* keep previous */ }
|
|
191
|
+
}
|
|
192
|
+
const questStash = cachedStash?.questStash ?? 0;
|
|
180
193
|
cachedQuota = {
|
|
181
194
|
tierRemaining: cleanTierRemaining,
|
|
182
195
|
tierUsed,
|
|
183
196
|
tierLimit,
|
|
197
|
+
questStash,
|
|
184
198
|
walletBalance: cleanWalletBalance,
|
|
185
199
|
nextResetAt: resetInfo.nextReset,
|
|
186
200
|
timeUntilReset: resetInfo.timeUntilReset,
|
|
@@ -209,6 +223,7 @@ function createDefaultQuota(tierName, limit) {
|
|
|
209
223
|
tierRemaining: 0,
|
|
210
224
|
tierUsed: 0,
|
|
211
225
|
tierLimit: limit,
|
|
226
|
+
questStash: 0,
|
|
212
227
|
walletBalance: 0,
|
|
213
228
|
nextResetAt: new Date(),
|
|
214
229
|
timeUntilReset: 0,
|
|
@@ -302,5 +317,37 @@ export function formatQuotaForToast(quota) {
|
|
|
302
317
|
const hours = Math.floor(ms / (1000 * 60 * 60));
|
|
303
318
|
const minutes = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60));
|
|
304
319
|
const resetIn = `${hours}h${minutes}m`;
|
|
305
|
-
|
|
320
|
+
const stashStr = quota.questStash > 0
|
|
321
|
+
? ` | 🎁 ~${quota.questStash.toFixed(2)} (stash)`
|
|
322
|
+
: '';
|
|
323
|
+
return `${quota.tierEmoji} ${quota.tierRemaining.toFixed(2)}/${quota.tierLimit} (${tierPercent}%)${stashStr} | 💎 $${quota.walletBalance.toFixed(2)} | ⏰ ${resetIn}`;
|
|
324
|
+
}
|
|
325
|
+
export async function fetchQuestStash(apiKey) {
|
|
326
|
+
let claimedQuestTier = 0;
|
|
327
|
+
let firstClaimMs = Infinity;
|
|
328
|
+
let tierConsumedSinceClaim = 0;
|
|
329
|
+
try {
|
|
330
|
+
const qres = await fetchAPI('/account/quests', apiKey);
|
|
331
|
+
for (const q of (qres?.quests || [])) {
|
|
332
|
+
const r = q.reward;
|
|
333
|
+
if (r && r.claimedAt && r.balanceBucket === 'tier') {
|
|
334
|
+
claimedQuestTier += (r.pollenAmount || 0);
|
|
335
|
+
const cms = new Date(r.claimedAt).getTime();
|
|
336
|
+
if (!isNaN(cms) && cms < firstClaimMs)
|
|
337
|
+
firstClaimMs = cms;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (claimedQuestTier > 0 && isFinite(firstClaimMs)) {
|
|
341
|
+
const ures = await fetchAPI('/account/usage?limit=500', apiKey);
|
|
342
|
+
for (const e of (ures?.usage || [])) {
|
|
343
|
+
const ts = new Date(String(e.timestamp).replace(' ', 'T') + (String(e.timestamp).includes('Z') ? '' : 'Z')).getTime();
|
|
344
|
+
if (e.meter_source === 'tier' && !isNaN(ts) && ts >= firstClaimMs) {
|
|
345
|
+
tierConsumedSinceClaim += (e.cost_usd || 0);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
catch { /* fallback gracefully */ }
|
|
351
|
+
const questStash = Math.max(0, claimedQuestTier - tierConsumedSinceClaim);
|
|
352
|
+
return { questStash, claimedQuestTier, tierConsumedSinceClaim };
|
|
306
353
|
}
|
|
@@ -37,7 +37,8 @@ Use 'action=update' to change these. NEVER confuse Chat Mode with Tools Protecti
|
|
|
37
37
|
thresholdsTier: tool.schema.number().optional().describe('Warning threshold PERCENTAGE (e.g. 10 for 10%) for Free Tier.'),
|
|
38
38
|
thresholdsWallet: tool.schema.number().optional().describe('Warning threshold PERCENTAGE (e.g. 50 for 50%) for Wallet balance.'),
|
|
39
39
|
lang: tool.schema.enum(['en', 'fr', 'es', 'de', 'it', 'zh']).optional().describe('Plugin language for commands and toasts (en, fr, es, de, it, zh).'),
|
|
40
|
-
refillOverride: tool.schema.number().optional().describe('Manual Quest Pollen hourly refill override (0.01, 0.15, 0.4, 0.8, or 10). Set to 0 for auto-deduction.')
|
|
40
|
+
refillOverride: tool.schema.number().optional().describe('Manual Quest Pollen hourly refill override (0.01, 0.15, 0.4, 0.8, or 10). Set to 0 for auto-deduction.'),
|
|
41
|
+
questStashInFreeMode: tool.schema.boolean().optional().describe('Count accumulated quest stash as free pollen in alwaysfree Safety Net (default: true).')
|
|
41
42
|
},
|
|
42
43
|
async execute(args, context) {
|
|
43
44
|
if (args.action === 'view') {
|
|
@@ -67,6 +68,8 @@ Use 'action=update' to change these. NEVER confuse Chat Mode with Tools Protecti
|
|
|
67
68
|
if (args.refillOverride !== undefined) {
|
|
68
69
|
updates.refillOverride = args.refillOverride === 0 ? undefined : args.refillOverride;
|
|
69
70
|
}
|
|
71
|
+
if (args.questStashInFreeMode !== undefined)
|
|
72
|
+
updates.questStashInFreeMode = args.questStashInFreeMode;
|
|
70
73
|
if (args.lang !== undefined)
|
|
71
74
|
updates.lang = args.lang;
|
|
72
75
|
if (args.thresholdsTier !== undefined || args.thresholdsWallet !== undefined) {
|
package/package.json
CHANGED