mirror of
https://github.com/davidkaya/aryx.git
synced 2026-07-29 07:58:47 +02:00
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>
193 lines
8.6 KiB
C#
193 lines
8.6 KiB
C#
using Aryx.AgentHost.Contracts;
|
|
using Aryx.AgentHost.Services;
|
|
|
|
namespace Aryx.AgentHost.Tests;
|
|
|
|
public sealed class AgentInstructionComposerTests
|
|
{
|
|
[Fact]
|
|
public void Compose_LeavesNonHandoffInstructionsUnchanged()
|
|
{
|
|
WorkflowDefinitionDto workflow = CreateWorkflow("sequential");
|
|
WorkflowNodeDto agent = CreateAgent("agent-reviewer", "Reviewer", "Review the proposal.");
|
|
|
|
string instructions = AgentInstructionComposer.Compose(workflow, agent, agentIndex: 0);
|
|
|
|
Assert.Equal("Review the proposal.", instructions);
|
|
}
|
|
|
|
[Fact]
|
|
public void Compose_StrengthensGroupChatCollaborationRoles()
|
|
{
|
|
WorkflowDefinitionDto workflow = CreateWorkflow("group-chat");
|
|
WorkflowNodeDto writer = CreateAgent("agent-group-writer", "Writer", "Draft an answer.");
|
|
WorkflowNodeDto reviewer = CreateAgent("agent-group-reviewer", "Reviewer", "Review the draft.");
|
|
|
|
string writerInstructions = AgentInstructionComposer.Compose(workflow, writer, agentIndex: 0);
|
|
string reviewerInstructions = AgentInstructionComposer.Compose(workflow, reviewer, agentIndex: 1);
|
|
|
|
Assert.Contains("collaborative multi-turn group chat", writerInstructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("refine your earlier draft", writerInstructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("specific critique or improvements", reviewerInstructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("Do not restart the conversation", reviewerInstructions, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[Fact]
|
|
public void Compose_LeavesHandoffTriagePromptFocusedOnAgentInstructions()
|
|
{
|
|
WorkflowDefinitionDto workflow = CreateWorkflow("handoff");
|
|
WorkflowNodeDto triage = CreateAgent(
|
|
"agent-handoff-triage",
|
|
"Triage",
|
|
"You triage requests and must hand them off to the most appropriate specialist.");
|
|
|
|
string instructions = AgentInstructionComposer.Compose(workflow, triage, agentIndex: 0);
|
|
|
|
Assert.Equal("You triage requests and must hand them off to the most appropriate specialist.", instructions);
|
|
Assert.DoesNotContain("routing", instructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.DoesNotContain("actual handoff", instructions, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[Fact]
|
|
public void Compose_LeavesHandoffSpecialistPromptFocusedOnAgentInstructions()
|
|
{
|
|
WorkflowDefinitionDto workflow = CreateWorkflow("handoff");
|
|
WorkflowNodeDto specialist = CreateAgent(
|
|
"agent-handoff-ux",
|
|
"UX Specialist",
|
|
"You focus on navigation, UX, and interaction details.");
|
|
|
|
string instructions = AgentInstructionComposer.Compose(workflow, specialist, agentIndex: 1);
|
|
|
|
Assert.Equal("You focus on navigation, UX, and interaction details.", instructions);
|
|
Assert.DoesNotContain("triage agent", instructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.DoesNotContain("substantive answer", instructions, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[Fact]
|
|
public void Compose_AddsScratchpadGuidanceForProjectlessQaSessions()
|
|
{
|
|
WorkflowDefinitionDto workflow = CreateWorkflow("single");
|
|
WorkflowNodeDto agent = CreateAgent("agent-primary", "Primary Agent", "You are a helpful assistant.");
|
|
|
|
string instructions = AgentInstructionComposer.Compose(
|
|
workflow,
|
|
agent,
|
|
agentIndex: 0,
|
|
workspaceKind: "scratchpad");
|
|
|
|
Assert.Contains("scratchpad mode", instructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("ad-hoc work inside the scratchpad workspace", instructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("use the available tools and files inside the scratchpad workspace", instructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.DoesNotContain("Do not inspect, modify, create, or delete files", instructions, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[Fact]
|
|
public void Compose_AddsPlanModeGuidanceWhenRequested()
|
|
{
|
|
WorkflowDefinitionDto workflow = CreateWorkflow("single");
|
|
WorkflowNodeDto agent = CreateAgent("agent-primary", "Primary Agent", "You are a helpful assistant.");
|
|
|
|
string instructions = AgentInstructionComposer.Compose(
|
|
workflow,
|
|
agent,
|
|
agentIndex: 0,
|
|
interactionMode: "plan");
|
|
|
|
Assert.Contains("operating in plan mode", instructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("produce a concrete implementation plan", instructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("exit_plan_mode", instructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("Do not continue into implementation", instructions, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[Fact]
|
|
public void Compose_InsertsProjectInstructionsBetweenBaseAndRuntimeGuidance()
|
|
{
|
|
WorkflowDefinitionDto workflow = CreateWorkflow("single");
|
|
WorkflowNodeDto agent = CreateAgent("agent-primary", "Primary Agent", "You are a helpful assistant.");
|
|
|
|
string instructions = AgentInstructionComposer.Compose(
|
|
workflow,
|
|
agent,
|
|
agentIndex: 0,
|
|
workspaceKind: "scratchpad",
|
|
projectInstructions: "Follow the repository guide.");
|
|
|
|
Assert.Contains("You are a helpful assistant.", instructions, StringComparison.Ordinal);
|
|
Assert.Contains("Follow the repository guide.", instructions, StringComparison.Ordinal);
|
|
Assert.Contains("scratchpad mode", instructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.True(
|
|
instructions.IndexOf("You are a helpful assistant.", StringComparison.Ordinal)
|
|
< instructions.IndexOf("Follow the repository guide.", StringComparison.Ordinal));
|
|
Assert.True(
|
|
instructions.IndexOf("Follow the repository guide.", StringComparison.Ordinal)
|
|
< instructions.IndexOf("scratchpad mode", StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
[Fact]
|
|
public void Compose_AppendsPromptInvocationAsATaskDirective()
|
|
{
|
|
WorkflowDefinitionDto workflow = CreateWorkflow("single");
|
|
WorkflowNodeDto agent = CreateAgent("agent-primary", "Primary Agent", "You are a helpful assistant.");
|
|
|
|
string instructions = AgentInstructionComposer.Compose(
|
|
workflow,
|
|
agent,
|
|
agentIndex: 0,
|
|
promptInvocation: new RunTurnPromptInvocationDto
|
|
{
|
|
Id = "project_customization_prompt_doc_review",
|
|
Name = "doc-review",
|
|
SourcePath = @".github\prompts\docs\doc-review.prompt.md",
|
|
Description = "Review docs for missing steps",
|
|
Agent = "plan",
|
|
Model = "Claude Sonnet 4.5",
|
|
Tools = ["view", "glob"],
|
|
ResolvedPrompt = "Review the docs for missing steps and propose updates."
|
|
});
|
|
|
|
Assert.Contains("repository prompt file", instructions, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains(@"Source: .github\prompts\docs\doc-review.prompt.md", instructions, StringComparison.Ordinal);
|
|
Assert.Contains("Name: doc-review", instructions, StringComparison.Ordinal);
|
|
Assert.Contains("Description: Review docs for missing steps", instructions, StringComparison.Ordinal);
|
|
Assert.Contains("Agent: plan", instructions, StringComparison.Ordinal);
|
|
Assert.Contains("Model: Claude Sonnet 4.5", instructions, StringComparison.Ordinal);
|
|
Assert.Contains("Tools: view, glob", instructions, StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"Prompt instructions:\nReview the docs for missing steps and propose updates.",
|
|
instructions,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
private static WorkflowDefinitionDto CreateWorkflow(string orchestrationMode)
|
|
{
|
|
return new WorkflowDefinitionDto
|
|
{
|
|
Id = $"{orchestrationMode}-workflow",
|
|
Name = "Workflow",
|
|
Settings = new WorkflowSettingsDto
|
|
{
|
|
OrchestrationMode = orchestrationMode,
|
|
},
|
|
};
|
|
}
|
|
|
|
private static WorkflowNodeDto CreateAgent(string id, string name, string instructions)
|
|
{
|
|
return new WorkflowNodeDto
|
|
{
|
|
Id = id,
|
|
Kind = "agent",
|
|
Label = name,
|
|
Config = new WorkflowNodeConfigDto
|
|
{
|
|
Kind = "agent",
|
|
Id = id,
|
|
Name = name,
|
|
Instructions = instructions,
|
|
Model = "gpt-5.4",
|
|
},
|
|
};
|
|
}
|
|
}
|