opencode-pollinations-plugin 6.1.0-beta.3 → 6.1.0-beta.30
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 +257 -61
- package/dist/index.js +53 -161
- package/dist/server/commands.d.ts +6 -0
- package/dist/server/commands.js +404 -73
- package/dist/server/config.d.ts +32 -23
- package/dist/server/config.js +183 -104
- package/dist/server/connect-response.d.ts +2 -0
- package/dist/server/connect-response.js +141 -0
- package/dist/server/generate-config.d.ts +3 -30
- package/dist/server/generate-config.js +164 -106
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +124 -149
- package/dist/server/logger.d.ts +8 -0
- package/dist/server/logger.js +36 -0
- package/dist/server/models/cache.d.ts +35 -0
- package/dist/server/models/cache.js +160 -0
- package/dist/server/models/fetcher.d.ts +18 -0
- package/dist/server/models/fetcher.js +150 -0
- package/dist/server/models/index.d.ts +6 -0
- package/dist/server/models/index.js +5 -0
- package/dist/server/models/manual.d.ts +15 -0
- package/dist/server/models/manual.js +92 -0
- package/dist/server/models/types.d.ts +55 -0
- package/dist/server/models/types.js +7 -0
- package/dist/server/models/worker.d.ts +21 -0
- package/dist/server/models/worker.js +97 -0
- package/dist/server/pollinations-api.d.ts +11 -0
- package/dist/server/pollinations-api.js +21 -8
- package/dist/server/proxy.js +195 -160
- package/dist/server/quota.d.ts +2 -0
- package/dist/server/quota.js +89 -86
- package/dist/server/scripts/pollinations_pricing.d.ts +8 -0
- package/dist/server/scripts/pollinations_pricing.js +246 -0
- package/dist/server/scripts/test_cost_endpoints.d.ts +1 -0
- package/dist/server/scripts/test_cost_endpoints.js +61 -0
- package/dist/server/scripts/test_dynamic_pricing.d.ts +1 -0
- package/dist/server/scripts/test_dynamic_pricing.js +39 -0
- package/dist/server/scripts/test_freetier_audit.d.ts +11 -0
- package/dist/server/scripts/test_freetier_audit.js +215 -0
- package/dist/server/scripts/test_parallel_cost.d.ts +1 -0
- package/dist/server/scripts/test_parallel_cost.js +104 -0
- package/dist/server/toast.d.ts +7 -1
- package/dist/server/toast.js +43 -10
- package/dist/tools/design/gen_diagram.d.ts +2 -0
- package/dist/tools/design/gen_diagram.js +94 -0
- package/dist/tools/design/gen_palette.d.ts +2 -0
- package/dist/tools/design/gen_palette.js +182 -0
- package/dist/tools/design/gen_qrcode.d.ts +2 -0
- package/dist/tools/design/gen_qrcode.js +50 -0
- package/dist/tools/ffmpeg.d.ts +24 -0
- package/dist/tools/ffmpeg.js +54 -0
- package/dist/tools/index.d.ts +25 -0
- package/dist/tools/index.js +86 -0
- package/dist/tools/pollinations/beta_discovery.d.ts +9 -0
- package/dist/tools/pollinations/beta_discovery.js +197 -0
- package/dist/tools/pollinations/cost-guard.d.ts +38 -0
- package/dist/tools/pollinations/cost-guard.js +141 -0
- package/dist/tools/pollinations/deepsearch.d.ts +7 -0
- package/dist/tools/pollinations/deepsearch.js +80 -0
- package/dist/tools/pollinations/gen_audio.d.ts +18 -0
- package/dist/tools/pollinations/gen_audio.js +246 -0
- package/dist/tools/pollinations/gen_image.d.ts +11 -0
- package/dist/tools/pollinations/gen_image.js +225 -0
- package/dist/tools/pollinations/gen_music.d.ts +14 -0
- package/dist/tools/pollinations/gen_music.js +180 -0
- package/dist/tools/pollinations/gen_video.d.ts +16 -0
- package/dist/tools/pollinations/gen_video.js +256 -0
- package/dist/tools/pollinations/polli_config.d.ts +2 -0
- package/dist/tools/pollinations/polli_config.js +88 -0
- package/dist/tools/pollinations/polli_gen_confirm.d.ts +2 -0
- package/dist/tools/pollinations/polli_gen_confirm.js +48 -0
- package/dist/tools/pollinations/polli_status.d.ts +2 -0
- package/dist/tools/pollinations/polli_status.js +31 -0
- package/dist/tools/pollinations/polli_web_search.d.ts +15 -0
- package/dist/tools/pollinations/polli_web_search.js +164 -0
- package/dist/tools/pollinations/search_crawl_scrape.d.ts +7 -0
- package/dist/tools/pollinations/search_crawl_scrape.js +85 -0
- package/dist/tools/pollinations/shared.d.ts +165 -0
- package/dist/tools/pollinations/shared.js +665 -0
- package/dist/tools/pollinations/test_estimators.d.ts +1 -0
- package/dist/tools/pollinations/test_estimators.js +22 -0
- package/dist/tools/pollinations/transcribe_audio.d.ts +13 -0
- package/dist/tools/pollinations/transcribe_audio.js +194 -0
- package/dist/tools/power/extract_audio.d.ts +2 -0
- package/dist/tools/power/extract_audio.js +179 -0
- package/dist/tools/power/extract_frames.d.ts +2 -0
- package/dist/tools/power/extract_frames.js +237 -0
- package/dist/tools/power/file_to_url.d.ts +2 -0
- package/dist/tools/power/file_to_url.js +217 -0
- package/dist/tools/power/remove_background.d.ts +2 -0
- package/dist/tools/power/remove_background.js +392 -0
- package/dist/tools/power/rmbg_keys.d.ts +2 -0
- package/dist/tools/power/rmbg_keys.js +79 -0
- package/dist/tools/shared.d.ts +30 -0
- package/dist/tools/shared.js +80 -0
- package/package.json +10 -4
- package/dist/server/models-seed.d.ts +0 -18
- package/dist/server/models-seed.js +0 -55
package/README.md
CHANGED
|
@@ -1,38 +1,156 @@
|
|
|
1
1
|
# 🌸 Pollinations AI Plugin for OpenCode
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
|
-
<img src="https://avatars.githubusercontent.com/u/88394740?s=400&v=4" alt="Pollinations.ai Logo" width="
|
|
5
|
-
<br>
|
|
6
|
-
<b>The
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
<img src="https://avatars.githubusercontent.com/u/88394740?s=400&v=4" alt="Pollinations.ai Logo" width="180">
|
|
5
|
+
<br><br>
|
|
6
|
+
<b>The most complete bridge between OpenCode and the Pollinations.ai ecosystem.</b><br>
|
|
7
|
+
Free AI models, multimodal generation, and smart quota management — directly in your editor.
|
|
8
|
+
<br><br>
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
|
+

