agentxchain 2.92.0 → 2.94.0

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.
@@ -76,6 +76,16 @@
76
76
  "rationale": {
77
77
  "type": "string",
78
78
  "minLength": 1
79
+ },
80
+ "durability": {
81
+ "type": "string",
82
+ "enum": ["run", "repo"],
83
+ "description": "Decision persistence scope. 'run' (default) dies with the run; 'repo' persists across runs as a binding constraint."
84
+ },
85
+ "overrides": {
86
+ "type": "string",
87
+ "pattern": "^DEC-\\d+$",
88
+ "description": "ID of an active repo-durable decision this decision supersedes."
79
89
  }
80
90
  }
81
91
  }
@@ -258,6 +268,16 @@
258
268
  "items": { "type": "string", "minLength": 1 },
259
269
  "minItems": 1,
260
270
  "description": "What the delegate must achieve for this delegation to be considered complete."
271
+ },
272
+ "required_decision_ids": {
273
+ "type": "array",
274
+ "items": {
275
+ "type": "string",
276
+ "pattern": "^DEC-\\d+$"
277
+ },
278
+ "minItems": 1,
279
+ "uniqueItems": true,
280
+ "description": "Optional named decisions the delegated child must emit before the parent review turn may advance phase/run lifecycle."
261
281
  }
262
282
  }
263
283
  }
@@ -263,6 +263,16 @@ function validateSchema(tr) {
263
263
  }
264
264
  }
265
265
 
266
+ if ('delegations' in tr) {
267
+ if (!Array.isArray(tr.delegations)) {
268
+ errors.push('delegations must be an array.');
269
+ } else {
270
+ for (let i = 0; i < tr.delegations.length; i++) {
271
+ errors.push(...validateDelegation(tr.delegations[i], i));
272
+ }
273
+ }
274
+ }
275
+
266
276
  errors.push(...collectUnfilledTemplatePlaceholderErrors(tr));
267
277
 
268
278
  return errors;
@@ -325,6 +335,8 @@ function checkPlaceholder(errors, fieldPath, value) {
325
335
  }
326
336
  }
327
337
 
