fix: strengthen handoff workflow guidance

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-21 21:38:02 +01:00
co-authored by Copilot
parent 0cb87d8b66
commit 039e570348
3 changed files with 108 additions and 3 deletions
@@ -500,11 +500,30 @@ public sealed class CopilotWorkflowRunner : ITurnWorkflowRunner
private Workflow BuildHandoffWorkflow(PatternDefinitionDto pattern)
{
AIAgent firstAgent = Agents[0];
IReadOnlyList<AIAgent> specialists = Agents.Skip(1).ToList();
PatternAgentDefinitionDto triageDefinition = pattern.Agents[0];
IReadOnlyList<(AIAgent Agent, PatternAgentDefinitionDto Definition)> specialists =
Agents.Skip(1)
.Zip(pattern.Agents.Skip(1), (agent, definition) => (agent, definition))
.ToList();
HandoffsWorkflowBuilder builder = AgentWorkflowBuilder.CreateHandoffBuilderWith(firstAgent)
.WithHandoffs(firstAgent, specialists)
.WithHandoffs(specialists, firstAgent);
.WithHandoffInstructions(HandoffWorkflowGuidance.CreateWorkflowInstructions());
foreach ((AIAgent specialist, PatternAgentDefinitionDto definition) in specialists)
{
builder = builder.WithHandoff(
firstAgent,
specialist,
HandoffWorkflowGuidance.CreateForwardReason(definition));
}
foreach ((AIAgent specialist, _) in specialists)
{
builder = builder.WithHandoff(
specialist,
firstAgent,
HandoffWorkflowGuidance.CreateReturnReason(triageDefinition));
}
return builder.Build();
}
@@ -0,0 +1,31 @@
using Kopaya.AgentHost.Contracts;
namespace Kopaya.AgentHost.Services;
internal static class HandoffWorkflowGuidance
{
public static string CreateWorkflowInstructions()
{
return """
This workflow uses explicit handoffs to transfer ownership between agents.
If another agent should do the substantive work, perform an actual handoff instead of answering as though the handoff already happened.
Do not claim that you delegated unless you actually executed the handoff.
The triage agent should route to the best specialist promptly once ownership is clear.
Specialists should complete the substantive work after handoff and only hand control back when the task needs re-routing, broader coordination, or is outside their specialty.
""";
}
public static string CreateForwardReason(PatternAgentDefinitionDto target)
{
string specialty = string.IsNullOrWhiteSpace(target.Description)
? target.Name
: target.Description.TrimEnd('.');
return $"Hand off when the request primarily concerns {specialty}. Once handed off, let {target.Name} own the substantive response.";
}
public static string CreateReturnReason(PatternAgentDefinitionDto triageAgent)
{
return $"Hand off back to {triageAgent.Name} only when the task needs re-routing, cross-specialist coordination, or is outside your specialty.";
}
}