@chllming/wave-orchestration 0.8.3 → 0.8.4
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/CHANGELOG.md +19 -0
- package/README.md +47 -11
- package/docs/README.md +6 -2
- package/docs/concepts/what-is-a-wave.md +1 -1
- package/docs/plans/architecture-hardening-migration.md +8 -1
- package/docs/plans/current-state.md +15 -7
- package/docs/plans/end-state-architecture.md +82 -69
- package/docs/plans/examples/wave-example-live-proof.md +1 -1
- package/docs/plans/migration.md +235 -62
- package/docs/plans/wave-orchestrator.md +37 -11
- package/docs/reference/cli-reference.md +34 -14
- package/docs/reference/coordination-and-closure.md +19 -6
- package/docs/reference/npmjs-trusted-publishing.md +5 -4
- package/docs/reference/sample-waves.md +4 -4
- package/package.json +1 -1
- package/releases/manifest.json +20 -0
- package/scripts/wave-orchestrator/agent-state.mjs +0 -491
- package/scripts/wave-orchestrator/autonomous.mjs +10 -6
- package/scripts/wave-orchestrator/{launcher-closure.mjs → closure-engine.mjs} +190 -74
- package/scripts/wave-orchestrator/{launcher-derived-state.mjs → derived-state-engine.mjs} +34 -146
- package/scripts/wave-orchestrator/{launcher-gates.mjs → gate-engine.mjs} +395 -139
- package/scripts/wave-orchestrator/human-input-resolution.mjs +14 -10
- package/scripts/wave-orchestrator/human-input-workflow.mjs +104 -0
- package/scripts/wave-orchestrator/implementation-engine.mjs +120 -0
- package/scripts/wave-orchestrator/launcher-runtime.mjs +5 -6
- package/scripts/wave-orchestrator/launcher.mjs +271 -724
- package/scripts/wave-orchestrator/projection-writer.mjs +256 -0
- package/scripts/wave-orchestrator/reconcile-format.mjs +32 -0
- package/scripts/wave-orchestrator/reducer-snapshot.mjs +297 -0
- package/scripts/wave-orchestrator/replay.mjs +3 -1
- package/scripts/wave-orchestrator/result-envelope.mjs +589 -0
- package/scripts/wave-orchestrator/retry-control.mjs +5 -0
- package/scripts/wave-orchestrator/{launcher-retry.mjs → retry-engine.mjs} +267 -18
- package/scripts/wave-orchestrator/role-helpers.mjs +51 -0
- package/scripts/wave-orchestrator/{launcher-supervisor.mjs → session-supervisor.mjs} +178 -103
- package/scripts/wave-orchestrator/shared.mjs +1 -0
- package/scripts/wave-orchestrator/traces.mjs +10 -1
- package/scripts/wave-orchestrator/wave-files.mjs +11 -9
- package/scripts/wave-orchestrator/wave-state-reducer.mjs +52 -5
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
readClarificationBarrier,
|
|
9
9
|
readWaveAssignmentBarrier,
|
|
10
10
|
readWaveDependencyBarrier,
|
|
11
|
-
} from "./
|
|
11
|
+
} from "./gate-engine.mjs";
|
|
12
12
|
import {
|
|
13
13
|
isOpenCoordinationStatus,
|
|
14
14
|
openClarificationLinkedRequests,
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
import { hashAgentPromptFingerprint } from "./context7.mjs";
|
|
34
34
|
import {
|
|
35
35
|
isSecurityReviewAgent,
|
|
36
|
+
resolveWaveRoleBindings,
|
|
36
37
|
} from "./role-helpers.mjs";
|
|
37
38
|
import {
|
|
38
39
|
commandForExecutor,
|
|
@@ -121,6 +122,7 @@ export function persistedRelaunchPlanMatchesCurrentState(
|
|
|
121
122
|
}
|
|
122
123
|
const componentGate = readWaveComponentGate(waveDefinition, agentRuns, {
|
|
123
124
|
laneProfile: lanePaths?.laneProfile,
|
|
125
|
+
mode: "live",
|
|
124
126
|
});
|
|
125
127
|
if (componentGate?.statusCode !== "shared-component-sibling-pending") {
|
|
126
128
|
return true;
|
|
@@ -271,7 +273,10 @@ export function reconcileFailuresAgainstSharedComponentState(wave, agentRuns, fa
|
|
|
271
273
|
return failures;
|
|
272
274
|
}
|
|
273
275
|
const summariesByAgentId = Object.fromEntries(
|
|
274
|
-
(agentRuns || []).map((runInfo) => [
|
|
276
|
+
(agentRuns || []).map((runInfo) => [
|
|
277
|
+
runInfo.agent.agentId,
|
|
278
|
+
readRunExecutionSummary(runInfo, wave, { mode: "live" }),
|
|
279
|
+
]),
|
|
275
280
|
);
|
|
276
281
|
const failureAgentIds = new Set(failures.map((failure) => failure.agentId).filter(Boolean));
|
|
277
282
|
const consumedSatisfiedAgentIds = new Set();
|
|
@@ -337,13 +342,12 @@ export function hasReusableSuccessStatus(agent, statusPath, options = {}) {
|
|
|
337
342
|
return true;
|
|
338
343
|
}
|
|
339
344
|
|
|
340
|
-
function isClosureAgentId(agent, lanePaths) {
|
|
341
|
-
return
|
|
342
|
-
lanePaths.
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
].includes(agent?.agentId) || isSecurityReviewAgent(agent);
|
|
345
|
+
function isClosureAgentId(agent, lanePaths, waveDefinition = null) {
|
|
346
|
+
return (
|
|
347
|
+
resolveWaveRoleBindings(waveDefinition, lanePaths, waveDefinition?.agents).closureAgentIds.includes(
|
|
348
|
+
agent?.agentId,
|
|
349
|
+
) || isSecurityReviewAgent(agent)
|
|
350
|
+
);
|
|
347
351
|
}
|
|
348
352
|
|
|
349
353
|
export function selectReusablePreCompletedAgentIds(
|
|
@@ -357,7 +361,7 @@ export function selectReusablePreCompletedAgentIds(
|
|
|
357
361
|
.filter(
|
|
358
362
|
(run) =>
|
|
359
363
|
!retryOverrideClearedAgentIds.has(run.agent.agentId) &&
|
|
360
|
-
!isClosureAgentId(run.agent, lanePaths) &&
|
|
364
|
+
!isClosureAgentId(run.agent, lanePaths, wave) &&
|
|
361
365
|
hasReusableSuccessStatus(run.agent, run.statusPath, {
|
|
362
366
|
wave,
|
|
363
367
|
derivedState,
|
|
@@ -369,9 +373,9 @@ export function selectReusablePreCompletedAgentIds(
|
|
|
369
373
|
);
|
|
370
374
|
}
|
|
371
375
|
|
|
372
|
-
export function selectInitialWaveRuns(agentRuns, lanePaths) {
|
|
376
|
+
export function selectInitialWaveRuns(agentRuns, lanePaths, waveDefinition = null) {
|
|
373
377
|
const implementationRuns = (agentRuns || []).filter(
|
|
374
|
-
(run) => !isClosureAgentId(run?.agent, lanePaths),
|
|
378
|
+
(run) => !isClosureAgentId(run?.agent, lanePaths, waveDefinition),
|
|
375
379
|
);
|
|
376
380
|
return implementationRuns.length > 0 ? implementationRuns : agentRuns;
|
|
377
381
|
}
|
|
@@ -560,7 +564,35 @@ function retryBarrierFromOutcomes(outcomes, failures) {
|
|
|
560
564
|
};
|
|
561
565
|
}
|
|
562
566
|
|
|
563
|
-
|
|
567
|
+
function runsFromAgentIds(agentRuns, agentIds) {
|
|
568
|
+
const runsByAgentId = new Map((agentRuns || []).map((run) => [run.agent.agentId, run]));
|
|
569
|
+
return Array.from(new Set((agentIds || []).filter(Boolean)))
|
|
570
|
+
.map((agentId) => runsByAgentId.get(agentId))
|
|
571
|
+
.filter(Boolean);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function resolveRunsForResumePhase(agentRuns, lanePaths, resumePhase, waveDefinition = null) {
|
|
575
|
+
const roleBindings = resolveWaveRoleBindings(waveDefinition, lanePaths, waveDefinition?.agents);
|
|
576
|
+
if (resumePhase === "integrating") {
|
|
577
|
+
return runsFromAgentIds(agentRuns, [roleBindings.integrationAgentId]);
|
|
578
|
+
}
|
|
579
|
+
if (resumePhase === "security-review") {
|
|
580
|
+
return (agentRuns || []).filter((run) => isSecurityReviewAgent(run.agent));
|
|
581
|
+
}
|
|
582
|
+
if (resumePhase === "docs-closure") {
|
|
583
|
+
return runsFromAgentIds(agentRuns, [roleBindings.documentationAgentId]);
|
|
584
|
+
}
|
|
585
|
+
if (resumePhase === "cont-qa-closure") {
|
|
586
|
+
return runsFromAgentIds(agentRuns, [roleBindings.contQaAgentId]);
|
|
587
|
+
}
|
|
588
|
+
if (resumePhase === "cont-eval") {
|
|
589
|
+
return runsFromAgentIds(agentRuns, [roleBindings.contEvalAgentId]);
|
|
590
|
+
}
|
|
591
|
+
return [];
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function resolveRelaunchRunsLegacy(agentRuns, failures, derivedState, lanePaths, waveDefinition = null) {
|
|
595
|
+
const roleBindings = resolveWaveRoleBindings(waveDefinition, lanePaths, waveDefinition?.agents);
|
|
564
596
|
const runsByAgentId = new Map(agentRuns.map((run) => [run.agent.agentId, run]));
|
|
565
597
|
const pendingFeedback = (derivedState?.coordinationState?.humanFeedback || []).filter((record) =>
|
|
566
598
|
isOpenCoordinationStatus(record.status),
|
|
@@ -693,7 +725,7 @@ export function resolveRelaunchRuns(agentRuns, failures, derivedState, lanePaths
|
|
|
693
725
|
}
|
|
694
726
|
if (derivedState?.ledger?.phase === "docs-closure") {
|
|
695
727
|
return {
|
|
696
|
-
runs: [runsByAgentId.get(
|
|
728
|
+
runs: [runsByAgentId.get(roleBindings.documentationAgentId)].filter(Boolean),
|
|
697
729
|
barrier: null,
|
|
698
730
|
};
|
|
699
731
|
}
|
|
@@ -705,19 +737,19 @@ export function resolveRelaunchRuns(agentRuns, failures, derivedState, lanePaths
|
|
|
705
737
|
}
|
|
706
738
|
if (derivedState?.ledger?.phase === "cont-eval") {
|
|
707
739
|
return {
|
|
708
|
-
runs: [runsByAgentId.get(
|
|
740
|
+
runs: [runsByAgentId.get(roleBindings.contEvalAgentId)].filter(Boolean),
|
|
709
741
|
barrier: null,
|
|
710
742
|
};
|
|
711
743
|
}
|
|
712
744
|
if (derivedState?.ledger?.phase === "cont-qa-closure") {
|
|
713
745
|
return {
|
|
714
|
-
runs: [runsByAgentId.get(
|
|
746
|
+
runs: [runsByAgentId.get(roleBindings.contQaAgentId)].filter(Boolean),
|
|
715
747
|
barrier: null,
|
|
716
748
|
};
|
|
717
749
|
}
|
|
718
750
|
if (derivedState?.ledger?.phase === "integrating") {
|
|
719
751
|
return {
|
|
720
|
-
runs: [runsByAgentId.get(
|
|
752
|
+
runs: [runsByAgentId.get(roleBindings.integrationAgentId)].filter(Boolean),
|
|
721
753
|
barrier: null,
|
|
722
754
|
};
|
|
723
755
|
}
|
|
@@ -742,6 +774,216 @@ export function resolveRelaunchRuns(agentRuns, failures, derivedState, lanePaths
|
|
|
742
774
|
};
|
|
743
775
|
}
|
|
744
776
|
|
|
777
|
+
function resolveRelaunchRunsFromWaveState(
|
|
778
|
+
agentRuns,
|
|
779
|
+
failures,
|
|
780
|
+
derivedState,
|
|
781
|
+
lanePaths,
|
|
782
|
+
waveDefinition,
|
|
783
|
+
waveState,
|
|
784
|
+
) {
|
|
785
|
+
const roleBindings = resolveWaveRoleBindings(waveDefinition, lanePaths, waveDefinition?.agents);
|
|
786
|
+
const pendingFeedback = (waveState?.coordinationState?.humanFeedback || []).filter((record) =>
|
|
787
|
+
isOpenCoordinationStatus(record.status),
|
|
788
|
+
);
|
|
789
|
+
const pendingHumanEscalations = (waveState?.coordinationState?.humanEscalations || []).filter(
|
|
790
|
+
(record) => isOpenCoordinationStatus(record.status),
|
|
791
|
+
);
|
|
792
|
+
if (pendingFeedback.length > 0 || pendingHumanEscalations.length > 0) {
|
|
793
|
+
return { runs: [], barrier: null };
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
const nextAttemptNumber = Number(derivedState?.ledger?.attempt || 0) + 1;
|
|
797
|
+
const fallbackResolution = applyRetryFallbacks(
|
|
798
|
+
agentRuns,
|
|
799
|
+
failures,
|
|
800
|
+
lanePaths,
|
|
801
|
+
nextAttemptNumber,
|
|
802
|
+
waveDefinition,
|
|
803
|
+
);
|
|
804
|
+
const retryBarrier = retryBarrierFromOutcomes(fallbackResolution.outcomes, failures);
|
|
805
|
+
if (retryBarrier) {
|
|
806
|
+
return { runs: [], barrier: retryBarrier };
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
const clarificationTargets = new Set();
|
|
810
|
+
for (const record of openClarificationLinkedRequests(waveState?.coordinationState)) {
|
|
811
|
+
for (const target of record.targets || []) {
|
|
812
|
+
if (String(target).startsWith("agent:")) {
|
|
813
|
+
clarificationTargets.add(String(target).slice("agent:".length));
|
|
814
|
+
} else {
|
|
815
|
+
clarificationTargets.add(target);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
if (clarificationTargets.size > 0) {
|
|
820
|
+
return {
|
|
821
|
+
runs: runsFromAgentIds(agentRuns, Array.from(clarificationTargets)),
|
|
822
|
+
barrier: null,
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
const blockingAssignments = (waveState?.capabilityAssignments || []).filter(
|
|
827
|
+
(assignment) => assignment.blocking,
|
|
828
|
+
);
|
|
829
|
+
if (blockingAssignments.length > 0) {
|
|
830
|
+
const unresolvedAssignments = blockingAssignments.filter((assignment) => !assignment.assignedAgentId);
|
|
831
|
+
if (unresolvedAssignments.length > 0) {
|
|
832
|
+
return {
|
|
833
|
+
runs: [],
|
|
834
|
+
barrier: {
|
|
835
|
+
statusCode: "helper-assignment-unresolved",
|
|
836
|
+
detail: `No matching assignee exists for helper requests (${unresolvedAssignments.map((assignment) => assignment.requestId).join(", ")}).`,
|
|
837
|
+
failures: unresolvedAssignments.map((assignment) => ({
|
|
838
|
+
agentId: null,
|
|
839
|
+
statusCode: "helper-assignment-unresolved",
|
|
840
|
+
logPath: null,
|
|
841
|
+
detail: assignment.assignmentDetail || assignment.summary || assignment.requestId,
|
|
842
|
+
})),
|
|
843
|
+
},
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
return {
|
|
847
|
+
runs: runsFromAgentIds(
|
|
848
|
+
agentRuns,
|
|
849
|
+
blockingAssignments.map((assignment) => assignment.assignedAgentId),
|
|
850
|
+
),
|
|
851
|
+
barrier: null,
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
const unresolvedInboundAssignments =
|
|
856
|
+
waveState?.dependencySnapshot?.unresolvedInboundAssignments || [];
|
|
857
|
+
if (unresolvedInboundAssignments.length > 0) {
|
|
858
|
+
return {
|
|
859
|
+
runs: [],
|
|
860
|
+
barrier: {
|
|
861
|
+
statusCode: "dependency-assignment-unresolved",
|
|
862
|
+
detail: `Required inbound dependencies are not assigned (${unresolvedInboundAssignments.map((record) => record.id).join(", ")}).`,
|
|
863
|
+
failures: unresolvedInboundAssignments.map((record) => ({
|
|
864
|
+
agentId: null,
|
|
865
|
+
statusCode: "dependency-assignment-unresolved",
|
|
866
|
+
logPath: null,
|
|
867
|
+
detail: record.assignmentDetail || record.summary || record.id,
|
|
868
|
+
})),
|
|
869
|
+
},
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
const inboundDependencyAgentIds = new Set(
|
|
874
|
+
(waveState?.dependencySnapshot?.openInbound || [])
|
|
875
|
+
.map((record) => record.assignedAgentId)
|
|
876
|
+
.filter(Boolean),
|
|
877
|
+
);
|
|
878
|
+
if (inboundDependencyAgentIds.size > 0) {
|
|
879
|
+
return {
|
|
880
|
+
runs: runsFromAgentIds(agentRuns, Array.from(inboundDependencyAgentIds)),
|
|
881
|
+
barrier: null,
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
const blockerAgentIds = new Set();
|
|
886
|
+
for (const record of waveState?.coordinationState?.blockers || []) {
|
|
887
|
+
if (!isOpenCoordinationStatus(record.status)) {
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
blockerAgentIds.add(record.agentId);
|
|
891
|
+
for (const target of record.targets || []) {
|
|
892
|
+
if (String(target).startsWith("agent:")) {
|
|
893
|
+
blockerAgentIds.add(String(target).slice("agent:".length));
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
if (blockerAgentIds.size > 0) {
|
|
898
|
+
return {
|
|
899
|
+
runs: runsFromAgentIds(agentRuns, Array.from(blockerAgentIds)),
|
|
900
|
+
barrier: null,
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
const sharedComponentWaitingAgentIds = new Set(
|
|
905
|
+
(failures || [])
|
|
906
|
+
.filter((failure) => failure.statusCode === "shared-component-sibling-pending")
|
|
907
|
+
.flatMap((failure) => failure.waitingOnAgentIds || [])
|
|
908
|
+
.filter(Boolean),
|
|
909
|
+
);
|
|
910
|
+
if (sharedComponentWaitingAgentIds.size > 0) {
|
|
911
|
+
return {
|
|
912
|
+
runs: runsFromAgentIds(agentRuns, Array.from(sharedComponentWaitingAgentIds)),
|
|
913
|
+
barrier: null,
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
const resumePlan = buildResumePlan(waveState, {
|
|
918
|
+
waveDefinition,
|
|
919
|
+
lanePaths,
|
|
920
|
+
});
|
|
921
|
+
if (!resumePlan.canResume || resumePlan.reason === "human-request") {
|
|
922
|
+
return { runs: [], barrier: null };
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
const phaseRuns = resolveRunsForResumePhase(
|
|
926
|
+
agentRuns,
|
|
927
|
+
lanePaths,
|
|
928
|
+
resumePlan.resumeFromPhase,
|
|
929
|
+
waveDefinition,
|
|
930
|
+
);
|
|
931
|
+
if (phaseRuns.length > 0 && resumePlan.resumeFromPhase !== "implementation") {
|
|
932
|
+
return {
|
|
933
|
+
runs: phaseRuns,
|
|
934
|
+
barrier: null,
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
const retryTargetAgentIds = normalizeRetryTargets(waveState?.retryTargetSet).map(
|
|
939
|
+
(target) => target.agentId,
|
|
940
|
+
);
|
|
941
|
+
const implementationAgentIds =
|
|
942
|
+
resumePlan.invalidatedAgentIds.length > 0
|
|
943
|
+
? resumePlan.invalidatedAgentIds
|
|
944
|
+
: retryTargetAgentIds;
|
|
945
|
+
if (implementationAgentIds.length > 0) {
|
|
946
|
+
return {
|
|
947
|
+
runs: runsFromAgentIds(agentRuns, implementationAgentIds),
|
|
948
|
+
barrier: null,
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
const failedAgentIds = new Set(failures.map((failure) => failure.agentId));
|
|
953
|
+
return {
|
|
954
|
+
runs: agentRuns.filter((run) => failedAgentIds.has(run.agent.agentId)),
|
|
955
|
+
barrier: null,
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
export function resolveRelaunchRuns(
|
|
960
|
+
agentRuns,
|
|
961
|
+
failures,
|
|
962
|
+
derivedState,
|
|
963
|
+
lanePaths,
|
|
964
|
+
waveDefinition = null,
|
|
965
|
+
options = {},
|
|
966
|
+
) {
|
|
967
|
+
const waveState = options?.waveState || null;
|
|
968
|
+
if (!waveState) {
|
|
969
|
+
return resolveRelaunchRunsLegacy(
|
|
970
|
+
agentRuns,
|
|
971
|
+
failures,
|
|
972
|
+
derivedState,
|
|
973
|
+
lanePaths,
|
|
974
|
+
waveDefinition,
|
|
975
|
+
);
|
|
976
|
+
}
|
|
977
|
+
return resolveRelaunchRunsFromWaveState(
|
|
978
|
+
agentRuns,
|
|
979
|
+
failures,
|
|
980
|
+
derivedState,
|
|
981
|
+
lanePaths,
|
|
982
|
+
waveDefinition,
|
|
983
|
+
waveState,
|
|
984
|
+
);
|
|
985
|
+
}
|
|
986
|
+
|
|
745
987
|
export function preflightWavesForExecutorAvailability(waves, lanePaths) {
|
|
746
988
|
for (const wave of waves) {
|
|
747
989
|
const mixValidation = validateWaveRuntimeMixAssignments(wave, {
|
|
@@ -778,10 +1020,17 @@ function phaseFromGate(gateName) {
|
|
|
778
1020
|
switch (gateName) {
|
|
779
1021
|
case "implementationGate":
|
|
780
1022
|
case "componentGate":
|
|
781
|
-
case "
|
|
1023
|
+
case "helperAssignmentBarrier":
|
|
1024
|
+
case "dependencyBarrier":
|
|
1025
|
+
case "clarificationBarrier":
|
|
782
1026
|
return "implementation";
|
|
1027
|
+
case "contEvalGate":
|
|
1028
|
+
return "cont-eval";
|
|
1029
|
+
case "securityGate":
|
|
1030
|
+
return "security-review";
|
|
783
1031
|
case "integrationBarrier":
|
|
784
1032
|
return "integrating";
|
|
1033
|
+
case "componentMatrixGate":
|
|
785
1034
|
case "documentationGate":
|
|
786
1035
|
return "docs-closure";
|
|
787
1036
|
case "contQaGate":
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
+
DEFAULT_CONT_QA_AGENT_ID,
|
|
2
3
|
DEFAULT_CONT_EVAL_AGENT_ID,
|
|
4
|
+
DEFAULT_DOCUMENTATION_AGENT_ID,
|
|
5
|
+
DEFAULT_INTEGRATION_AGENT_ID,
|
|
3
6
|
DEFAULT_SECURITY_ROLE_PROMPT_PATH,
|
|
4
7
|
} from "./config.mjs";
|
|
5
8
|
|
|
@@ -82,3 +85,51 @@ export function resolveSecurityReviewReportPath(agent) {
|
|
|
82
85
|
const ownedPaths = Array.isArray(agent?.ownedPaths) ? agent.ownedPaths.map(cleanPath).filter(Boolean) : [];
|
|
83
86
|
return ownedPaths.find((ownedPath) => isSecurityReportPath(ownedPath)) || null;
|
|
84
87
|
}
|
|
88
|
+
|
|
89
|
+
export function resolveWaveRoleBindings(wave = {}, lanePaths = {}, agents = wave?.agents || []) {
|
|
90
|
+
const contQaAgentId =
|
|
91
|
+
wave?.contQaAgentId || lanePaths?.contQaAgentId || DEFAULT_CONT_QA_AGENT_ID;
|
|
92
|
+
const contEvalAgentId =
|
|
93
|
+
wave?.contEvalAgentId || lanePaths?.contEvalAgentId || DEFAULT_CONT_EVAL_AGENT_ID;
|
|
94
|
+
const integrationAgentId =
|
|
95
|
+
wave?.integrationAgentId || lanePaths?.integrationAgentId || DEFAULT_INTEGRATION_AGENT_ID;
|
|
96
|
+
const documentationAgentId =
|
|
97
|
+
wave?.documentationAgentId ||
|
|
98
|
+
lanePaths?.documentationAgentId ||
|
|
99
|
+
DEFAULT_DOCUMENTATION_AGENT_ID;
|
|
100
|
+
const securityReviewerAgentIds = Array.from(
|
|
101
|
+
new Set(
|
|
102
|
+
(Array.isArray(agents) ? agents : [])
|
|
103
|
+
.filter((agent) =>
|
|
104
|
+
isSecurityReviewAgent(agent, {
|
|
105
|
+
securityRolePromptPath: lanePaths?.securityRolePromptPath,
|
|
106
|
+
}),
|
|
107
|
+
)
|
|
108
|
+
.map((agent) => agent.agentId)
|
|
109
|
+
.filter(Boolean),
|
|
110
|
+
),
|
|
111
|
+
).sort();
|
|
112
|
+
const closureAgentIds = Array.from(
|
|
113
|
+
new Set(
|
|
114
|
+
[
|
|
115
|
+
contEvalAgentId,
|
|
116
|
+
integrationAgentId,
|
|
117
|
+
documentationAgentId,
|
|
118
|
+
contQaAgentId,
|
|
119
|
+
...securityReviewerAgentIds,
|
|
120
|
+
].filter(Boolean),
|
|
121
|
+
),
|
|
122
|
+
).sort();
|
|
123
|
+
return {
|
|
124
|
+
contQaAgentId,
|
|
125
|
+
contEvalAgentId,
|
|
126
|
+
integrationAgentId,
|
|
127
|
+
documentationAgentId,
|
|
128
|
+
securityReviewerAgentIds,
|
|
129
|
+
closureAgentIds,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function isClosureRoleAgentId(agentId, roleBindings) {
|
|
134
|
+
return (roleBindings?.closureAgentIds || []).includes(agentId);
|
|
135
|
+
}
|