qwen-opencode-provider 1.0.2 → 1.0.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.
Files changed (3) hide show
  1. package/README.md +37 -115
  2. package/index.js +72 -394
  3. package/package.json +3 -11
package/README.md CHANGED
@@ -1,143 +1,65 @@
1
1
  # OpenCode Qwen Plugin
2
2
 
3
- Plugin cho OpenCode để thêm Qwen AI provider với đầy đủ models.
3
+ OpenCode plugin for Qwen AI - auto adds provider with 28+ models.
4
4
 
5
- ## Tính năng
5
+ ## Features
6
6
 
7
- - **Tự động thêm Qwen provider** vào OpenCode config
8
- - **28+ Qwen models** được tích hợp sẵn
9
- - **Custom tools** để làm việc với Qwen API:
10
- - `qwen-validate-token` - Validate Qwen token
11
- - `qwen-list-models` - Liệt kê models
12
- - `qwen-setup` - Hướng dẫn cài đặt
13
- - `qwen-test` - Test kết nối API
7
+ - **Auto-configure**: Automatically adds Qwen provider to OpenCode
8
+ - **28+ Models**: All Qwen models pre-configured
9
+ - **Native auth**: Uses OpenCode's built-in auth system (`/connect`)
14
10
 
15
- ## Cài đặt
11
+ ## Installation
16
12
 
17
- ### Cách 1: Local Plugin (Khuyến nghị)
18
-
19
- 1. **Tạo thư mục plugins:**
20
- ```bash
21
- mkdir -p ~/.config/opencode/plugins
22
- ```
23
-
24
- 2. **Copy plugin vào thư mục:**
25
- ```bash
26
- cp -r opencode-qwen-plugin/* ~/.config/opencode/plugins/qwen/
27
- ```
28
-
29
- 3. **Tạo package.json trong config directory:**
30
- ```bash
31
- mkdir -p ~/.config/opencode
32
- cp opencode-qwen-plugin/package.json ~/.config/opencode/
33
- ```
34
-
35
- 4. **Khởi động lại OpenCode**
36
-
37
- ### Cách 2: NPM Package
38
-
39
- Thêm vào `opencode.json`:
13
+ Add to `opencode.json`:
40
14
  ```json
41
15
  {
42
16
  "plugin": ["qwen-opencode-provider"]
43
17
  }
44
18
  ```
45
19
 
46
- ## Cách lấy Qwen API Token
47
-
48
- ### Bước 1: Đăng nhập Qwen
49
- Truy cập https://chat.qwen.ai và đăng nhập
50
-
51
- ### Bước 2: Lấy Token
52
- Mở Developer Console (F12) và chạy:
53
- ```javascript
54
- localStorage.getItem('token')
55
- ```
56
-
57
- Hoặc sử dụng bookmarklet:
58
- ```javascript
59
- javascript:(function(){if(window.location.hostname!=="chat.qwen.ai"){alert("🚀 This code is for chat.qwen.ai");window.open("https://chat.qwen.ai","_blank");return;}function getApiKeyData(){const token=localStorage.getItem(!token){alert("token");if("❌ qwen access_token not found !!!");return null;}return token;}async function copyToClipboard(text){try{await navigator.clipboard.writeText(text);return true;}catch(err){console.error("❌ Failed to copy to clipboard:",err);const textarea=document.createElement("textarea");textarea.value=text;textarea.style.position="fixed";textarea.style.opacity="0";document.body.appendChild(textarea);textarea.focus();textarea.select();const success=document.execCommand("copy");document.body.removeChild(textarea);return success;}}const apiKeyData=getApiKeyData();if(!apiKeyData)return;copyToClipboard(apiKeyData).then((success)=>{if(success){alert("🔑 Qwen access_token copied to clipboard !!! 🎉");}else{prompt("🔰 Qwen access_token:",apiKeyData);}});})();
60
- ```
20
+ ## Usage
61
21
 
62
- ### Bước 3: Thêm vào OpenCode
22
+ ### 1. Connect Qwen Account
63
23
  ```bash
64
24
  /connect
65
25
  ```
66
- Tìm "Qwen" nhập token của bạn.
26
+ Search for "qwen" and enter your Qwen access token.
67
27
 
68
- ## Sử dụng
28
+ ### 2. Get Your Token
29
+ 1. Visit https://chat.qwen.ai and login
30
+ 2. Open Developer Console (F12)
31
+ 3. Run: `localStorage.getItem('token')`
69
32
 