|
|
14
|
+

|
|
15
|
+
|
|
9
16
|
</div>
|
|
10
17
|
|
|
11
|
-
|
|
18
|
+
---
|
|
12
19
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
> **"No closed doors, no corporate hoops — just good tools and good people."**
|
|
21
|
+
>
|
|
22
|
+
> Pollinations.ai is an open-source platform built by and for the creative community. This plugin brings it entirely inside OpenCode: text, image, audio, video, music, diagrams, and more — with a transparent fallback system that means you're *never* blocked.
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
---
|
|
18
25
|
|
|
19
|
-
|
|
26
|
+
## ✨ What's New in v6.1-beta.22
|
|
27
|
+
|
|
28
|
+
The jump from v5.9 to v6.1 is not incremental. The plugin has grown from a smart proxy into a **full multimodal agent toolkit**:
|
|
29
|
+
|
|
30
|
+
- **15+ native tools** for generation, design, and media processing — usable directly in OpenCode's agent mode
|
|
31
|
+
- **Smart Fetch Quota**: 100% exact math fetching directly from Pollinations API for quota verification (zero local cache)
|
|
32
|
+
- **Dynamic Pricing**: Tool costs are estimated live based on Tinybird API model stats. Token models have a built-in max theoretical threshold limit (Cost Guard).
|
|
33
|
+
- **Stealth notifications**: status toasts now only fire in relevant contexts, no more noise
|
|
34
|
+
- **Background removal** with multi-key rotation and automatic fallback to free provider
|
|
35
|
+
- **Video, music, audio generation** via the Pollinations API
|
|
36
|
+
- **Web search + scraping** integrated as agent tools
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 🚀 Quick Start
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Install globally
|
|
44
|
+
npm install -g opencode-pollinations-plugin
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then in OpenCode:
|
|
48
|
+
```
|
|
49
|
+
/connect
|
|
50
|
+
```
|
|
51
|
+
Select **pollinations** → Enter your API key from [enter.pollinations.ai](https://enter.pollinations.ai), or leave blank to use the free tier.
|
|
52
|
+
|
|
53
|
+
Select any `pollinations/*` text model and start chatting. **No key required for text.**
|
|
54
|
+
|
|
55
|
+
> ⚠️ **Note:** Image generation (`gen_image`) requires a Pollinations API Key. Text models remain free.
|
|
56
|
+
|
|
57
|
+
> ⚠️ After connecting a new key, restart OpenCode once for the model list to update.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 🌐 Free Universe — No Key Required
|
|
62
|
+
|
|
63
|
+
Access a wide range of models with **zero setup**, supported by Pollinations' ad model:
|
|
64
|
+
|
|
65
|
+
| Model | Speed | Context | Notes |
|
|
66
|
+
|-------|:-----:|:-------:|-------|
|
|
67
|
+
| `openai` / `openai-large` | Fast | 128k | GPT-4o class |
|
|
68
|
+
| `gemini` / `gemini-search` | Fast | 1M | Google Gemini |
|
|
69
|
+
| `mistral` / `qwen-coder` | Fast | 32k | Code-focused |
|
|
70
|
+
| `nova-fast` / `grok` | Very Fast | 32k | Quick tasks |
|
|
71
|
+
| `deepseek` / `kimi` | Medium | 128k | Reasoning |
|
|
72
|
+
|
|
73
|
+
> 💡 Using Gemini with tool calls? The plugin auto-detects incompatibilities and transparently falls back to OpenAI — your workflow never breaks.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 💎 Pro Mode — Unlock Premium Models
|
|
78
|
+
|
|
79
|
+
Connect your [Pollinations API key](https://enter.pollinations.ai) to access enterprise-grade models charged in **Pollen** (the unified credit, ~$1 = 1 Pollen):
|
|
80
|
+
|
|
81
|
+
| Model | Provider | Notes |
|
|
82
|
+
|-------|----------|-------|
|
|
83
|
+
| `claude` / `claude-large` | Anthropic | Requires wallet credits |
|
|
84
|
+
| `gemini-large` | Google | Requires wallet credits |
|
|
85
|
+
| `gpt-4o` / `openai-large` | OpenAI | Daily grant available |
|
|
86
|
+
| `deepseek-coder` | DeepSeek | Daily grant available |
|
|
87
|
+
|
|
88
|
+
### 🛡️ Safety Net — You're Never Blocked
|
|
89
|
+
|
|
90
|
+
If your quota or wallet runs low mid-session, the plugin switches automatically to a free model, injects a visible warning in the response stream, and continues. No errors. No broken sessions.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 🔧 Agent Tools (v6.1 — New)
|
|
95
|
+
|
|
96
|
+
When OpenCode uses the plugin in agent mode, it gets access to a rich toolbox organized in three categories:
|
|
97
|
+
|
|
98
|
+
### 🎨 Pollinations Generation Tools
|
|
99
|
+
|
|
100
|
+
These tools call the Pollinations APIs directly, enabling the AI to generate media as part of its reasoning:
|
|
101
|
+
|
|
102
|
+
| Tool | Description |
|
|
103
|
+
|------|-------------|
|
|
104
|
+
| `gen_image` | Generate images from a text prompt (Flux, SDXL, etc.) **[Requires Key]** |
|
|
105
|
+
| `gen_audio` | Generate speech or sound effects |
|
|
106
|
+
| `gen_music` | Generate music from a description |
|
|
107
|
+
| `gen_video` | Generate short video clips |
|
|
108
|
+
| `transcribe_audio` | Transcribe an audio file to text |
|
|
109
|
+
| `deepsearch` | Multi-step AI-powered research |
|
|
110
|
+
| `search_crawl_scrape` | Web search with full page scraping |
|
|
111
|
+
| `beta_discovery` | Probe undocumented model parameters (400 validation extraction) |
|
|
112
|
+
|
|
113
|
+
### 🖌️ Design Tools
|
|
114
|
+
|
|
115
|
+
| Tool | Description |
|
|
116
|
+
|------|-------------|
|
|
117
|
+
| `gen_diagram` | Generate diagrams (flowcharts, architecture, etc.) |
|
|
118
|
+
| `gen_palette` | Create color palettes from a description or image |
|
|
119
|
+
| `gen_qrcode` | Generate styled QR codes |
|
|
120
|
+
|
|
121
|
+
### ⚡ Power Tools
|
|
122
|
+
|
|
123
|
+
| Tool | Description |
|
|
124
|
+
|------|-------------|
|
|
125
|
+
| `remove_background` | Remove image backgrounds (free or BackgroundCut HD) |
|
|
126
|
+
| `rmbg_keys` | Manage BackgroundCut API keys with rotation |
|
|
127
|
+
| `extract_audio` | Extract the audio track from a video file |
|
|
128
|
+
| `extract_frames` | Extract frames from a video at a given interval |
|
|
129
|
+
| `file_to_url` | Upload a local file and return a public URL |
|
|
130
|
+
|
|
131
|
+
> **Background Removal** supports multi-key rotation: if one BackgroundCut key is exhausted or rate-limited, the plugin automatically rotates to the next available key, then falls back to the free provider if all keys fail.
|
|
20
132
|
|
|
21
133
|
---
|
|
22
134
|
|
|
23
|
-
##
|
|
135
|
+
## 👁️ Vision Support
|
|
24
136
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
137
|
+
Paste images directly into the chat or use an image URL. The plugin handles encoding automatically.
|
|
138
|
+
|
|
139
|
+
| Model | Vision | Reasoning | Tools |
|
|
140
|
+
|-------|:------:|:---------:|:-----:|
|
|
141
|
+
| `openai` / `openai-large` | ✅ | — | ✅ |
|
|
142
|
+
| `gemini` / `gemini-search` | ✅ | — | ✅ |
|
|
143
|
+
| `claude` / `claude-large` | ✅ | — | ✅ |
|
|
144
|
+
| `kimi` | ✅ | ✅ | — |
|
|
145
|
+
| `openai-audio` | ✅ | — | ✅ |
|
|
30
146
|
|
|
31
147
|
---
|
|
32
148
|
|
|
33
|
-
##
|
|
149
|
+
## 💰 Understanding Pollen & Tiers
|
|
150
|
+
|
|
151
|
+
**Pollen** is Pollinations' unified credit system. **$1 ≈ 1 Pollen.**
|
|
34
152
|
|
|
35
|
-
|
|
153
|
+
Every registered user receives a **daily Pollen grant** based on their tier:
|
|
36
154
|
|
|
37
155
|
| Tier | Daily Grant | Requirement |
|
|
38
156
|
|:-----|:------------|:------------|
|
|
@@ -42,76 +160,154 @@
|
|
|
42
160
|
| 🌸 **Flower** | 10 Pollen | Published app |
|
|
43
161
|
| 🍯 **Nectar** | 20 Pollen | Major contributor |
|
|
44
162
|
|
|
45
|
-
>
|
|
163
|
+
> 🌸 Publishing this plugin to the OpenCode ecosystem earned its author **Flower** tier (10 Pollen/day). [Register here to claim yours.](https://enter.pollinations.ai)
|
|
164
|
+
|
|
165
|
+
Certain models (`claude-large`, `gemini-large`, `veo`, `seedream-pro`) are **Paid-Only**: they require wallet credits on top of (or instead of) daily grants.
|
|
46
166
|
|
|
47
167
|
---
|
|
48
168
|
|
|
49
|
-
##
|
|
169
|
+
## 📊 Commands
|
|
50
170
|
|
|
51
|
-
### 1. Install Plugin
|
|
52
|
-
```bash
|
|
53
|
-
npm install -g opencode-pollinations-plugin
|
|
54
|
-
npx opencode-pollinations-plugin
|
|
55
171
|
```
|
|
56
|
-
|
|
57
|
-
|
|
172
|
+
/pollinations usage # View Pollen balance + tier status
|
|
173
|
+
/pollinations usage full # Detailed per-model breakdown
|
|
174
|
+
/pollinations mode [manual|alwaysfree|pro] # Change routing mode
|
|
175
|
+
/pollinations status # Plugin health check
|
|
176
|
+
/pollinations config [key] [value] # Read or write config values
|
|
177
|
+
/pollinations fallback <main> [agent] # Configure fallback models
|
|
178
|
+
/pollinations help # Full command reference
|
|
58
179
|
```
|
|
59
|
-
/connect
|
|
60
|
-
```
|
|
61
|
-
Select **pollinations** → Enter your API key from [enter.pollinations.ai](https://enter.pollinations.ai)
|
|
62
180
|
|
|
63
|
-
|
|
64
|
-
Select any `pollinations/*` model in OpenCode and chat!
|
|
181
|
+
Aliases: `/poll` works as a shorthand for all commands.
|
|
65
182
|
|
|
66
|
-
|
|
183
|
+
### Config Keys & Agent Understanding
|
|
67
184
|
|
|
68
|
-
|
|
185
|
+
The plugin employs a **strict separation of concerns** between Chat/Conversational settings and Tool (generation/search) settings.
|
|
69
186
|
|
|
70
|
-
|
|
187
|
+
#### 1. Chat Models & Fallbacks
|
|
188
|
+
| Key | Values | Description |
|
|
189
|
+
|-----|--------|-------------|
|
|
190
|
+
| `mode` | `manual` / `alwaysfree` / `pro` | Automatic fallback routing strategy for chat. |
|
|
191
|
+
| `threshold_tier` | `0-100` | Alert threshold percentage for Free Tier quota. |
|
|
192
|
+
| `threshold_wallet` | `0-100` | Alert threshold percentage for Premium Wallet balance. |
|
|
71
193
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
194
|
+
#### 2. Tools Protection
|
|
195
|
+
| Key | Values | Description |
|
|
196
|
+
|-----|--------|-------------|
|
|
197
|
+
| `enablePaidTools` | `true` / `false` | Allows generation tools to consume Wallet pollen. |
|
|
198
|
+
| `costConfirmationRequired` | `true` / `false` | Demands validation if a tool estimate exceeds threshold. |
|
|
199
|
+
| `costThreshold` | numeric (e.g., `0.05`) | Trigger limit in Pollen for the confirmation lock. |
|
|
200
|
+
| `cost_estimator` | `true` / `false` | Shows live cost estimates in tool outputs. |
|
|
79
201
|
|
|
80
|
-
|
|
202
|
+
#### 3. UI & Notifications
|
|
203
|
+
| Key | Values | Description |
|
|
204
|
+
|-----|--------|-------------|
|
|
205
|
+
| `status_gui` | `none` / `alert` / `all` | Toast notification verbosity. |
|
|
206
|
+
| `logs_gui` | `none` / `error` / `verbose` | Technical log verbosity. |
|
|
207
|
+
| `status_bar` | `true` / `false` | Status bar widget visibility. |
|
|
81
208
|
|
|
82
209
|
---
|
|
83
210
|
|
|
84
|
-
##
|
|
211
|
+
## 🔑 API Key Types
|
|
212
|
+
|
|
213
|
+
| Type | Access |
|
|
214
|
+
|------|--------|
|
|
215
|
+
| **Standard (`pk_...`)** | Full access: models, usage dashboard, quota |
|
|
216
|
+
| **Limited** | Generation only. Dashboard shows a restriction alert. The plugin auto-switches to Manual mode to avoid quota errors. |
|
|
217
|
+
| **Legacy (`sk_...`)** | Accepted for backward compatibility |
|
|
85
218
|
|
|
86
|
-
|
|
87
|
-
- **OpenAI**: `openai`, `openai-fast`, `openai-large`
|
|
88
|
-
- **Gemini**: `gemini`, `gemini-fast`, `gemini-search`, `gemini-large` 💎
|
|
89
|
-
- **Claude**: `claude-fast`, `claude`, `claude-large` 💎
|
|
90
|
-
- **Reasoning**: `deepseek`, `kimi`, `perplexity-reasoning`
|
|
91
|
-
- **Code**: `qwen-coder`, `mistral`
|
|
92
|
-
- **Fast**: `nova-fast`, `grok`
|
|
219
|
+
---
|
|
93
220
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
221
|
+
## 🛠️ Routing Modes
|
|
222
|
+
|
|
223
|
+
| Mode | Behavior |
|
|
224
|
+
|------|----------|
|
|
225
|
+
| `manual` | You choose the model, no automatic switching |
|
|
226
|
+
| `alwaysfree` | Only free models, never charges Pollen |
|
|
227
|
+
| `pro` | Enterprise models with automatic free fallback when quota/wallet is low |
|
|
97
228
|
|
|
98
229
|
---
|
|
99
230
|
|
|
100
|
-
##
|
|
231
|
+
## 🏗️ Architecture (Summary)
|
|
232
|
+
|
|
233
|
+
The plugin runs a **local HTTP proxy** on a dynamically assigned port (system port 0 — no conflicts, cross-platform). OpenCode points its `pollinations` provider at this proxy. The proxy reads your config, checks quota, applies model-specific sanitizations, and forwards requests to the correct Pollinations endpoint.
|
|
101
234
|
|
|
102
235
|
```
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
236
|
+
OpenCode TUI
|
|
237
|
+
│ POST /v1/chat/completions
|
|
238
|
+
▼
|
|
239
|
+
Local Proxy (Dynamic Port)
|
|
240
|
+
├── Safety Net Logic (quota check, fallback)
|
|
241
|
+
├── Model Sanitization (Azure/Vertex/Gemini/Kimi)
|
|
242
|
+
└── Route to:
|
|
243
|
+
├── text.pollinations.ai (Free Universe)
|
|
244
|
+
└── gen.pollinations.ai (Enterprise Universe)
|
|
106
245
|
```
|
|
107
246
|
|
|
247
|
+
Config is read from (highest priority first):
|
|
248
|
+
1. `~/.pollinations/config.json`
|
|
249
|
+
2. `~/.local/share/opencode/auth.json`
|
|
250
|
+
3. `~/.config/opencode/opencode.json`
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## 🗺️ Roadmap
|
|
255
|
+
|
|
256
|
+
### ✅ Shipped (v5.x → v6.1-beta)
|
|
257
|
+
- Free + Enterprise proxy with transparent fallback (Safety Net)
|
|
258
|
+
- Dynamic port allocation — cross-platform (no more `fuser`, no port conflicts)
|
|
259
|
+
- Pollen/tier quota tracking with Smart Fetch API (no local logging)
|
|
260
|
+
- Dynamic Pricing (Tinybird stats) and Cost Guard max thresholds
|
|
261
|
+
- Agent tools: image, audio, music, video generation
|
|
262
|
+
- Agent tools: web search, scraping, deep research
|
|
263
|
+
- Design tools: diagrams, palettes, QR codes
|
|
264
|
+
- Power tools: background removal with key rotation, frame/audio extraction
|
|
265
|
+
- Stealth notification mode (toasts only in relevant sessions)
|
|
266
|
+
- Limited-key support with automatic mode switching
|
|
267
|
+
- Gemini tools auto-fallback to OpenAI
|
|
268
|
+
- Enterprise schema sanitization (Azure, Vertex, Bedrock, Kimi)
|
|
269
|
+
|
|
270
|
+
### 🔜 Next (v6.2 — v6.5, 2026)
|
|
271
|
+
- **Config file watcher** — hot-reload without restarting OpenCode
|
|
272
|
+
- **Signature map rotation** — LRU eviction to prevent unbounded memory growth
|
|
273
|
+
- **Unit tests** — coverage for `proxy.ts`, `quota.ts`, `tools/`
|
|
274
|
+
- **`/poll status` one-liner** — faster than opening the dashboard
|
|
275
|
+
- **Structured logging** — JSON format, configurable log levels, log rotation
|
|
276
|
+
- **Model search** — `/poll models <query>` to filter the model list
|
|
277
|
+
|
|
278
|
+
### 🔭 Longer Term (v7.0+, 2027)
|
|
279
|
+
- **Smart Router** — cost-aware and latency-aware model selection
|
|
280
|
+
- **Multi-provider failover** — fallback to OpenRouter if Pollinations is unreachable
|
|
281
|
+
- **Web Dashboard** — browser UI for monitoring, config, and analytics
|
|
282
|
+
- **Team features** — shared quotas and API keys
|
|
283
|
+
- **Persistent memory** — vector DB integration for long-running agents
|
|
284
|
+
|
|
285
|
+
> Community ideas with the most votes: API usage alerts, conversation export (Markdown/JSON), model comparison mode. Open an issue to vote!
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## 🤝 Contributing
|
|
290
|
+
|
|
291
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for setup instructions, code guidelines, and priority areas (testing, docs, i18n, DevOps).
|
|
292
|
+
|
|
293
|
+
### Areas Where Help Is Needed
|
|
294
|
+
- 🧪 **Testing** — Unit + integration tests for the proxy and tools
|
|
295
|
+
- 📚 **Docs** — User guides, tool examples
|
|
296
|
+
- 🌍 **i18n** — French/English consistency, German and Spanish translations
|
|
297
|
+
- 🎨 **UX** — Command output formatting improvements
|
|
298
|
+
|
|
108
299
|
---
|
|
109
300
|
|
|
110
301
|
## 🔗 Links
|
|
111
302
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
303
|
+
| Resource | Link |
|
|
304
|
+
|----------|------|
|
|
305
|
+
| Sign up for Pollinations (free tiers + paid models) | [enter.pollinations.ai](https://enter.pollinations.ai) |
|
|
306
|
+
| Pollinations website | [pollinations.ai](https://pollinations.ai) |
|
|
307
|
+
| Pollinations GitHub | [github.com/pollinations/pollinations](https://github.com/pollinations/pollinations) |
|
|
308
|
+
| Discord community | [Join us!](https://discord.gg/pollinations-ai-885844321461485618) |
|
|
309
|
+
| OpenCode ecosystem | [opencode.ai/docs/ecosystem](https://opencode.ai/docs/ecosystem#plugins) |
|
|
310
|
+
| Plugin author | [@fkom13](https://github.com/fkom13) |
|
|
115
311
|
|
|
116
312
|
---
|
|
117
313
|
|
package/dist/index.js
CHANGED
|
@@ -1,31 +1,21 @@
|
|
|
1
1
|
import * as http from 'http';
|
|
2
|
-
import * as fs from 'fs';
|
|
3
2
|
import { generatePollinationsConfig } from './server/generate-config.js';
|
|
4
|
-
import { loadConfig,
|
|
3
|
+
import { loadConfig, migrateLegacyConfig } from './server/config.js';
|
|
5
4
|
import { handleChatCompletion } from './server/proxy.js';
|
|
6
|
-
import { createToastHooks, setGlobalClient } from './server/toast.js';
|
|
5
|
+
import { createToastHooks, createToolHooks, setGlobalClient } from './server/toast.js';
|
|
7
6
|
import { createStatusHooks } from './server/status.js';
|
|
8
|
-
import { createCommandHooks } from './server/commands.js';
|
|
7
|
+
import { createCommandHooks, setClientForCommands } from './server/commands.js';
|
|
8
|
+
import { createToolRegistry } from './tools/index.js';
|
|
9
9
|
import { createRequire } from 'module';
|
|
10
10
|
const require = createRequire(import.meta.url);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
fs.appendFileSync(LOG_FILE, `[${new Date().toISOString()}] ${msg}\n`);
|
|
15
|
-
}
|
|
16
|
-
catch (e) { }
|
|
17
|
-
}
|
|
18
|
-
// === PROXY SERVER (Singleton with Fixed Port) ===
|
|
19
|
-
const DEFAULT_PORT = 18888;
|
|
20
|
-
const GLOBAL_SERVER_KEY = '__POLLINATIONS_PROXY_SERVER__';
|
|
11
|
+
import { log } from './server/logger.js';
|
|
12
|
+
import { ModelRegistry } from './server/models/index.js';
|
|
13
|
+
const sessionModels = new Map();
|
|
21
14
|
const startProxy = () => {
|
|
22
|
-
// Check if server exists in global scope (survives module reloads)
|
|
23
|
-
if (global[GLOBAL_SERVER_KEY]) {
|
|
24
|
-
log(`[Proxy] Reusing existing global server on port ${DEFAULT_PORT}`);
|
|
25
|
-
return Promise.resolve(DEFAULT_PORT);
|
|
26
|
-
}
|
|
27
15
|
return new Promise((resolve) => {
|
|
28
16
|
const server = http.createServer(async (req, res) => {
|
|
17
|
+
// ... (Request Handling) ...
|
|
18
|
+
// We reuse the existing logic structure but simplified startup
|
|
29
19
|
log(`[Proxy] Request: ${req.method} ${req.url}`);
|
|
30
20
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
31
21
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
@@ -67,156 +57,59 @@ const startProxy = () => {
|
|
|
67
57
|
res.writeHead(404);
|
|
68
58
|
res.end("Not Found");
|
|
69
59
|
});
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
log(`[Proxy] Port ${port} in use, falling back to dynamic port`);
|
|
82
|
-
server.removeAllListeners('error');
|
|
83
|
-
tryListen(0, false); // Try dynamic port
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
log(`[Proxy] Fatal Error: ${e}`);
|
|
87
|
-
resolve(0);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
};
|
|
91
|
-
tryListen(DEFAULT_PORT, true);
|
|
60
|
+
// Listen on random port (0) to avoid conflicts (CLI/IDE)
|
|
61
|
+
server.listen(0, '127.0.0.1', () => {
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
const assignedPort = server.address().port;
|
|
64
|
+
log(`[Proxy] Started v${require('../package.json').version} (Dynamic Port) on port ${assignedPort}`);
|
|
65
|
+
resolve(assignedPort);
|
|
66
|
+
});
|
|
67
|
+
server.on('error', (e) => {
|
|
68
|
+
log(`[Proxy] Fatal Error: ${e}`);
|
|
69
|
+
resolve(0);
|
|
70
|
+
});
|
|
92
71
|
});
|
|
93
72
|
};
|
|
94
|
-
// === AUTH HOOK: Native /connect Integration ===
|
|
95
|
-
// Auth Hook moved inside plugin to access context
|
|
96
73
|
// === PLUGIN EXPORT ===
|
|
97
74
|
export const PollinationsPlugin = async (ctx) => {
|
|
98
|
-
|
|
99
|
-
|
|
75
|
+
const v = require('../package.json').version;
|
|
76
|
+
log(`Plugin Initializing v${v}...`);
|
|
77
|
+
log(`[ENV] Keys: ${Object.keys(process.env).filter(k => k.includes('OPENCODE') || k.includes('APP') || k.includes('DATA')).join(', ')}`);
|
|
78
|
+
console.log(`🚀 POLLINATIONS PLUGIN v${v} LOADED 🚀`);
|
|
79
|
+
// MIGRATE CONFIG
|
|
80
|
+
migrateLegacyConfig();
|
|
81
|
+
// START PROXY
|
|
100
82
|
const port = await startProxy();
|
|
101
83
|
const localBaseUrl = `http://127.0.0.1:${port}/v1`;
|
|
84
|
+
// INIT MODEL REGISTRY (non-blocking, fire-and-forget)
|
|
85
|
+
ModelRegistry.refresh().then(() => {
|
|
86
|
+
const stats = ModelRegistry.stats();
|
|
87
|
+
log(`[ModelRegistry] Ready: ${stats.image} image, ${stats.video} video, ${stats.audio} audio, ${stats.text} text`);
|
|
88
|
+
// Démarrage du patcher asynchrone des descriptions des Outils (Phase 1.5)
|
|
89
|
+
import('./server/models/worker.js').then(module => {
|
|
90
|
+
module.ToolRegistryWorker.start();
|
|
91
|
+
}).catch(e => log(`[ToolWorker] Failed to load worker: ${e}`));
|
|
92
|
+
}).catch(e => log(`[ModelRegistry] Init failed (will use fallback): ${e}`));
|
|
102
93
|
setGlobalClient(ctx.client);
|
|
94
|
+
setClientForCommands(ctx.client);
|
|
103
95
|
const toastHooks = createToastHooks(ctx.client);
|
|
104
96
|
const commandHooks = createCommandHooks();
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (isRefreshing)
|
|
109
|
-
return;
|
|
110
|
-
isRefreshing = true;
|
|
111
|
-
try {
|
|
112
|
-
log('[Event] Refreshing provider config after auth update...');
|
|
113
|
-
const modelsArray = await generatePollinationsConfig();
|
|
114
|
-
const modelsObj = {};
|
|
115
|
-
for (const m of modelsArray) {
|
|
116
|
-
modelsObj[m.id] = m;
|
|
117
|
-
}
|
|
118
|
-
const version = require('../package.json').version;
|
|
119
|
-
// CRITICAL: Fetch current config first to avoid overwriting other providers
|
|
120
|
-
let currentConfig = {};
|
|
121
|
-
try {
|
|
122
|
-
// Try to fetch existing config to preserve other providers
|
|
123
|
-
const response = await ctx.client.fetch('/config');
|
|
124
|
-
if (response.ok) {
|
|
125
|
-
currentConfig = await response.json();
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
catch (err) {
|
|
129
|
-
log(`[Event] Warning: Could not fetch current config: ${err}`);
|
|
130
|
-
}
|
|
131
|
-
// Safe Merge
|
|
132
|
-
if (!currentConfig.provider)
|
|
133
|
-
currentConfig.provider = {};
|
|
134
|
-
currentConfig.provider.pollinations = {
|
|
135
|
-
id: 'openai',
|
|
136
|
-
name: `Pollinations AI (v${version})`,
|
|
137
|
-
options: {
|
|
138
|
-
baseURL: localBaseUrl,
|
|
139
|
-
apiKey: 'plugin-managed',
|
|
140
|
-
},
|
|
141
|
-
models: modelsObj
|
|
142
|
-
};
|
|
143
|
-
// Use Server API to update config with the MERGED object
|
|
144
|
-
await ctx.client.fetch('/config', {
|
|
145
|
-
method: 'PATCH',
|
|
146
|
-
headers: { 'Content-Type': 'application/json' },
|
|
147
|
-
body: JSON.stringify({
|
|
148
|
-
provider: currentConfig.provider
|
|
149
|
-
})
|
|
150
|
-
});
|
|
151
|
-
log(`[Event] Provider config refreshed with ${Object.keys(modelsObj).length} models.`);
|
|
152
|
-
}
|
|
153
|
-
catch (e) {
|
|
154
|
-
log(`[Event] Failed to refresh provider config: ${e}`);
|
|
155
|
-
}
|
|
156
|
-
finally {
|
|
157
|
-
// Debounce: prevent another refresh for 5 seconds
|
|
158
|
-
setTimeout(() => { isRefreshing = false; }, 5000);
|
|
159
|
-
}
|
|
160
|
-
};
|
|
97
|
+
// Build tool registry (conditional on API key presence)
|
|
98
|
+
const toolRegistry = createToolRegistry();
|
|
99
|
+
log(`[Tools] ${Object.keys(toolRegistry).length} tools registered`);
|
|
161
100
|
return {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
log(
|
|
167
|
-
|
|
168
|
-
const authData = await auth();
|
|
169
|
-
if (authData && 'key' in authData) {
|
|
170
|
-
const k = authData.key;
|
|
171
|
-
saveConfig({ apiKey: k });
|
|
172
|
-
return { apiKey: k };
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
catch (e) {
|
|
176
|
-
log(`[AuthHook] loader error: ${e}`);
|
|
177
|
-
}
|
|
178
|
-
const config = loadConfig();
|
|
179
|
-
if (config.apiKey)
|
|
180
|
-
return { apiKey: config.apiKey };
|
|
181
|
-
return {};
|
|
182
|
-
},
|
|
183
|
-
methods: [{
|
|
184
|
-
type: 'api',
|
|
185
|
-
label: 'Pollinations API Key',
|
|
186
|
-
prompts: [{
|
|
187
|
-
type: 'text',
|
|
188
|
-
key: 'apiKey',
|
|
189
|
-
message: 'Enter Pollinations API Key (starts with sk_)',
|
|
190
|
-
validate: (v) => (!v || v.length < 10) ? 'Invalid key' : undefined
|
|
191
|
-
}],
|
|
192
|
-
authorize: async (inputs) => {
|
|
193
|
-
log(`[AuthHook] authorize() called`);
|
|
194
|
-
if (!inputs?.apiKey)
|
|
195
|
-
return { type: 'failed' };
|
|
196
|
-
try {
|
|
197
|
-
const r = await fetch('https://gen.pollinations.ai/text/models', {
|
|
198
|
-
headers: { 'Authorization': `Bearer ${inputs.apiKey}` }
|
|
199
|
-
});
|
|
200
|
-
if (r.ok) {
|
|
201
|
-
log('[AuthHook] Success. Saving & Refreshing Config...');
|
|
202
|
-
saveConfig({ apiKey: inputs.apiKey });
|
|
203
|
-
// CRITICAL: Refresh config IMMEDIATELY after successful auth
|
|
204
|
-
await refreshProviderConfig();
|
|
205
|
-
return { type: 'success', key: inputs.apiKey };
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
catch (e) {
|
|
209
|
-
log(`[AuthHook] Auth error: ${e}`);
|
|
210
|
-
}
|
|
211
|
-
return { type: 'failed' };
|
|
212
|
-
}
|
|
213
|
-
}]
|
|
101
|
+
"chat.message": async (input) => {
|
|
102
|
+
const m = input.model;
|
|
103
|
+
if (m && m.modelID) {
|
|
104
|
+
sessionModels.set(input.sessionID, `${m.providerID}/${m.modelID}`);
|
|
105
|
+
log(`[Hook] Saved active model ${m.providerID}/${m.modelID} for session ${input.sessionID}`);
|
|
106
|
+
}
|
|
214
107
|
},
|
|
215
|
-
|
|
216
|
-
event: async ({ event }) => { },
|
|
108
|
+
tool: toolRegistry,
|
|
217
109
|
async config(config) {
|
|
218
110
|
log("[Hook] config() called");
|
|
219
|
-
//
|
|
111
|
+
// STARTUP only - No complex hot reload logic
|
|
112
|
+
// The user must restart OpenCode to refresh this list if they change keys.
|
|
220
113
|
const modelsArray = await generatePollinationsConfig();
|
|
221
114
|
const modelsObj = {};
|
|
222
115
|
for (const m of modelsArray) {
|
|
@@ -224,19 +117,18 @@ export const PollinationsPlugin = async (ctx) => {
|
|
|
224
117
|
}
|
|
225
118
|
if (!config.provider)
|
|
226
119
|
config.provider = {};
|
|
120
|
+
// Dynamic Provider Name
|
|
227
121
|
const version = require('../package.json').version;
|
|
228
122
|
config.provider['pollinations'] = {
|
|
229
|
-
id: '
|
|
123
|
+
id: 'pollinations',
|
|
230
124
|
name: `Pollinations AI (v${version})`,
|
|
231
|
-
options: {
|
|
232
|
-
baseURL: localBaseUrl,
|
|
233
|
-
apiKey: 'plugin-managed', // Key is managed by auth hook
|
|
234
|
-
},
|
|
125
|
+
options: { baseURL: localBaseUrl },
|
|
235
126
|
models: modelsObj
|
|
236
127
|
};
|
|
237
128
|
log(`[Hook] Registered ${Object.keys(modelsObj).length} models.`);
|
|
238
129
|
},
|
|
239
130
|
...toastHooks,
|
|
131
|
+
...createToolHooks(ctx.client),
|
|
240
132
|
...createStatusHooks(ctx.client),
|
|
241
133
|
...commandHooks
|
|
242
134
|
};
|
|
@@ -9,8 +9,14 @@ interface CommandResult {
|
|
|
9
9
|
response?: string;
|
|
10
10
|
error?: string;
|
|
11
11
|
}
|
|
12
|
+
export declare function setClientForCommands(client: any): void;
|
|
12
13
|
export declare function handleCommand(command: string): Promise<CommandResult>;
|
|
14
|
+
export declare function handleUsageCommand(args: string[]): Promise<CommandResult>;
|
|
15
|
+
export declare function handleModelsCommand(args: string[]): Promise<CommandResult>;
|
|
16
|
+
export declare function handlePricingCommand(): Promise<CommandResult>;
|
|
17
|
+
export declare function handleInfosCommand(): Promise<CommandResult>;
|
|
13
18
|
export declare function createCommandHooks(): {
|
|
14
19
|
'tui.command.execute': (input: any, output: any) => Promise<void>;
|
|
20
|
+
'command.execute.before': (input: any, output: any) => Promise<void>;
|
|
15
21
|
};
|
|
16
22
|
export {};
|