agentxchain 2.155.65 → 2.155.67
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/package.json
CHANGED
|
@@ -30,7 +30,11 @@ import {
|
|
|
30
30
|
} from '../turn-paths.js';
|
|
31
31
|
import { verifyDispatchManifestForAdapter } from '../dispatch-manifest.js';
|
|
32
32
|
import { hasMeaningfulStagedResult } from '../staged-result-proof.js';
|
|
33
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
getClaudeSubprocessAuthIssue,
|
|
35
|
+
hasClaudeAuthenticationFailureText,
|
|
36
|
+
isClaudeLocalCliRuntime,
|
|
37
|
+
} from '../claude-local-auth.js';
|
|
34
38
|
|
|
35
39
|
const DIAGNOSTIC_ENV_KEYS = [
|
|
36
40
|
'PATH',
|
|
@@ -43,7 +47,6 @@ const DIAGNOSTIC_ENV_KEYS = [
|
|
|
43
47
|
const DIAGNOSTIC_STDERR_EXCERPT_LIMIT = 800;
|
|
44
48
|
const DEFAULT_STARTUP_WATCHDOG_MS = 180_000;
|
|
45
49
|
const DEFAULT_STARTUP_WATCHDOG_SIGKILL_GRACE_MS = 10_000;
|
|
46
|
-
const CLAUDE_AUTH_FAILURE_RE = /authentication_failed|authentication_error|invalid authentication credentials|unauthorized|API Error:\s*401/i;
|
|
47
50
|
|
|
48
51
|
/**
|
|
49
52
|
* Launch a local CLI subprocess for a governed turn.
|
|
@@ -659,7 +662,7 @@ function appendDiagnostic(logs, label, payload) {
|
|
|
659
662
|
|
|
660
663
|
function hasClaudeAuthFailureOutput(logs) {
|
|
661
664
|
if (!Array.isArray(logs)) return false;
|
|
662
|
-
return logs.some((line) =>
|
|
665
|
+
return logs.some((line) => hasClaudeAuthenticationFailureText(line));
|
|
663
666
|
}
|
|
664
667
|
|
|
665
668
|
function pickDiagnosticEnv(env) {
|
|
@@ -10,6 +10,7 @@ const CLAUDE_ENV_AUTH_KEYS = [
|
|
|
10
10
|
|
|
11
11
|
const DEFAULT_SMOKE_PROBE_TIMEOUT_MS = 10_000;
|
|
12
12
|
const DEFAULT_SMOKE_PROBE_STDIN = 'ok';
|
|
13
|
+
const CLAUDE_AUTH_FAILURE_RE = /authentication_failed|authentication_error|invalid authentication credentials|unauthorized|API Error:\s*401/i;
|
|
13
14
|
|
|
14
15
|
function normalizeCommandTokens(runtime) {
|
|
15
16
|
if (Array.isArray(runtime?.command)) {
|
|
@@ -32,6 +33,10 @@ export function isClaudeLocalCliRuntime(runtime) {
|
|
|
32
33
|
return head === 'claude' || head.endsWith('/claude');
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
export function hasClaudeAuthenticationFailureText(text) {
|
|
37
|
+
return typeof text === 'string' && CLAUDE_AUTH_FAILURE_RE.test(text);
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
export function hasClaudeBareFlag(runtime) {
|
|
36
41
|
return normalizeCommandTokens(runtime).includes('--bare');
|
|
37
42
|
}
|
|
@@ -53,10 +53,15 @@ import {
|
|
|
53
53
|
formatPhantomIntentSupersessionNotice,
|
|
54
54
|
} from './intent-startup-migration.js';
|
|
55
55
|
import { checkpointAcceptedTurn } from './turn-checkpoint.js';
|
|
56
|
+
import {
|
|
57
|
+
hasClaudeAuthenticationFailureText,
|
|
58
|
+
isClaudeLocalCliRuntime,
|
|
59
|
+
} from './claude-local-auth.js';
|
|
56
60
|
|
|
57
61
|
const CONTINUOUS_SESSION_PATH = '.agentxchain/continuous-session.json';
|
|
58
62
|
const PRODUCTIVE_TIMEOUT_RETRY_MAX_PER_RUN = 1;
|
|
59
63
|
const PRODUCTIVE_TIMEOUT_RETRY_DEADLINE_MINUTES = 60;
|
|
64
|
+
const PROVIDER_REQUEST_TIMEOUT_RE = /request timed out|timed out waiting for (?:provider|api)|provider request timed out/i;
|
|
60
65
|
|
|
61
66
|
function getRoadmapReplenishmentTriageHints(root) {
|
|
62
67
|
const context = loadProjectContext(root);
|
|
@@ -309,6 +314,87 @@ function getBlockedCategory(state) {
|
|
|
309
314
|
return state?.blocked_reason?.category || null;
|
|
310
315
|
}
|
|
311
316
|
|
|
317
|
+
const CLAUDE_AUTH_RECOVERY_ACTION =
|
|
318
|
+
'Refresh Claude credentials before resuming: export a valid ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN, then run agentxchain step --resume.';
|
|
319
|
+
|
|
320
|
+
function findRetainedClaudeAuthEscalation(root, state, config) {
|
|
321
|
+
if (!state || state.status !== 'blocked') return null;
|
|
322
|
+
if (state.blocked_reason?.category !== 'retries_exhausted') return null;
|
|
323
|
+
if (typeof state.blocked_on !== 'string' || !state.blocked_on.startsWith('escalation:retries-exhausted:')) {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
const turnId = state.blocked_reason?.turn_id || state.escalation?.from_turn_id || null;
|
|
327
|
+
const activeTurns = state.active_turns || {};
|
|
328
|
+
const candidateIds = turnId && activeTurns[turnId] ? [turnId] : Object.keys(activeTurns);
|
|
329
|
+
for (const candidateId of candidateIds) {
|
|
330
|
+
const turn = activeTurns[candidateId];
|
|
331
|
+
if (!turn || turn.status !== 'failed') continue;
|
|
332
|
+
if (turn.last_rejection?.failed_stage !== 'dispatch') continue;
|
|
333
|
+
const runtime = config?.runtimes?.[turn.runtime_id];
|
|
334
|
+
if (!isClaudeLocalCliRuntime(runtime)) continue;
|
|
335
|
+
const stagingPath = join(root, getTurnStagingResultPath(candidateId));
|
|
336
|
+
if (existsSync(stagingPath)) continue;
|
|
337
|
+
const logPath = join(root, getDispatchLogPath(candidateId));
|
|
338
|
+
if (!existsSync(logPath)) continue;
|
|
339
|
+
let logText = '';
|
|
340
|
+
try {
|
|
341
|
+
logText = readFileSync(logPath, 'utf8');
|
|
342
|
+
} catch {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
if (!hasClaudeAuthenticationFailureText(logText)) continue;
|
|
346
|
+
return { turn_id: candidateId, turn, previous_blocked_on: state.blocked_on };
|
|
347
|
+
}
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function maybeReclassifyRetainedClaudeAuthEscalation(context, session, state, log = console.log) {
|
|
352
|
+
const { root, config } = context;
|
|
353
|
+
const candidate = findRetainedClaudeAuthEscalation(root, state, config);
|
|
354
|
+
if (!candidate) return null;
|
|
355
|
+
|
|
356
|
+
const blockedAt = new Date().toISOString();
|
|
357
|
+
const nextState = {
|
|
358
|
+
...state,
|
|
359
|
+
status: 'blocked',
|
|
360
|
+
blocked_on: 'dispatch:claude_auth_failed',
|
|
361
|
+
blocked_reason: {
|
|
362
|
+
category: 'dispatch_error',
|
|
363
|
+
blocked_at: blockedAt,
|
|
364
|
+
turn_id: candidate.turn_id,
|
|
365
|
+
reclassified_from: {
|
|
366
|
+
blocked_on: state.blocked_on || null,
|
|
367
|
+
category: state.blocked_reason?.category || null,
|
|
368
|
+
},
|
|
369
|
+
recovery: {
|
|
370
|
+
typed_reason: 'dispatch_error',
|
|
371
|
+
owner: 'human',
|
|
372
|
+
recovery_action: CLAUDE_AUTH_RECOVERY_ACTION,
|
|
373
|
+
turn_retained: true,
|
|
374
|
+
detail: `claude_auth_failed: ${CLAUDE_AUTH_RECOVERY_ACTION}`,
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
escalation: null,
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
writeGovernedState(root, nextState);
|
|
381
|
+
emitRunEvent(root, 'retained_claude_auth_escalation_reclassified', {
|
|
382
|
+
run_id: nextState.run_id || session.current_run_id || null,
|
|
383
|
+
phase: nextState.phase || null,
|
|
384
|
+
status: 'blocked',
|
|
385
|
+
turn: { turn_id: candidate.turn_id, role_id: candidate.turn.assigned_role || null },
|
|
386
|
+
payload: {
|
|
387
|
+
turn_id: candidate.turn_id,
|
|
388
|
+
previous_blocked_on: candidate.previous_blocked_on,
|
|
389
|
+
blocked_on: nextState.blocked_on,
|
|
390
|
+
runtime_id: candidate.turn.runtime_id || null,
|
|
391
|
+
recovery_action: CLAUDE_AUTH_RECOVERY_ACTION,
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
log(`Reclassified retained Claude auth escalation for ${candidate.turn_id} as dispatch:claude_auth_failed.`);
|
|
395
|
+
return nextState;
|
|
396
|
+
}
|
|
397
|
+
|
|
312
398
|
const RECOVERABLE_ACTIVE_TURN_STATUSES = new Set(['assigned', 'dispatched', 'starting', 'running']);
|
|
313
399
|
|
|
314
400
|
function hasOnlyRecoverableActiveTurns(activeTurns = {}) {
|
|
@@ -452,7 +538,16 @@ function findPrimaryProductiveTimeoutTurn(root, state) {
|
|
|
452
538
|
...(Array.isArray(turn.last_rejection?.validation_errors) ? turn.last_rejection.validation_errors : []),
|
|
453
539
|
].join('\n');
|
|
454
540
|
const looksDeadlineKilled = /code 143|dispatch timed out|timed out/i.test(reason);
|
|
455
|
-
|
|
541
|
+
let looksProviderTimedOut = false;
|
|
542
|
+
const logPath = join(root, getDispatchLogPath(candidateId));
|
|
543
|
+
if (!looksDeadlineKilled && existsSync(logPath)) {
|
|
544
|
+
try {
|
|
545
|
+
looksProviderTimedOut = PROVIDER_REQUEST_TIMEOUT_RE.test(readFileSync(logPath, 'utf8'));
|
|
546
|
+
} catch {
|
|
547
|
+
looksProviderTimedOut = false;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
if (!looksDeadlineKilled && !looksProviderTimedOut) continue;
|
|
456
551
|
if (!turn.first_output_at) continue;
|
|
457
552
|
const stagingPath = join(root, getTurnStagingResultPath(candidateId));
|
|
458
553
|
if (existsSync(stagingPath)) continue;
|
|
@@ -1714,7 +1809,9 @@ export async function advanceContinuousRunOnce(context, session, contOpts, execu
|
|
|
1714
1809
|
|
|
1715
1810
|
const startupGovernedState = loadProjectState(root, context.config);
|
|
1716
1811
|
if (startupGovernedState?.status === 'blocked') {
|
|
1717
|
-
const
|
|
1812
|
+
const reclassifiedState = maybeReclassifyRetainedClaudeAuthEscalation(context, session, startupGovernedState, log);
|
|
1813
|
+
const effectiveBlockedState = reclassifiedState || startupGovernedState;
|
|
1814
|
+
const retried = await maybeAutoRetryContinuousBlocker(context, session, contOpts, effectiveBlockedState, log);
|
|
1718
1815
|
if (retried) return retried;
|
|
1719
1816
|
session.status = 'paused';
|
|
1720
1817
|
writeContinuousSession(root, session);
|
|
@@ -1722,9 +1819,9 @@ export async function advanceContinuousRunOnce(context, session, contOpts, execu
|
|
|
1722
1819
|
ok: true,
|
|
1723
1820
|
status: 'blocked',
|
|
1724
1821
|
action: 'still_blocked',
|
|
1725
|
-
run_id: session.current_run_id ||
|
|
1726
|
-
recovery_action: getBlockedRecoveryAction(
|
|
1727
|
-
blocked_category: getBlockedCategory(
|
|
1822
|
+
run_id: session.current_run_id || effectiveBlockedState.run_id || null,
|
|
1823
|
+
recovery_action: getBlockedRecoveryAction(effectiveBlockedState),
|
|
1824
|
+
blocked_category: getBlockedCategory(effectiveBlockedState),
|
|
1728
1825
|
};
|
|
1729
1826
|
}
|
|
1730
1827
|
|
package/src/lib/run-events.js
CHANGED
|
@@ -48,6 +48,7 @@ export const VALID_RUN_EVENTS = [
|
|
|
48
48
|
'ghost_retry_exhausted',
|
|
49
49
|
'auto_retried_productive_timeout',
|
|
50
50
|
'productive_timeout_retry_exhausted',
|
|
51
|
+
'retained_claude_auth_escalation_reclassified',
|
|
51
52
|
'state_reconciled_operator_commits',
|
|
52
53
|
'operator_commit_reconcile_refused',
|
|
53
54
|
'charter_materialization_required',
|