elsa-core/test/unit/Elsa.AI.Copilot.UnitTests/ElsaCopilotToolFunctionTests.cs
2026-06-08 00:35:47 +02:00

92 lines
3.3 KiB
C#

using Elsa.AI.Abstractions.Contracts;
using Elsa.AI.Abstractions.Models;
using Elsa.AI.Copilot.Adapters;
using GitHub.Copilot;
using Microsoft.Extensions.AI;
using System.Text.Json.Nodes;
namespace Elsa.AI.Copilot.UnitTests;
public class ElsaCopilotToolFunctionTests
{
[Fact(DisplayName = "Tool function preserves Elsa metadata and schema")]
public void ToolFunctionPreservesElsaMetadataAndSchema()
{
var definition = CreateDefinition();
var function = new ElsaCopilotToolFunction(definition, new CapturingToolInvoker());
Assert.Equal("workflow.inspect", function.Name);
Assert.Equal("Inspect workflow", function.Description);
Assert.Equal("workflowId", function.JsonSchema.GetProperty("required")[0].GetString());
var additionalProperties = function.AdditionalProperties!;
Assert.Equal("Proposal", additionalProperties["elsa_mutability"]);
Assert.Equal("Medium", additionalProperties["elsa_danger_level"]);
Assert.False((bool)additionalProperties["skip_permission"]!);
}
[Fact(DisplayName = "Tool function invokes Elsa provider tool invoker")]
public async Task ToolFunctionInvokesElsaProviderToolInvoker()
{
var invoker = new CapturingToolInvoker();
var function = new ElsaCopilotToolFunction(CreateDefinition(), invoker);
var arguments = new AIFunctionArguments(new Dictionary<string, object?>
{
["workflowId"] = "workflow-1"
})
{
Context = new Dictionary<object, object?>
{
["copilotInvocation"] = new ToolInvocation
{
ToolCallId = "sdk-tool-call-1"
}
}
};
var result = await function.InvokeAsync(arguments);
var toolResult = Assert.IsType<ToolResultAIContent>(result);
Assert.Equal("Workflow inspected", toolResult.Result.TextResultForLlm);
var invocation = Assert.Single(invoker.Invocations);
Assert.Equal("sdk-tool-call-1", invocation.Id);
Assert.Equal("workflow.inspect", invocation.ToolName);
Assert.Equal("workflow-1", invocation.Arguments["workflowId"]!.GetValue<string>());
}
private static AIToolDefinition CreateDefinition() =>
new()
{
Name = "workflow.inspect",
Description = "Inspect workflow",
Mutability = AIToolMutability.Proposal,
DangerLevel = AIToolDangerLevel.Medium,
Schema = new JsonObject
{
["type"] = "object",
["required"] = new JsonArray("workflowId"),
["properties"] = new JsonObject
{
["workflowId"] = new JsonObject
{
["type"] = "string"
}
}
}
};
private class CapturingToolInvoker : IAIProviderToolInvoker
{
public List<AIProviderToolInvocation> Invocations { get; } = [];
public ValueTask<AIToolResult> InvokeAsync(AIProviderToolInvocation invocation, CancellationToken cancellationToken = default)
{
Invocations.Add(invocation);
return ValueTask.FromResult(new AIToolResult
{
Summary = "Workflow inspected"
});
}
}
}