-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathCopilotToolTests.cs
More file actions
138 lines (119 loc) · 4.94 KB
/
CopilotToolTests.cs
File metadata and controls
138 lines (119 loc) · 4.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------------------------------------------*/
using Microsoft.Extensions.AI;
using System.ComponentModel;
using System.Text.Json;
using Xunit;
namespace GitHub.Copilot.Test.Unit;
public class CopilotToolTests
{
[Fact]
public void DefineTool_Sets_Name_Description_And_Copilot_Metadata()
{
var function = CopilotTool.DefineTool(
ReturnsOk,
new CopilotToolOptions
{
OverridesBuiltInTool = true,
SkipPermission = true
});
Assert.Equal("test_tool", function.Name);
Assert.Equal("Test tool", function.Description);
Assert.True(function.AdditionalProperties.TryGetValue("is_override", out var isOverride));
Assert.True((bool)isOverride!);
Assert.True(function.AdditionalProperties.TryGetValue("skip_permission", out var skipPermission));
Assert.True((bool)skipPermission!);
}
[Fact]
public void DefineTool_Omits_Copilot_Metadata_When_Flags_Are_False()
{
var function = CopilotTool.DefineTool(ReturnsOk);
Assert.False(function.AdditionalProperties.ContainsKey("is_override"));
Assert.False(function.AdditionalProperties.ContainsKey("skip_permission"));
}
[Fact]
public void DefineTool_Accepts_Lambda_Handlers_Without_Casts()
{
var function = CopilotTool.DefineTool((string value) => value, factoryOptions: new() { Name = "echo", Description = "Echo a value" });
Assert.Equal("echo", function.Name);
}
[Fact]
public async Task DefineTool_Binds_ToolInvocation_And_Excludes_It_From_Schema()
{
var function = CopilotTool.DefineTool(
(string value, ToolInvocation invocation) => $"{value}:{invocation.ToolName}",
factoryOptions: new() { Name = "echo", Description = "Echo a value" });
var schema = function.JsonSchema.GetRawText();
Assert.Contains("\"value\"", schema);
Assert.DoesNotContain("\"invocation\"", schema);
using var document = JsonDocument.Parse("\"hello\"");
var result = await function.InvokeAsync(new AIFunctionArguments
{
["value"] = document.RootElement.Clone(),
Context = new Dictionary<object, object?>
{
[typeof(ToolInvocation)] = new ToolInvocation { ToolName = "echo" }
}
});
Assert.Equal("hello:echo", Assert.IsType<JsonElement>(result).GetString());
}
[Fact]
public async Task DefineTool_Preserves_Custom_Parameter_Binding()
{
var function = CopilotTool.DefineTool(
(string value, string suffix, ToolInvocation invocation) => $"{value}:{suffix}:{invocation.ToolName}",
factoryOptions: new()
{
Name = "echo",
Description = "Echo a value",
ConfigureParameterBinding = pi =>
pi.Name == "suffix"
? new AIFunctionFactoryOptions.ParameterBindingOptions
{
ExcludeFromSchema = true,
BindParameter = static (_, _) => "bound"
}
: default
});
var schema = function.JsonSchema.GetRawText();
Assert.Contains("\"value\"", schema);
Assert.DoesNotContain("\"suffix\"", schema);
Assert.DoesNotContain("\"invocation\"", schema);
using var document = JsonDocument.Parse("\"hello\"");
var result = await function.InvokeAsync(new AIFunctionArguments
{
["value"] = document.RootElement.Clone(),
Context = new Dictionary<object, object?>
{
[typeof(ToolInvocation)] = new ToolInvocation { ToolName = "echo" }
}
});
Assert.Equal("hello:bound:echo", Assert.IsType<JsonElement>(result).GetString());
}
[Fact]
public void DefineTool_Preserves_Additional_Properties_And_ToolOptions_Take_Precedence()
{
var function = CopilotTool.DefineTool(
ReturnsOk,
new CopilotToolOptions
{
SkipPermission = true
},
new AIFunctionFactoryOptions
{
Name = "test_tool",
AdditionalProperties = new Dictionary<string, object?>
{
["custom"] = 42,
["skip_permission"] = false,
}
});
Assert.Equal(42, function.AdditionalProperties["custom"]);
Assert.True(function.AdditionalProperties.TryGetValue("skip_permission", out var skipPermission));
Assert.True((bool)skipPermission!);
}
[DisplayName("test_tool")]
[Description("Test tool")]
private static string ReturnsOk() => "ok";
}