diff --git a/src/renderer/components/SettingsPanel.tsx b/src/renderer/components/SettingsPanel.tsx index 0162976..0487c66 100644 --- a/src/renderer/components/SettingsPanel.tsx +++ b/src/renderer/components/SettingsPanel.tsx @@ -199,6 +199,7 @@ export function SettingsPanel({ }} workflow={editingWorkflow} workflows={workflows} + workspaceAgents={workspaceAgents} /> ); diff --git a/src/renderer/components/WorkflowEditor.tsx b/src/renderer/components/WorkflowEditor.tsx index 577b1a2..bcdd72d 100644 --- a/src/renderer/components/WorkflowEditor.tsx +++ b/src/renderer/components/WorkflowEditor.tsx @@ -13,6 +13,7 @@ import type { SubWorkflowConfig, WorkflowStateScope, } from '@shared/domain/workflow'; +import type { WorkspaceAgentDefinition } from '@shared/domain/workspaceAgent'; import { validateWorkflowDefinition, isBuilderBasedMode, syncBuilderModeEdgeIterations } from '@shared/domain/workflow'; import { createId } from '@shared/utils/ids'; import { ToggleSwitch } from '@renderer/components/ui'; @@ -25,6 +26,7 @@ import { OrchestrationModePanel } from './workflow/OrchestrationModePanel'; interface WorkflowEditorProps { availableModels: ReadonlyArray; + workspaceAgents: ReadonlyArray; workflow: WorkflowDefinition; workflows: ReadonlyArray; onChange: (workflow: WorkflowDefinition) => void; @@ -152,6 +154,7 @@ function createMinimalInlineWorkflow(): WorkflowDefinition { export function WorkflowEditor({ availableModels, + workspaceAgents, workflow, workflows, onChange, @@ -251,6 +254,36 @@ export function WorkflowEditor({ setSelectedEdgeId(null); } + function handleAddWorkspaceAgentNode(agentId: string) { + const agent = workspaceAgents.find((a) => a.id === agentId); + if (!agent) return; + const nodeId = createId('wf-agent'); + const config: AgentNodeConfig = { + kind: 'agent', + id: createId('agent'), + name: agent.name, + description: agent.description, + instructions: agent.instructions, + model: agent.model, + reasoningEffort: agent.reasoningEffort, + copilot: agent.copilot, + workspaceAgentId: agent.id, + }; + const newNode: WorkflowNode = { + id: nodeId, + kind: 'agent', + label: agent.name, + position: { x: 300, y: 200 }, + config, + }; + emitGraphChange({ + ...activeWorkflow.graph, + nodes: [...activeWorkflow.graph.nodes, newNode], + }); + setSelectedNodeId(nodeId); + setSelectedEdgeId(null); + } + function handleNodeChange(nodeId: string, patch: Partial) { emitGraphChange({ ...activeWorkflow.graph, @@ -486,7 +519,12 @@ export function WorkflowEditor({
{/* Left palette */}
- +
{/* Center column: validation + canvas + settings */} @@ -551,6 +589,7 @@ export function WorkflowEditor({ validationIssues={issues} workflow={activeWorkflow} workflows={workflows} + workspaceAgents={workspaceAgents} />
diff --git a/src/renderer/components/workflow/WorkflowGraphInspector.tsx b/src/renderer/components/workflow/WorkflowGraphInspector.tsx index c98af08..a7b0059 100644 --- a/src/renderer/components/workflow/WorkflowGraphInspector.tsx +++ b/src/renderer/components/workflow/WorkflowGraphInspector.tsx @@ -1,5 +1,5 @@ -import { useCallback } from 'react'; -import { AlertCircle, Bot, FunctionSquare, GitBranch, Info, Radio, Trash2 } from 'lucide-react'; +import { useCallback, useMemo } from 'react'; +import { AlertCircle, Bot, FunctionSquare, GitBranch, Info, Link2, Radio, RotateCcw, Trash2, Unlink } from 'lucide-react'; import { findModel, @@ -16,8 +16,10 @@ import type { WorkflowOrchestrationMode, WorkflowValidationIssue, AgentNodeConfig, + WorkflowAgentOverrides, } from '@shared/domain/workflow'; import { isBuilderBasedMode } from '@shared/domain/workflow'; +import type { WorkspaceAgentDefinition } from '@shared/domain/workspaceAgent'; import { ModelSelect, ReasoningEffortSelect } from '@renderer/components/AgentConfigFields'; import { InvokeFunctionInspector } from '@renderer/components/workflow/InvokeFunctionInspector'; import { ConditionEditor } from '@renderer/components/workflow/ConditionEditor'; @@ -26,6 +28,7 @@ import { SubWorkflowInspector } from '@renderer/components/workflow/SubWorkflowI interface WorkflowGraphInspectorProps { availableModels: ReadonlyArray; + workspaceAgents: ReadonlyArray; workflow: WorkflowDefinition; workflows: ReadonlyArray; selectedNodeId: string | null; @@ -39,6 +42,12 @@ interface WorkflowGraphInspectorProps { onDrillIntoSubWorkflow: (node: WorkflowNode) => void; } +const inputBaseClass = + 'w-full rounded-lg border border-[var(--color-border)] bg-[var(--color-surface-1)] px-3 py-2 text-[13px] text-[var(--color-text-primary)] placeholder-[var(--color-text-muted)] outline-none transition focus:border-[var(--color-accent)]/50'; + +const selectClass = + 'w-full rounded-lg border border-[var(--color-border)] bg-[var(--color-surface-1)] px-3 py-2 text-[13px] text-[var(--color-text-primary)] outline-none transition focus:border-[var(--color-accent)]/50'; + function InputField({ label, value, @@ -52,21 +61,19 @@ function InputField({ multiline?: boolean; placeholder?: string; }) { - const base = - 'w-full rounded-lg border border-[var(--color-border)] bg-[var(--color-surface-1)] px-3 py-2 text-[13px] text-[var(--color-text-primary)] placeholder-[var(--color-text-muted)] outline-none transition focus:border-[var(--color-accent)]/50'; return (