fix: agent node deletion, inspector layout, and header overlap

- Enable Delete-key removal of agent nodes on the canvas; system nodes
  remain non-deletable. Removals route through the authoritative
  removeAgent path which prevents deleting the last agent.
- Stack Model and Reasoning selects vertically in the inspector panel
  so they fit within the 320px-wide column without truncation.
- Add right padding (pr-36 / 144px) to the editor header so the Save
  and Delete buttons clear the Windows title-bar overlay controls.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-24 23:32:22 +01:00
co-authored by Copilot
parent c81ea6f83b
commit 24bbf1ded3
4 changed files with 26 additions and 7 deletions
+2 -1
View File
@@ -231,7 +231,7 @@ export function PatternEditor({
return (
<div className="flex h-full flex-col">
{/* Header */}
<div className="drag-region flex items-center justify-between border-b border-[var(--color-border)] px-5 pb-3 pt-3">
<div className="drag-region flex items-center justify-between border-b border-[var(--color-border)] pb-3 pl-5 pr-36 pt-3">
<div className="flex items-center gap-3">
<button
className="no-drag flex size-8 items-center justify-center rounded-lg text-zinc-400 transition hover:bg-zinc-800 hover:text-zinc-200"
@@ -320,6 +320,7 @@ export function PatternEditor({
pattern={pattern}
availableModels={availableModels}
onGraphChange={emitGraphChange}
onAgentRemove={removeAgent}
onNodeSelect={setSelectedNodeId}
selectedNodeId={selectedNodeId}
/>
@@ -39,6 +39,7 @@ interface PatternGraphCanvasProps {
pattern: PatternDefinition;
availableModels?: ReadonlyArray<ModelDefinition>;
onGraphChange: (graph: PatternGraph) => void;
onAgentRemove: (agentId: string) => void;
onNodeSelect: (nodeId: string | null) => void;
selectedNodeId: string | null;
}
@@ -47,6 +48,7 @@ function PatternGraphCanvasInner({
pattern,
availableModels,
onGraphChange,
onAgentRemove,
onNodeSelect,
selectedNodeId,
}: PatternGraphCanvasProps) {
@@ -69,12 +71,28 @@ function PatternGraphCanvasInner({
const handleNodesChange: OnNodesChange<Node<GraphNodeData>> = useCallback(
(changes) => {
onNodesChange(changes);
// Intercept node removals and route agent deletions through the
// authoritative removal path (which also removes from pattern.agents).
const removals = changes.filter((c) => c.type === 'remove');
const nonRemovals = changes.filter((c) => c.type !== 'remove');
const hasDragStart = changes.some(
for (const removal of removals) {
if (removal.type === 'remove') {
const graphNode = graph.nodes.find((n) => n.id === removal.id);
if (graphNode?.kind === 'agent' && graphNode.agentId) {
onAgentRemove(graphNode.agentId);
}
}
}
if (nonRemovals.length > 0) {
onNodesChange(nonRemovals);
}
const hasDragStart = nonRemovals.some(
(c) => c.type === 'position' && 'dragging' in c && c.dragging,
);
const hasDragStop = changes.some(
const hasDragStop = nonRemovals.some(
(c) => c.type === 'position' && !('dragging' in c && c.dragging),
);
@@ -91,7 +109,7 @@ function PatternGraphCanvasInner({
});
}
},
[onNodesChange, pattern, onGraphChange, setNodes],
[onNodesChange, pattern, graph, onGraphChange, onAgentRemove, setNodes],
);
const handleEdgesChange: OnEdgesChange = useCallback(
@@ -184,7 +184,7 @@ function AgentNodeInspector({
value={agent.name}
/>
<div className="grid gap-3 sm:grid-cols-2">
<div className="space-y-3">
<ModelSelect
models={availableModels}
onChange={(value) => {
+1 -1
View File
@@ -96,7 +96,7 @@ export function toCanvasNodes(
},
draggable: true,
selectable: true,
deletable: false,
deletable: node.kind === 'agent',
};
});
}