opencode-qwen-cli-auth 2.2.6 → 2.2.8

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/dist/index.js +99 -29
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -15,10 +15,13 @@ import { PROVIDER_ID, AUTH_LABELS, DEVICE_FLOW, PORTAL_HEADERS } from "./lib/con
15
15
  import { logError, logInfo, logWarn, LOGGING_ENABLED } from "./lib/logger.js";
16
16
  const CHAT_REQUEST_TIMEOUT_MS = 30000;
17
17
  const CHAT_MAX_RETRIES = 0;
18
+ const CHAT_MAX_TOKENS_CAP = 2048;
19
+ const CHAT_DEFAULT_MAX_TOKENS = 2048;
18
20
  const MAX_CONSECUTIVE_POLL_FAILURES = 3;
19
21
  const QUOTA_DEGRADE_MAX_TOKENS = 1024;
20
22
  const CLI_FALLBACK_TIMEOUT_MS = 8000;
21
23
  const CLI_FALLBACK_MAX_BUFFER_CHARS = 1024 * 1024;
24
+ const ENABLE_CLI_FALLBACK = process.env.OPENCODE_QWEN_ENABLE_CLI_FALLBACK === "1";
22
25
  const PLUGIN_USER_AGENT = "opencode-qwen-cli-auth/2.2.1";
