agent-rev 0.3.4 → 0.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/dist/utils/qwen-auth.d.ts +12 -1
- package/dist/utils/qwen-auth.js +68 -14
- package/package.json +1 -1
|
@@ -10,6 +10,17 @@ export declare function qwenAuthStatus(): Promise<{
|
|
|
10
10
|
}>;
|
|
11
11
|
export declare function fetchQwenModels(): Promise<string[]>;
|
|
12
12
|
export declare function getQwenAccessToken(): Promise<string | null>;
|
|
13
|
+
/**
|
|
14
|
+
* Call Qwen by spawning the `qwen` CLI with piped stdin.
|
|
15
|
+
* The qwen CLI manages its own token refresh and uses the correct API format.
|
|
16
|
+
* Falls back to direct HTTP call if the qwen CLI is not available.
|
|
17
|
+
*/
|
|
13
18
|
export declare function callQwenAPI(prompt: string, model?: string): Promise<string>;
|
|
14
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Call Qwen API using credentials from a specific file path (for role binaries).
|
|
21
|
+
* The role binary CLI (e.g. agent-explorer) manages its own qwen auth via the
|
|
22
|
+
* shared ~/.qwen/oauth_creds.json — we spawn it with piped stdin so it runs
|
|
23
|
+
* in non-interactive mode without TTY issues.
|
|
24
|
+
* Falls back to direct HTTP if the role binary is not found.
|
|
25
|
+
*/
|
|
15
26
|
export declare function callQwenAPIFromCreds(prompt: string, model: string, credsPath: string): Promise<string>;
|
package/dist/utils/qwen-auth.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from 'fs/promises';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import * as crypto from 'crypto';
|
|
4
|
+
import { spawnSync } from 'child_process';
|
|
4
5
|
import open from 'open';
|
|
5
6
|
import { AGENT_HOME } from './config.js';
|
|
6
7
|
const QWEN_OAUTH_BASE_URL = 'https://chat.qwen.ai';
|
|
@@ -42,14 +43,20 @@ async function loadToken() {
|
|
|
42
43
|
};
|
|
43
44
|
if (!token.accessToken)
|
|
44
45
|
return null;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
// Refresh proactivo: si vence en menos de 2 minutos (o ya venció)
|
|
47
|
+
const TWO_MIN = 2 * 60 * 1000;
|
|
48
|
+
if (token.expiresAt - Date.now() < TWO_MIN && token.refreshToken) {
|
|
49
|
+
const refreshed = await doRefreshToken(token.refreshToken);
|
|
50
|
+
if (refreshed) {
|
|
51
|
+
await saveToken(refreshed);
|
|
52
|
+
return refreshed;
|
|
53
|
+
}
|
|
54
|
+
// Si el refresh falla pero el token aún no venció del todo, seguir con él
|
|
55
|
+
if (token.expiresAt > Date.now())
|
|
56
|
+
return token;
|
|
57
|
+
return null;
|
|
51
58
|
}
|
|
52
|
-
return
|
|
59
|
+
return token;
|
|
53
60
|
}
|
|
54
61
|
catch {
|
|
55
62
|
return null;
|
|
@@ -267,7 +274,30 @@ async function callQwenAPIWithToken(token, prompt, model) {
|
|
|
267
274
|
const data = await response.json();
|
|
268
275
|
return data.choices?.[0]?.message?.content || '';
|
|
269
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* Call Qwen by spawning the `qwen` CLI with piped stdin.
|
|
279
|
+
* The qwen CLI manages its own token refresh and uses the correct API format.
|
|
280
|
+
* Falls back to direct HTTP call if the qwen CLI is not available.
|
|
281
|
+
*/
|
|
270
282
|
export async function callQwenAPI(prompt, model = 'coder-model') {
|
|
283
|
+
// Try using the qwen CLI subprocess first — it handles auth/refresh/format automatically
|
|
284
|
+
const qwenBin = process.env.QWEN_BIN || 'qwen';
|
|
285
|
+
try {
|
|
286
|
+
const result = spawnSync(qwenBin, [], {
|
|
287
|
+
input: prompt,
|
|
288
|
+
encoding: 'utf-8',
|
|
289
|
+
timeout: 300000, // 5 minutes
|
|
290
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
291
|
+
});
|
|
292
|
+
if (result.status === 0 && result.stdout?.trim()) {
|
|
293
|
+
return result.stdout.trim();
|
|
294
|
+
}
|
|
295
|
+
// qwen not available or failed — fall through to direct API
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
// qwen not installed — fall through
|
|
299
|
+
}
|
|
300
|
+
// Fallback: direct API call (requires valid token in AGENT_HOME)
|
|
271
301
|
let token = await loadToken();
|
|
272
302
|
if (!token) {
|
|
273
303
|
throw new Error('QWEN_AUTH_EXPIRED: No hay token de Qwen. Ejecutá --login primero.');
|
|
@@ -278,7 +308,6 @@ export async function callQwenAPI(prompt, model = 'coder-model') {
|
|
|
278
308
|
catch (err) {
|
|
279
309
|
if (!err.message?.startsWith('QWEN_AUTH_EXPIRED'))
|
|
280
310
|
throw err;
|
|
281
|
-
// 401 — intentar refresh antes de rendirse
|
|
282
311
|
if (token.refreshToken) {
|
|
283
312
|
const refreshed = await doRefreshToken(token.refreshToken);
|
|
284
313
|
if (refreshed) {
|
|
@@ -289,14 +318,39 @@ export async function callQwenAPI(prompt, model = 'coder-model') {
|
|
|
289
318
|
throw new Error('QWEN_AUTH_EXPIRED: Sesión expirada. Ejecutá: agent-mp --login');
|
|
290
319
|
}
|
|
291
320
|
}
|
|
292
|
-
/**
|
|
321
|
+
/**
|
|
322
|
+
* Call Qwen API using credentials from a specific file path (for role binaries).
|
|
323
|
+
* The role binary CLI (e.g. agent-explorer) manages its own qwen auth via the
|
|
324
|
+
* shared ~/.qwen/oauth_creds.json — we spawn it with piped stdin so it runs
|
|
325
|
+
* in non-interactive mode without TTY issues.
|
|
326
|
+
* Falls back to direct HTTP if the role binary is not found.
|
|
327
|
+
*/
|
|
293
328
|
export async function callQwenAPIFromCreds(prompt, model, credsPath) {
|
|
329
|
+
// Derive the role binary name from the creds path (e.g. ~/.agent-explorer/ → agent-explorer)
|
|
330
|
+
const cliName = path.basename(path.dirname(credsPath)).replace(/^\./, '');
|
|
331
|
+
// Try spawning the role binary with piped stdin (non-interactive mode)
|
|
332
|
+
const qwenBin = process.env.QWEN_BIN || 'qwen';
|
|
333
|
+
try {
|
|
334
|
+
const result = spawnSync(qwenBin, [], {
|
|
335
|
+
input: prompt,
|
|
336
|
+
encoding: 'utf-8',
|
|
337
|
+
timeout: 300000,
|
|
338
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
339
|
+
});
|
|
340
|
+
if (result.status === 0 && result.stdout?.trim()) {
|
|
341
|
+
return result.stdout.trim();
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
// qwen not available
|
|
346
|
+
}
|
|
347
|
+
// Fallback: direct HTTP with stored creds
|
|
294
348
|
let raw;
|
|
295
349
|
try {
|
|
296
350
|
raw = JSON.parse(await fs.readFile(credsPath, 'utf-8'));
|
|
297
351
|
}
|
|
298
352
|
catch {
|
|
299
|
-
throw new Error(`No credentials found at ${credsPath}. Run
|
|
353
|
+
throw new Error(`No credentials found at ${credsPath}. Run: ${cliName} --login`);
|
|
300
354
|
}
|
|
301
355
|
let token = {
|
|
302
356
|
accessToken: raw.accessToken || raw.access_token || '',
|
|
@@ -306,10 +360,11 @@ export async function callQwenAPIFromCreds(prompt, model, credsPath) {
|
|
|
306
360
|
resourceUrl: raw.resourceUrl || raw.resource_url,
|
|
307
361
|
};
|
|
308
362
|
if (!token.accessToken) {
|
|
309
|
-
throw new Error(`Invalid credentials at ${credsPath}. Run
|
|
363
|
+
throw new Error(`Invalid credentials at ${credsPath}. Run: ${cliName} --login`);
|
|
310
364
|
}
|
|
311
|
-
// Refresh
|
|
312
|
-
|
|
365
|
+
// Refresh proactivo: si vence en menos de 2 minutos (o ya venció)
|
|
366
|
+
const TWO_MIN = 2 * 60 * 1000;
|
|
367
|
+
if (token.expiresAt - Date.now() < TWO_MIN && token.refreshToken) {
|
|
313
368
|
const refreshed = await doRefreshToken(token.refreshToken);
|
|
314
369
|
if (refreshed) {
|
|
315
370
|
token = refreshed;
|
|
@@ -330,7 +385,6 @@ export async function callQwenAPIFromCreds(prompt, model, credsPath) {
|
|
|
330
385
|
return callQwenAPIWithToken(refreshed, prompt, model);
|
|
331
386
|
}
|
|
332
387
|
}
|
|
333
|
-
const cliName = path.basename(path.dirname(credsPath)).replace(/^\./, '');
|
|
334
388
|
throw new Error(`QWEN_AUTH_EXPIRED: Sesión expirada. Ejecutá: ${cliName} --login`);
|
|
335
389
|
}
|
|
336
390
|
}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"agent-rev","version":"0.3.
|
|
1
|
+
{"name":"agent-rev","version":"0.3.6","description":"agent-rev agent","type":"module","main":"./dist/index.js","files":["dist/"],"bin":{"agent-rev":"dist/index.js"},"scripts":{"build":"tsc"},"keywords":["ai","agent","cli"],"license":"MIT","dependencies":{"@anthropic-ai/sdk":"^0.39.0","@google/generative-ai":"^0.24.0","chalk":"^5.4.1","commander":"^13.1.0","open":"^11.0.0","openai":"^4.91.0"},"engines":{"node":">=18.0.0"}}
|