mirror of
https://github.com/davidkaya/aryx.git
synced 2026-07-30 08:28:48 +02:00
fix: emit completed activity for sequential agents
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -54,6 +54,11 @@ internal sealed class CopilotTurnExecutionState
|
||||
}
|
||||
}
|
||||
|
||||
public void QueueCompletedActivity(AgentIdentity agent)
|
||||
{
|
||||
_pendingEvents.Enqueue(CreateCompletedActivity(agent));
|
||||
}
|
||||
|
||||
public void ApplyEvent(SidecarEventDto evt)
|
||||
{
|
||||
if (evt is AgentActivityEventDto activity
|
||||
@@ -310,6 +315,19 @@ internal sealed class CopilotTurnExecutionState
|
||||
};
|
||||
}
|
||||
|
||||
private AgentActivityEventDto CreateCompletedActivity(AgentIdentity agent)
|
||||
{
|
||||
return new AgentActivityEventDto
|
||||
{
|
||||
Type = "agent-activity",
|
||||
RequestId = _command.RequestId,
|
||||
SessionId = _command.SessionId,
|
||||
ActivityType = "completed",
|
||||
AgentId = agent.AgentId,
|
||||
AgentName = agent.AgentName,
|
||||
};
|
||||
}
|
||||
|
||||
private MessageReclassifiedEventDto CreateMessageReclassifiedEvent(string messageId)
|
||||
{
|
||||
return new MessageReclassifiedEventDto
|
||||
|
||||
@@ -375,6 +375,7 @@ public sealed class CopilotWorkflowRunner : ITurnWorkflowRunner
|
||||
out AgentIdentity completedAgent))
|
||||
{
|
||||
TraceHandoff(command, $"Executor completed: {completed.ExecutorId} -> {completedAgent.AgentName} ({completedAgent.AgentId}).");
|
||||
state.QueueCompletedActivity(completedAgent);
|
||||
state.ClearActiveAgentIfMatching(completedAgent);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -94,6 +94,22 @@ public sealed class CopilotTurnExecutionStateTests
|
||||
Assert.Equal("handoff_to_specialist", toolName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void QueueCompletedActivity_QueuesCompletedAgentActivity()
|
||||
{
|
||||
RunTurnCommandDto command = CreateCommand();
|
||||
CopilotTurnExecutionState state = new(command);
|
||||
|
||||
state.QueueCompletedActivity(new AgentIdentity("agent-1", "Primary"));
|
||||
|
||||
AgentActivityEventDto activity = Assert.Single(state.DrainPendingEvents().OfType<AgentActivityEventDto>());
|
||||
Assert.Equal("completed", activity.ActivityType);
|
||||
Assert.Equal("agent-1", activity.AgentId);
|
||||
Assert.Equal("Primary", activity.AgentName);
|
||||
Assert.Equal(command.RequestId, activity.RequestId);
|
||||
Assert.Equal(command.SessionId, activity.SessionId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObserveSessionEvent_AssistantMessageWithToolRequests_QueuesMessageReclassifiedEvent()
|
||||
{
|
||||
|
||||
@@ -945,6 +945,54 @@ public sealed class CopilotWorkflowRunnerTests
|
||||
Assert.Equal("InvalidOperationException", diagnostic.ExceptionType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleWorkflowEventAsync_QueuesCompletedActivityForCompletedExecutor()
|
||||
{
|
||||
RunTurnCommandDto command = CreateApprovalCommand();
|
||||
CopilotTurnExecutionState state = new(command);
|
||||
WorkflowNodeDto primaryAgent = command.Workflow.GetAgentNodes()[0];
|
||||
|
||||
state.ObserveSessionEvent(
|
||||
primaryAgent,
|
||||
SessionEvent.FromJson(
|
||||
"""
|
||||
{
|
||||
"type": "assistant.message_delta",
|
||||
"data": {
|
||||
"messageId": "msg-1",
|
||||
"deltaContent": "Working"
|
||||
},
|
||||
"id": "11111111-1111-1111-1111-111111111111",
|
||||
"timestamp": "2026-03-27T00:00:00Z"
|
||||
}
|
||||
"""));
|
||||
_ = state.DrainPendingEvents();
|
||||
|
||||
MethodInfo handleWorkflowEvent = typeof(CopilotWorkflowRunner).GetMethod(
|
||||
"HandleWorkflowEventAsync",
|
||||
BindingFlags.NonPublic | BindingFlags.Static)!;
|
||||
Task<bool> handleTask = (Task<bool>)handleWorkflowEvent.Invoke(
|
||||
null,
|
||||
[
|
||||
command,
|
||||
new ExecutorCompletedEvent("agent-1", null),
|
||||
Array.Empty<ChatMessage>(),
|
||||
state,
|
||||
(Func<TurnDeltaEventDto, Task>)(_ => Task.CompletedTask),
|
||||
(Func<SidecarEventDto, Task>)(_ => Task.CompletedTask),
|
||||
])!;
|
||||
|
||||
bool shouldEndTurn = await handleTask;
|
||||
|
||||
Assert.False(shouldEndTurn);
|
||||
Assert.Null(state.ActiveAgent);
|
||||
|
||||
AgentActivityEventDto completed = Assert.Single(state.DrainPendingEvents().OfType<AgentActivityEventDto>());
|
||||
Assert.Equal("completed", completed.ActivityType);
|
||||
Assert.Equal("agent-1", completed.AgentId);
|
||||
Assert.Equal("Primary", completed.AgentName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleWorkflowEventAsync_EmitsWorkflowWarningDiagnostic()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user