pi-free 2.0.4 → 2.0.5
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/banner.svg +132 -0
- package/index.ts +1 -1
- package/lib/model-detection.ts +176 -139
- package/lib/registry.ts +28 -21
- package/lib/util.ts +10 -4
- package/package.json +2 -1
- package/provider-failover/benchmark-lookup.ts +189 -138
- package/providers/cline/cline.ts +27 -10
- package/providers/dynamic-built-in/index.ts +3 -1
- package/providers/nvidia/nvidia.ts +48 -50
- package/providers/qwen/qwen.ts +47 -49
- package/scripts/check-extensions.mjs +8 -1
package/providers/qwen/qwen.ts
CHANGED
|
@@ -10,18 +10,18 @@
|
|
|
10
10
|
* 1,000 free API calls/day — run /login qwen to authenticate.~~
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import type {
|
|
13
|
+
import type { Api, Model, OAuthCredentials } from "@mariozechner/pi-ai";
|
|
14
14
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
15
15
|
import { PROVIDER_QWEN, URL_QWEN_TOS } from "../../constants.ts";
|
|
16
|
+
import { createLogger } from "../../lib/logger.ts";
|
|
17
|
+
import { logWarning } from "../../lib/util.ts";
|
|
16
18
|
import {
|
|
19
|
+
createReRegister,
|
|
17
20
|
enhanceWithCI,
|
|
18
21
|
type StoredModels,
|
|
19
22
|
setupProvider,
|
|
20
|
-
createReRegister,
|
|
21
23
|
} from "../../provider-helper.ts";
|
|
22
|
-
import {
|
|
23
|
-
import { createLogger } from "../../lib/logger.ts";
|
|
24
|
-
import { loginQwen, refreshQwenToken, getQwenBaseUrl } from "./qwen-auth.ts";
|
|
24
|
+
import { getQwenBaseUrl, loginQwen, refreshQwenToken } from "./qwen-auth.ts";
|
|
25
25
|
import { fetchQwenModels } from "./qwen-models.ts";
|
|
26
26
|
|
|
27
27
|
// =============================================================================
|
|
@@ -61,10 +61,12 @@ const DASHSCOPE_HEADERS = {
|
|
|
61
61
|
|
|
62
62
|
export default async function (pi: ExtensionAPI) {
|
|
63
63
|
// DEPRECATION WARNING
|
|
64
|
-
_logger.warn(
|
|
64
|
+
_logger.warn(
|
|
65
|
+
"Qwen provider is deprecated. The 1,000 req/day free tier is no longer available.",
|
|
66
|
+
);
|
|
65
67
|
|
|
66
68
|
// Fetch static free-tier models
|
|
67
|
-
|
|
69
|
+
const models = await fetchQwenModels().catch((err) => {
|
|
68
70
|
logWarning("qwen", "Failed to load models at startup", err);
|
|
69
71
|
return [];
|
|
70
72
|
});
|
|
@@ -148,55 +150,51 @@ export default async function (pi: ExtensionAPI) {
|
|
|
148
150
|
// getApiKey() call will trigger a token refresh via refreshToken().
|
|
149
151
|
// This mirrors qwen-code's executeWithCredentialManagement() retry logic.
|
|
150
152
|
//
|
|
153
|
+
function isQwenAuthError(msg: {
|
|
154
|
+
role?: string;
|
|
155
|
+
errorMessage?: string;
|
|
156
|
+
}): boolean {
|
|
157
|
+
if (msg.role !== "assistant" || !msg.errorMessage) return false;
|
|
158
|
+
const errLower = msg.errorMessage.toLowerCase();
|
|
159
|
+
return AUTH_ERROR_PATTERNS.some((p) => errLower.includes(p));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function forceExpireQwenToken(
|
|
163
|
+
ctx: any,
|
|
164
|
+
msg: { errorMessage?: string },
|
|
165
|
+
): void {
|
|
166
|
+
_logger.warn("Qwen auth error detected, force-expiring token for refresh", {
|
|
167
|
+
error: (msg.errorMessage ?? "").slice(0, 100),
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const authStorage = (ctx as any).modelRegistry?.authStorage;
|
|
172
|
+
if (authStorage) {
|
|
173
|
+
const cred = authStorage.get(PROVIDER_QWEN);
|
|
174
|
+
if (cred?.type === "oauth" && cred.expires > Date.now()) {
|
|
175
|
+
authStorage.set(PROVIDER_QWEN, { ...cred, expires: 0 });
|
|
176
|
+
_logger.info(
|
|
177
|
+
"Qwen token force-expired; will refresh on next request",
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
ctx.ui.notify("Qwen: auth error detected, refreshing token…", "warning");
|
|
182
|
+
} catch (e) {
|
|
183
|
+
_logger.warn("Failed to force-expire Qwen token", {
|
|
184
|
+
error: e instanceof Error ? e.message : String(e),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
151
189
|
pi.on("turn_end", async (event, ctx) => {
|
|
152
190
|
if (ctx.model?.provider !== PROVIDER_QWEN) return;
|
|
153
|
-
// NOTE: Request counting removed - usage tracking was deleted in refactor
|
|
154
191
|
|
|
155
192
|
const msg = (
|
|
156
193
|
event as { message?: { role?: string; errorMessage?: string } }
|
|
157
194
|
).message;
|
|
158
195
|
|
|
159
|
-
if (msg
|
|
160
|
-
|
|
161
|
-
const isAuthError = AUTH_ERROR_PATTERNS.some((p) =>
|
|
162
|
-
errLower.includes(p),
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
if (isAuthError) {
|
|
166
|
-
_logger.warn(
|
|
167
|
-
"Qwen auth error detected, force-expiring token for refresh",
|
|
168
|
-
{ error: msg.errorMessage.slice(0, 100) },
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
// Force-expire the stored credential so the next getApiKey() call
|
|
172
|
-
// triggers refreshQwenToken(). The credential object in auth.json
|
|
173
|
-
// is updated with expires = 0 (already past).
|
|
174
|
-
try {
|
|
175
|
-
const authStorage =
|
|
176
|
-
(ctx as any).modelRegistry?.authStorage;
|
|
177
|
-
if (authStorage) {
|
|
178
|
-
const cred = authStorage.get(PROVIDER_QWEN);
|
|
179
|
-
if (cred?.type === "oauth" && cred.expires > Date.now()) {
|
|
180
|
-
// Set expiry to 0 to force refresh on next request
|
|
181
|
-
authStorage.set(PROVIDER_QWEN, {
|
|
182
|
-
...cred,
|
|
183
|
-
expires: 0,
|
|
184
|
-
});
|
|
185
|
-
_logger.info(
|
|
186
|
-
"Qwen token force-expired; will refresh on next request",
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
ctx.ui.notify(
|
|
191
|
-
"Qwen: auth error detected, refreshing token…",
|
|
192
|
-
"warning",
|
|
193
|
-
);
|
|
194
|
-
} catch (e) {
|
|
195
|
-
_logger.warn("Failed to force-expire Qwen token", {
|
|
196
|
-
error: e instanceof Error ? e.message : String(e),
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
}
|
|
196
|
+
if (msg && isQwenAuthError(msg)) {
|
|
197
|
+
forceExpireQwenToken(ctx, msg);
|
|
200
198
|
}
|
|
201
199
|
});
|
|
202
200
|
}
|
|
@@ -17,7 +17,14 @@ const fromSource = process.argv[2] == null;
|
|
|
17
17
|
function getFiles() {
|
|
18
18
|
if (fromSource) {
|
|
19
19
|
// Use npm pack --dry-run to get exactly the files that would be published
|
|
20
|
-
const
|
|
20
|
+
const execOptions = { encoding: "utf8" };
|
|
21
|
+
if (process.platform !== "win32") {
|
|
22
|
+
execOptions.env = {
|
|
23
|
+
...process.env,
|
|
24
|
+
PATH: "/usr/local/bin:/usr/bin:/bin",
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const out = execSync("npm pack --dry-run 2>&1", execOptions);
|
|
21
28
|
return out
|
|
22
29
|
.split("\n")
|
|
23
30
|
.map((l) => l.match(/npm notice \S+\s+(.+)/)?.[1]?.trim())
|