75 lines
3.2 KiB
C#
75 lines
3.2 KiB
C#
using System.Text;
|
|
using System.Text.Json;
|
|
using A2A;
|
|
using Volcanic.AgenticCore.A2A.Server.Agent;
|
|
using Volcanic.AgenticCore.A2A.Server.Callers;
|
|
|
|
namespace Volcanic.AgenticCore.A2A.Server.Tests;
|
|
|
|
public sealed class PromptTests : IDisposable
|
|
{
|
|
private readonly string _ws = Path.Combine(Path.GetTempPath(), "a2a-prompt", Guid.NewGuid().ToString("N"));
|
|
private A2ACaller Caller => new("travel-bot", "isolated", _ws, "p", "1");
|
|
|
|
private static Message Msg(params Part[] parts) => new() { Role = Role.User, MessageId = "m", Parts = [.. parts] };
|
|
|
|
[Fact]
|
|
public async Task Prompt_HasFramingHeader_AndText()
|
|
{
|
|
var text = await A2APrompt.BuildAsync(Caller, Msg(Part.FromText("Book a table")), true, 1024, new HttpClient(), TimeProvider.System, default);
|
|
Assert.StartsWith("[A2A message from \"travel-bot\", an external agent, not your owner.", text);
|
|
Assert.Contains("Book a table", text);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true)]
|
|
[InlineData(false)]
|
|
public async Task Header_MentionsNotifyOwner_OnlyWhenTheToolExists(bool canNotifyOwner)
|
|
{
|
|
var text = await A2APrompt.BuildAsync(Caller, Msg(Part.FromText("hi")), canNotifyOwner, 1024, new HttpClient(), TimeProvider.System, default);
|
|
var header = text.Split('\n')[0];
|
|
Assert.Equal(canNotifyOwner, header.Contains("notify_owner"));
|
|
Assert.Contains("request_input to ask the caller a question.]", header);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Files_InboundPart_SavedToInbox()
|
|
{
|
|
var part = Part.FromRaw(Encoding.UTF8.GetBytes("hello"), "text/plain", "../../plan.txt");
|
|
var text = await A2APrompt.BuildAsync(Caller, Msg(Part.FromText("see file"), part), true, 1024, new HttpClient(), TimeProvider.System, default);
|
|
var line = text.Split('\n').Single(l => l.StartsWith("Files: "));
|
|
var relative = line["Files: ".Length..];
|
|
Assert.StartsWith("inbox/a2a-travel-bot-", relative);
|
|
Assert.EndsWith("-plan.txt", relative);
|
|
Assert.Equal("hello", File.ReadAllText(Path.Combine(_ws, relative)));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Files_BadUrl_Throws()
|
|
{
|
|
var part = Part.FromUrl("not a url", "text/plain", null);
|
|
await Assert.ThrowsAsync<A2APromptException>(() =>
|
|
A2APrompt.BuildAsync(Caller, Msg(part), true, 1024, new HttpClient(), TimeProvider.System, default));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DataPart_BecomesFencedJson()
|
|
{
|
|
using var doc = JsonDocument.Parse("""{"a":1}""");
|
|
var text = await A2APrompt.BuildAsync(Caller, Msg(Part.FromData(doc.RootElement.Clone())), true, 1024, new HttpClient(), TimeProvider.System, default);
|
|
Assert.Contains("```json\n{\"a\":1}\n```", text);
|
|
}
|
|
|
|
[Fact]
|
|
public void Hops_ReadsNumberOrString_DefaultZero()
|
|
{
|
|
Assert.Equal(0, Hops.Read(null, null));
|
|
var meta = new Dictionary<string, JsonElement> { [Hops.Key] = JsonSerializer.SerializeToElement(2) };
|
|
Assert.Equal(2, Hops.Read(meta, null));
|
|
var asString = new Dictionary<string, JsonElement> { [Hops.Key] = JsonSerializer.SerializeToElement("3") };
|
|
Assert.Equal(3, Hops.Read(null, asString));
|
|
}
|
|
|
|
public void Dispose() { try { Directory.Delete(_ws, true); } catch (IOException) { } }
|
|
}
|