opencode-qwen-cli-auth 2.3.4 → 2.3.6
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 +6 -5
- package/README.vi.md +6 -5
- package/dist/index.js +69 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,10 +50,10 @@ The plugin stores each successful login in the multi-account store and can auto-
|
|
|
50
50
|
|
|
51
51
|
## Supported Models
|
|
52
52
|
|
|
53
|
-
| Model | ID | Context | Max Output | Cost |
|
|
54
|
-
|
|
55
|
-
| Qwen Coder (Qwen 3.5 Plus) | `coder-model` | 1M tokens | 65,536 tokens | Free |
|
|
56
|
-
| Qwen VL Plus (Vision) | `vision-model` | 128K tokens | 8,192 tokens | Free |
|
|
53
|
+
| Model | ID | Input | Output | Context | Max Output | Cost |
|
|
54
|
+
|-------|-----|-------|--------|---------|------------|---------|
|
|
55
|
+
| Qwen Coder (Qwen 3.5 Plus) | `coder-model` | text | text | 1M tokens | 65,536 tokens | Free |
|
|
56
|
+
| Qwen VL Plus (Vision) | `vision-model` | text, image | text | 128K tokens | 8,192 tokens | Free |
|
|
57
57
|
|
|
58
58
|
## Configuration
|
|
59
59
|
|
|
@@ -124,7 +124,8 @@ When hitting a `429 insufficient_quota` error, the plugin automatically:
|
|
|
124
124
|
1. **Marks current account exhausted** for cooldown window
|
|
125
125
|
2. **Switches to next healthy account** and retries with same payload
|
|
126
126
|
3. **Degrades payload** if no healthy account can be switched
|
|
127
|
-
4. **CLI fallback** (optional) - invokes `qwen` CLI
|
|
127
|
+
4. **CLI fallback** (optional) - invokes `qwen` CLI only for text-only payloads when `OPENCODE_QWEN_ENABLE_CLI_FALLBACK=1` is set
|
|
128
|
+
5. **Multimodal safety guard** - skips CLI fallback for non-text parts (image/audio/file/video) to avoid semantic loss
|
|
128
129
|
|
|
129
130
|
### Token Expiration
|
|
130
131
|
|
package/README.vi.md
CHANGED
|
@@ -50,10 +50,10 @@ Plugin sẽ lưu từng lần đăng nhập thành công vào kho đa tài kho
|
|
|
50
50
|
|
|
51
51
|
## Models hỗ trợ
|
|
52
52
|
|
|
53
|
-
| Model | ID | Context | Max Output | Chi phí |
|
|
54
|
-
|
|
55
|
-
| Qwen Coder (Qwen 3.5 Plus) | `coder-model` | 1M tokens | 65,536 tokens | Miễn phí |
|
|
56
|
-
| Qwen VL Plus (Vision) | `vision-model` | 128K tokens | 8,192 tokens | Miễn phí |
|
|
53
|
+
| Model | ID | Input | Output | Context | Max Output | Chi phí |
|
|
54
|
+
|-------|-----|-------|--------|---------|------------|---------|
|
|
55
|
+
| Qwen Coder (Qwen 3.5 Plus) | `coder-model` | text | text | 1M tokens | 65,536 tokens | Miễn phí |
|
|
56
|
+
| Qwen VL Plus (Vision) | `vision-model` | text, image | text | 128K tokens | 8,192 tokens | Miễn phí |
|
|
57
57
|
|
|
58
58
|
## Cấu hình
|
|
59
59
|
|
|
@@ -124,7 +124,8 @@ Khi gặp lỗi `429 insufficient_quota`, plugin sẽ tự động:
|
|
|
124
124
|
1. **Đánh dấu tài khoản hiện tại đã hết quota** trong cửa sổ cooldown
|
|
125
125
|
2. **Đổi sang tài khoản khỏe tiếp theo** và retry với payload ban đầu
|
|
126
126
|
3. **Degrade payload** nếu không còn tài khoản khỏe để đổi
|
|
127
|
-
4. **CLI fallback** (tùy chọn) - gọi `qwen` CLI
|
|
127
|
+
4. **CLI fallback** (tùy chọn) - chỉ gọi `qwen` CLI cho payload chỉ có text khi bật `OPENCODE_QWEN_ENABLE_CLI_FALLBACK=1`
|
|
128
|
+
5. **Guard multimodal an toàn** - bỏ qua CLI fallback khi payload có phần non-text (image/audio/file/video) để tránh mất ngữ nghĩa
|
|
128
129
|
|
|
129
130
|
### Token Hết Hạn
|
|
130
131
|
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @license MIT with Usage Disclaimer (see LICENSE file)
|
|
13
13
|
* @repository https://github.com/TVD-00/opencode-qwen-cli-auth
|
|
14
|
-
* @version 2.
|
|
14
|
+
* @version 2.3.6
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { randomUUID } from "node:crypto";
|
|
@@ -40,7 +40,7 @@ const CLI_FALLBACK_MAX_BUFFER_CHARS = 1024 * 1024;
|
|
|
40
40
|
/** Enable CLI fallback feature via environment variable */
|
|
41
41
|
const ENABLE_CLI_FALLBACK = process.env.OPENCODE_QWEN_ENABLE_CLI_FALLBACK === "1";
|
|
42
42
|
/** User agent string for plugin identification */
|
|
43
|
-
const PLUGIN_USER_AGENT = "opencode-qwen-cli-auth/2.
|
|
43
|
+
const PLUGIN_USER_AGENT = "opencode-qwen-cli-auth/2.3.4";
|
|
44
44
|
/** Output token limits per model for DashScope OAuth */
|
|
45
45
|
const DASH_SCOPE_OUTPUT_LIMITS = {
|
|
46
46
|
"coder-model": 65536,
|
|
@@ -490,6 +490,54 @@ function extractMessageText(content) {
|
|
|
490
490
|
return "";
|
|
491
491
|
}).filter(Boolean).join("\n").trim();
|
|
492
492
|
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Checks whether content contains non-text parts
|
|
496
|
+
* @param {*} content - Message content
|
|
497
|
+
* @returns {boolean} True if any non-text part is present
|
|
498
|
+
*/
|
|
499
|
+
function hasNonTextContentPart(content) {
|
|
500
|
+
if (typeof content === "string") {
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
if (Array.isArray(content)) {
|
|
504
|
+
return content.some((part) => {
|
|
505
|
+
if (typeof part === "string") {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
if (!part || typeof part !== "object") {
|
|
509
|
+
return true;
|
|
510
|
+
}
|
|
511
|
+
if (typeof part.text === "string") {
|
|
512
|
+
return false;
|
|
513
|
+
}
|
|
514
|
+
const partType = typeof part.type === "string" ? part.type.toLowerCase() : "";
|
|
515
|
+
if (partType === "text" && typeof part.text === "string") {
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
return true;
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
if (content && typeof content === "object") {
|
|
522
|
+
return typeof content.text !== "string";
|
|
523
|
+
}
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Checks whether payload contains any multimodal message content
|
|
529
|
+
* @param {Object} payload - Request payload
|
|
530
|
+
* @returns {boolean} True if payload contains non-text message parts
|
|
531
|
+
*/
|
|
532
|
+
function payloadContainsNonTextMessages(payload) {
|
|
533
|
+
const messages = Array.isArray(payload?.messages) ? payload.messages : [];
|
|
534
|
+
for (const message of messages) {
|
|
535
|
+
if (hasNonTextContentPart(message?.content)) {
|
|
536
|
+
return true;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
493
541
|
/**
|
|
494
542
|
* Builds prompt text from chat messages for CLI fallback
|
|
495
543
|
* @param {Object} payload - Request payload with messages
|
|
@@ -691,6 +739,20 @@ function makeQwenCliCompletionResponse(model, content, context, streamMode) {
|
|
|
691
739
|
async function runQwenCliFallback(payload, context, abortSignal) {
|
|
692
740
|
const model = typeof payload?.model === "string" && payload.model.length > 0 ? payload.model : "coder-model";
|
|
693
741
|
const streamMode = payload?.stream === true;
|
|
742
|
+
if (payloadContainsNonTextMessages(payload)) {
|
|
743
|
+
if (LOGGING_ENABLED) {
|
|
744
|
+
logWarn("Skipping qwen CLI fallback for multimodal payload", {
|
|
745
|
+
request_id: context.requestId,
|
|
746
|
+
sessionID: context.sessionID,
|
|
747
|
+
modelID: model,
|
|
748
|
+
accountID: context.accountID,
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
return {
|
|
752
|
+
ok: false,
|
|
753
|
+
reason: "cli_fallback_unsupported_multimodal_payload",
|
|
754
|
+
};
|
|
755
|
+
}
|
|
694
756
|
const prompt = buildQwenCliPrompt(payload);
|
|
695
757
|
const args = [prompt, "-o", "json", "--max-session-turns", "1", "--model", model];
|
|
696
758
|
if (LOGGING_ENABLED) {
|
|
@@ -1338,9 +1400,10 @@ export const QwenAuthPlugin = async (_input) => {
|
|
|
1338
1400
|
models: {
|
|
1339
1401
|
"coder-model": {
|
|
1340
1402
|
id: "coder-model",
|
|
1341
|
-
name: "Qwen
|
|
1403
|
+
name: "Qwen 3.5 Plus)",
|
|
1342
1404
|
// Qwen does not support reasoning_effort from OpenCode UI
|
|
1343
1405
|
// Thinking is always enabled by default on server side (qwen3.5-plus)
|
|
1406
|
+
attachment: false,
|
|
1344
1407
|
reasoning: false,
|
|
1345
1408
|
limit: { context: 1048576, output: CHAT_MAX_TOKENS_CAP },
|
|
1346
1409
|
cost: { input: 0, output: 0 },
|
|
@@ -1348,11 +1411,12 @@ export const QwenAuthPlugin = async (_input) => {
|
|
|
1348
1411
|
},
|
|
1349
1412
|
"vision-model": {
|
|
1350
1413
|
id: "vision-model",
|
|
1351
|
-
name: "Qwen
|
|
1414
|
+
name: "Qwen Vision",
|
|
1415
|
+
attachment: true,
|
|
1352
1416
|
reasoning: false,
|
|
1353
1417
|
limit: { context: 131072, output: DASH_SCOPE_OUTPUT_LIMITS["vision-model"] },
|
|
1354
1418
|
cost: { input: 0, output: 0 },
|
|
1355
|
-
modalities: { input: ["text"], output: ["text"] },
|
|
1419
|
+
modalities: { input: ["text", "image"], output: ["text"] },
|
|
1356
1420
|
},
|
|
1357
1421
|
},
|
|
1358
1422
|
};
|
package/package.json
CHANGED