70
- ### Chọn model:
33
+ ### 3. Select Model
71
34
  ```bash
72
35
  /models
73
36
  ```
74
- Chọn model Qwen bạn muốn sử dụng.
37
+ Choose any Qwen model.
75
38
 
76
- ### Sử dụng custom tools:
77
-
78
- ```bash
79
- # Validate token
80
- qwen-validate-token --token YOUR_TOKEN
81
-
82
- # List models
83
- qwen-list-models --apiKey YOUR_API_KEY
84
-
85
- # Test connection
86
- qwen-test --apiKey YOUR_API_KEY --message "Hello!"
87
-
88
- # Xem hướng dẫn setup
89
- qwen-setup
90
- ```
91
-
92
- ## Models có sẵn
39
+ ## Supported Models
93
40
 
94
41
  | Model | Description |
95
42
  |-------|-------------|
96
- | `qwen-max` | Latest Qwen Max |
97
- | `qwen2.5-max` | Best overall with vision + web search |
98
- | `qwen2.5-turbo` | Fast responses |
99
- | `qwen2.5-plus` | Balanced performance |
100
- | `qwen2.5-coder-32b` | Code generation |
101
- | `qwen3-next-80b-a3b` | Next gen 80B |
102
- | `qwen3-coder` | Code + tool calling |
103
- | `qwen3-max` | Best Qwen3 |
104
- | `qwq-32b` | Reasoning with thinking |
105
- | `qwen-deep-research` | Research + web search |
106
- | `q | Web development |
107
- wen-web-dev`| `qwen-full-stack` | Full-stack apps |
108
-
109
- ## Tính năng Qwen API
110
-
111
- - 👁️ **Vision** - Phân tích hình ảnh
112
- - 🌐 **Web Search** - Tìm kiếm web
113
- - 🧠 **Thinking Mode** - Chế độ suy nghĩ
114
- - 🎨 **Image Generation** - Tạo hình ảnh
115
- - 👨‍💻 **Code Generation** - Viết code
116
-
117
- ## Cấu hình thủ công
118
-
119
- Nếu plugin không tự động thêm provider, thêm vào `~/.config/opencode/opencode.json`:
120
-
121
- ```json
122
- {
123
- "provider": {
124
- "qwen": {
125
- "npm": "@ai-sdk/openai-compatible",
126
- "name": "Qwen AI",
127
- "options": {
128
- "baseURL": "https://qwen.aikit.club/v1",
129
- "headers": {
130
- "Authorization": "Bearer ${QWEN_API_KEY}"
131
- }
132
- },
133
- "models": {
134
- "qwen2.5-max": { "name": "Qwen2.5 Max" },
135
- "qwen2.5-turbo": { "name": "Qwen2.5 Turbo" }
136
- }
137
- }
138
- }
139
- }
140
- ```
43
+ | qwen-max | Latest Qwen Max |
44
+ | qwen2.5-max | Best overall + vision + web search |
45
+ | qwen2.5-turbo | Fast responses |
46
+ | qwen2.5-plus | Balanced performance |
47
+ | qwen2.5-coder-32b | Code generation |
48
+ | qwen3-coder | Code + tool calling |
49
+ | qwen3-max | Best Qwen3 |
50
+ | qwq-32b | Reasoning with thinking |
51
+ | qwen-deep-research | Research + web search |
52
+ | qwen-web-dev | Web development |
53
+ | qwen-full-stack | Full-stack apps |
54
+ | qwen-cogview | Image generation |
55
+
56
+ ## API Features
57
+
58
+ - 👁️ Vision (image analysis)
59
+ - 🌐 Web Search
60
+ - 🧠 Thinking Mode
61
+ - 🎨 Image Generation
62
+ - 👨‍💻 Code Generation
141
63
 
142
64
  ## License
143
65
 
package/index.js CHANGED
@@ -1,240 +1,97 @@
1
1
  /**
2
2
  * OpenCode Qwen API Plugin
3
3
  *
4
- * This plugin adds Qwen AI provider to OpenCode and provides custom tools
5
- * for validating tokens and listing models.
4
+ * Automatically adds Qwen AI provider to OpenCode with 28+ models.
5
+ * Uses OpenCode's built-in auth system (/connect).
6
6
  *
7
7
  * Provider ID: qwen
8
8
  * Base URL: https://qwen.aikit.club/v1
9
9
  */
