mirror of
https://github.com/davidkaya/aryx.git
synced 2026-07-23 21:18:40 +02:00
fix: wire PatternEditor to mode-aware graph mutations
Replace the old disconnected-node addAgentNodeToGraph with the mode-aware addAgentToGraph so new agents are automatically wired into the graph topology. Replace the graph-nuking removeAgent path with removeAgentFromGraph for surgical node removal. Split emitChange into graph-preserving and mode-change paths so editing agent properties no longer discards custom positions and edges. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -18,6 +18,8 @@ import {
|
||||
import type { ApprovalCheckpointKind, ApprovalPolicy } from '@shared/domain/approval';
|
||||
import type { ModelDefinition } from '@shared/domain/models';
|
||||
import {
|
||||
addAgentToGraph,
|
||||
removeAgentFromGraph,
|
||||
resolvePatternGraph,
|
||||
syncPatternGraph,
|
||||
validatePatternDefinition,
|
||||
@@ -35,7 +37,6 @@ import {
|
||||
} from '@shared/domain/tooling';
|
||||
|
||||
import { ToggleSwitch } from '@renderer/components/ui';
|
||||
import { addAgentNodeToGraph } from '@renderer/lib/patternGraph';
|
||||
import { PatternGraphCanvas } from './pattern-graph/PatternGraphCanvas';
|
||||
import { PatternGraphInspector } from './pattern-graph/PatternGraphInspector';
|
||||
|
||||
@@ -143,6 +144,10 @@ export function PatternEditor({
|
||||
const graph = resolvePatternGraph(pattern);
|
||||
|
||||
function emitChange(nextPattern: PatternDefinition) {
|
||||
onChange({ ...nextPattern, graph: resolvePatternGraph(nextPattern) });
|
||||
}
|
||||
|
||||
function emitModeChange(nextPattern: PatternDefinition) {
|
||||
onChange(syncPatternGraph(nextPattern));
|
||||
}
|
||||
|
||||
@@ -159,7 +164,7 @@ export function PatternEditor({
|
||||
model: 'gpt-5.4',
|
||||
reasoningEffort: 'high',
|
||||
};
|
||||
const updatedGraph = addAgentNodeToGraph(graph, newAgent);
|
||||
const updatedGraph = addAgentToGraph(graph, pattern.mode, newAgent);
|
||||
onChange({ ...pattern, agents: [...pattern.agents, newAgent], graph: updatedGraph });
|
||||
}
|
||||
|
||||
@@ -175,9 +180,11 @@ export function PatternEditor({
|
||||
return;
|
||||
}
|
||||
|
||||
emitChange({
|
||||
const updatedGraph = removeAgentFromGraph(graph, pattern.mode, agentId);
|
||||
onChange({
|
||||
...pattern,
|
||||
agents: pattern.agents.filter((a) => a.id !== agentId),
|
||||
graph: updatedGraph,
|
||||
});
|
||||
setSelectedNodeId(null);
|
||||
}
|
||||
@@ -374,7 +381,7 @@ export function PatternEditor({
|
||||
}`}
|
||||
disabled={disabled}
|
||||
key={mode}
|
||||
onClick={() => emitChange({ ...pattern, mode })}
|
||||
onClick={() => emitModeChange({ ...pattern, mode })}
|
||||
type="button"
|
||||
>
|
||||
<div className="flex items-center gap-1.5">
|
||||
|
||||
@@ -246,32 +246,6 @@ export function removeEdge(graph: PatternGraph, removeEdgeId: string): PatternGr
|
||||
return { ...graph, edges: graph.edges.filter((e) => e.id !== removeEdgeId) };
|
||||
}
|
||||
|
||||
/* ── Add disconnected agent node ───────────────────────────── */
|
||||
|
||||
export function addAgentNodeToGraph(
|
||||
graph: PatternGraph,
|
||||
agent: PatternAgentDefinition,
|
||||
): PatternGraph {
|
||||
const existingAgentNodes = graph.nodes.filter((n) => n.kind === 'agent');
|
||||
const nextOrder = existingAgentNodes.length;
|
||||
|
||||
// Place new node below existing agent nodes
|
||||
const maxY = existingAgentNodes.reduce((max, n) => Math.max(max, n.position.y), 0);
|
||||
const avgX = existingAgentNodes.length > 0
|
||||
? Math.round(existingAgentNodes.reduce((sum, n) => sum + n.position.x, 0) / existingAgentNodes.length)
|
||||
: 400;
|
||||
|
||||
const newNode: PatternGraphNode = {
|
||||
id: `agent-node-${agent.id}`,
|
||||
kind: 'agent',
|
||||
agentId: agent.id,
|
||||
order: nextOrder,
|
||||
position: { x: avgX, y: maxY + 120 },
|
||||
};
|
||||
|
||||
return { ...graph, nodes: [...graph.nodes, newNode] };
|
||||
}
|
||||
|
||||
/* ── Sequential reorder ────────────────────────────────────── */
|
||||
|
||||
export function swapSequentialOrder(
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
|
||||
import { createBuiltinPatterns, resolvePatternGraph, type PatternDefinition } from '@shared/domain/pattern';
|
||||
import { addAgentToGraph, createBuiltinPatterns, resolvePatternGraph, type PatternDefinition } from '@shared/domain/pattern';
|
||||
import {
|
||||
addAgentNodeToGraph,
|
||||
addEdge,
|
||||
autoLayoutGraph,
|
||||
canMoveSequential,
|
||||
@@ -208,20 +207,20 @@ describe('pattern graph mutation helpers', () => {
|
||||
expect(updated.edges.find((e) => e.id === firstEdge.id)).toBeUndefined();
|
||||
});
|
||||
|
||||
test('addAgentNodeToGraph places a disconnected agent node on the canvas', () => {
|
||||
test('addAgentToGraph inserts a wired agent node for sequential mode', () => {
|
||||
const pattern = findPattern('sequential');
|
||||
const graph = resolvePatternGraph(pattern);
|
||||
const newAgent = { id: 'new-1', name: 'New Agent', description: '', instructions: '', model: 'gpt-5.4' };
|
||||
|
||||
const updated = addAgentNodeToGraph(graph, newAgent);
|
||||
const updated = addAgentToGraph(graph, pattern.mode, newAgent);
|
||||
expect(updated.nodes.length).toBe(graph.nodes.length + 1);
|
||||
|
||||
const newNode = updated.nodes.find((n) => n.agentId === 'new-1');
|
||||
expect(newNode).toBeDefined();
|
||||
expect(newNode!.kind).toBe('agent');
|
||||
|
||||
// No new edges added — node is disconnected
|
||||
expect(updated.edges.length).toBe(graph.edges.length);
|
||||
// New agent is wired into the chain, so edge count stays at agents+1
|
||||
expect(updated.edges.length).toBe(graph.edges.length + 1);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user