23
26
  const CLIENT_ONLY_BODY_FIELDS = new Set([
24
27
  "providerID",
@@ -97,6 +100,34 @@ function appendLimitedText(current, chunk) {
97
100
  }
98
101
  return next.slice(next.length - CLI_FALLBACK_MAX_BUFFER_CHARS);
99
102
  }
103
+ function isRequestInstance(value) {
104
+ return typeof Request !== "undefined" && value instanceof Request;
105
+ }
106
+ async function normalizeFetchInvocation(input, init) {
107
+ const requestInit = init ? { ...init } : {};
108
+ let requestInput = input;
109
+ if (!isRequestInstance(input)) {
110
+ return { requestInput, requestInit };
111
+ }
112
+ requestInput = input.url;
113
+ if (!requestInit.method) {
114
+ requestInit.method = input.method;
115
+ }
116
+ if (!requestInit.headers) {
117
+ requestInit.headers = new Headers(input.headers);
118
+ }
119
+ if (requestInit.body === undefined) {
120
+ try {
121
+ requestInit.body = await input.clone().text();
122
+ }
123
+ catch (_error) {
124
+ }
125
+ }
126
+ if (!requestInit.signal) {
127
+ requestInit.signal = input.signal;
128
+ }
129
+ return { requestInput, requestInit };
130
+ }
100
131
  function getHeaderValue(headers, headerName) {
101
132
  if (!headers) {
102
133
  return undefined;
@@ -178,6 +209,14 @@ function sanitizeOutgoingPayload(payload) {
178
209
  delete sanitized.stream_options;
179
210
  changed = true;
180
211
  }
212
+ if (typeof sanitized.max_tokens === "number" && sanitized.max_tokens > CHAT_MAX_TOKENS_CAP) {
213
+ sanitized.max_tokens = CHAT_MAX_TOKENS_CAP;
214
+ changed = true;
215
+ }
216
+ if (typeof sanitized.max_completion_tokens === "number" && sanitized.max_completion_tokens > CHAT_MAX_TOKENS_CAP) {
217
+ sanitized.max_completion_tokens = CHAT_MAX_TOKENS_CAP;
218
+ changed = true;
219
+ }
181
220
  return changed ? sanitized : payload;
182
221
  }
183
222
  function createQuotaDegradedPayload(payload) {
@@ -543,7 +582,9 @@ async function sendWithTimeout(input, requestInit) {
543
582
  }
544
583
  }
545
584
  async function failFastFetch(input, init) {
546
- const requestInit = init ? { ...init } : {};
585
+ const normalized = await normalizeFetchInvocation(input, init);
586
+ const requestInput = normalized.requestInput;
587
+ const requestInit = normalized.requestInit;
547
588
  const sourceSignal = requestInit.signal;
548
589
  const rawPayload = parseJsonRequestBody(requestInit);
549
590
  const sessionID = typeof rawPayload?.sessionID === "string" ? rawPayload.sessionID : undefined;
@@ -565,10 +606,14 @@ async function failFastFetch(input, init) {
565
606
  request_id: context.requestId,
566
607
  sessionID: context.sessionID,
567
608
  modelID: context.modelID,
609
+ max_tokens: typeof payload?.max_tokens === "number" ? payload.max_tokens : undefined,
610
+ max_completion_tokens: typeof payload?.max_completion_tokens === "number" ? payload.max_completion_tokens : undefined,
611
+ message_count: Array.isArray(payload?.messages) ? payload.messages.length : undefined,
612
+ stream: payload?.stream === true,
568
613
  });
569
614
  }
570
615
  try {
571
- let response = await sendWithTimeout(input, requestInit);
616
+ let response = await sendWithTimeout(requestInput, requestInit);
572
617
  if (LOGGING_ENABLED) {
573
618
  logInfo("Qwen request response", {
574
619
  request_id: context.requestId,
@@ -593,7 +638,7 @@ async function failFastFetch(input, init) {
593
638
  attempt: 2,
594
639
  });
595
640
  }
596
- response = await sendWithTimeout(input, fallbackInit);
641
+ response = await sendWithTimeout(requestInput, fallbackInit);
597
642
  if (LOGGING_ENABLED) {
598
643
  logInfo("Qwen request response", {
599
644
  request_id: context.requestId,
@@ -607,6 +652,27 @@ async function failFastFetch(input, init) {
607
652
  return response;
608
653
  }
609
654
  const fallbackBody = await response.text().catch(() => "");
655
+ if (ENABLE_CLI_FALLBACK) {
656
+ const cliFallback = await runQwenCliFallback(payload, context, sourceSignal);
657
+ if (cliFallback.ok) {
658
+ return cliFallback.response;
659
+ }
660
+ if (cliFallback.reason === "cli_aborted") {
661
+ return makeFailFastErrorResponse(400, "request_aborted", "Qwen request was aborted");
662
+ }
663
+ if (LOGGING_ENABLED) {
664
+ logWarn("Qwen CLI fallback failed", {
665
+ request_id: context.requestId,
666
+ sessionID: context.sessionID,
667
+ modelID: context.modelID,
668
+ reason: cliFallback.reason,
669
+ stderr: cliFallback.stderr,
670
+ });
671
+ }
672
+ }
673
+ return makeQuotaFailFastResponse(fallbackBody, response.headers, context);
674
+ }
675
+ if (ENABLE_CLI_FALLBACK) {
610
676
  const cliFallback = await runQwenCliFallback(payload, context, sourceSignal);
611
677
  if (cliFallback.ok) {
612
678
  return cliFallback.response;
@@ -623,23 +689,6 @@ async function failFastFetch(input, init) {
623
689
  stderr: cliFallback.stderr,
624
690
  });
625
691
  }
626
- return makeQuotaFailFastResponse(fallbackBody, response.headers, context);
627
- }
628
- const cliFallback = await runQwenCliFallback(payload, context, sourceSignal);
629
- if (cliFallback.ok) {
630
- return cliFallback.response;
631
- }
632
- if (cliFallback.reason === "cli_aborted") {
633
- return makeFailFastErrorResponse(400, "request_aborted", "Qwen request was aborted");
634
- }
635
- if (LOGGING_ENABLED) {
636
- logWarn("Qwen CLI fallback failed", {
637
- request_id: context.requestId,
638
- sessionID: context.sessionID,
639
- modelID: context.modelID,
640
- reason: cliFallback.reason,
641
- stderr: cliFallback.stderr,
642
- });
643
692
  }
644
693
  }
645
694
  return makeQuotaFailFastResponse(firstBody, response.headers, context);
@@ -872,21 +921,21 @@ export const QwenAuthPlugin = async (_input) => {
872
921
  maxRetries: CHAT_MAX_RETRIES,
873
922
  },
874
923
  models: {
875
- "coder-model": {
876
- id: "coder-model",
877
- name: "Qwen Coder (Qwen 3.5 Plus)",
924
+ "coder-model": {
925
+ id: "coder-model",
926
+ name: "Qwen Coder (Qwen 3.5 Plus)",
878
927
  // Qwen does not support reasoning_effort from OpenCode UI
879
928
  // Thinking is always enabled by default on server side (qwen3.5-plus)
880
929
  reasoning: false,
881
- limit: { context: 1048576, output: 65536 },
930
+ limit: { context: 1048576, output: CHAT_MAX_TOKENS_CAP },
882
931
  cost: { input: 0, output: 0 },
883
932
  modalities: { input: ["text"], output: ["text"] },
884
933
  },
885
- "vision-model": {
886
- id: "vision-model",
887
- name: "Qwen VL Plus (vision)",
888
- reasoning: false,
889
- limit: { context: 131072, output: 8192 },
934
+ "vision-model": {
935
+ id: "vision-model",
936
+ name: "Qwen VL Plus (vision)",
937
+ reasoning: false,
938
+ limit: { context: 131072, output: CHAT_MAX_TOKENS_CAP },
890
939
  cost: { input: 0, output: 0 },
891
940
  modalities: { input: ["text"], output: ["text"] },
892
941
  },
@@ -901,12 +950,33 @@ export const QwenAuthPlugin = async (_input) => {
901
950
  if (typeof output.options.timeout !== "number" || output.options.timeout > CHAT_REQUEST_TIMEOUT_MS) {
902
951
  output.options.timeout = CHAT_REQUEST_TIMEOUT_MS;
903
952
  }
953
+ if (typeof output.max_tokens !== "number" || output.max_tokens > CHAT_MAX_TOKENS_CAP) {
954
+ output.max_tokens = CHAT_DEFAULT_MAX_TOKENS;
955
+ }
956
+ if (typeof output.max_completion_tokens !== "number" || output.max_completion_tokens > CHAT_MAX_TOKENS_CAP) {
957
+ output.max_completion_tokens = CHAT_DEFAULT_MAX_TOKENS;
958
+ }
959
+ if (typeof output.maxTokens !== "number" || output.maxTokens > CHAT_MAX_TOKENS_CAP) {
960
+ output.maxTokens = CHAT_DEFAULT_MAX_TOKENS;
961
+ }
962
+ if (typeof output.options.max_tokens !== "number" || output.options.max_tokens > CHAT_MAX_TOKENS_CAP) {
963
+ output.options.max_tokens = CHAT_DEFAULT_MAX_TOKENS;
964
+ }
965
+ if (typeof output.options.max_completion_tokens !== "number" || output.options.max_completion_tokens > CHAT_MAX_TOKENS_CAP) {
966
+ output.options.max_completion_tokens = CHAT_DEFAULT_MAX_TOKENS;
967
+ }
968
+ if (typeof output.options.maxTokens !== "number" || output.options.maxTokens > CHAT_MAX_TOKENS_CAP) {
969
+ output.options.maxTokens = CHAT_DEFAULT_MAX_TOKENS;
970
+ }
904
971
  if (LOGGING_ENABLED) {
905
972
  logInfo("Applied chat.params hotfix", {
906
973
  sessionID: input?.sessionID,
907
974
  modelID: input?.model?.id,
908
975
  timeout: output.options.timeout,
909
976
  maxRetries: output.options.maxRetries,
977
+ max_tokens: output.max_tokens,
978
+ max_completion_tokens: output.max_completion_tokens,
979
+ maxTokens: output.maxTokens,
910
980
  });
911
981
  }
912
982
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-qwen-cli-auth",
3
- "version": "2.2.6",
3
+ "version": "2.2.8",
4
4
  "description": "Qwen OAuth authentication plugin for opencode - use your Qwen account instead of API keys",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",