10
10
 
11
11
  import { readFileSync, writeFileSync, existsSync } from 'fs';
12
- import { join, dirname } from 'path';
12
+ import { join } from 'path';
13
13
  import { homedir } from 'os';
14
14
 
15
- // Qwen API Configuration
16
15
  const QWEN_BASE_URL = 'https://qwen.aikit.club/v1';
17
16
  const QWEN_PROVIDER_ID = 'qwen';
18
17
 
19
- /**
20
- * Get the OpenCode config file path
21
- */
18
+ const QWEN_MODELS = {
19
+ "qwen-max": { name: "Qwen Max", description: "Latest Qwen Max model" },
20
+ "qwen-max-latest": { name: "Qwen Max Latest", description: "Latest version of Qwen Max" },
21
+ "qwen2.5-max": { name: "Qwen2.5 Max", description: "Best overall with vision + web search" },
22
+ "qwen2.5-plus": { name: "Qwen2.5 Plus", description: "Balanced performance" },
23
+ "qwen2.5-turbo": { name: "Qwen2.5 Turbo", description: "Fast responses" },
24
+ "qwen2.5-14b-instruct-1m": { name: "Qwen2.5 14B Instruct 1M", description: "1M context" },
25
+ "qwen2.5-72b-instruct": { name: "Qwen2.5 72B Instruct", description: "72B parameters" },
26
+ "qwen2.5-coder-32b-instruct": { name: "Qwen2.5 Coder 32B", description: "Code generation" },
27
+ "qwen2.5-omni-7b": { name: "Qwen2.5 Omni 7B", description: "Multimodal" },
28
+ "qwen2.5-vl-32b-instruct": { name: "Qwen2.5 VL 32B", description: "Vision-language" },
29
+ "qwen3-next-80b-a3b": { name: "Qwen3 Next 80B A3B", description: "Next gen" },
30
+ "qwen3-235b-a22b-2507": { name: "Qwen3 235B A22B", description: "Large model" },
31
+ "qwen3-30b-a3b-2507": { name: "Qwen3 30B A3B", description: "Compact high-perf" },
32
+ "qwen3-coder": { name: "Qwen3 Coder", description: "Code + tool calling" },
33
+ "qwen3-coder-flash": { name: "Qwen3 Coder Flash", description: "Fast code" },
34
+ "qwen3-max": { name: "Qwen3 Max", description: "Best Qwen3" },
35
+ "qwen3-omni-flash": { name: "Qwen3 Omni Flash", description: "Fast multimodal" },
36
+ "qwen3-vl-235b-a22b": { name: "Qwen3 VL 235B", description: "Large vision" },
37
+ "qwen3-vl-32b": { name: "Qwen3 VL 32B", description: "Vision 32B" },
38
+ "qwen3-vl-30b-a3b": { name: "Qwen3 VL 30B A3B", description: "Compact vision" },
39
+ "qvq-max": { name: "QVQ Max", description: "Vision reasoning" },
40
+ "qwq-32b": { name: "QWQ 32B", description: "Reasoning with thinking" },
41
+ "qwen-deep-research": { name: "Qwen Deep Research", description: "Research + web search" },
42
+ "qwen-web-dev": { name: "Qwen Web Dev", description: "Web development" },
43
+ "qwen-full-stack": { name: "Qwen Full Stack", description: "Full-stack apps" },
44
+ "qwen-cogview": { name: "Qwen CogView", description: "Image generation" }
45
+ };
46
+
22
47
  function getConfigPath() {
23
- const homeDir = homedir();
24
- return join(homeDir, '.config', 'opencode', 'opencode.json');
48
+ return join(homedir(), '.config', 'opencode', 'opencode.json');
25
49
  }
26
50
 
27
- /**
28
- * Read and parse OpenCode config
29
- */
30
51
  function readConfig() {
31
52
  const configPath = getConfigPath();
32
- if (!existsSync(configPath)) {
33
- return null;
34
- }
53
+ if (!existsSync(configPath)) return null;
35
54
  try {
36
- const content = readFileSync(configPath, 'utf-8');
37
- return JSON.parse(content);
55
+ return JSON.parse(readFileSync(configPath, 'utf-8'));
38
56
  } catch {
39
57
  return null;
40
58
  }
41
59
  }
42
60
 
