@bill10/agent-007 0.12.2001 → 0.12.2002
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/VERSION +1 -1
- package/package.json +1 -1
- package/server/owner.js +34 -4
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.12.2.
|
|
1
|
+
0.12.2.2
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bill10/agent-007",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.2002",
|
|
4
4
|
"description": "From web terminals for your coding agents to a self-running agent company: Claude Code and Codex in parallel git worktrees, a job board they pick work from, and one agent that runs the board from a goal.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
package/server/owner.js
CHANGED
|
@@ -59,11 +59,17 @@ async function call(method, params, { env = process.env, signal } = {}) {
|
|
|
59
59
|
...(form ? { body: params } : { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params) }),
|
|
60
60
|
signal,
|
|
61
61
|
});
|
|
62
|
-
body = await res.json().catch(() => ({ ok: false, description: `HTTP ${res.status}` }));
|
|
62
|
+
body = await res.json().catch(() => ({ ok: false, error_code: res.status, description: `HTTP ${res.status}` }));
|
|
63
63
|
} catch (err) {
|
|
64
|
-
|
|
64
|
+
// reason: a short label for the poll loop's offline line.
|
|
65
|
+
const reason = /ENOTFOUND|EAI_AGAIN/.test(err.cause?.code) ? 'DNS'
|
|
66
|
+
: err.name === 'TimeoutError' || /timeout/i.test(err.message) ? 'timeout' : 'no network';
|
|
67
|
+
throw Object.assign(new Error(redact(err.cause?.message || err.message, env)), { reason });
|
|
68
|
+
}
|
|
69
|
+
if (!body?.ok) {
|
|
70
|
+
const status = body?.error_code;
|
|
71
|
+
throw Object.assign(new Error(redact(body?.description || 'Telegram said no', env)), { status, reason: status ? `HTTP ${status}` : 'Telegram said no' });
|
|
65
72
|
}
|
|
66
|
-
if (!body?.ok) throw new Error(redact(body?.description || 'Telegram said no', env));
|
|
67
73
|
return body.result;
|
|
68
74
|
}
|
|
69
75
|
|
|
@@ -414,6 +420,16 @@ export async function pollOnce(offset, { broadcast, env = process.env, signal }
|
|
|
414
420
|
|
|
415
421
|
let stopper = null;
|
|
416
422
|
|
|
423
|
+
// Failures that retrying will not fix, and what the owner should do about them.
|
|
424
|
+
const POLL_HINTS = {
|
|
425
|
+
401: 'the bot token is wrong or revoked',
|
|
426
|
+
409: 'another process is polling this bot',
|
|
427
|
+
};
|
|
428
|
+
const OFFLINE_AFTER_MS = 60 * 1000;
|
|
429
|
+
const OFFLINE_AFTER_FAILURES = 3;
|
|
430
|
+
|
|
431
|
+
const since = ms => ms < 120e3 ? `${Math.round(ms / 1000)}s` : `${Math.round(ms / 60e3)}m`;
|
|
432
|
+
|
|
417
433
|
const pause = (ms, signal) => new Promise(resolve => {
|
|
418
434
|
const timer = setTimeout(resolve, ms);
|
|
419
435
|
signal.addEventListener('abort', () => { clearTimeout(timer); resolve(); }, { once: true });
|
|
@@ -432,13 +448,27 @@ export function startTelegram({ broadcast, env = process.env } = {}) {
|
|
|
432
448
|
(async () => {
|
|
433
449
|
let offset = 0;
|
|
434
450
|
let backoff = 1000;
|
|
451
|
+
// Sleep, wake and network changes fail a poll or two; log only going
|
|
452
|
+
// offline and coming back, not every retry.
|
|
453
|
+
let failures = 0, failingSince = 0, offline = false;
|
|
435
454
|
while (!controller.signal.aborted) {
|
|
436
455
|
try {
|
|
437
456
|
offset = await pollOnce(offset, { broadcast, env, signal: controller.signal });
|
|
457
|
+
if (offline) console.log(`Telegram: back online after ${since(Date.now() - failingSince)}`);
|
|
458
|
+
failures = 0;
|
|
459
|
+
offline = false;
|
|
438
460
|
backoff = 1000;
|
|
439
461
|
} catch (err) {
|
|
440
462
|
if (controller.signal.aborted) break;
|
|
441
|
-
|
|
463
|
+
if (!failures++) failingSince = Date.now();
|
|
464
|
+
const hint = POLL_HINTS[err.status];
|
|
465
|
+
// A hint logs even mid-outage: a token revoked while offline still needs saying.
|
|
466
|
+
if (hint ? offline !== hint : !offline && (failures >= OFFLINE_AFTER_FAILURES || Date.now() - failingSince > OFFLINE_AFTER_MS)) {
|
|
467
|
+
offline = hint || true;
|
|
468
|
+
console.error(hint
|
|
469
|
+
? `Telegram: getUpdates failed (${err.message}): ${hint}; retrying quietly`
|
|
470
|
+
: `Telegram: offline (${err.reason || 'no network'}), retrying quietly`);
|
|
471
|
+
}
|
|
442
472
|
await pause(backoff, controller.signal);
|
|
443
473
|
backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);
|
|
444
474
|
}
|