agentxchain 2.155.13 → 2.155.15
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 +1 -1
- package/src/lib/dispatch-bundle.js +12 -0
- package/src/lib/governed-state.js +16 -11
package/package.json
CHANGED
|
@@ -529,6 +529,12 @@ function renderPrompt(role, roleId, turn, state, config, root) {
|
|
|
529
529
|
lines.push(`- **You are in the \`${currentPhase}\` phase.** When your work is complete${gateClause}, set \`phase_transition_request: "${nextPhase}"\` to advance to the next phase.`);
|
|
530
530
|
} else if (phaseIdx === phaseNames.length - 1) {
|
|
531
531
|
lines.push(`- **You are in the \`${currentPhase}\` phase (final phase).** When ready to ship, set \`run_completion_request: true\` and \`phase_transition_request: null\`.`);
|
|
532
|
+
if (runCompletionAutoApprovalApplies(config)) {
|
|
533
|
+
lines.push('- Run completion is governed by `approval_policy.run_completion.action: "auto_approve"` for this run.');
|
|
534
|
+
lines.push('- Do NOT set `status: "needs_human"` solely to request final run approval. If the required artifacts are complete and there are no genuine blockers, set `status: "completed"` with `run_completion_request: true`; the orchestrator will evaluate and auto-approve completion.');
|
|
535
|
+
} else {
|
|
536
|
+
lines.push('- If final approval is human-gated, set `run_completion_request: true` when ready; the orchestrator will route the approval gate.');
|
|
537
|
+
}
|
|
532
538
|
}
|
|
533
539
|
}
|
|
534
540
|
// Phase-specific guidance for proposed roles
|
|
@@ -542,6 +548,12 @@ function renderPrompt(role, roleId, turn, state, config, root) {
|
|
|
542
548
|
lines.push(`- **You are in the \`${currentPhase}\` phase (not final phase).** When your work is complete${gateClause}, set \`phase_transition_request: "${nextPhase}"\`.`);
|
|
543
549
|
} else if (phaseIdx >= 0 && phaseIdx === phaseNames.length - 1) {
|
|
544
550
|
lines.push(`- **You are in the \`${currentPhase}\` phase (final phase).** When ready to ship, set \`run_completion_request: true\` and \`phase_transition_request: null\`.`);
|
|
551
|
+
if (runCompletionAutoApprovalApplies(config)) {
|
|
552
|
+
lines.push('- Run completion is governed by `approval_policy.run_completion.action: "auto_approve"` for this run.');
|
|
553
|
+
lines.push('- Do NOT set `status: "needs_human"` solely to request final run approval. If the required artifacts are complete and there are no genuine blockers, set `status: "completed"` with `run_completion_request: true`; the orchestrator will evaluate and auto-approve completion.');
|
|
554
|
+
} else {
|
|
555
|
+
lines.push('- If final approval is human-gated, set `run_completion_request: true` when ready; the orchestrator will route the approval gate.');
|
|
556
|
+
}
|
|
545
557
|
if (runtimeType === 'api_proxy' || runtimeType === 'remote_agent') {
|
|
546
558
|
lines.push('- **Completion turns must be no-op:** set `proposed_changes` to `[]` or omit it, set `files_changed` to `[]`, and set `artifact.type` to `"review"`. Do NOT propose file changes on a completion turn.');
|
|
547
559
|
}
|
|
@@ -5023,17 +5023,21 @@ function _acceptGovernedTurnLocked(root, config, opts) {
|
|
|
5023
5023
|
const remainingReservations = { ...(state.budget_reservations || {}) };
|
|
5024
5024
|
delete remainingReservations[currentTurn.turn_id];
|
|
5025
5025
|
const costUsd = turnResult.cost?.usd || 0;
|
|
5026
|
+
const isIdleExpansionNewIntake = idleExpansionResultSummary?.kind === 'new_intake_intent';
|
|
5027
|
+
const suppressIdleExpansionNeedsHuman = isIdleExpansionNewIntake && turnResult.status === 'needs_human';
|
|
5026
5028
|
let updatedState = {
|
|
5027
5029
|
...state,
|
|
5028
5030
|
turn_sequence: acceptedSequence,
|
|
5029
5031
|
last_completed_turn_id: currentTurn.turn_id,
|
|
5030
5032
|
active_turns: remainingTurns,
|
|
5031
5033
|
budget_reservations: remainingReservations,
|
|
5032
|
-
blocked_on: turnResult.status === 'needs_human' ? `human:${turnResult.needs_human_reason || 'unspecified'}` : null,
|
|
5034
|
+
blocked_on: turnResult.status === 'needs_human' && !suppressIdleExpansionNeedsHuman ? `human:${turnResult.needs_human_reason || 'unspecified'}` : null,
|
|
5033
5035
|
blocked_reason: null,
|
|
5034
5036
|
escalation: null,
|
|
5035
5037
|
accepted_integration_ref: derivedRef,
|
|
5036
|
-
next_recommended_role:
|
|
5038
|
+
next_recommended_role: suppressIdleExpansionNeedsHuman
|
|
5039
|
+
? currentTurn.assigned_role
|
|
5040
|
+
: deriveNextRecommendedRole(turnResult, state, config),
|
|
5037
5041
|
budget_status: {
|
|
5038
5042
|
...(state.budget_status || {}),
|
|
5039
5043
|
spent_usd: (state.budget_status?.spent_usd || 0) + costUsd,
|
|
@@ -5153,7 +5157,7 @@ function _acceptGovernedTurnLocked(root, config, opts) {
|
|
|
5153
5157
|
updatedState.escalation = null;
|
|
5154
5158
|
}
|
|
5155
5159
|
|
|
5156
|
-
if (turnResult.status === 'needs_human') {
|
|
5160
|
+
if (turnResult.status === 'needs_human' && !suppressIdleExpansionNeedsHuman) {
|
|
5157
5161
|
updatedState.status = 'blocked';
|
|
5158
5162
|
updatedState.blocked_reason = buildBlockedReason({
|
|
5159
5163
|
category: 'needs_human',
|
|
@@ -5223,11 +5227,11 @@ function _acceptGovernedTurnLocked(root, config, opts) {
|
|
|
5223
5227
|
let completionResult = null;
|
|
5224
5228
|
let timeoutResult = null;
|
|
5225
5229
|
|
|
5226
|
-
// BUG-70: idle-expansion new_intake_intent is a proposal, not a chartered plan.
|
|
5227
|
-
// Suppress phase_transition_request
|
|
5228
|
-
// planning artifacts by a subsequent
|
|
5229
|
-
|
|
5230
|
-
if (isIdleExpansionNewIntake && turnResult.phase_transition_request) {
|
|
5230
|
+
// BUG-70/71: idle-expansion new_intake_intent is a proposal, not a chartered plan.
|
|
5231
|
+
// Suppress phase_transition_request and human-only intake approval escalations —
|
|
5232
|
+
// the new intake must be materialized into planning artifacts by a subsequent
|
|
5233
|
+
// planning turn before implementation can proceed.
|
|
5234
|
+
if (isIdleExpansionNewIntake && (turnResult.phase_transition_request || suppressIdleExpansionNeedsHuman)) {
|
|
5231
5235
|
const rawIdleResult = turnResult.idle_expansion_result;
|
|
5232
5236
|
updatedState.charter_materialization_pending = {
|
|
5233
5237
|
charter: rawIdleResult?.new_intake_intent?.charter
|
|
@@ -5235,7 +5239,7 @@ function _acceptGovernedTurnLocked(root, config, opts) {
|
|
|
5235
5239
|
|| null,
|
|
5236
5240
|
acceptance_contract: rawIdleResult?.new_intake_intent?.acceptance_contract
|
|
5237
5241
|
|| [],
|
|
5238
|
-
suppressed_transition: turnResult.phase_transition_request,
|
|
5242
|
+
suppressed_transition: turnResult.phase_transition_request || 'implementation',
|
|
5239
5243
|
source_turn_id: turnResult.turn_id,
|
|
5240
5244
|
recorded_at: now,
|
|
5241
5245
|
};
|
|
@@ -5245,9 +5249,10 @@ function _acceptGovernedTurnLocked(root, config, opts) {
|
|
|
5245
5249
|
status: updatedState.status,
|
|
5246
5250
|
turn: { turn_id: currentTurn.turn_id, role_id: currentTurn.assigned_role },
|
|
5247
5251
|
payload: {
|
|
5248
|
-
suppressed_transition: turnResult.phase_transition_request,
|
|
5252
|
+
suppressed_transition: turnResult.phase_transition_request || 'implementation',
|
|
5249
5253
|
reason: 'New intake from idle expansion must be materialized into planning artifacts before implementation dispatch.',
|
|
5250
5254
|
new_intake_charter: updatedState.charter_materialization_pending.charter,
|
|
5255
|
+
suppressed_needs_human: suppressIdleExpansionNeedsHuman,
|
|
5251
5256
|
},
|
|
5252
5257
|
});
|
|
5253
5258
|
}
|
|
@@ -5259,7 +5264,7 @@ function _acceptGovernedTurnLocked(root, config, opts) {
|
|
|
5259
5264
|
}
|
|
5260
5265
|
|
|
5261
5266
|
const hasRemainingTurns = Object.keys(remainingTurns).length > 0;
|
|
5262
|
-
if (turnResult.status !== 'needs_human') {
|
|
5267
|
+
if (turnResult.status !== 'needs_human' || suppressIdleExpansionNeedsHuman) {
|
|
5263
5268
|
if (hasRemainingTurns) {
|
|
5264
5269
|
if (turnResult.run_completion_request && !updatedState.queued_run_completion) {
|
|
5265
5270
|
updatedState.queued_run_completion = {
|