agent-mp 0.4.12 → 0.4.13
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/core/engine.js +42 -24
- package/dist/utils/qwen-auth.js +22 -3
- package/package.json +1 -1
package/dist/core/engine.js
CHANGED
|
@@ -6,7 +6,7 @@ import { CLI_REGISTRY } from '../types.js';
|
|
|
6
6
|
import { writeJson, readJson, fileExists, writeFile, readFile } from '../utils/fs.js';
|
|
7
7
|
import { log } from '../utils/logger.js';
|
|
8
8
|
import chalk from 'chalk';
|
|
9
|
-
import { callQwenAPIFromCreds } from '../utils/qwen-auth.js';
|
|
9
|
+
import { callQwenAPI, callQwenAPIFromCreds } from '../utils/qwen-auth.js';
|
|
10
10
|
import * as fs from 'fs/promises';
|
|
11
11
|
/** Thrown when a slash command inside a conversation requests exit */
|
|
12
12
|
export class ExitError extends Error {
|
|
@@ -89,9 +89,12 @@ async function ask(prompt, rl, fi) {
|
|
|
89
89
|
return new Promise((resolve) => tempRl.question(prompt, (a) => { tempRl.close(); resolve(a); }));
|
|
90
90
|
}
|
|
91
91
|
function runCli(cmd, prompt, timeoutMs = 600000, envOverride, onData) {
|
|
92
|
-
// Si el comando es "qwen-direct",
|
|
92
|
+
// Si el comando es "qwen-direct", usar la API directa sin CLI
|
|
93
93
|
if (cmd.startsWith('qwen-direct')) {
|
|
94
|
-
|
|
94
|
+
const model = cmd.includes('-m') ? cmd.split('-m')[1]?.trim().split(/\s/)[0] : 'coder-model';
|
|
95
|
+
return callQwenAPI(prompt, model)
|
|
96
|
+
.then(output => ({ output, exitCode: 0 }))
|
|
97
|
+
.catch(err => ({ output: `Error: ${err.message}`, exitCode: 1 }));
|
|
95
98
|
}
|
|
96
99
|
return new Promise((resolve, reject) => {
|
|
97
100
|
const parts = cmd.trim().split(/\s+/);
|
|
@@ -297,18 +300,24 @@ INSTRUCCIONES:
|
|
|
297
300
|
const envOverride = {};
|
|
298
301
|
let res;
|
|
299
302
|
if (this.coordinatorCmd.startsWith('qwen')) {
|
|
300
|
-
// Use
|
|
301
|
-
|
|
302
|
-
const
|
|
303
|
+
// Use Qwen API directly — avoids the qwen CLI's own OAuth flow
|
|
304
|
+
// which causes mid-session auth popups and breaks display.
|
|
305
|
+
const model = this.coordinatorCmd.match(/(?:-m|--model)\s+(\S+)/)?.[1] || 'coder-model';
|
|
306
|
+
const sp = this._startSpinner(`coordinador ${model}`);
|
|
303
307
|
try {
|
|
304
|
-
|
|
305
|
-
this._parseChunk(chunk).forEach(l => sp.push(l));
|
|
306
|
-
});
|
|
308
|
+
const result = await callQwenAPI(prompt, model, (c) => this._parseChunk(c).forEach(l => sp.push(l)));
|
|
307
309
|
sp.stop();
|
|
310
|
+
return result;
|
|
308
311
|
}
|
|
309
312
|
catch (err) {
|
|
310
313
|
sp.stop();
|
|
311
|
-
|
|
314
|
+
if (err.message?.startsWith('QWEN_AUTH_EXPIRED')) {
|
|
315
|
+
console.log(chalk.red('\n ✗ Sesión Qwen expirada.'));
|
|
316
|
+
console.log(chalk.yellow(' Ejecutá: /login para re-autenticarte.\n'));
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
console.log(chalk.red(`\n ✗ Error Qwen: ${err.message}`));
|
|
320
|
+
}
|
|
312
321
|
return '';
|
|
313
322
|
}
|
|
314
323
|
}
|
|
@@ -574,19 +583,28 @@ INSTRUCCIONES:
|
|
|
574
583
|
}
|
|
575
584
|
}
|
|
576
585
|
}
|
|
577
|
-
// Try global fallback — use
|
|
586
|
+
// Try global fallback — use callQwenAPI directly for streaming (no subprocess)
|
|
578
587
|
if (this.config.fallback_global) {
|
|
579
588
|
const fb = this.config.fallback_global;
|
|
580
589
|
log.warn(`Using global fallback: ${fb.cli} (${fb.model})`);
|
|
581
590
|
const sp = this._startSpinner(`${fb.cli} ${fb.model} (fallback)`);
|
|
591
|
+
let lineBuf = '';
|
|
592
|
+
const onChunk = (delta) => {
|
|
593
|
+
lineBuf += delta;
|
|
594
|
+
const lines = lineBuf.split('\n');
|
|
595
|
+
lineBuf = lines.pop() || '';
|
|
596
|
+
for (const l of lines) {
|
|
597
|
+
if (l.trim())
|
|
598
|
+
sp.push(l.trim());
|
|
599
|
+
}
|
|
600
|
+
};
|
|
582
601
|
try {
|
|
583
|
-
const
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
});
|
|
602
|
+
const globalResult = await callQwenAPI(rolePrompt, fb.model, onChunk);
|
|
603
|
+
if (lineBuf.trim())
|
|
604
|
+
sp.push(lineBuf.trim());
|
|
587
605
|
sp.stop();
|
|
588
|
-
trackTokens(globalResult
|
|
589
|
-
return globalResult
|
|
606
|
+
trackTokens(globalResult, fb.cli, fb.model);
|
|
607
|
+
return globalResult;
|
|
590
608
|
}
|
|
591
609
|
catch (err) {
|
|
592
610
|
sp.stop();
|
|
@@ -1043,17 +1061,17 @@ REGLAS:
|
|
|
1043
1061
|
let result;
|
|
1044
1062
|
const sp = this._startSpinner(`agent-explorer ${role.model}`);
|
|
1045
1063
|
try {
|
|
1046
|
-
|
|
1047
|
-
const explorerCliRes = await runCli('qwen --yolo', prompt, 600000, undefined, (chunk) => {
|
|
1048
|
-
this._parseChunk(chunk).forEach(l => sp.push(l));
|
|
1049
|
-
});
|
|
1050
|
-
result = explorerCliRes.output;
|
|
1064
|
+
result = await callQwenAPI(prompt, role.model, (c) => this._parseChunk(c).forEach(l => sp.push(l)));
|
|
1051
1065
|
sp.stop();
|
|
1052
1066
|
}
|
|
1053
1067
|
catch (err) {
|
|
1054
1068
|
sp.stop();
|
|
1055
|
-
|
|
1056
|
-
|
|
1069
|
+
if (err.message?.startsWith('QWEN_AUTH_EXPIRED')) {
|
|
1070
|
+
console.log(chalk.red('\n ✗ Sesión Qwen expirada.'));
|
|
1071
|
+
console.log(chalk.yellow(' Ejecutá: agent-mp --login (o agent-explorer --login)\n'));
|
|
1072
|
+
return '';
|
|
1073
|
+
}
|
|
1074
|
+
throw err;
|
|
1057
1075
|
}
|
|
1058
1076
|
try {
|
|
1059
1077
|
await writeFile(path.join(contextDir, 'explorer-last.md'), `# Explorer Report\n\nTask: ${effectiveTask}\nDate: ${new Date().toISOString()}\n\n${result}\n`);
|
package/dist/utils/qwen-auth.js
CHANGED
|
@@ -235,7 +235,8 @@ export async function fetchQwenModels() {
|
|
|
235
235
|
if (!token)
|
|
236
236
|
return [];
|
|
237
237
|
try {
|
|
238
|
-
const
|
|
238
|
+
const host = token.resourceUrl ? `https://${token.resourceUrl}` : 'https://chat.qwen.ai';
|
|
239
|
+
const res = await fetch(`${host}/api/models`, {
|
|
239
240
|
headers: { Authorization: `Bearer ${token.accessToken}` },
|
|
240
241
|
});
|
|
241
242
|
if (!res.ok)
|
|
@@ -252,17 +253,35 @@ export async function getQwenAccessToken() {
|
|
|
252
253
|
return token?.accessToken || null;
|
|
253
254
|
}
|
|
254
255
|
async function callQwenAPIWithToken(token, prompt, model, onData) {
|
|
255
|
-
|
|
256
|
+
// Use resource_url from token (e.g. "portal.qwen.ai"), fallback to DashScope
|
|
257
|
+
const rawHost = token.resourceUrl || 'dashscope.aliyuncs.com/compatible-mode';
|
|
258
|
+
const host = rawHost.startsWith('http') ? rawHost : `https://${rawHost}`;
|
|
259
|
+
const baseUrl = host.endsWith('/v1') ? host : `${host}/v1`;
|
|
256
260
|
const useStream = !!onData;
|
|
261
|
+
const userAgent = `QwenCode/0.14.2 (${process.platform}; ${process.arch})`;
|
|
262
|
+
// portal.qwen.ai requires content parts format (plain strings return 400)
|
|
263
|
+
const toContentParts = (text) => [{ type: 'text', text }];
|
|
257
264
|
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
258
265
|
method: 'POST',
|
|
259
266
|
headers: {
|
|
260
267
|
'Authorization': `Bearer ${token.accessToken}`,
|
|
261
268
|
'Content-Type': 'application/json',
|
|
269
|
+
'Accept': 'application/json',
|
|
270
|
+
'User-Agent': userAgent,
|
|
271
|
+
'x-dashscope-authtype': 'qwen-oauth',
|
|
272
|
+
'x-dashscope-cachecontrol': 'enable',
|
|
273
|
+
'x-dashscope-useragent': userAgent,
|
|
274
|
+
'x-stainless-lang': 'js',
|
|
275
|
+
'x-stainless-package-version': '5.11.0',
|
|
276
|
+
'x-stainless-os': process.platform,
|
|
277
|
+
'x-stainless-arch': process.arch,
|
|
278
|
+
'x-stainless-runtime': 'node',
|
|
279
|
+
'x-stainless-runtime-version': process.version,
|
|
280
|
+
'x-stainless-retry-count': '0',
|
|
262
281
|
},
|
|
263
282
|
body: JSON.stringify({
|
|
264
283
|
model: model || 'coder-model',
|
|
265
|
-
messages: [{ role: 'user', content: prompt }],
|
|
284
|
+
messages: [{ role: 'user', content: toContentParts(prompt) }],
|
|
266
285
|
stream: useStream,
|
|
267
286
|
}),
|
|
268
287
|
});
|