agentxchain 2.29.0 → 2.30.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.
package/package.json
CHANGED
|
@@ -10,6 +10,7 @@ const SECTION_DEFINITIONS = [
|
|
|
10
10
|
{ id: 'last_turn_verification', header: null, required: false },
|
|
11
11
|
{ id: 'blockers', header: 'Blockers', required: true },
|
|
12
12
|
{ id: 'escalation', header: 'Escalation', required: true },
|
|
13
|
+
{ id: 'workflow_artifacts', header: 'Workflow Artifacts', required: false },
|
|
13
14
|
{ id: 'gate_required_files', header: 'Gate Required Files', required: false },
|
|
14
15
|
{ id: 'phase_gate_status', header: 'Phase Gate Status', required: false },
|
|
15
16
|
];
|
|
@@ -88,6 +89,7 @@ export function renderContextSections(sections) {
|
|
|
88
89
|
|
|
89
90
|
appendTopLevelSection(lines, 'Blockers', [sectionMap.get('blockers')?.content]);
|
|
90
91
|
appendTopLevelSection(lines, 'Escalation', [sectionMap.get('escalation')?.content]);
|
|
92
|
+
appendTopLevelSection(lines, 'Workflow Artifacts', [sectionMap.get('workflow_artifacts')?.content]);
|
|
91
93
|
appendTopLevelSection(lines, 'Gate Required Files', [sectionMap.get('gate_required_files')?.content]);
|
|
92
94
|
appendTopLevelSection(lines, 'Phase Gate Status', [sectionMap.get('phase_gate_status')?.content]);
|
|
93
95
|
|
|
@@ -248,6 +248,31 @@ function renderPrompt(role, roleId, turn, state, config, root) {
|
|
|
248
248
|
lines.push('');
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
+
const workflowResponsibilities = getWorkflowPromptResponsibilities(config, phase, roleId, root);
|
|
252
|
+
if (workflowResponsibilities.length > 0) {
|
|
253
|
+
const isReviewOnlyOwner = role.write_authority === 'review_only';
|
|
254
|
+
lines.push('## Workflow-Kit Responsibilities');
|
|
255
|
+
lines.push('');
|
|
256
|
+
if (isReviewOnlyOwner) {
|
|
257
|
+
lines.push(`You are accountable for reviewing and attesting to these workflow-kit artifacts in phase \`${phase}\`:`);
|
|
258
|
+
} else {
|
|
259
|
+
lines.push(`You are accountable for producing these workflow-kit artifacts in phase \`${phase}\`:`);
|
|
260
|
+
}
|
|
261
|
+
lines.push('');
|
|
262
|
+
for (const artifact of workflowResponsibilities) {
|
|
263
|
+
const requiredLabel = artifact.required ? 'required' : 'optional';
|
|
264
|
+
const semanticsLabel = artifact.semantics ? `\`${artifact.semantics}\`` : '—';
|
|
265
|
+
lines.push(`- \`${artifact.path}\` — ${requiredLabel}; semantics: ${semanticsLabel}; status: ${artifact.status}`);
|
|
266
|
+
}
|
|
267
|
+
lines.push('');
|
|
268
|
+
if (isReviewOnlyOwner) {
|
|
269
|
+
lines.push('You cannot write repo files directly. Your accountability means you must confirm these artifacts exist, meet quality standards, and satisfy their semantic requirements. If a required artifact you own is missing, escalate to the producing role — do not request phase transition.');
|
|
270
|
+
} else {
|
|
271
|
+
lines.push('Do not request phase transition or run completion while a required workflow-kit artifact you own is missing or incomplete.');
|
|
272
|
+
}
|
|
273
|
+
lines.push('');
|
|
274
|
+
}
|
|
275
|
+
|
|
251
276
|
// Gate requirements
|
|
252
277
|
if (gateConfig) {
|
|
253
278
|
lines.push('## Phase Exit Gate');
|
|
@@ -421,6 +446,47 @@ function renderPrompt(role, roleId, turn, state, config, root) {
|
|
|
421
446
|
};
|
|
422
447
|
}
|
|
423
448
|
|
|
449
|
+
function getWorkflowPromptResponsibilities(config, phase, roleId, root) {
|
|
450
|
+
const artifacts = config?.workflow_kit?.phases?.[phase]?.artifacts;
|
|
451
|
+
if (!Array.isArray(artifacts) || artifacts.length === 0) {
|
|
452
|
+
return [];
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const entryRole = config?.routing?.[phase]?.entry_role || null;
|
|
456
|
+
const responsibilities = [];
|
|
457
|
+
|
|
458
|
+
for (const artifact of artifacts) {
|
|
459
|
+
if (!artifact?.path) {
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const owner = typeof artifact.owned_by === 'string' && artifact.owned_by
|
|
464
|
+
? artifact.owned_by
|
|
465
|
+
: null;
|
|
466
|
+
const responsibleRole = owner || entryRole;
|
|
467
|
+
if (responsibleRole !== roleId) {
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const absPath = join(root, artifact.path);
|
|
472
|
+
let exists = false;
|
|
473
|
+
try {
|
|
474
|
+
exists = existsSync(absPath);
|
|
475
|
+
} catch {
|
|
476
|
+
exists = false;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
responsibilities.push({
|
|
480
|
+
path: artifact.path,
|
|
481
|
+
required: artifact.required !== false,
|
|
482
|
+
semantics: artifact.semantics || null,
|
|
483
|
+
status: exists ? 'exists' : 'MISSING',
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return responsibilities;
|
|
488
|
+
}
|
|
489
|
+
|
|
424
490
|
// ── Context Rendering ───────────────────────────────────────────────────────
|
|
425
491
|
|
|
426
492
|
function renderContext(state, config, root, turn, role) {
|
|
@@ -621,8 +687,59 @@ function renderContext(state, config, root, turn, role) {
|
|
|
621
687
|
lines.push('');
|
|
622
688
|
}
|
|
623
689
|
|
|
624
|
-
//
|
|
690
|
+
// Workflow-kit artifacts for the current phase
|
|
625
691
|
const phase = state.phase;
|
|
692
|
+
const wkArtifacts = config?.workflow_kit?.phases?.[phase]?.artifacts;
|
|
693
|
+
if (Array.isArray(wkArtifacts) && wkArtifacts.length > 0) {
|
|
694
|
+
lines.push('## Workflow Artifacts');
|
|
695
|
+
lines.push('');
|
|
696
|
+
lines.push(`Current phase **${phase}** declares the following artifacts:`);
|
|
697
|
+
lines.push('');
|
|
698
|
+
lines.push('| Artifact | Required | Semantics | Owner | Status |');
|
|
699
|
+
lines.push('|----------|----------|-----------|-------|--------|');
|
|
700
|
+
const isReviewRole = role?.write_authority === 'review_only';
|
|
701
|
+
const reviewPreviews = [];
|
|
702
|
+
for (const art of wkArtifacts) {
|
|
703
|
+
if (!art?.path) continue;
|
|
704
|
+
const absPath = join(root, art.path);
|
|
705
|
+
let exists = false;
|
|
706
|
+
try { exists = existsSync(absPath); } catch { /* treat as missing */ }
|
|
707
|
+
const req = art.required !== false ? 'yes' : 'no';
|
|
708
|
+
const owner = art.owned_by || '—';
|
|
709
|
+
const status = exists ? 'exists' : 'MISSING';
|
|
710
|
+
const semCol = art.semantics ? `\`${art.semantics}\`` : '—';
|
|
711
|
+
lines.push(`| \`${art.path}\` | ${req} | ${semCol} | ${owner} | ${status} |`);
|
|
712
|
+
if (isReviewRole && exists) {
|
|
713
|
+
reviewPreviews.push(art);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
lines.push('');
|
|
717
|
+
if (reviewPreviews.length > 0) {
|
|
718
|
+
for (const art of reviewPreviews) {
|
|
719
|
+
const absPath = join(root, art.path);
|
|
720
|
+
const preview = buildGateFilePreview(absPath);
|
|
721
|
+
if (preview) {
|
|
722
|
+
lines.push(`### \`${art.path}\``);
|
|
723
|
+
lines.push('');
|
|
724
|
+
const semantic = extractGateFileSemantic(art.path, preview.raw);
|
|
725
|
+
if (semantic) {
|
|
726
|
+
lines.push(`**Semantic: ${semantic}**`);
|
|
727
|
+
lines.push('');
|
|
728
|
+
}
|
|
729
|
+
lines.push('```');
|
|
730
|
+
lines.push(preview.content);
|
|
731
|
+
lines.push('```');
|
|
732
|
+
if (preview.truncated) {
|
|
733
|
+
lines.push('');
|
|
734
|
+
lines.push(`_Preview truncated after ${GATE_FILE_PREVIEW_MAX_LINES} lines._`);
|
|
735
|
+
}
|
|
736
|
+
lines.push('');
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// Phase gate requirements
|
|
626
743
|
const routing = config.routing?.[phase];
|
|
627
744
|
const exitGate = routing?.exit_gate;
|
|
628
745
|
const gateConfig = exitGate ? config.gates?.[exitGate] : null;
|
|
@@ -628,6 +628,25 @@ export function validateWorkflowKitConfig(wk, routing, roles) {
|
|
|
628
628
|
errors.push(`${prefix} owned_by "${artifact.owned_by}" is not a valid role ID (must be lowercase alphanumeric with hyphens/underscores)`);
|
|
629
629
|
} else if (roles && typeof roles === 'object' && !roles[artifact.owned_by]) {
|
|
630
630
|
errors.push(`${prefix} owned_by "${artifact.owned_by}" does not reference a defined role`);
|
|
631
|
+
} else if (
|
|
632
|
+
artifact.required !== false &&
|
|
633
|
+
roles && typeof roles === 'object' &&
|
|
634
|
+
roles[artifact.owned_by]?.write_authority === 'review_only'
|
|
635
|
+
) {
|
|
636
|
+
// Check if any authoritative/proposed role exists in this phase's routing
|
|
637
|
+
const phaseRouting = routing?.[phase];
|
|
638
|
+
const phaseRoles = new Set([
|
|
639
|
+
...(phaseRouting?.allowed_next_roles || []),
|
|
640
|
+
...(phaseRouting?.entry_role ? [phaseRouting.entry_role] : []),
|
|
641
|
+
]);
|
|
642
|
+
const hasWriter = [...phaseRoles].some(rid =>
|
|
643
|
+
roles[rid]?.write_authority === 'authoritative' || roles[rid]?.write_authority === 'proposed',
|
|
644
|
+
);
|
|
645
|
+
if (!hasWriter) {
|
|
646
|
+
warnings.push(
|
|
647
|
+
`${prefix} owned_by "${artifact.owned_by}" is a review_only role in phase "${phase}" with no authoritative or proposed role — nobody can write this required artifact`,
|
|
648
|
+
);
|
|
649
|
+
}
|
|
631
650
|
}
|
|
632
651
|
}
|
|
633
652
|
}
|