Enhanced Version - Added request throttling, 429 handling, header alignment and other enhancements based on opencode-qwencode-auth

cd ~/.config/opencode && npm install github:RunMintOn/OpenCode-Qwen-Proxy
cd ~/.config/opencode
npm uninstall opencode-qwen-proxy
npm install github:RunMintOn/OpenCode-Qwen-Proxy
Then fully restart OpenCode.
If you need to pin a specific version for troubleshooting, use:
npm install github:RunMintOn/OpenCode-Qwen-Proxy#vX.Y.Z
Edit ~/.config/opencode/opencode.jsonc:
{
"plugin": ["opencode-qwen-proxy"],
"provider": {
"qwen-code": {
"npm": "@ai-sdk/openai-compatible",
"name": "Qwen Code",
"options": {
"baseURL": "https://portal.qwen.ai/v1"
},
"models": {
"coder-model": {
"name": "Qwen Coder",
"limit": { "context": 1048576, "output": 65536 },
"modalities": { "input": ["text"], "output": ["text"] }
},
"vision-model": {
"name": "Qwen Vision",
"limit": { "context": 131072, "output": 32768 },
"modalities": { "input": ["text", "image"], "output": ["text"] },
"attachment": true
}
}
}
}
}
opencode auth login
Then repeatedly press "↓" and select "Other" → Enter qwen-code → Select "Qwen Code (qwen.ai OAuth)"
Browser will open automatically, log in to qwen.ai and authorize.
opencode models
You should see qwen-code/coder-model and qwen-code/vision-model in the list.
~/.qwen/oauth_creds.json with Qwen Code CLIImportant: Qwen OAuth only supports 2 models, fully aligned with qwen-code CLI.
| Model | Context | Max Output | Description |
|---|---|---|---|
coder-model | 1M tokens | 64K tokens | Code model (default, recommended) |
vision-model | 128K tokens | 32K tokens | Vision model |
# Use code model (recommended)
opencode --provider qwen-code --model coder-model
# Use vision model
opencode --provider qwen-code --model vision-model
Note:
According to qwen code description, coder-model is the newly released qwen 3.5 plus
| Plan | Rate Limit | Daily Limit |
|---|---|---|
| Free (OAuth) | 60 times/minute | 1000 times/day |
Limits reset at 0:00 Beijing Time next day. For higher limits, use DashScope API.
┌─────────────────────────────────────────────────────────────────┐ │ User Input Question │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ OpenCode CLI │ │ ┌────────────────────────────────────────────────────────────┐ │ │ │ Load Plugin │ │ │ │ ├─ loader: Returns apiKey + fetch function │ │ │ │ └─ methods: Handles OAuth authentication │ │ │ └────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Plugin fetch Interceptor │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ 1. Add Headers │ │ │ │ - User-Agent: QwenCode/0.10.3 (linux; x64) │ │ │ │ - X-DashScope-CacheControl: enable │ │ │ │ - X-DashScope-AuthType: qwen-oauth │ │ │ │ 2. Add Authorization: Bearer <token> │ │ │ │ 3. Request Throttling (1 second interval + jitter) │ │ │ │ 4. 429 Handling (wait and retry) │ │ │ └──────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ portal.qwen.ai/v1 │ └─────────────────────────────────────────────────────────────────┘
| Role | Function | Purpose |
|---|---|---|
| Auth Provider | loader | Returns config (apiKey + baseURL + fetch) |
| Request Interceptor | fetch | Intercepts all requests, adds headers + throttling |
| OAuth Entry | methods | Handles user login, gets access token |
Problem: OpenCode generates more requests than Qwen Code CLI, easily hitting 60 times/minute limit.
Solution: Request queue controls rate.
class RequestQueue {
private lastRequestTime = 0;
private readonly MIN_INTERVAL = 1000; // 1 second
async enqueue<T>(fn: () => Promise<T>): Promise<T> {
const elapsed = Date.now() - this.lastRequestTime;
const waitTime = Math.max(0, this.MIN_INTERVAL - elapsed);
if (waitTime > 0) {
await new Promise(resolve => setTimeout(resolve, waitTime));
}
this.lastRequestTime = Date.now();
return fn();
}
}
Effect: Ensures each request interval ≥ 1 second, won't exceed 60 times/minute.
Problem: Fixed interval requests may be identified as "abnormal user".
Solution: Add 0.5-1.5s random delay on top of 1 second.
// src/plugin/request-queue.ts
private readonly JITTER_MIN = 500;
private readonly JITTER_MAX = 1500;
private getJitter(): number {
return Math.random() * (this.JITTER_MAX - this.JITTER_MIN) + this.JITTER_MIN;
}
Effect: Request interval = 1 second + (0.5~1.5s random) = 1.5-2.5s random, more like real user behavior.
Problem: Server may identify client source through Headers.
Solution: Simulate qwen-code CLI Headers.
headers.set('User-Agent', `QwenCode/0.10.3 (${platform}; ${arch})`);
headers.set('X-DashScope-CacheControl', 'enable');
headers.set('X-DashScope-UserAgent', `QwenCode/0.10.3 (${platform}; ${arch})`);
headers.set('X-DashScope-AuthType', 'qwen-oauth`);
Effect: From Headers perspective, requests are indistinguishable from qwen-code CLI.
Problem: Even with throttling, occasional rate limiting may still occur.
Solution: Automatically wait and retry.
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || '60';
await sleep(parseInt(retryAfter) * 1000);
return fetch(input, { headers }); // Retry
}
Effect: Automatically recovers from rate limiting without user intervention.
| Feature | Description |
|---|---|
| ⏱️ Request Throttling | 1 second interval + 0.5-1.5s random jitter, avoid hitting 60 times/minute limit |
| 📡 429 Auto Retry | Automatically wait and retry when rate limited |
| 🏷️ Header Alignment | User-Agent, X-DashScope-* exactly matching qwen-code CLI |
| 💾 Token Cache | No refresh within 5 minutes, reduce extra requests |
| 🎯 Streamlined Models | Only supports 2 models (coder-model, vision-model), aligned with qwen-code CLI |
Plugin automatically refreshes Token. If issues persist:
# Delete old credentials
rm ~/.qwen/oauth_creds.json
# Re-authenticate
opencode auth login
In opencode auth login:
qwen-codeStep 1: Clone Project
git clone https://github.com/RunMintOn/OpenCode-Qwen-Proxy.git
cd OpenCode-Qwen-Proxy
Step 2: Install Dependencies
npm install
Step 3: Link Plugin
# Run link in plugin project directory
npm link
Step 4: Configure in OpenCode
# Enter OpenCode config directory
cd ~/.config/opencode
# If package.json already exists, just add dependency
npm install opencode-qwen-proxy --save
# If no package.json, initialize first
npm init -y
npm install opencode-qwen-proxy --save
Step 5: Verify Plugin Loaded
# Restart OpenCode or start new conversation
opencode --version
Step 1-3: Same as above
# Clone project and install dependencies
git clone https://github.com/RunMintOn/OpenCode-Qwen-Proxy.git
cd OpenCode-Qwen-Proxy
npm install
Step 4: Build Plugin First
# Build plugin (must build first)
npm run build
Note:
file:protocol needs to point to directory containingpackage.json, so build must run first.
Step 5: Configure Local Link
Edit ~/.config/opencode/package.json:
{
"dependencies": {
"opencode-qwen-proxy": "file:/path/to/OpenCode-Qwen-Proxy"
}
}
Replace
/path/to/OpenCode-Qwen-Proxywith actual absolute path, for example:
- Linux/Mac:
file:/home/username/OpenCode-Qwen-Proxy- Windows:
file:C:/Users/username/OpenCode-Qwen-Proxy
Step 6: Install Dependencies
cd ~/.config/opencode && npm install
During development, use watch mode for auto-reload:
# In plugin project directory
npm run dev
This will auto-rebuild when code changes, convenient for real-time debugging.
| Command | Description |
|---|---|
npm run build | Build production version to dist/ directory |
npm run dev | Development mode, watch files and auto rebuild |
npm run typecheck | TypeScript type checking |
1. Enable Debug Logs
# Temporarily enable debug logs
OPENCODE_QWEN_DEBUG=1 opencode ...
2. View Plugin Logs
Plugin outputs debug information when debug mode is enabled, helps troubleshooting.
3. Check Credentials
# View credential file location
cat ~/.qwen/oauth_creds.json
Q: Do I need to reinstall after modifying code?
A: Using
npm link- no; Usingfile:protocol - yes, need to reinstall after code changes (or usenpm run devauto-build then restart OpenCode).
Q: How to confirm plugin is loaded?
A: In OpenCode, execute
opencode auth login, if you can see "Qwen Code (qwen.ai OAuth)" option, plugin is loaded correctly.
Q: What to do if problems occur?
A:
- Confirm
"plugin": ["opencode-qwen-proxy"]is added in~/.config/opencode/opencode.jsonc- Run
npm run typecheckto check for syntax errors- Check console output for error messages
opencode-qwen-proxy/ ├── src/ │ ├── index.ts # Plugin entry (loader + fetch + methods) │ ├── constants.ts # OAuth endpoints, model configuration │ ├── types.ts # TypeScript types │ ├── qwen/ │ │ └── oauth.ts # OAuth Device Flow + PKCE │ └── plugin/ │ ├── request-queue.ts # Request queue + throttling │ └── auth.ts # Credential management ├── package.json └── README.md
MIT
Enhanced from opencode-wencode-auth