Files
VolcanicAgenticCore/tests/Volcanic.AgenticCore.Extensions.Tests/A2A/A2AHopsTests.cs

50 lines
2.1 KiB
C#

using Volcanic.AgenticCore.Abstractions.Extensions;
using Volcanic.AgenticCore.Abstractions.Extensions.Events;
using Volcanic.AgenticCore.Abstractions.Json;
using Volcanic.AgenticCore.Extensions.A2A;
using Volcanic.AgenticCore.Extensions.Tests.A2A.Support;
using Volcanic.AgenticCore.Testing;
namespace Volcanic.AgenticCore.Extensions.Tests.A2A;
public class A2AHopsTests
{
/// <summary>Plays the server's per-session extension: emits a2a.inbound like an inbound A2A run would.</summary>
private sealed class InboundEmitter(int hops) : IExtension
{
public string Name => "inbound-emitter";
public ValueTask ActivateAsync(IExtensionApi api, CancellationToken cancellationToken)
{
api.On<BeforeAgentStartEvent>((_, _, _) =>
{
api.Events.Emit(A2AClientExtension.InboundChannel, VolcanicJson.ToElement(new { hops, caller = "upstream" }));
return ValueTask.CompletedTask;
});
return ValueTask.CompletedTask;
}
}
[Fact]
public async Task Hops_Incremented_WithoutInbound()
{
await using var remote = await RemoteAgentServer.StartAsync(o => o.MaxHops = 1);
remote.Faux.Enqueue(FauxTurn.Say("fine"));
await using var host = new A2AClientHost(remote);
var session = await host.CreateSessionAsync();
var (text, _) = await host.CallToolAsync(session, new { action = "send", agent = "remote", message = "hi" });
Assert.Contains("completed", text); // sent with hops 1, allowed at MaxHops 1
}
[Fact]
public async Task Hops_FromInboundEvent()
{
await using var remote = await RemoteAgentServer.StartAsync(o => o.MaxHops = 3);
await using var host = new A2AClientHost(remote, null, new InboundEmitter(3));
var session = await host.CreateSessionAsync();
var (text, _) = await host.CallToolAsync(session, new { action = "send", agent = "remote", message = "hi" });
Assert.Contains("failed", text);
Assert.Contains("hop limit", text);
Assert.Empty(remote.Faux.Requests);
}
}