qwen-opencode-provider 3.0.0 → 3.1.0

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.
Files changed (2) hide show
  1. package/index.js +82 -34
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * OpenCode Qwen API Plugin
3
3
  *
4
4
  * Uses local proxy (like Pollinations) to handle auth automatically.
5
- * No manual config needed!
5
+ * Auto-fetches all models from Qwen API.
6
6
  */
7
7
 
8
8
  import http from 'http';
@@ -16,27 +16,6 @@ const LOG_FILE = path.join(LOG_DIR, 'debug.log');
16
16
  const PROVIDER_ID = 'qwen';
17
17
  const API_BASE_URL = 'https://qwen.aikit.club/v1';
18
18
 
19
- const QWEN_MODELS = {
20
- 'qwen3-max': { name: 'Qwen3 Max', limit: { context: 262144, output: 32768 } },
21
- 'qwen3-max-2026-01-23': { name: 'Qwen3 Max', limit: { context: 262144, output: 32768 } },
22
- 'qwen3-vl-plus': { name: 'Qwen3 VL Plus', limit: { context: 262144, output: 32768 } },
23
- 'qwen3-coder-plus': { name: 'Qwen3 Coder Plus', limit: { context: 1048576, output: 65536 } },
24
- 'qwen3-vl-32b': { name: 'Qwen3 VL 32B', limit: { context: 131072, output: 32768 } },
25
- 'qwen3-vl-30b-a3b': { name: 'Qwen3 VL 30B A3B', limit: { context: 131072, output: 32768 } },
26
- 'qwen3-omni-flash': { name: 'Qwen3 Omni Flash', limit: { context: 65536, output: 13684 } },
27
- 'qwen3-30b-a3b': { name: 'Qwen3 30B A3B', limit: { context: 131072, output: 32768 } },
28
- 'qwen3-coder-30b-a3b-instruct': { name: 'Qwen3 Coder Flash', limit: { context: 262144, output: 65536 } },
29
- 'qwen-max': { name: 'Qwen Max' },
30
- 'qwen2.5-max': { name: 'Qwen2.5 Max' },
31
- 'qwen2.5-plus': { name: 'Qwen2.5 Plus' },
32
- 'qwen2.5-turbo': { name: 'Qwen2.5 Turbo' },
33
- 'qwq-32b': { name: 'QWQ 32B' },
34
- 'qwen-deep-research': { name: 'Qwen Deep Research' },
35
- 'qwen-web-dev': { name: 'Qwen Web Dev' },
36
- 'qwen-full-stack': { name: 'Qwen Full Stack' },
37
- 'qwen-cogview': { name: 'Qwen CogView' }
38
- };
39
-
40
19
  function ensureLogDir() {
41
20
  try {
42
21
  if (!fs.existsSync(LOG_DIR)) {
@@ -67,11 +46,8 @@ function readApiKeyFromAuth() {
67
46
 
68
47
  const providerAuth = auth[PROVIDER_ID];
69
48
  if (providerAuth) {
70
- // Read BOTH key and apiKey fields - OpenCode can use either
71
49
  const apiKey = providerAuth.key || providerAuth.apiKey || providerAuth.token || null;
72
- if (apiKey) {
73
- return apiKey;
74
- }
50
+ return apiKey;
75
51
  }
76
52
  }
77
53
  } catch (e) {
@@ -80,6 +56,72 @@ function readApiKeyFromAuth() {
80
56
  return null;
81
57
  }
82
58
 
59
+ async function fetchModels() {
60
+ return new Promise((resolve) => {
61
+ const apiKey = readApiKeyFromAuth();
62
+
63
+ const options = {
64
+ hostname: 'qwen.aikit.club',
65
+ port: 443,
66
+ path: '/v1/models',
67
+ method: 'GET',
68
+ headers: {
69
+ 'Host': 'qwen.aikit.club',
70
+ 'Content-Type': 'application/json'
71
+ }
72
+ };
73
+
74
+ if (apiKey) {
75
+ options.headers['Authorization'] = `Bearer ${apiKey}`;
76
+ }
77
+
78
+ const req = https.request(options, (res) => {
79
+ let data = '';
80
+ res.on('data', chunk => data += chunk);
81
+ res.on('end', () => {
82
+ try {
83
+ const json = JSON.parse(data);
84
+ if (json.data && Array.isArray(json.data)) {
85
+ const models = {};
86
+ json.data.forEach(model => {
87
+ models[model.id] = { name: model.id };
88
+ });
89
+ log(`[Models] Fetched ${Object.keys(models).length} models`);
90
+ resolve(models);
91
+ } else {
92
+ log(`[Models] Unexpected response: ${data.substring(0, 200)}`);
93
+ resolve(getDefaultModels());
94
+ }
95
+ } catch (e) {
96
+ log(`[Models] Parse error: ${e.message}`);
97
+ resolve(getDefaultModels());
98
+ }
99
+ });
100
+ });
101
+
102
+ req.on('error', (e) => {
103
+ log(`[Models] Error: ${e.message}`);
104
+ resolve(getDefaultModels());
105
+ });
106
+
107
+ req.end();
108
+ });
109
+ }
110
+
111
+ function getDefaultModels() {
112
+ return {
113
+ 'qwen-max': { name: 'Qwen Max' },
114
+ 'qwen2.5-max': { name: 'Qwen2.5 Max' },
115
+ 'qwen2.5-plus': { name: 'Qwen2.5 Plus' },
116
+ 'qwen2.5-turbo': { name: 'Qwen2.5 Turbo' },
117
+ 'qwq-32b': { name: 'QWQ 32B' },
118
+ 'qwen-deep-research': { name: 'Qwen Deep Research' }
119
+ };
120
+ }
121
+
122
+ let cachedModels = null;
123
+ let proxyPort = 0;
124
+
83
125
  function startProxy() {
84
126
  return new Promise((resolve) => {
85
127
  const server = http.createServer(async (req, res) => {
@@ -99,7 +141,8 @@ function startProxy() {
99
141
  res.end(JSON.stringify({
100
142
  status: 'ok',
101
143
  provider: 'qwen',
102
- hasKey: !!apiKey
144
+ hasKey: !!apiKey,
145
+ modelsCount: cachedModels ? Object.keys(cachedModels).length : 0
103
146
  }));
104
147
  return;
105
148
  }
@@ -142,9 +185,9 @@ function startProxy() {
142
185
  });
143
186
 
144
187
  server.listen(0, '127.0.0.1', () => {
145
- const port = server.address().port;
146
- log(`[Proxy] Started on port ${port}`);
147
- resolve(port);
188
+ proxyPort = server.address().port;
189
+ log(`[Proxy] Started on port ${proxyPort}`);
190
+ resolve(proxyPort);
148
191
  });
149
192
 
150
193
  server.on('error', (e) => {
@@ -157,8 +200,13 @@ function startProxy() {
157
200
  export const QwenPlugin = async (ctx) => {
158
201
  log('[Plugin] Starting Qwen Plugin...');
159
202
 
160
- const port = await startProxy();
161
- const localBaseUrl = `http://127.0.0.1:${port}/v1`;
203
+ await startProxy();
204
+
205
+ // Fetch models from API
206
+ cachedModels = await fetchModels();
207
+ log(`[Plugin] Loaded ${Object.keys(cachedModels).length} models`);
208
+
209
+ const localBaseUrl = `http://127.0.0.1:${proxyPort}/v1`;
162
210
 
163
211
  return {
164
212
  config: async (config) => {
@@ -170,10 +218,10 @@ export const QwenPlugin = async (ctx) => {
170
218
  id: PROVIDER_ID,
171
219
  name: 'Qwen AI',
172
220
  options: { baseURL: localBaseUrl },
173
- models: QWEN_MODELS
221
+ models: cachedModels
174
222
  };
175
223
 
176
- log(`[Hook] Registered provider with ${Object.keys(QWEN_MODELS).length} models`);
224
+ log(`[Hook] Registered provider with ${Object.keys(cachedModels).length} models`);
177
225
  }
178
226
  };
179
227
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwen-opencode-provider",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "OpenCode plugin for Qwen API - auto adds provider with 28+ models",
5
5
  "main": "index.js",
6
6
  "type": "module",