mirror of
https://github.com/davidkaya/aryx.git
synced 2026-07-29 07:58:47 +02:00
fix: synchronize workflow iteration settings across edges, mode settings, and scaffold
For builder-based orchestration modes (group-chat, handoff), the loop edge maxIterations, workflow settings.maxIterations, and mode-specific settings (e.g. groupChat.maxRounds) were independently editable but only the mode settings controlled runtime behavior. This caused confusion when changing one did not update the others. Changes: - Add syncBuilderModeEdgeIterations() to keep loop edge maxIterations in sync with the authoritative mode settings for builder-based modes - Wire sync into normalizeWorkflowDefinition so edges are consistent on load/normalization - Update scaffoldGraphForMode to accept optional settings instead of hardcoded iteration values (4 for handoff, 5 for group-chat) - Sync settings.maxIterations <-> groupChat.maxRounds bidirectionally when either changes in the UI - Make loop edge controls read-only in the graph inspector for builder-based modes with explanatory text - Add 8 consistency tests validating built-in workflows, scaffold behavior, and normalization sync Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -640,3 +640,110 @@ describe('workflow validation', () => {
|
||||
expect(groupChatWorkflow?.settings.modeSettings).toEqual(createDefaultModeSettings('group-chat'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('built-in workflow consistency', () => {
|
||||
const builtinWorkflows = createBuiltinWorkflows(TIMESTAMP);
|
||||
|
||||
test('all built-in workflows pass validation without errors', () => {
|
||||
for (const workflow of builtinWorkflows) {
|
||||
const issues = validateWorkflowDefinition(workflow);
|
||||
const errors = issues.filter((i) => i.level === 'error');
|
||||
expect(errors).toEqual([]);
|
||||
}
|
||||
});
|
||||
|
||||
test('all built-in workflows are stable under normalization', () => {
|
||||
for (const workflow of builtinWorkflows) {
|
||||
const normalized = normalizeWorkflowDefinition(workflow);
|
||||
expect(normalized.graph.edges).toEqual(workflow.graph.edges);
|
||||
expect(normalized.settings).toEqual(workflow.settings);
|
||||
}
|
||||
});
|
||||
|
||||
test('group-chat workflow has consistent maxIterations across settings and edges', () => {
|
||||
const workflow = builtinWorkflows.find((w) => w.settings.orchestrationMode === 'group-chat')!;
|
||||
const maxRounds = workflow.settings.modeSettings!.groupChat!.maxRounds;
|
||||
const maxIterations = workflow.settings.maxIterations;
|
||||
|
||||
expect(maxIterations).toBeDefined();
|
||||
expect(maxRounds).toBe(maxIterations!);
|
||||
|
||||
const loopEdges = workflow.graph.edges.filter((e) => e.isLoop);
|
||||
expect(loopEdges.length).toBeGreaterThan(0);
|
||||
for (const edge of loopEdges) {
|
||||
expect(edge.maxIterations).toBe(maxRounds);
|
||||
}
|
||||
});
|
||||
|
||||
test('handoff workflow has consistent maxIterations across settings and edges', () => {
|
||||
const workflow = builtinWorkflows.find((w) => w.settings.orchestrationMode === 'handoff')!;
|
||||
const maxIterations = workflow.settings.maxIterations;
|
||||
|
||||
const loopEdges = workflow.graph.edges.filter((e) => e.isLoop);
|
||||
expect(loopEdges.length).toBeGreaterThan(0);
|
||||
for (const edge of loopEdges) {
|
||||
expect(edge.maxIterations).toBe(maxIterations);
|
||||
}
|
||||
});
|
||||
|
||||
test('scaffoldGraphForMode respects provided settings for group-chat', () => {
|
||||
const graph = scaffoldGraphForMode('group-chat', {
|
||||
settings: {
|
||||
checkpointing: { enabled: false },
|
||||
executionMode: 'off-thread',
|
||||
orchestrationMode: 'group-chat',
|
||||
modeSettings: { groupChat: { selectionStrategy: 'round-robin', maxRounds: 12 } },
|
||||
maxIterations: 12,
|
||||
},
|
||||
});
|
||||
|
||||
const loopEdges = graph.edges.filter((e) => e.isLoop);
|
||||
expect(loopEdges.length).toBeGreaterThan(0);
|
||||
for (const edge of loopEdges) {
|
||||
expect(edge.maxIterations).toBe(12);
|
||||
}
|
||||
});
|
||||
|
||||
test('scaffoldGraphForMode respects provided settings for handoff', () => {
|
||||
const graph = scaffoldGraphForMode('handoff', {
|
||||
settings: {
|
||||
checkpointing: { enabled: false },
|
||||
executionMode: 'off-thread',
|
||||
orchestrationMode: 'handoff',
|
||||
maxIterations: 8,
|
||||
},
|
||||
});
|
||||
|
||||
const loopEdges = graph.edges.filter((e) => e.isLoop);
|
||||
expect(loopEdges.length).toBeGreaterThan(0);
|
||||
for (const edge of loopEdges) {
|
||||
expect(edge.maxIterations).toBe(8);
|
||||
}
|
||||
});
|
||||
|
||||
test('normalizeWorkflowDefinition syncs loop edge maxIterations for group-chat', () => {
|
||||
const workflow = createBuiltinWorkflows(TIMESTAMP).find((w) => w.settings.orchestrationMode === 'group-chat')!;
|
||||
const modified: WorkflowDefinition = {
|
||||
...workflow,
|
||||
settings: {
|
||||
...workflow.settings,
|
||||
maxIterations: 10,
|
||||
modeSettings: {
|
||||
groupChat: { selectionStrategy: 'round-robin', maxRounds: 10 },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const normalized = normalizeWorkflowDefinition(modified);
|
||||
const loopEdges = normalized.graph.edges.filter((e) => e.isLoop);
|
||||
for (const edge of loopEdges) {
|
||||
expect(edge.maxIterations).toBe(10);
|
||||
}
|
||||
});
|
||||
|
||||
test('normalizeWorkflowDefinition does not modify loop edges for graph-based modes', () => {
|
||||
const workflow = createBuiltinWorkflows(TIMESTAMP).find((w) => w.settings.orchestrationMode === 'sequential')!;
|
||||
const normalized = normalizeWorkflowDefinition(workflow);
|
||||
expect(normalized.graph.edges).toEqual(workflow.graph.edges);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user