refactor: remove legacy patterns system, unify on workflows

Remove the entire patterns domain model, IPC channels, sidecar services,
renderer components, and tests. Sessions now bind exclusively to workflows
via workflowId. Builtin workflows replace builtin patterns.

Backend:
- Make AgentNodeConfig standalone (no longer extends PatternAgentDefinition)
- Add WorkflowOrchestrationMode and WorkflowExecutionDefinition
- Create builtin workflows (single-agent, sequential, concurrent, handoff, group-chat)
- Rewrite session model config helpers for workflow-only
- Remove pattern IPC channels, handlers, and preload bindings
- Merge createSession/createWorkflowSession into single method
- Remove sidecar PatternGraphResolver, PatternValidator, pattern DTOs
- Add workspace migration for legacy sessions (patternId -> workflowId)

Frontend:
- Delete PatternEditor, pattern-graph components, patternGraph lib
- Delete NewSessionModal (session creation uses workflows directly)
- Remove PatternsSection from SettingsPanel
- Update App.tsx, ChatPane, ActivityPanel, Sidebar, RunTimeline,
  AgentConfigFields, InlinePills, sessionActivity to use workflow types
- Delete pattern.ts domain module

78 files changed across backend and frontend.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-04-06 22:37:00 +02:00
co-authored by Copilot
parent 69d0804161
commit 805e369b67
78 changed files with 2303 additions and 4441 deletions
@@ -8,14 +8,14 @@ public sealed class AgentIdentityResolverTests
[Fact]
public void TryResolveKnownAgentIdentity_MatchesRuntimeExecutorIdentifier()
{
PatternDefinitionDto pattern = CreatePattern(
WorkflowDefinitionDto workflow = CreateWorkflow(
[
CreateAgent(id: "agent-concurrent-architect", name: "Architect"),
CreateAgent(id: "agent-concurrent-product", name: "Product"),
CreateAgent("agent-concurrent-architect", "Architect"),
CreateAgent("agent-concurrent-product", "Product"),
]);
bool resolved = AgentIdentityResolver.TryResolveKnownAgentIdentity(
pattern,
workflow,
"Architect_agent_concurrent_architect",
out AgentIdentity agent);
@@ -27,14 +27,14 @@ public sealed class AgentIdentityResolverTests
[Fact]
public void TryResolveKnownAgentIdentity_MatchesSanitizedNameAndId()
{
PatternDefinitionDto pattern = CreatePattern(
WorkflowDefinitionDto workflow = CreateWorkflow(
[
CreateAgent(id: "agent-single-primary", name: "Primary Agent"),
CreateAgent("agent-single-primary", "Primary Agent"),
],
mode: "single");
orchestrationMode: "single");
bool resolved = AgentIdentityResolver.TryResolveKnownAgentIdentity(
pattern,
workflow,
"Primary_Agent_agent_single_primary",
out AgentIdentity agent);
@@ -46,14 +46,14 @@ public sealed class AgentIdentityResolverTests
[Fact]
public void TryResolveKnownAgentIdentity_MapsAssistantToSingleAgent()
{
PatternDefinitionDto pattern = CreatePattern(
WorkflowDefinitionDto workflow = CreateWorkflow(
[
CreateAgent(id: "agent-single-primary", name: "Primary Agent"),
CreateAgent("agent-single-primary", "Primary Agent"),
],
mode: "single");
orchestrationMode: "single");
bool resolved = AgentIdentityResolver.TryResolveKnownAgentIdentity(
pattern,
workflow,
"assistant",
out AgentIdentity agent);
@@ -63,16 +63,16 @@ public sealed class AgentIdentityResolverTests
}
[Fact]
public void TryResolveKnownAgentIdentity_DoesNotGuessAssistantForMultiAgentPattern()
public void TryResolveKnownAgentIdentity_DoesNotGuessAssistantForMultiAgentWorkflow()
{
PatternDefinitionDto pattern = CreatePattern(
WorkflowDefinitionDto workflow = CreateWorkflow(
[
CreateAgent(id: "agent-concurrent-architect", name: "Architect"),
CreateAgent(id: "agent-concurrent-product", name: "Product"),
CreateAgent("agent-concurrent-architect", "Architect"),
CreateAgent("agent-concurrent-product", "Product"),
]);
bool resolved = AgentIdentityResolver.TryResolveKnownAgentIdentity(
pattern,
workflow,
"assistant",
out _);
@@ -82,14 +82,14 @@ public sealed class AgentIdentityResolverTests
[Fact]
public void ResolveDisplayAuthorName_UsesCanonicalAgentName()
{
PatternDefinitionDto pattern = CreatePattern(
WorkflowDefinitionDto workflow = CreateWorkflow(
[
CreateAgent(id: "agent-concurrent-implementer", name: "Implementer"),
CreateAgent("agent-concurrent-implementer", "Implementer"),
],
mode: "single");
orchestrationMode: "single");
string authorName = AgentIdentityResolver.ResolveDisplayAuthorName(
pattern,
workflow,
"Implementer_agent_concurrent_implementer");
Assert.Equal("Implementer", authorName);
@@ -98,14 +98,14 @@ public sealed class AgentIdentityResolverTests
[Fact]
public void TryResolveObservedAgentIdentity_UsesFallbackAgentForGenericAssistant()
{
PatternDefinitionDto pattern = CreatePattern(
WorkflowDefinitionDto workflow = CreateWorkflow(
[
CreateAgent(id: "agent-handoff-ux", name: "UX Specialist"),
CreateAgent(id: "agent-handoff-runtime", name: "Runtime Specialist"),
CreateAgent("agent-handoff-ux", "UX Specialist"),
CreateAgent("agent-handoff-runtime", "Runtime Specialist"),
]);
bool resolved = AgentIdentityResolver.TryResolveObservedAgentIdentity(
pattern,
workflow,
"assistant",
new AgentIdentity("agent-handoff-ux", "UX Specialist"),
out AgentIdentity agent);
@@ -115,28 +115,43 @@ public sealed class AgentIdentityResolverTests
Assert.Equal("UX Specialist", agent.AgentName);
}
private static PatternDefinitionDto CreatePattern(
IReadOnlyList<PatternAgentDefinitionDto> agents,
string mode = "concurrent")
private static WorkflowDefinitionDto CreateWorkflow(
IReadOnlyList<WorkflowNodeDto> agents,
string orchestrationMode = "concurrent")
{
return new PatternDefinitionDto
return new WorkflowDefinitionDto
{
Id = $"{mode}-pattern",
Name = "Pattern",
Mode = mode,
Availability = "available",
Agents = agents,
Id = $"{orchestrationMode}-workflow",
Name = "Workflow",
Graph = new WorkflowGraphDto
{
Nodes =
[
.. agents,
],
},
Settings = new WorkflowSettingsDto
{
OrchestrationMode = orchestrationMode,
},
};
}
private static PatternAgentDefinitionDto CreateAgent(string id, string name)
private static WorkflowNodeDto CreateAgent(string id, string name)
{
return new PatternAgentDefinitionDto
return new WorkflowNodeDto
{
Id = id,
Name = name,
Model = "gpt-5.4",
Instructions = "Help with the request.",
Kind = "agent",
Label = name,
Config = new WorkflowNodeConfigDto
{
Kind = "agent",
Id = id,
Name = name,
Model = "gpt-5.4",
Instructions = "Help with the request.",
},
};
}
}