338
+ const VALID_DURABILITIES = ['run', 'repo'];
339
+
328
340
  function validateDecision(dec, index) {
329
341
  const errors = [];
330
342
  const prefix = `decisions[${index}]`;
@@ -344,6 +356,17 @@ function validateDecision(dec, index) {
344
356
  if (typeof dec.rationale !== 'string' || !dec.rationale.trim()) {
345
357
  errors.push(`${prefix}.rationale must be a non-empty string.`);
346
358
  }
359
+ if (dec.durability !== undefined && !VALID_DURABILITIES.includes(dec.durability)) {
360
+ errors.push(`${prefix}.durability must be one of: ${VALID_DURABILITIES.join(', ')}.`);
361
+ }
362
+ if (dec.overrides !== undefined) {
363
+ if (typeof dec.overrides !== 'string' || !/^DEC-\d+$/.test(dec.overrides)) {
364
+ errors.push(`${prefix}.overrides must match pattern DEC-NNN.`);
365
+ }
366
+ if (dec.overrides === dec.id) {
367
+ errors.push(`${prefix}.overrides cannot reference itself.`);
368
+ }
369
+ }
347
370
  return errors;
348
371
  }
349
372
 
@@ -369,6 +392,54 @@ function validateObjection(obj, index) {
369
392
  return errors;
370
393
  }
371
394
 
395
+ function validateDelegation(del, index) {
396
+ const errors = [];
397
+ const prefix = `delegations[${index}]`;
398
+
399
+ if (del === null || typeof del !== 'object' || Array.isArray(del)) {
400
+ return [`${prefix} must be an object.`];
401
+ }
402
+ if (typeof del.id !== 'string' || !/^del-\d{3}$/.test(del.id)) {
403
+ errors.push(`${prefix}.id must match pattern del-NNN.`);
404
+ }
405
+ if (typeof del.to_role !== 'string' || !/^[a-z0-9_-]+$/.test(del.to_role)) {
406
+ errors.push(`${prefix}.to_role must match pattern ^[a-z0-9_-]+$.`);
407
+ }
408
+ if (typeof del.charter !== 'string' || !del.charter.trim()) {
409
+ errors.push(`${prefix}.charter must be a non-empty string.`);
410
+ }
411
+ if (!Array.isArray(del.acceptance_contract) || del.acceptance_contract.length === 0) {
412
+ errors.push(`${prefix}.acceptance_contract must be a non-empty array.`);
413
+ } else {
414
+ for (let i = 0; i < del.acceptance_contract.length; i++) {
415
+ if (typeof del.acceptance_contract[i] !== 'string' || !del.acceptance_contract[i].trim()) {
416
+ errors.push(`${prefix}.acceptance_contract[${i}] must be a non-empty string.`);
417
+ }
418
+ }
419
+ }
420
+ if (del.required_decision_ids !== undefined) {
421
+ if (!Array.isArray(del.required_decision_ids) || del.required_decision_ids.length === 0) {
422
+ errors.push(`${prefix}.required_decision_ids must be a non-empty array when provided.`);
423
+ } else {
424
+ const seen = new Set();
425
+ for (let i = 0; i < del.required_decision_ids.length; i++) {
426
+ const id = del.required_decision_ids[i];
427
+ if (typeof id !== 'string' || !/^DEC-\d+$/.test(id)) {
428
+ errors.push(`${prefix}.required_decision_ids[${i}] must match pattern DEC-NNN.`);
429
+ continue;
430
+ }
431
+ if (seen.has(id)) {
432
+ errors.push(`${prefix}.required_decision_ids contains duplicate "${id}".`);
433
+ continue;
434
+ }
435
+ seen.add(id);
436
+ }
437
+ }
438
+ }
439
+
440
+ return errors;
441
+ }
442
+
372
443
  // ── Stage B: Assignment Validation ───────────────────────────────────────────
373
444
 
374
445
  function validateAssignment(tr, state) {
@@ -550,6 +621,7 @@ function validateProtocol(tr, state, config) {
550
621
 
551
622
  const role = config.roles?.[tr.role];
552
623
  const writeAuthority = role?.write_authority;
624
+ const activeTurn = getActiveTurn(state) || state?.current_turn || null;
553
625
 
554
626
  // Challenge requirement: review_only roles MUST raise at least one objection
555
627
  if (config.rules?.challenge_required !== false) {
@@ -615,7 +687,6 @@ function validateProtocol(tr, state, config) {
615
687
  }
616
688
 
617
689
  // No recursive delegation: if this turn is a delegation review, it cannot delegate further
618
- const activeTurn = state?.active_turns ? Object.values(state.active_turns)[0] : null;
619
690
  if (activeTurn?.delegation_context) {
620
691
  errors.push('Delegation review turns cannot contain further delegations.');
621
692
  }
@@ -650,6 +721,26 @@ function validateProtocol(tr, state, config) {
650
721
  }
651
722
  }
652
723
 
724
+ if (activeTurn?.delegation_review) {
725
+ const unmetDecisionContracts = (activeTurn.delegation_review.results || [])
726
+ .filter((result) => Array.isArray(result?.missing_decision_ids) && result.missing_decision_ids.length > 0);
727
+ if (unmetDecisionContracts.length > 0) {
728
+ const detail = unmetDecisionContracts
729
+ .map((result) => `${result.delegation_id}: ${result.missing_decision_ids.join(', ')}`)
730
+ .join('; ');
731
+ if (tr.phase_transition_request) {
732
+ errors.push(
733
+ `Delegation review cannot request phase transition while required child decisions are missing: ${detail}.`
734
+ );
735
+ }
736
+ if (tr.run_completion_request) {
737
+ errors.push(
738
+ `Delegation review cannot request run completion while required child decisions are missing: ${detail}.`
739
+ );
740
+ }
741
+ }
742
+ }
743
+
653
744
  return { errors, warnings };
654
745
  }
655
746