agentxchain 2.155.51 → 2.155.53
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
|
@@ -523,6 +523,7 @@ function renderPrompt(role, roleId, turn, state, config, root) {
|
|
|
523
523
|
if (phaseNames.length > 0) {
|
|
524
524
|
lines.push(`- \`phase_transition_request\`: set to a **phase name** when gate requirements are met, or \`null\`. Valid phases: ${phaseNames.map((p) => `\`"${p}"\``).join(', ')}`);
|
|
525
525
|
lines.push('- **Do NOT use exit gate names** (e.g., `planning_signoff`, `implementation_complete`, `qa_ship_verdict`) as `phase_transition_request` values — those are gate identifiers, not phase names');
|
|
526
|
+
lines.push('- **Do NOT skip ahead to later phases**. Use only the immediate next phase named below for the current phase.');
|
|
526
527
|
} else {
|
|
527
528
|
lines.push('- `phase_transition_request`: set to next phase name when gate requirements are met, or `null`');
|
|
528
529
|
}
|
|
@@ -4758,7 +4758,7 @@ function _acceptGovernedTurnLocked(root, config, opts) {
|
|
|
4758
4758
|
// early — the agent didn't do the work required for the transition.
|
|
4759
4759
|
if (turnResult.phase_transition_request && !isIdleExpansionNewIntakeProposal) {
|
|
4760
4760
|
const preGateResult = evaluatePhaseExit({
|
|
4761
|
-
state,
|
|
4761
|
+
state: { ...state, history: historyEntries },
|
|
4762
4762
|
config,
|
|
4763
4763
|
acceptedTurn: turnResult,
|
|
4764
4764
|
root,
|
|
@@ -1390,6 +1390,9 @@ export function normalizeTurnResult(tr, config, context = {}) {
|
|
|
1390
1390
|
if (allowedNextRoles.length === 0) return null;
|
|
1391
1391
|
return allowedNextRoles.find((role) => role !== assignedRole) || allowedNextRoles[0] || null;
|
|
1392
1392
|
};
|
|
1393
|
+
const nextPhaseEntryRole = nextPhase && routing?.[nextPhase]?.entry_role
|
|
1394
|
+
? routing[nextPhase].entry_role
|
|
1395
|
+
: null;
|
|
1393
1396
|
|
|
1394
1397
|
// ── Rule 0: infer missing status only when intent is unambiguous ──────
|
|
1395
1398
|
if (!('status' in normalized)) {
|
|
@@ -1537,6 +1540,54 @@ export function normalizeTurnResult(tr, config, context = {}) {
|
|
|
1537
1540
|
}
|
|
1538
1541
|
|
|
1539
1542
|
// ── Rule 5: correct invalid or non-forward lifecycle requests ─────────
|
|
1543
|
+
if (
|
|
1544
|
+
isKnownPhase &&
|
|
1545
|
+
!isTerminalPhase &&
|
|
1546
|
+
!isReviewOnly &&
|
|
1547
|
+
normalized.status === 'completed' &&
|
|
1548
|
+
typeof normalized.phase_transition_request === 'string' &&
|
|
1549
|
+
!normalized.run_completion_request
|
|
1550
|
+
) {
|
|
1551
|
+
const requested = normalized.phase_transition_request;
|
|
1552
|
+
const requestedIndex = phaseNames.indexOf(requested);
|
|
1553
|
+
const skipsImmediateNextPhase = requestedIndex > currentPhaseIndex + 1;
|
|
1554
|
+
|
|
1555
|
+
if (skipsImmediateNextPhase && nextPhase) {
|
|
1556
|
+
normalized.phase_transition_request = nextPhase;
|
|
1557
|
+
corrections.push(
|
|
1558
|
+
`phase_transition_request: corrected skip-forward "${requested}" to immediate next phase "${nextPhase}"`
|
|
1559
|
+
);
|
|
1560
|
+
normalizationEvents.push({
|
|
1561
|
+
field: 'phase_transition_request',
|
|
1562
|
+
original_value: requested,
|
|
1563
|
+
normalized_value: nextPhase,
|
|
1564
|
+
rationale: 'skip_forward_phase_corrected_to_next_phase',
|
|
1565
|
+
});
|
|
1566
|
+
|
|
1567
|
+
const proposedRoleIsStalePhase = normalized.proposed_next_role === requested;
|
|
1568
|
+
const proposedRoleIsRoutingIllegal = typeof normalized.proposed_next_role === 'string'
|
|
1569
|
+
&& normalized.proposed_next_role !== 'human'
|
|
1570
|
+
&& allowedNextRoles.length > 0
|
|
1571
|
+
&& !allowedNextRoles.includes(normalized.proposed_next_role);
|
|
1572
|
+
if (
|
|
1573
|
+
nextPhaseEntryRole &&
|
|
1574
|
+
allowedNextRoles.includes(nextPhaseEntryRole) &&
|
|
1575
|
+
(proposedRoleIsStalePhase || proposedRoleIsRoutingIllegal)
|
|
1576
|
+
) {
|
|
1577
|
+
corrections.push(
|
|
1578
|
+
`proposed_next_role: corrected "${normalized.proposed_next_role}" to entry role "${nextPhaseEntryRole}" for corrected phase "${nextPhase}"`
|
|
1579
|
+
);
|
|
1580
|
+
normalizationEvents.push({
|
|
1581
|
+
field: 'proposed_next_role',
|
|
1582
|
+
original_value: normalized.proposed_next_role,
|
|
1583
|
+
normalized_value: nextPhaseEntryRole,
|
|
1584
|
+
rationale: 'aligned_to_corrected_phase_entry_role',
|
|
1585
|
+
});
|
|
1586
|
+
normalized.proposed_next_role = nextPhaseEntryRole;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1540
1591
|
if (
|
|
1541
1592
|
isKnownPhase &&
|
|
1542
1593
|
isReviewOnly &&
|