@pellux/goodvibes-sdk 0.33.24 → 0.33.26
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/dist/contracts/artifacts/operator-contract.json +1 -1
- package/dist/events/agents.d.ts +3 -3
- package/dist/events/agents.d.ts.map +1 -1
- package/dist/events/orchestration.d.ts +1 -1
- package/dist/events/orchestration.d.ts.map +1 -1
- package/dist/events/workflows.d.ts +1 -1
- package/dist/events/workflows.d.ts.map +1 -1
- package/dist/platform/agents/archetypes.d.ts.map +1 -1
- package/dist/platform/agents/archetypes.js +14 -0
- package/dist/platform/agents/communication-policy.d.ts.map +1 -1
- package/dist/platform/agents/communication-policy.js +4 -0
- package/dist/platform/agents/orchestrator-prompts.d.ts.map +1 -1
- package/dist/platform/agents/orchestrator-prompts.js +2 -0
- package/dist/platform/agents/worktree.d.ts +3 -0
- package/dist/platform/agents/worktree.d.ts.map +1 -1
- package/dist/platform/agents/worktree.js +64 -2
- package/dist/platform/agents/wrfc-controller.d.ts +16 -1
- package/dist/platform/agents/wrfc-controller.d.ts.map +1 -1
- package/dist/platform/agents/wrfc-controller.js +484 -16
- package/dist/platform/agents/wrfc-runtime-events.d.ts +1 -1
- package/dist/platform/agents/wrfc-runtime-events.d.ts.map +1 -1
- package/dist/platform/agents/wrfc-types.d.ts +29 -4
- package/dist/platform/agents/wrfc-types.d.ts.map +1 -1
- package/dist/platform/agents/wrfc-workmap.d.ts +2 -1
- package/dist/platform/agents/wrfc-workmap.d.ts.map +1 -1
- package/dist/platform/git/service.d.ts +4 -0
- package/dist/platform/git/service.d.ts.map +1 -1
- package/dist/platform/git/service.js +33 -0
- package/dist/platform/runtime/emitters/agents.d.ts +3 -3
- package/dist/platform/runtime/emitters/agents.d.ts.map +1 -1
- package/dist/platform/runtime/emitters/orchestration.d.ts +1 -1
- package/dist/platform/runtime/emitters/orchestration.d.ts.map +1 -1
- package/dist/platform/runtime/store/domains/agents.d.ts +2 -2
- package/dist/platform/runtime/store/domains/agents.d.ts.map +1 -1
- package/dist/platform/runtime/store/domains/orchestration.d.ts +1 -1
- package/dist/platform/runtime/store/domains/orchestration.d.ts.map +1 -1
- package/dist/platform/tools/agent/index.d.ts.map +1 -1
- package/dist/platform/tools/agent/index.js +2 -0
- package/dist/platform/tools/agent/manager.d.ts +2 -0
- package/dist/platform/tools/agent/manager.d.ts.map +1 -1
- package/dist/platform/tools/agent/manager.js +22 -3
- package/dist/platform/tools/agent/schema.d.ts +2 -0
- package/dist/platform/tools/agent/schema.d.ts.map +1 -1
- package/dist/platform/tools/agent/schema.js +4 -4
- package/dist/platform/tools/agent/wrfc-batch-policy.d.ts +1 -0
- package/dist/platform/tools/agent/wrfc-batch-policy.d.ts.map +1 -1
- package/dist/platform/tools/agent/wrfc-batch-policy.js +95 -1
- package/dist/platform/version.js +1 -1
- package/package.json +9 -9
|
@@ -16,7 +16,8 @@ import { runWrfcGateChecks } from './wrfc-gate-runtime.js';
|
|
|
16
16
|
export { extractScoreFromText, extractPassedFromText, extractIssuesFromText } from './wrfc-reporting.js';
|
|
17
17
|
const VALID_TRANSITIONS = {
|
|
18
18
|
pending: ['engineering'],
|
|
19
|
-
engineering: ['reviewing', 'failed'],
|
|
19
|
+
engineering: ['integrating', 'reviewing', 'failed'],
|
|
20
|
+
integrating: ['reviewing', 'failed'],
|
|
20
21
|
reviewing: ['fixing', 'awaiting_gates', 'failed'],
|
|
21
22
|
fixing: ['reviewing', 'failed'],
|
|
22
23
|
awaiting_gates: ['gating', 'failed'],
|
|
@@ -149,10 +150,13 @@ export class WrfcController {
|
|
|
149
150
|
emitWrfcStateChanged(this.runtimeBus, this.sessionId, chain.id, from, to);
|
|
150
151
|
logger.debug('WrfcController.transition', { chainId: chain.id, from, to });
|
|
151
152
|
}
|
|
152
|
-
applyWrfcAgentMetadata(chain, record, role) {
|
|
153
|
+
applyWrfcAgentMetadata(chain, record, role, subtaskId) {
|
|
153
154
|
record.wrfcId = chain.id;
|
|
154
155
|
record.wrfcRole = role;
|
|
155
156
|
record.wrfcPhaseOrder = this.wrfcPhaseOrder(role);
|
|
157
|
+
if (subtaskId) {
|
|
158
|
+
record.wrfcSubtaskId = subtaskId;
|
|
159
|
+
}
|
|
156
160
|
if (role === 'owner') {
|
|
157
161
|
record.progress = this.ownerProgress(chain);
|
|
158
162
|
}
|
|
@@ -207,20 +211,28 @@ export class WrfcController {
|
|
|
207
211
|
});
|
|
208
212
|
}
|
|
209
213
|
ownerProgress(chain) {
|
|
214
|
+
if (chain.subtasks && chain.subtasks.length > 0) {
|
|
215
|
+
const passed = chain.subtasks.filter((subtask) => subtask.state === 'passed').length;
|
|
216
|
+
return `WRFC owner supervising compound chain (${chain.state}, ${passed}/${chain.subtasks.length} deliverables passed)`;
|
|
217
|
+
}
|
|
210
218
|
return `WRFC owner supervising child agents (${chain.state})`;
|
|
211
219
|
}
|
|
212
220
|
wrfcPhaseOrder(role) {
|
|
213
221
|
switch (role) {
|
|
214
222
|
case 'owner':
|
|
215
223
|
return 0;
|
|
224
|
+
case 'orchestrator':
|
|
225
|
+
return 0;
|
|
216
226
|
case 'engineer':
|
|
217
227
|
return 1;
|
|
218
228
|
case 'reviewer':
|
|
219
229
|
return 2;
|
|
220
230
|
case 'fixer':
|
|
221
231
|
return 3;
|
|
222
|
-
case '
|
|
232
|
+
case 'integrator':
|
|
223
233
|
return 4;
|
|
234
|
+
case 'verifier':
|
|
235
|
+
return 5;
|
|
224
236
|
}
|
|
225
237
|
}
|
|
226
238
|
setupListeners() {
|
|
@@ -264,6 +276,23 @@ export class WrfcController {
|
|
|
264
276
|
state: chain.state,
|
|
265
277
|
outputLength: rawOutput.length,
|
|
266
278
|
});
|
|
279
|
+
const subtask = this.findSubtaskByAgentId(chain, agentId);
|
|
280
|
+
if (subtask) {
|
|
281
|
+
await this.onCompoundSubtaskAgentComplete(chain, subtask, agentId, rawOutput, record ?? undefined);
|
|
282
|
+
if (this.planManager) {
|
|
283
|
+
completePlanItemsForAgent(agentId, this.planManager);
|
|
284
|
+
}
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (agentId === chain.integratorAgentId) {
|
|
288
|
+
const report = parseEngineerCompletionReport(rawOutput, record?.template);
|
|
289
|
+
this.setWrfcWorkPlanTaskStatus(chain, agentId, 'done');
|
|
290
|
+
this.handleIntegratorCompletion(chain, agentId, report);
|
|
291
|
+
if (this.planManager) {
|
|
292
|
+
completePlanItemsForAgent(agentId, this.planManager);
|
|
293
|
+
}
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
267
296
|
if (chain.state === 'pending') {
|
|
268
297
|
chain.bufferedCompletion = { agentId, fullOutput: rawOutput };
|
|
269
298
|
logger.debug('WrfcController.onAgentComplete: chain pending, buffering completion', {
|
|
@@ -541,6 +570,47 @@ export class WrfcController {
|
|
|
541
570
|
constraintFailure: unsatisfiedConstraintIds.length > 0,
|
|
542
571
|
};
|
|
543
572
|
}
|
|
573
|
+
evaluateSubtaskConstraints(subtask, review) {
|
|
574
|
+
if (subtask.constraints.length === 0) {
|
|
575
|
+
return {
|
|
576
|
+
constraintsSatisfied: 0,
|
|
577
|
+
constraintsTotal: 0,
|
|
578
|
+
unsatisfiedConstraintIds: [],
|
|
579
|
+
ignoredConstraintFindingIds: [],
|
|
580
|
+
constraintFailure: false,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
const expectedIds = new Set(subtask.constraints.map((constraint) => constraint.id));
|
|
584
|
+
const findingMap = new Map();
|
|
585
|
+
const ignoredConstraintFindingIds = [];
|
|
586
|
+
for (const finding of review.constraintFindings ?? []) {
|
|
587
|
+
if (!expectedIds.has(finding.constraintId)) {
|
|
588
|
+
ignoredConstraintFindingIds.push(finding.constraintId);
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
if (!findingMap.has(finding.constraintId)) {
|
|
592
|
+
findingMap.set(finding.constraintId, finding);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
let constraintsSatisfied = 0;
|
|
596
|
+
const unsatisfiedConstraintIds = [];
|
|
597
|
+
for (const constraint of subtask.constraints) {
|
|
598
|
+
const finding = findingMap.get(constraint.id);
|
|
599
|
+
if (finding?.satisfied === true) {
|
|
600
|
+
constraintsSatisfied += 1;
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
unsatisfiedConstraintIds.push(constraint.id);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
return {
|
|
607
|
+
constraintsSatisfied,
|
|
608
|
+
constraintsTotal: subtask.constraints.length,
|
|
609
|
+
unsatisfiedConstraintIds,
|
|
610
|
+
ignoredConstraintFindingIds,
|
|
611
|
+
constraintFailure: unsatisfiedConstraintIds.length > 0,
|
|
612
|
+
};
|
|
613
|
+
}
|
|
544
614
|
async processGateResults(chain, results) {
|
|
545
615
|
if (!chain.currentNodeId?.includes(':gate:')) {
|
|
546
616
|
chain.currentNodeId = startWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, `gate:${chain.reviewCycles}:${chain.fixAttempts}`, 'verifier', 'Quality gates');
|
|
@@ -635,6 +705,7 @@ export class WrfcController {
|
|
|
635
705
|
const allChains = Array.from(this.chains.values()).filter((chain) => chain.state !== 'passed' && chain.state !== 'failed');
|
|
636
706
|
const activeWorkChains = allChains.filter((chain) => (chain.state === 'pending'
|
|
637
707
|
|| chain.state === 'engineering'
|
|
708
|
+
|| chain.state === 'integrating'
|
|
638
709
|
|| chain.state === 'reviewing'
|
|
639
710
|
|| chain.state === 'fixing'));
|
|
640
711
|
if (activeWorkChains.length > 0) {
|
|
@@ -662,11 +733,9 @@ export class WrfcController {
|
|
|
662
733
|
}
|
|
663
734
|
async autoCommit(chain) {
|
|
664
735
|
this.transition(chain, 'committing');
|
|
665
|
-
const
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
if (!agentId) {
|
|
669
|
-
this.failChain(chain, 'autoCommit: no agent ID found on chain');
|
|
736
|
+
const commitCandidateIds = this.autoCommitCandidateAgentIds(chain);
|
|
737
|
+
if (commitCandidateIds.length === 0) {
|
|
738
|
+
this.failChain(chain, 'autoCommit: no write-capable WRFC agent found on chain');
|
|
670
739
|
return;
|
|
671
740
|
}
|
|
672
741
|
if (!existsSync(join(this.projectRoot, '.git'))) {
|
|
@@ -675,11 +744,29 @@ export class WrfcController {
|
|
|
675
744
|
return;
|
|
676
745
|
}
|
|
677
746
|
const worktree = this.createWorktree();
|
|
747
|
+
let completed = false;
|
|
678
748
|
try {
|
|
679
|
-
const
|
|
680
|
-
|
|
749
|
+
const commitMessage = this.autoCommitMessage(chain);
|
|
750
|
+
const directCommitHash = worktree.commitWorkingTree
|
|
751
|
+
? await worktree.commitWorkingTree(commitMessage)
|
|
752
|
+
: null;
|
|
753
|
+
let mergedCount = 0;
|
|
754
|
+
for (const agentId of commitCandidateIds) {
|
|
755
|
+
if (await worktree.merge(agentId)) {
|
|
756
|
+
mergedCount += 1;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
const headHash = mergedCount > 0 && worktree.currentHead ? await worktree.currentHead() : directCommitHash;
|
|
760
|
+
emitWrfcAutoCommitted(this.runtimeBus, this.sessionId, chain.id, headHash ?? undefined);
|
|
681
761
|
this.completeChainAsPassed(chain);
|
|
682
|
-
|
|
762
|
+
completed = true;
|
|
763
|
+
logger.debug('WrfcController.autoCommit: success', {
|
|
764
|
+
chainId: chain.id,
|
|
765
|
+
commitCandidateIds,
|
|
766
|
+
directCommitHash,
|
|
767
|
+
mergedCount,
|
|
768
|
+
headHash,
|
|
769
|
+
});
|
|
683
770
|
}
|
|
684
771
|
catch (error) {
|
|
685
772
|
const reason = summarizeError(error);
|
|
@@ -687,7 +774,10 @@ export class WrfcController {
|
|
|
687
774
|
this.failChain(chain, `autoCommit failed: ${reason}`);
|
|
688
775
|
}
|
|
689
776
|
finally {
|
|
690
|
-
|
|
777
|
+
const cleanupIds = completed
|
|
778
|
+
? chain.allAgentIds
|
|
779
|
+
: chain.allAgentIds.filter((id) => !commitCandidateIds.includes(id));
|
|
780
|
+
for (const id of cleanupIds) {
|
|
691
781
|
worktree.cleanup(id).catch((error) => {
|
|
692
782
|
logger.warn('WrfcController.autoCommit: cleanup failed', {
|
|
693
783
|
agentId: id,
|
|
@@ -697,12 +787,49 @@ export class WrfcController {
|
|
|
697
787
|
}
|
|
698
788
|
}
|
|
699
789
|
}
|
|
790
|
+
autoCommitCandidateAgentIds(chain) {
|
|
791
|
+
const candidates = [];
|
|
792
|
+
const add = (agentId) => {
|
|
793
|
+
if (agentId && !candidates.includes(agentId))
|
|
794
|
+
candidates.push(agentId);
|
|
795
|
+
};
|
|
796
|
+
if (chain.subtasks && chain.subtasks.length > 0) {
|
|
797
|
+
for (const subtask of chain.subtasks) {
|
|
798
|
+
add(subtask.fixerAgentId ?? subtask.engineerAgentId);
|
|
799
|
+
}
|
|
800
|
+
add(chain.integratorAgentId);
|
|
801
|
+
return candidates;
|
|
802
|
+
}
|
|
803
|
+
add(chain.fixerAgentId ?? chain.engineerAgentId);
|
|
804
|
+
add(chain.integratorAgentId);
|
|
805
|
+
if (candidates.length > 0) {
|
|
806
|
+
return candidates;
|
|
807
|
+
}
|
|
808
|
+
const writeRoles = new Set(['engineer', 'fixer', 'integrator']);
|
|
809
|
+
for (const agentId of chain.allAgentIds) {
|
|
810
|
+
const recordRole = this.agentManager.getStatus(agentId)?.wrfcRole;
|
|
811
|
+
const role = recordRole ?? this.workPlanRoleForAgent(chain, agentId);
|
|
812
|
+
if (role && writeRoles.has(role))
|
|
813
|
+
add(agentId);
|
|
814
|
+
}
|
|
815
|
+
return candidates;
|
|
816
|
+
}
|
|
817
|
+
autoCommitMessage(chain) {
|
|
818
|
+
const firstLine = chain.task.trim().replace(/\s+/g, ' ').slice(0, 72) || chain.id;
|
|
819
|
+
return `WRFC: ${firstLine}`;
|
|
820
|
+
}
|
|
700
821
|
failChain(chain, reason) {
|
|
701
822
|
if (chain.state === 'pending') {
|
|
702
823
|
this.chainQueue = this.chainQueue.filter((queued) => queued.record.id !== chain.ownerAgentId);
|
|
703
824
|
}
|
|
704
825
|
const wasActive = chain.state !== 'passed' && chain.state !== 'failed' && chain.state !== 'pending';
|
|
705
826
|
this.failCurrentNode(chain, reason);
|
|
827
|
+
for (const subtask of chain.subtasks ?? []) {
|
|
828
|
+
if (subtask.currentNodeId) {
|
|
829
|
+
failWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, subtask.currentNodeId, reason);
|
|
830
|
+
subtask.currentNodeId = undefined;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
706
833
|
try {
|
|
707
834
|
this.transition(chain, 'failed');
|
|
708
835
|
}
|
|
@@ -854,7 +981,26 @@ export class WrfcController {
|
|
|
854
981
|
failWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, chain.currentNodeId, error);
|
|
855
982
|
chain.currentNodeId = undefined;
|
|
856
983
|
}
|
|
984
|
+
completeSubtaskNode(chain, subtask, summary) {
|
|
985
|
+
if (!subtask.currentNodeId)
|
|
986
|
+
return;
|
|
987
|
+
completeWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, subtask.currentNodeId, summary);
|
|
988
|
+
subtask.currentNodeId = undefined;
|
|
989
|
+
}
|
|
857
990
|
createBaseChain(ownerRecord) {
|
|
991
|
+
const subtasks = (ownerRecord.wrfcSubtasks ?? [])
|
|
992
|
+
.filter((task) => typeof task.task === 'string' && task.task.trim().length > 0)
|
|
993
|
+
.map((task, index) => ({
|
|
994
|
+
id: `deliverable-${index + 1}`,
|
|
995
|
+
title: task.task.trim().slice(0, 80),
|
|
996
|
+
task: task.task.trim(),
|
|
997
|
+
state: 'pending',
|
|
998
|
+
fixAttempts: 0,
|
|
999
|
+
reviewCycles: 0,
|
|
1000
|
+
reviewScores: [],
|
|
1001
|
+
constraints: [],
|
|
1002
|
+
constraintsEnumerated: false,
|
|
1003
|
+
}));
|
|
858
1004
|
const chain = {
|
|
859
1005
|
id: this.generateWrfcId(),
|
|
860
1006
|
state: 'pending',
|
|
@@ -869,6 +1015,7 @@ export class WrfcController {
|
|
|
869
1015
|
constraints: [],
|
|
870
1016
|
constraintsEnumerated: false,
|
|
871
1017
|
createdAt: Date.now(),
|
|
1018
|
+
...(subtasks.length > 1 ? { subtasks } : {}),
|
|
872
1019
|
};
|
|
873
1020
|
this.chains.set(chain.id, chain);
|
|
874
1021
|
emitWrfcGraphCreated(this.runtimeBus, this.sessionId, chain.id, `WRFC: ${ownerRecord.task}`);
|
|
@@ -886,6 +1033,10 @@ export class WrfcController {
|
|
|
886
1033
|
return chain;
|
|
887
1034
|
}
|
|
888
1035
|
startEngineeringChain(chain, emitCreated) {
|
|
1036
|
+
if (chain.subtasks && chain.subtasks.length > 1) {
|
|
1037
|
+
this.startCompoundEngineeringChain(chain, emitCreated);
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
889
1040
|
this.activeChainCount += 1;
|
|
890
1041
|
this.transition(chain, 'engineering');
|
|
891
1042
|
this.setWrfcWorkPlanTaskStatus(chain, chain.ownerAgentId, 'in_progress');
|
|
@@ -909,6 +1060,34 @@ export class WrfcController {
|
|
|
909
1060
|
});
|
|
910
1061
|
this.upsertWrfcWorkPlanTask(chain, 'engineer', engineerRecord, 'in_progress');
|
|
911
1062
|
}
|
|
1063
|
+
startCompoundEngineeringChain(chain, emitCreated) {
|
|
1064
|
+
this.activeChainCount += 1;
|
|
1065
|
+
this.transition(chain, 'engineering');
|
|
1066
|
+
this.setWrfcWorkPlanTaskStatus(chain, chain.ownerAgentId, 'in_progress');
|
|
1067
|
+
if (emitCreated) {
|
|
1068
|
+
emitWrfcChainCreated(this.runtimeBus, this.sessionId, chain.id, chain.task);
|
|
1069
|
+
}
|
|
1070
|
+
this.appendOwnerDecision(chain, 'compound_started', `Compound WRFC owner supervising ${chain.subtasks?.length ?? 0} deliverables under one chain`, { agentId: chain.ownerAgentId });
|
|
1071
|
+
for (const subtask of chain.subtasks ?? []) {
|
|
1072
|
+
subtask.state = 'engineering';
|
|
1073
|
+
const engineerRecord = this.spawnWrfcAgent(chain, 'engineer', 'engineer', this.buildSubtaskEngineerTask(chain, subtask), true, subtask.id);
|
|
1074
|
+
this.applyWrfcAgentMetadata(chain, engineerRecord, 'engineer', subtask.id);
|
|
1075
|
+
subtask.engineerAgentId = engineerRecord.id;
|
|
1076
|
+
chain.allAgentIds.push(engineerRecord.id);
|
|
1077
|
+
this.messageBus.registerAgent({
|
|
1078
|
+
agentId: engineerRecord.id,
|
|
1079
|
+
role: 'engineer',
|
|
1080
|
+
wrfcId: chain.id,
|
|
1081
|
+
});
|
|
1082
|
+
subtask.currentNodeId = startWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, `subtask:${subtask.id}:engineer:0`, 'engineer', `Engineer ${subtask.title}`, engineerRecord.id);
|
|
1083
|
+
this.appendOwnerDecision(chain, 'spawn_engineer', this.withRouteReason(`Start compound WRFC engineer child for ${subtask.id}`, engineerRecord), {
|
|
1084
|
+
agentId: engineerRecord.id,
|
|
1085
|
+
role: 'engineer',
|
|
1086
|
+
record: engineerRecord,
|
|
1087
|
+
});
|
|
1088
|
+
this.upsertWrfcWorkPlanTask(chain, 'engineer', engineerRecord, 'in_progress', subtask.id);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
912
1091
|
handleEngineerCompletion(chain, agentId, report) {
|
|
913
1092
|
let reportForReview = report;
|
|
914
1093
|
this.completeCurrentNode(chain, report.summary);
|
|
@@ -981,6 +1160,278 @@ export class WrfcController {
|
|
|
981
1160
|
}
|
|
982
1161
|
this.startReview(chain, reportForReview);
|
|
983
1162
|
}
|
|
1163
|
+
buildSubtaskEngineerTask(chain, subtask) {
|
|
1164
|
+
return [
|
|
1165
|
+
`Compound WRFC engineer task`,
|
|
1166
|
+
`Parent WRFC ask (authoritative whole):`,
|
|
1167
|
+
chain.task,
|
|
1168
|
+
``,
|
|
1169
|
+
`Sub-deliverable ${subtask.id}:`,
|
|
1170
|
+
subtask.task,
|
|
1171
|
+
``,
|
|
1172
|
+
`Instructions:`,
|
|
1173
|
+
`1. Implement only this sub-deliverable, but keep the parent ask in mind for compatibility.`,
|
|
1174
|
+
`2. Do not review or verify sibling deliverables. The WRFC owner controls review/fix phases after your output exists.`,
|
|
1175
|
+
`3. Return a structured EngineerReport JSON block.`,
|
|
1176
|
+
].join('\n');
|
|
1177
|
+
}
|
|
1178
|
+
buildCompoundIntegrationTask(chain) {
|
|
1179
|
+
const subtaskSummaries = (chain.subtasks ?? []).map((subtask) => [
|
|
1180
|
+
`## ${subtask.id}: ${subtask.title}`,
|
|
1181
|
+
`Task: ${subtask.task}`,
|
|
1182
|
+
`Review cycles: ${subtask.reviewCycles}`,
|
|
1183
|
+
`Last score: ${subtask.reviewScores.at(-1) ?? 'n/a'}`,
|
|
1184
|
+
`Engineer summary: ${subtask.engineerReport?.summary ?? '(no summary)'}`,
|
|
1185
|
+
`Reviewer summary: ${subtask.reviewerReport?.summary ?? '(no review)'}`,
|
|
1186
|
+
].join('\n')).join('\n\n');
|
|
1187
|
+
return [
|
|
1188
|
+
`Compound WRFC integration task`,
|
|
1189
|
+
`Parent WRFC ask (authoritative full scope):`,
|
|
1190
|
+
chain.task,
|
|
1191
|
+
``,
|
|
1192
|
+
`All sub-deliverables have individually passed review. Integrate them into one coherent final result.`,
|
|
1193
|
+
``,
|
|
1194
|
+
subtaskSummaries,
|
|
1195
|
+
``,
|
|
1196
|
+
`Instructions:`,
|
|
1197
|
+
`1. Inspect the current workspace and the sub-deliverable outputs before editing.`,
|
|
1198
|
+
`2. Resolve cross-deliverable API, export, documentation, and test consistency issues.`,
|
|
1199
|
+
`3. Preserve all accepted sub-deliverable behavior; do not start unrelated new work.`,
|
|
1200
|
+
`4. Return a structured EngineerReport JSON block so the final reviewer can inspect integration changes.`,
|
|
1201
|
+
].join('\n');
|
|
1202
|
+
}
|
|
1203
|
+
findSubtaskByAgentId(chain, agentId) {
|
|
1204
|
+
for (const subtask of chain.subtasks ?? []) {
|
|
1205
|
+
if (subtask.engineerAgentId === agentId
|
|
1206
|
+
|| subtask.reviewerAgentId === agentId
|
|
1207
|
+
|| subtask.fixerAgentId === agentId) {
|
|
1208
|
+
return subtask;
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
return null;
|
|
1212
|
+
}
|
|
1213
|
+
async onCompoundSubtaskAgentComplete(chain, subtask, agentId, rawOutput, record) {
|
|
1214
|
+
if (agentId === subtask.engineerAgentId || agentId === subtask.fixerAgentId) {
|
|
1215
|
+
const report = parseEngineerCompletionReport(rawOutput, record?.template);
|
|
1216
|
+
this.setWrfcWorkPlanTaskStatus(chain, agentId, 'done');
|
|
1217
|
+
this.handleCompoundEngineerCompletion(chain, subtask, agentId, report);
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
if (agentId === subtask.reviewerAgentId) {
|
|
1221
|
+
const review = parseReviewerCompletionReport(chain.id, rawOutput, getWrfcScoreThreshold(this.configManager));
|
|
1222
|
+
subtask.reviewerReport = review;
|
|
1223
|
+
subtask.reviewCycles += 1;
|
|
1224
|
+
this.setWrfcWorkPlanTaskStatus(chain, agentId, 'done');
|
|
1225
|
+
await this.processCompoundSubtaskReview(chain, subtask, review);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
handleCompoundEngineerCompletion(chain, subtask, agentId, report) {
|
|
1229
|
+
let reportForReview = report;
|
|
1230
|
+
this.completeSubtaskNode(chain, subtask, report.summary);
|
|
1231
|
+
if (subtask.state === 'engineering') {
|
|
1232
|
+
subtask.engineerReport = report;
|
|
1233
|
+
this.workmap.append({
|
|
1234
|
+
ts: new Date().toISOString(),
|
|
1235
|
+
wrfcId: chain.id,
|
|
1236
|
+
event: 'engineer_complete',
|
|
1237
|
+
agentId,
|
|
1238
|
+
task: subtask.task,
|
|
1239
|
+
subtaskId: subtask.id,
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
const isEngineerReportShape = (r) => r.archetype === 'engineer';
|
|
1243
|
+
if (!subtask.constraintsEnumerated) {
|
|
1244
|
+
subtask.constraints = isEngineerReportShape(report) ? (report.constraints ?? []) : [];
|
|
1245
|
+
subtask.constraintsEnumerated = true;
|
|
1246
|
+
}
|
|
1247
|
+
else if (isEngineerReportShape(report)) {
|
|
1248
|
+
const fixerConstraints = report.constraints ?? [];
|
|
1249
|
+
reportForReview = this.canonicalizeFixerReportConstraints(report, subtask.constraints);
|
|
1250
|
+
if (subtask.constraints.length === 0) {
|
|
1251
|
+
if (fixerConstraints.length > 0) {
|
|
1252
|
+
logger.warn('WrfcController: ignored compound fixer-invented constraints for unconstrained subtask', {
|
|
1253
|
+
chainId: chain.id,
|
|
1254
|
+
subtaskId: subtask.id,
|
|
1255
|
+
extra: fixerConstraints.map((constraint) => constraint.id),
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
else {
|
|
1260
|
+
const expectedIds = new Set(subtask.constraints.map((constraint) => constraint.id));
|
|
1261
|
+
const actualIds = new Set(fixerConstraints.map((constraint) => constraint.id));
|
|
1262
|
+
const missing = [...expectedIds].filter((id) => !actualIds.has(id));
|
|
1263
|
+
const extra = [...actualIds].filter((id) => !expectedIds.has(id));
|
|
1264
|
+
if (missing.length > 0 || extra.length > 0) {
|
|
1265
|
+
const description = `Fixer regressed constraint continuity for ${subtask.id}: missing=[${missing.join(',')}] extra=[${extra.join(',')}]`;
|
|
1266
|
+
logger.warn('WrfcController: compound fixer constraint-continuity violation', {
|
|
1267
|
+
chainId: chain.id,
|
|
1268
|
+
subtaskId: subtask.id,
|
|
1269
|
+
missing,
|
|
1270
|
+
extra,
|
|
1271
|
+
});
|
|
1272
|
+
subtask.syntheticIssues ??= [];
|
|
1273
|
+
subtask.syntheticIssues.push({ severity: 'critical', description });
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
else if (subtask.constraints.length > 0) {
|
|
1278
|
+
const description = `Fixer regressed constraint continuity for ${subtask.id}: missing=[${subtask.constraints.map((constraint) => constraint.id).join(',')}] extra=[]`;
|
|
1279
|
+
logger.warn('WrfcController: compound fixer constraint-continuity violation', {
|
|
1280
|
+
chainId: chain.id,
|
|
1281
|
+
subtaskId: subtask.id,
|
|
1282
|
+
missing: subtask.constraints.map((constraint) => constraint.id),
|
|
1283
|
+
extra: [],
|
|
1284
|
+
});
|
|
1285
|
+
subtask.syntheticIssues ??= [];
|
|
1286
|
+
subtask.syntheticIssues.push({ severity: 'critical', description });
|
|
1287
|
+
}
|
|
1288
|
+
subtask.engineerReport = reportForReview;
|
|
1289
|
+
this.startCompoundSubtaskReview(chain, subtask, reportForReview);
|
|
1290
|
+
}
|
|
1291
|
+
startCompoundSubtaskReview(chain, subtask, report) {
|
|
1292
|
+
subtask.state = 'reviewing';
|
|
1293
|
+
let reviewTask = buildReviewTask(chain.id, `Parent WRFC ask:\n${chain.task}\n\nSub-deliverable ${subtask.id}:\n${subtask.task}`, report, getWrfcScoreThreshold(this.configManager), subtask.constraints);
|
|
1294
|
+
if (subtask.syntheticIssues && subtask.syntheticIssues.length > 0) {
|
|
1295
|
+
const syntheticBlock = [
|
|
1296
|
+
`## Synthetic issues from controller`,
|
|
1297
|
+
``,
|
|
1298
|
+
...subtask.syntheticIssues.map((issue) => `- [${issue.severity.toUpperCase()}] ${issue.description}`),
|
|
1299
|
+
].join('\n');
|
|
1300
|
+
reviewTask = syntheticBlock + '\n\n---\n\n' + reviewTask;
|
|
1301
|
+
subtask.syntheticIssues = [];
|
|
1302
|
+
}
|
|
1303
|
+
const reviewerRecord = this.spawnWrfcAgent(chain, 'reviewer', 'reviewer', reviewTask, true, subtask.id);
|
|
1304
|
+
subtask.reviewerAgentId = reviewerRecord.id;
|
|
1305
|
+
this.applyWrfcAgentMetadata(chain, reviewerRecord, 'reviewer', subtask.id);
|
|
1306
|
+
chain.allAgentIds.push(reviewerRecord.id);
|
|
1307
|
+
this.messageBus.registerAgent({
|
|
1308
|
+
agentId: reviewerRecord.id,
|
|
1309
|
+
role: 'reviewer',
|
|
1310
|
+
wrfcId: chain.id,
|
|
1311
|
+
});
|
|
1312
|
+
subtask.currentNodeId = startWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, `subtask:${subtask.id}:review:${subtask.reviewCycles + 1}`, 'reviewer', `Review ${subtask.title}`, reviewerRecord.id);
|
|
1313
|
+
this.appendOwnerDecision(chain, 'spawn_reviewer', this.withRouteReason(`Review compound sub-deliverable ${subtask.id} after engineer output exists`, reviewerRecord), {
|
|
1314
|
+
agentId: reviewerRecord.id,
|
|
1315
|
+
role: 'reviewer',
|
|
1316
|
+
record: reviewerRecord,
|
|
1317
|
+
});
|
|
1318
|
+
this.upsertWrfcWorkPlanTask(chain, 'reviewer', reviewerRecord, 'in_progress', subtask.id);
|
|
1319
|
+
}
|
|
1320
|
+
async processCompoundSubtaskReview(chain, subtask, review) {
|
|
1321
|
+
const threshold = getWrfcScoreThreshold(this.configManager);
|
|
1322
|
+
const constraintEvaluation = this.evaluateSubtaskConstraints(subtask, review);
|
|
1323
|
+
const passed = review.score >= threshold && !constraintEvaluation.constraintFailure;
|
|
1324
|
+
this.completeSubtaskNode(chain, subtask, `Score ${review.score}/10${passed ? ' passed' : ' needs fixes'}`);
|
|
1325
|
+
emitWorkflowReviewCompleted(this.runtimeBus, createWrfcWorkflowContext(this.sessionId, chain.id), {
|
|
1326
|
+
chainId: chain.id,
|
|
1327
|
+
score: review.score,
|
|
1328
|
+
passed,
|
|
1329
|
+
...(subtask.constraints.length > 0
|
|
1330
|
+
? {
|
|
1331
|
+
constraintsSatisfied: constraintEvaluation.constraintsSatisfied,
|
|
1332
|
+
constraintsTotal: constraintEvaluation.constraintsTotal,
|
|
1333
|
+
unsatisfiedConstraintIds: constraintEvaluation.unsatisfiedConstraintIds,
|
|
1334
|
+
}
|
|
1335
|
+
: {}),
|
|
1336
|
+
});
|
|
1337
|
+
this.workmap.append({
|
|
1338
|
+
ts: new Date().toISOString(),
|
|
1339
|
+
wrfcId: chain.id,
|
|
1340
|
+
event: 'review_complete',
|
|
1341
|
+
agentId: subtask.reviewerAgentId,
|
|
1342
|
+
score: review.score,
|
|
1343
|
+
passed,
|
|
1344
|
+
subtaskId: subtask.id,
|
|
1345
|
+
issues: review.issues?.slice(0, 10).map((issue) => ({
|
|
1346
|
+
severity: issue.severity,
|
|
1347
|
+
description: issue.description,
|
|
1348
|
+
file: issue.file,
|
|
1349
|
+
})),
|
|
1350
|
+
});
|
|
1351
|
+
subtask.reviewScores.push(review.score);
|
|
1352
|
+
if (passed) {
|
|
1353
|
+
subtask.state = 'passed';
|
|
1354
|
+
this.appendOwnerDecision(chain, 'subtask_review_passed', `Sub-deliverable ${subtask.id} passed review with ${review.score}/10`, {
|
|
1355
|
+
agentId: subtask.reviewerAgentId,
|
|
1356
|
+
role: 'reviewer',
|
|
1357
|
+
reviewScore: review.score,
|
|
1358
|
+
});
|
|
1359
|
+
if ((chain.subtasks ?? []).every((candidate) => candidate.state === 'passed')) {
|
|
1360
|
+
this.startIntegration(chain);
|
|
1361
|
+
}
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
const maxFixAttempts = getWrfcMaxFixAttempts(this.configManager);
|
|
1365
|
+
if (subtask.fixAttempts >= maxFixAttempts) {
|
|
1366
|
+
subtask.state = 'failed';
|
|
1367
|
+
this.failChain(chain, `Sub-deliverable ${subtask.id} review score ${review.score}/10 below threshold ${threshold}/10 after ${subtask.fixAttempts} fix attempt${subtask.fixAttempts !== 1 ? 's' : ''}`);
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
this.appendOwnerDecision(chain, 'subtask_review_failed', `Sub-deliverable ${subtask.id} review did not pass`, {
|
|
1371
|
+
agentId: subtask.reviewerAgentId,
|
|
1372
|
+
role: 'reviewer',
|
|
1373
|
+
reviewScore: review.score,
|
|
1374
|
+
});
|
|
1375
|
+
this.startCompoundSubtaskFix(chain, subtask, review);
|
|
1376
|
+
}
|
|
1377
|
+
startCompoundSubtaskFix(chain, subtask, review) {
|
|
1378
|
+
subtask.fixAttempts += 1;
|
|
1379
|
+
subtask.state = 'fixing';
|
|
1380
|
+
const targetConstraintIds = this.evaluateSubtaskConstraints(subtask, review).unsatisfiedConstraintIds;
|
|
1381
|
+
emitWorkflowFixAttempted(this.runtimeBus, createWrfcWorkflowContext(this.sessionId, chain.id), {
|
|
1382
|
+
chainId: chain.id,
|
|
1383
|
+
attempt: subtask.fixAttempts,
|
|
1384
|
+
maxAttempts: getWrfcMaxFixAttempts(this.configManager),
|
|
1385
|
+
...(targetConstraintIds.length > 0 ? { targetConstraintIds } : {}),
|
|
1386
|
+
});
|
|
1387
|
+
const fixerRecord = this.spawnWrfcAgent(chain, 'fixer', 'engineer', buildFixTask(chain.id, `Parent WRFC ask:\n${chain.task}\n\nSub-deliverable ${subtask.id}:\n${subtask.task}`, review, getWrfcScoreThreshold(this.configManager), subtask.fixAttempts, subtask.constraints, review.constraintFindings ?? []), true, subtask.id);
|
|
1388
|
+
subtask.fixerAgentId = fixerRecord.id;
|
|
1389
|
+
this.applyWrfcAgentMetadata(chain, fixerRecord, 'fixer', subtask.id);
|
|
1390
|
+
chain.allAgentIds.push(fixerRecord.id);
|
|
1391
|
+
this.messageBus.registerAgent({
|
|
1392
|
+
agentId: fixerRecord.id,
|
|
1393
|
+
role: 'fixer',
|
|
1394
|
+
wrfcId: chain.id,
|
|
1395
|
+
});
|
|
1396
|
+
subtask.currentNodeId = startWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, `subtask:${subtask.id}:fix:${subtask.fixAttempts}`, 'fixer', `Fix ${subtask.title}`, fixerRecord.id);
|
|
1397
|
+
this.appendOwnerDecision(chain, 'spawn_fixer', this.withRouteReason(`Fix compound sub-deliverable ${subtask.id}`, fixerRecord), {
|
|
1398
|
+
agentId: fixerRecord.id,
|
|
1399
|
+
role: 'fixer',
|
|
1400
|
+
record: fixerRecord,
|
|
1401
|
+
});
|
|
1402
|
+
this.upsertWrfcWorkPlanTask(chain, 'fixer', fixerRecord, 'in_progress', subtask.id);
|
|
1403
|
+
}
|
|
1404
|
+
startIntegration(chain) {
|
|
1405
|
+
this.transition(chain, 'integrating');
|
|
1406
|
+
const integratorRecord = this.spawnWrfcAgent(chain, 'integrator', 'integrator', this.buildCompoundIntegrationTask(chain), true);
|
|
1407
|
+
chain.integratorAgentId = integratorRecord.id;
|
|
1408
|
+
this.applyWrfcAgentMetadata(chain, integratorRecord, 'integrator');
|
|
1409
|
+
chain.allAgentIds.push(integratorRecord.id);
|
|
1410
|
+
this.messageBus.registerAgent({
|
|
1411
|
+
agentId: integratorRecord.id,
|
|
1412
|
+
role: 'integrator',
|
|
1413
|
+
wrfcId: chain.id,
|
|
1414
|
+
});
|
|
1415
|
+
chain.currentNodeId = startWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, `integrator:${Date.now()}`, 'integrator', 'Integrate passed deliverables', integratorRecord.id);
|
|
1416
|
+
this.appendOwnerDecision(chain, 'spawn_integrator', this.withRouteReason('Integrate all passed compound WRFC deliverables before final full-scope review', integratorRecord), {
|
|
1417
|
+
agentId: integratorRecord.id,
|
|
1418
|
+
role: 'integrator',
|
|
1419
|
+
record: integratorRecord,
|
|
1420
|
+
});
|
|
1421
|
+
this.upsertWrfcWorkPlanTask(chain, 'integrator', integratorRecord, 'in_progress');
|
|
1422
|
+
}
|
|
1423
|
+
handleIntegratorCompletion(chain, agentId, report) {
|
|
1424
|
+
chain.integratorReport = report;
|
|
1425
|
+
this.completeCurrentNode(chain, report.summary);
|
|
1426
|
+
this.workmap.append({
|
|
1427
|
+
ts: new Date().toISOString(),
|
|
1428
|
+
wrfcId: chain.id,
|
|
1429
|
+
event: 'integrator_complete',
|
|
1430
|
+
agentId,
|
|
1431
|
+
task: chain.task,
|
|
1432
|
+
});
|
|
1433
|
+
this.startReview(chain, report);
|
|
1434
|
+
}
|
|
984
1435
|
canonicalizeFixerReportConstraints(report, constraints) {
|
|
985
1436
|
const canonical = {
|
|
986
1437
|
...report,
|
|
@@ -997,7 +1448,7 @@ export class WrfcController {
|
|
|
997
1448
|
].join('\n');
|
|
998
1449
|
return canonical;
|
|
999
1450
|
}
|
|
1000
|
-
spawnWrfcAgent(chain, role, template, task, dangerouslyDisableWrfc) {
|
|
1451
|
+
spawnWrfcAgent(chain, role, template, task, dangerouslyDisableWrfc, subtaskId) {
|
|
1001
1452
|
const owner = this.agentManager.getStatus(chain.ownerAgentId);
|
|
1002
1453
|
const selectedRoute = this.selectChildRoute?.({ chain, role, task, ownerAgent: owner }) ?? null;
|
|
1003
1454
|
const model = selectedRoute?.model ?? owner?.model;
|
|
@@ -1016,9 +1467,13 @@ export class WrfcController {
|
|
|
1016
1467
|
...(routing ? { routing } : {}),
|
|
1017
1468
|
...(reasoningEffort ? { reasoningEffort } : {}),
|
|
1018
1469
|
...(template === 'engineer' ? { systemPromptAddendum: '\n\n---\n\n' + buildEngineerConstraintAddendum() } : {}),
|
|
1470
|
+
...(template === 'integrator' ? { systemPromptAddendum: '\n\n---\n\n' + buildEngineerConstraintAddendum() } : {}),
|
|
1019
1471
|
...(dangerouslyDisableWrfc ? { dangerously_disable_wrfc: true } : {}),
|
|
1020
1472
|
});
|
|
1021
1473
|
record.wrfcId = chain.id;
|
|
1474
|
+
if (subtaskId) {
|
|
1475
|
+
record.wrfcSubtaskId = subtaskId;
|
|
1476
|
+
}
|
|
1022
1477
|
if (selectedRoute?.reason) {
|
|
1023
1478
|
record.wrfcRouteReason = selectedRoute.reason;
|
|
1024
1479
|
}
|
|
@@ -1075,16 +1530,18 @@ export class WrfcController {
|
|
|
1075
1530
|
});
|
|
1076
1531
|
}
|
|
1077
1532
|
}
|
|
1078
|
-
upsertWrfcWorkPlanTask(chain, role, record, status) {
|
|
1533
|
+
upsertWrfcWorkPlanTask(chain, role, record, status, subtaskId) {
|
|
1079
1534
|
if (!this.workPlanService)
|
|
1080
1535
|
return;
|
|
1081
1536
|
const taskId = this.workPlanTaskIdForAgent(chain, record.id, role);
|
|
1082
1537
|
const task = {
|
|
1083
1538
|
taskId,
|
|
1084
|
-
title: this.workPlanTaskTitle(role, chain.task),
|
|
1539
|
+
title: this.workPlanTaskTitle(role, role === 'owner' ? chain.task : record.task),
|
|
1085
1540
|
notes: role === 'owner'
|
|
1086
1541
|
? 'WRFC owner chain supervising lifecycle child agents.'
|
|
1087
|
-
:
|
|
1542
|
+
: subtaskId
|
|
1543
|
+
? `WRFC ${role} phase for compound deliverable ${subtaskId}.`
|
|
1544
|
+
: `WRFC ${role} phase for the owner chain.`,
|
|
1088
1545
|
owner: role,
|
|
1089
1546
|
status,
|
|
1090
1547
|
source: 'wrfc',
|
|
@@ -1097,6 +1554,7 @@ export class WrfcController {
|
|
|
1097
1554
|
metadata: {
|
|
1098
1555
|
wrfcState: chain.state,
|
|
1099
1556
|
agentTemplate: record.template,
|
|
1557
|
+
...(subtaskId ? { wrfcSubtaskId: subtaskId } : {}),
|
|
1100
1558
|
},
|
|
1101
1559
|
};
|
|
1102
1560
|
this.enqueueWrfcWorkPlanTaskOperation(taskId, async () => {
|
|
@@ -1177,6 +1635,16 @@ export class WrfcController {
|
|
|
1177
1635
|
return 'reviewer';
|
|
1178
1636
|
if (agentId === chain.fixerAgentId)
|
|
1179
1637
|
return 'fixer';
|
|
1638
|
+
if (agentId === chain.integratorAgentId)
|
|
1639
|
+
return 'integrator';
|
|
1640
|
+
for (const subtask of chain.subtasks ?? []) {
|
|
1641
|
+
if (agentId === subtask.engineerAgentId)
|
|
1642
|
+
return 'engineer';
|
|
1643
|
+
if (agentId === subtask.reviewerAgentId)
|
|
1644
|
+
return 'reviewer';
|
|
1645
|
+
if (agentId === subtask.fixerAgentId)
|
|
1646
|
+
return 'fixer';
|
|
1647
|
+
}
|
|
1180
1648
|
return null;
|
|
1181
1649
|
}
|
|
1182
1650
|
workPlanTaskIdForAgent(chain, agentId, role) {
|
|
@@ -6,7 +6,7 @@ export type WorkflowContext = {
|
|
|
6
6
|
traceId: string;
|
|
7
7
|
source: string;
|
|
8
8
|
};
|
|
9
|
-
export type WrfcNodeRole = 'engineer' | 'reviewer' | 'fixer' | 'verifier';
|
|
9
|
+
export type WrfcNodeRole = 'orchestrator' | 'engineer' | 'reviewer' | 'fixer' | 'integrator' | 'verifier';
|
|
10
10
|
export declare function createWrfcWorkflowContext(sessionId: string, chainId: string): WorkflowContext;
|
|
11
11
|
export declare function createWrfcOrchestrationGraphId(chainId: string): string;
|
|
12
12
|
export declare function emitWrfcStateChanged(runtimeBus: RuntimeEventBus, sessionId: string, chainId: string, from: WrfcState, to: WrfcState): void;
|