manus-api 0.1.0-beta.4 → 0.1.0-beta.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/dist/index.cjs +19 -0
- package/dist/index.mjs +19 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
2
2
|
|
|
3
3
|
var rl = require('@henrygd/queue/rl');
|
|
4
4
|
var extractErrorMessage = require('foxts/extract-error-message');
|
|
5
|
+
var isNetworkError = require('foxts/is-network-error');
|
|
5
6
|
var wait = require('foxts/wait');
|
|
6
7
|
|
|
7
8
|
const AGENT_PROFILES = [
|
|
@@ -73,6 +74,11 @@ const MANUS_API_BASE_URL = 'https://api.manus.ai';
|
|
|
73
74
|
return rl.newQueue(concurrency, ratePerMinute, 60000);
|
|
74
75
|
}
|
|
75
76
|
const MAX_RATE_LIMIT_RETRIES = 5;
|
|
77
|
+
/**
|
|
78
|
+
* Network failures and 5xx are retried for GET only: a POST that failed mid-flight may already have
|
|
79
|
+
* created the task or sent the message. A request timeout is not retried either: the caller has
|
|
80
|
+
* already waited `timeoutMs`, and three more hangs would cost minutes.
|
|
81
|
+
*/ const MAX_TRANSIENT_RETRIES = 3;
|
|
76
82
|
const MAX_BACKOFF_MS = 60000;
|
|
77
83
|
const TRAILING_SLASHES = /\/+$/;
|
|
78
84
|
function backoffMs(attempt, retryAfterHeader) {
|
|
@@ -222,6 +228,7 @@ class ManusClient {
|
|
|
222
228
|
}
|
|
223
229
|
let retriedAuth = false;
|
|
224
230
|
let rateLimitRetries = 0;
|
|
231
|
+
let transientRetries = 0;
|
|
225
232
|
for(;;){
|
|
226
233
|
// eslint-disable-next-line no-await-in-loop -- sequential retry loop
|
|
227
234
|
const apiKey = await this.options.getApiKey();
|
|
@@ -248,6 +255,12 @@ class ManusClient {
|
|
|
248
255
|
// eslint-disable-next-line no-await-in-loop -- sequential retry loop
|
|
249
256
|
({ res, text } = await (init.poll && this.options.pollQueue ? this.options.pollQueue.add(send) : send()));
|
|
250
257
|
} catch (error) {
|
|
258
|
+
if (method === 'GET' && transientRetries < MAX_TRANSIENT_RETRIES && isNetworkError.isNetworkError(error)) {
|
|
259
|
+
transientRetries++;
|
|
260
|
+
// eslint-disable-next-line no-await-in-loop -- sequential retry loop
|
|
261
|
+
await this.sleep(backoffMs(transientRetries, null));
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
251
264
|
throw new ManusApiError(extractErrorMessage.extractErrorMessage(error) ?? 'request failed', {
|
|
252
265
|
status: 0,
|
|
253
266
|
code: 'network',
|
|
@@ -280,6 +293,12 @@ class ManusClient {
|
|
|
280
293
|
await this.sleep(backoffMs(rateLimitRetries, res.headers.get('retry-after')));
|
|
281
294
|
continue;
|
|
282
295
|
}
|
|
296
|
+
if (method === 'GET' && transientRetries < MAX_TRANSIENT_RETRIES && res.status >= 500) {
|
|
297
|
+
transientRetries++;
|
|
298
|
+
// eslint-disable-next-line no-await-in-loop -- sequential retry loop
|
|
299
|
+
await this.sleep(backoffMs(transientRetries, res.headers.get('retry-after')));
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
283
302
|
throw new ManusApiError(json?.error?.message ?? `Manus API ${method} ${endpoint} failed with HTTP ${res.status}`, {
|
|
284
303
|
status: res.status,
|
|
285
304
|
code: json?.error?.code ?? (res.status === 429 ? 'rate_limited' : `http_${res.status}`),
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { newQueue } from '@henrygd/queue/rl';
|
|
2
2
|
import { extractErrorMessage } from 'foxts/extract-error-message';
|
|
3
|
+
import { isNetworkError } from 'foxts/is-network-error';
|
|
3
4
|
import { wait } from 'foxts/wait';
|
|
4
5
|
|
|
5
6
|
const AGENT_PROFILES = [
|
|
@@ -71,6 +72,11 @@ const MANUS_API_BASE_URL = 'https://api.manus.ai';
|
|
|
71
72
|
return newQueue(concurrency, ratePerMinute, 60000);
|
|
72
73
|
}
|
|
73
74
|
const MAX_RATE_LIMIT_RETRIES = 5;
|
|
75
|
+
/**
|
|
76
|
+
* Network failures and 5xx are retried for GET only: a POST that failed mid-flight may already have
|
|
77
|
+
* created the task or sent the message. A request timeout is not retried either: the caller has
|
|
78
|
+
* already waited `timeoutMs`, and three more hangs would cost minutes.
|
|
79
|
+
*/ const MAX_TRANSIENT_RETRIES = 3;
|
|
74
80
|
const MAX_BACKOFF_MS = 60000;
|
|
75
81
|
const TRAILING_SLASHES = /\/+$/;
|
|
76
82
|
function backoffMs(attempt, retryAfterHeader) {
|
|
@@ -220,6 +226,7 @@ class ManusClient {
|
|
|
220
226
|
}
|
|
221
227
|
let retriedAuth = false;
|
|
222
228
|
let rateLimitRetries = 0;
|
|
229
|
+
let transientRetries = 0;
|
|
223
230
|
for(;;){
|
|
224
231
|
// eslint-disable-next-line no-await-in-loop -- sequential retry loop
|
|
225
232
|
const apiKey = await this.options.getApiKey();
|
|
@@ -246,6 +253,12 @@ class ManusClient {
|
|
|
246
253
|
// eslint-disable-next-line no-await-in-loop -- sequential retry loop
|
|
247
254
|
({ res, text } = await (init.poll && this.options.pollQueue ? this.options.pollQueue.add(send) : send()));
|
|
248
255
|
} catch (error) {
|
|
256
|
+
if (method === 'GET' && transientRetries < MAX_TRANSIENT_RETRIES && isNetworkError(error)) {
|
|
257
|
+
transientRetries++;
|
|
258
|
+
// eslint-disable-next-line no-await-in-loop -- sequential retry loop
|
|
259
|
+
await this.sleep(backoffMs(transientRetries, null));
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
249
262
|
throw new ManusApiError(extractErrorMessage(error) ?? 'request failed', {
|
|
250
263
|
status: 0,
|
|
251
264
|
code: 'network',
|
|
@@ -278,6 +291,12 @@ class ManusClient {
|
|
|
278
291
|
await this.sleep(backoffMs(rateLimitRetries, res.headers.get('retry-after')));
|
|
279
292
|
continue;
|
|
280
293
|
}
|
|
294
|
+
if (method === 'GET' && transientRetries < MAX_TRANSIENT_RETRIES && res.status >= 500) {
|
|
295
|
+
transientRetries++;
|
|
296
|
+
// eslint-disable-next-line no-await-in-loop -- sequential retry loop
|
|
297
|
+
await this.sleep(backoffMs(transientRetries, res.headers.get('retry-after')));
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
281
300
|
throw new ManusApiError(json?.error?.message ?? `Manus API ${method} ${endpoint} failed with HTTP ${res.status}`, {
|
|
282
301
|
status: res.status,
|
|
283
302
|
code: json?.error?.code ?? (res.status === 429 ? 'rate_limited' : `http_${res.status}`),
|