43
- /**
44
- * Write OpenCode config
45
- */
46
61
  function writeConfig(config) {
47
- const configPath = getConfigPath();
48
- writeFileSync(configPath, JSON.stringify(config, null, 2));
62
+ writeFileSync(getConfigPath(), JSON.stringify(config, null, 2));
49
63
  }
50
64
 
51
- /**
52
- * Check if Qwen provider is already configured
53
- */
54
65
  function isQwenProviderConfigured(config) {
55
- return config?.provider?.qwen !== undefined;
66
+ return config?.provider?.[QWEN_PROVIDER_ID] !== undefined;
56
67
  }
57
68
 
58
- /**
59
- * Add Qwen provider to OpenCode config
60
- */
61
69
  function addQwenProvider() {
62
- const configPath = getConfigPath();
63
70
  let config = readConfig();
64
71
 
72
+ const qwenConfig = {
73
+ npm: "@ai-sdk/openai-compatible",
74
+ name: "Qwen AI",
75
+ options: {
76
+ baseURL: QWEN_BASE_URL,
77
+ headers: {
78
+ "Authorization": "Bearer ${QWEN_API_KEY}"
79
+ }
80
+ },
81
+ models: QWEN_MODELS
82
+ };
83
+
65
84
  if (!config) {
66
- // new Create config with Qwen provider
67
85
  config = {
68
86
  $schema: "https://opencode.ai/config.json",
69
87
  provider: {
70
- [QWEN_PROVIDER_ID]: {
71
- npm: "@ai-sdk/openai-compatible",
72
- name: "Qwen AI",
73
- options: {
74
- baseURL: QWEN_BASE_URL,
75
- headers: {
76
- "Authorization": "Bearer ${QWEN_API_KEY}"
77
- }
78
- },
79
- models: {
80
- // Chat Completions
81
- "qwen-max": {
82
- name: "Qwen Max",
83
- description: "Latest Qwen Max model with best performance"
84
- },
85
- "qwen-max-latest": {
86
- name: "Qwen Max Latest",
87
- description: "Latest version of Qwen Max"
88
- },
89
- "qwen2.5-max": {
90
- name: "Qwen2.5 Max",
91
- description: "Qwen2.5 series with vision, reasoning and web search"
92
- },
93
- "qwen2.5-plus": {
94
- name: "Qwen2.5 Plus",
95
- description: "Balanced performance with vision support"
96
- },
97
- "qwen2.5-turbo": {
98
- name: "Qwen2.5 Turbo",
99
- description: "Fast responses with vision support"
100
- },
101
- "qwen2.5-14b-instruct-1m": {
102
- name: "Qwen2.5 14B Instruct 1M",
103
- description: "14B parameters with 1M context window"
104
- },
105
- "qwen2.5-72b-instruct": {
106
- name: "Qwen2.5 72B Instruct",
107
- description: "72B parameters for complex tasks"
108
- },
109
- "qwen2.5-coder-32b-instruct": {
110
- name: "Qwen2.5 Coder 32B",
111
- description: "Specialized code generation model"
112
- },
113
- "qwen2.5-omni-7b": {
114
- name: "Qwen2.5 Omni 7B",
115
- description: "Multimodal model with text, image, audio support"
116
- },
117
- "qwen2.5-vl-32b-instruct": {
118
- name: "Qwen2.5 VL 32B",
119
- description: "Vision-language model"
120
- },
121
- // Qwen3 Series
122
- "qwen3-next-80b-a3b": {
123
- name: "Qwen3 Next 80B A3B",
124
- description: "Next generation with 80B parameters"
125
- },
126
- "qwen3-235b-a22b-2507": {
127
- name: "Qwen3 235B A22B",
128
- description: "Large model with 235B parameters"
129
- },
130
- "qwen3-30b-a3b-2507": {
131
- name: "Qwen3 30B A3B",
132
- description: "Compact high-performance model"
133
- },
134
- "qwen3-coder": {
135
- name: "Qwen3 Coder",
136
- description: "Code generation with tool calling"
137
- },
138
- "qwen3-coder-flash": {
139
- name: "Qwen3 Coder Flash",
140
- description: "Fast code generation"
141
- },
142
- "qwen3-max": {
143
- name: "Qwen3 Max",
144
- description: "Best Qwen3 performance"
145
- },
146
- "qwen3-omni-flash": {
147
- name: "Qwen3 Omni Flash",
148
- description: "Fast multimodal model"
149
- },
150
- "qwen3-vl-235b-a22b": {
151
- name: "Qwen3 VL 235B A22B",
152
- description: "Large vision-language model"
153
- },
154
- "qwen3-vl-32b": {
155
- name: "Qwen3 VL 32B",
156
- description: "Vision-language model 32B"
157
- },
158
- "qwen3-vl-30b-a3b": {
159
- name: "Qwen3 VL 30B A3B",
160
- description: "Compact vision-language model"
161
- },
162
- // Reasoning Models
163
- "qvq-max": {
164
- name: "QVQ Max",
165
- description: "Vision reasoning model"
166
- },
167
- "qwq-32b": {
168
- name: "QWQ 32B",
169
- description: "Reasoning model with thinking"
170
- },
171
- "qwen-deep-research": {
172
- name: "Qwen Deep Research",
173
- description: "Research-focused model with web search"
174
- },
175
- // Development Models
176
- "qwen-web-dev": {
177
- name: "Qwen Web Dev",
178
- description: "Web development specialized model"
179
- },
180
- "qwen-full-stack": {
181
- name: "Qwen Full Stack",
182
- description: "Full-stack application development"
183
- },
184
- // Image Generation
185
- "qwen-cogview": {
186
- name: "Qwen CogView",
187
- description: "Image generation model"
188
- }
189
- }
190
- }
88
+ [QWEN_PROVIDER_ID]: qwenConfig
191
89
  }
192
90
  };
193
91
  } else {
194
- // Add Qwen provider to existing config
195
- if (!config.provider) {
196
- config.provider = {};
197
- }
198
-
92
+ if (!config.provider) config.provider = {};
199
93
  if (!isQwenProviderConfigured(config)) {
200
- config.provider[QWEN_PROVIDER_ID] = {
201
- npm: "@ai-sdk/openai-compatible",
202
- name: "Qwen AI",
203
- options: {
204
- baseURL: QWEN_BASE_URL,
205
- headers: {
206
- "Authorization": "Bearer ${QWEN_API_KEY}"
207
- }
208
- },
209
- models: {
210
- "qwen-max": { name: "Qwen Max" },
211
- "qwen-max-latest": { name: "Qwen Max Latest" },
212
- "qwen2.5-max": { name: "Qwen2.5 Max" },
213
- "qwen2.5-plus": { name: "Qwen2.5 Plus" },
214
- "qwen2.5-turbo": { name: "Qwen2.5 Turbo" },
215
- "qwen2.5-14b-instruct-1m": { name: "Qwen2.5 14B Instruct 1M" },
216
- "qwen2.5-72b-instruct": { name: "Qwen2.5 72B Instruct" },
217
- "qwen2.5-coder-32b-instruct": { name: "Qwen2.5 Coder 32B" },
218
- "qwen2.5-omni-7b": { name: "Qwen2.5 Omni 7B" },
219
- "qwen2.5-vl-32b-instruct": { name: "Qwen2.5 VL 32B" },
220
- "qwen3-next-80b-a3b": { name: "Qwen3 Next 80B A3B" },
221
- "qwen3-235b-a22b-2507": { name: "Qwen3 235B A22B" },
222
- "qwen3-30b-a3b-2507": { name: "Qwen3 30B A3B" },
223
- "qwen3-coder": { name: "Qwen3 Coder" },
224
- "qwen3-coder-flash": { name: "Qwen3 Coder Flash" },
225
- "qwen3-max": { name: "Qwen3 Max" },
226
- "qwen3-omni-flash": { name: "Qwen3 Omni Flash" },
227
- "qwen3-vl-235b-a22b": { name: "Qwen3 VL 235B A22B" },
228
- "qwen3-vl-32b": { name: "Qwen3 VL 32B" },
229
- "qwen3-vl-30b-a3b": { name: "Qwen3 VL 30B A3B" },
230
- "qvq-max": { name: "QVQ Max" },
231
- "qwq-32b": { name: "QWQ 32B" },
232
- "qwen-deep-research": { name: "Qwen Deep Research" },
233
- "qwen-web-dev": { name: "Qwen Web Dev" },
234
- "qwen-full-stack": { name: "Qwen Full Stack" },
235
- "qwen-cogview": { name: "Qwen CogView" }
236
- }
237
- };
94
+ config.provider[QWEN_PROVIDER_ID] = qwenConfig;
238
95
  }
239
96
  }
240
97
 
@@ -242,213 +99,34 @@ function addQwenProvider() {
242
99
  return true;
243
100
  }
244
101
 
245
- /**
246
- * OpenCode Plugin
247
- */
248
- export const QwenPlugin = async ({ project, client, $, directory, worktree }) => {
249
- // Automatically add Qwen provider on first load
102
+ export const QwenPlugin = async ({ client }) => {
250
103
  try {
251
- const configPath = getConfigPath();
252
- if (!existsSync(dirname(configPath))) {
253
- // Config directory doesn't exist yet, skip
254
- } else {
255
- const config = readConfig();
256
- if (!isQwenProviderConfigured(config)) {
257
- addQwenProvider();
258
- await client.app.log({
259
- body: {
260
- service: "qwen-plugin",
261
- level: "info",
262
- message: "Qwen provider added to OpenCode config",
263
- }
264
- });
265
- }
104
+ const config = readConfig();
105
+ if (!isQwenProviderConfigured(config)) {
106
+ addQwenProvider();
107
+ await client.app.log({
108
+ body: {
109
+ service: "qwen-plugin",
110
+ level: "info",
111
+ message: "Qwen provider added to OpenCode config"
112
+ }
113
+ });
266
114
  }
267
115
  } catch (error) {
268
- // Silently fail - provider can be added manually
116
+ // Silent fail
269
117
  }
270
118
 
271
119
  return {
272
- // Custom tools for Qwen API
273
- tool: {
274
- /**
275
- * Validate Qwen API token
276
- */
277
- "qwen-validate-token": {
278
- description: "Validate a Qwen API access token",
279
- args: {
280
- token: {
281
- type: "string",
282
- description: "The Qwen access token to validate",
283
- required: true
284
- }
285
- },
286
- async execute(args, context) {
287
- const { directory, worktree } = context;
288
-
289
- try {
290
- const response = await fetch(`${QWEN_BASE_URL}/validate?token=${args.token}`, {
291
- method: "GET",
292
- headers: {
293
- "Content-Type": "application/json"
294
- }
295
- });
296
-
297
- const data = await response.json();
298
-
299
- if (data.valid) {
300
- return `✅ Token is valid!\nUser ID: ${data.user_id || 'N/A'}\nExpires: ${data.expires_at || 'N/A'}`;
301
- } else {
302
- return `❌ Token is invalid or expired`;
303
- }
304
- } catch (error) {
305
- return `Error validating token: ${error.message}`;
306
- }
307
- }
308
- },
309
-
310
- /**
311
- * List available Qwen models
312
- */
313
- "qwen-list-models": {
314
- description: "List all available Qwen models",
315
- args: {
316
- apiKey: {
317
- type: "string",
318
- description: "Qwen API key (Bearer token)",
319
- required: true
320
- }
321
- },
322
- async execute(args, context) {
323
- try {
324
- const response = await fetch(`${QWEN_BASE_URL}/models`, {
325
- method: "GET",
326
- headers: {
327
- "Authorization": `Bearer ${args.apiKey}`,
328
- "Content-Type": "application/json"
329
- }
330
- });
331
-
332
- const data = await response.json();
333
-
334
- if (data.data && Array.isArray(data.data)) {
335
- const models = data.data.map(m => `• ${m.id} - ${m.description || 'No description'}`).join('\n');
336
- return `Available Qwen Models:\n\n${models}`;
337
- } else {
338
- return `Error: Could not fetch models - ${JSON.stringify(data)}`;
339
- }
340
- } catch (error) {
341
- return `Error listing models: ${error.message}`;
342
- }
343
- }
344
- },
345
-
346
- /**
347
- * Get Qwen API setup instructions
348
- */
349
- "qwen-setup": {
350
- description: "Get instructions for setting up Qwen API in OpenCode",
351
- args: {},
352
- async execute(args, context) {
353
- return `
354
- ╔══════════════════════════════════════════════════════════════════╗
355
- ║ QWEN API SETUP GUIDE ║
356
- ╠══════════════════════════════════════════════════════════════════╣
357
- ║ ║
358
- ║ 1. GET YOUR TOKEN: ║
359
- ║ • Visit https://chat.qwen.ai ║
360
- ║ • Login and open Developer Console (F12) ║
361
- ║ • Run: localStorage.getItem('token') ║
362
- ║ • Or use the provided JavaScript bookmarklet ║
363
- ║ ║
364
- ║ 2. ADD TO OPENCODE: ║
365
- ║ Run: /connect ║
366
- ║ Search: qwen ║
367
- ║ Enter your token ║
368
- ║ ║
369
- ║ 3. SELECT MODEL: ║
370
- ║ Run: /models ║
371
- ║ Select a Qwen model ║
372
- ║ ║
373
- ║ AVAILABLE MODELS: ║
374
- ║ • qwen2.5-max - Best overall performance ║
375
- ║ • qwen2.5-turbo - Fast responses ║
376
- ║ • qwen2.5-plus - Balanced ║
377
- ║ • qwen3-coder - Code generation ║
378
- ║ • qwen3-max - Latest Qwen3 ║
379
- ║ • qwen-deep-research - Research tasks ║
380
- ║ • qwen-web-dev - Web development ║
381
- ║ • qwen-full-stack - Full-stack apps ║
382
- ║ ║
383
- ║ FEATURES: ║
384
- ║ ✅ Vision (image analysis) ║
385
- ║ ✅ Web Search ║
386
- ║ ✅ Thinking Mode ║
387
- ║ ✅ Image Generation ║
388
- ║ ✅ Code Generation ║
389
- ║ ║
390
- ╚══════════════════════════════════════════════════════════════════╝
391
- `;
392
- }
393
- },
394
-
395
- /**
396
- * Test Qwen API connection
397
- */
398
- "qwen-test": {
399
- description: "Test Qwen API connection with a simple prompt",
400
- args: {
401
- apiKey: {
402
- type: "string",
403
- description: "Qwen API key",
404
- required: true
405
- },
406
- message: {
407
- type: "string",
408
- description: "Test message (default: 'Hello')",
409
- required: false
410
- }
411
- },
412
- async execute(args, context) {
413
- const message = args.message || "Hello, how are you?";
414
-
415
- try {
416
- const response = await fetch(`${QWEN_BASE_URL}/chat/completions`, {
417
- method: "POST",
418
- headers: {
419
- "Authorization": `Bearer ${args.apiKey}`,
420
- "Content-Type": "application/json"
421
- },
422
- body: JSON.stringify({
423
- model: "qwen2.5-turbo",
424
- messages: [{ role: "user", content: message }],
425
- stream: false
426
- })
427
- });
428
-
429
- const data = await response.json();
430
-
431
- if (data.choices && data.choices[0]) {
432
- return `✅ Connection successful!\n\nModel: ${data.model}\nResponse: ${data.choices[0].message.content}`;
433
- } else {
434
- return `❌ Error: ${JSON.stringify(data)}`;
435
- }
436
- } catch (error) {
437
- return `❌ Connection failed: ${error.message}`;
438
- }
120
+ "installation.updated": async ({ installation }) {
121
+ try {
122
+ const config = readConfig();
123
+ if (config?.provider?.[QWEN_PROVIDER_ID]) {
124
+ config.provider[QWEN_PROVIDER_ID].models = QWEN_MODELS;
125
+ writeConfig(config);
439
126
  }
127
+ } catch (error) {
128
+ // Silent fail
440
129
  }
441
- },
442
-
443
- // Event hooks
444
- "session.created": async ({ session }) => {
445
- await client.app.log({
446
- body: {
447
- service: "qwen-plugin",
448
- level: "debug",
449
- message: `New session created: ${session.id}`,
450
- }
451
- });
452
130
  }
453
131
  };
454
132
  };
package/package.json CHANGED
@@ -1,19 +1,11 @@
1
1
  {
2
2
  "name": "qwen-opencode-provider",
3
- "version": "1.0.2",
4
- "description": "OpenCode plugin for Qwen API - adds provider and 28+ models with custom tools",
3
+ "version": "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",
7
- "keywords": ["opencode", "plugin", "qwen", "ai", "alibaba", "qwen-api", "chatgpt"],
7
+ "keywords": ["opencode", "plugin", "qwen", "ai", "alibaba"],
8
8
  "author": "",
9
9
  "license": "MIT",
10
- "repository": {
11
- "type": "git",
12
- "url": "https://github.com/tanu1337/qwen-api"
13
- },
14
- "homepage": "https://github.com/tanu1337/qwen-api#readme",
15
- "bugs": {
16
- "url": "https://github.com/tanu1337/qwen-api/issues"
17
- },
18
10
  "dependencies": {}
19
11
  }