microsoft/teams.net

Public

mirrored fromhttps://github.com/microsoft/teams.netAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
fix/msal-cache

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

Libraries/Microsoft.Teams.AI/Function.cs

157lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT License.
3
4using System.Reflection;
5using System.Text.Json;
6using System.Text.Json.Nodes;
7using System.Text.Json.Serialization;
8
9using Json.Schema;
10using Json.Schema.Generation;
11
12using Microsoft.Teams.AI.Annotations;
13using Microsoft.Teams.AI.Messages;
14using Microsoft.Teams.Common.Extensions;
15using Microsoft.Teams.Common.Json;
16
17namespace Microsoft.Teams.AI;
18
19/// <summary>
20/// defines a block of code that
21/// can be called by a model
22/// </summary>
23[JsonConverter(typeof(TrueTypeJsonConverter<IFunction>))]
24[Obsolete("Microsoft.Teams.AI is deprecated and will be removed by end of summer 2026.")]
25public interface IFunction
26{
27 /// <summary>
28 /// the unique name
29 /// </summary>
30 public string Name { get; }
31
32 /// <summary>
33 /// a description of what the function
34 /// should be used for
35 /// </summary>
36 public string? Description { get; }
37
38 /// <summary>
39 /// the Json Schema representing what
40 /// parameters the function accepts
41 /// </summary>
42 public JsonSchema? Parameters { get; }
43}
44
45/// <summary>
46/// defines a block of code that
47/// can be called by a model
48/// </summary>
49[Obsolete("Microsoft.Teams.AI is deprecated and will be removed by end of summer 2026.")]
50public class Function : IFunction
51{
52 [JsonPropertyName("name")]
53 [JsonPropertyOrder(0)]
54 public string Name { get; set; }
55
56 [JsonPropertyName("description")]
57 [JsonPropertyOrder(1)]
58 public string? Description { get; set; }
59
60 [JsonPropertyName("parameters")]
61 [JsonPropertyOrder(2)]
62 public JsonSchema? Parameters { get; set; }
63
64 [JsonIgnore]
65 public Delegate Handler { get; set; }
66
67 public Function(string name, string? description, Delegate handler)
68 {
69 Name = name;
70 Description = description;
71 Handler = handler;
72 Parameters = GenerateParametersSchema(handler);
73 }
74
75 public Function(string name, string? description, JsonSchema parameters, Delegate handler)
76 {
77 Name = name;
78 Description = description;
79 Parameters = parameters;
80 Handler = handler;
81 }
82
83 internal Task<object?> Invoke(FunctionCall call)
84 {
85 if (call.Arguments is not null && Parameters is not null)
86 {
87 var valid = Parameters.Evaluate(JsonNode.Parse(call.Arguments), new() { EvaluateAs = SpecVersion.DraftNext });
88
89 if (!valid.IsValid)
90 {
91 Console.WriteLine(JsonSerializer.Serialize(valid));
92 throw new ArgumentException(
93 string.Join("\n", valid.Errors?.Select(e => $"{e.Key} => {e.Value}") ?? [])
94 );
95 }
96 }
97
98 var args = call.Parse() ?? new Dictionary<string, object?>();
99 var method = Handler.GetMethodInfo();
100 var parameters = method.GetParameters().Select(param =>
101 {
102 var name = param.GetCustomAttribute<ParamAttribute>()?.Name ?? param.Name ?? param.Position.ToString();
103 args.TryGetValue(name, out var value);
104
105 if (value is JsonElement element)
106 {
107 return element.Deserialize(param.ParameterType);
108 }
109
110 // Special param type to get the arguments dictionary (IDictionary<string, object?> args)
111 if (value is null && name == "args" && param.ParameterType == typeof(IDictionary<string, object?>))
112 {
113 value = args;
114 }
115
116 return value;
117 }).ToArray();
118
119 return method.InvokeAsync(Handler.Target, parameters);
120 }
121
122 public override string ToString()
123 {
124 return JsonSerializer.Serialize(this, new JsonSerializerOptions()
125 {
126 WriteIndented = true
127 });
128 }
129
130 /// <summary>
131 /// Generates a JsonSchema for the parameters of a delegate handler using reflection
132 /// </summary>
133 private static JsonSchema? GenerateParametersSchema(Delegate handler)
134 {
135 var method = handler.GetMethodInfo();
136 var methodParams = method.GetParameters();
137
138 if (methodParams.Length == 0)
139 {
140 return null;
141 }
142
143 var parameters = methodParams.Select(p =>
144 {
145 var paramName = p.GetCustomAttribute<ParamAttribute>()?.Name ?? p.Name ?? p.Position.ToString();
146 var schema = new JsonSchemaBuilder().FromType(p.ParameterType).Build();
147 var required = !p.IsOptional;
148 return (paramName, schema, required);
149 });
150
151 return new JsonSchemaBuilder()
152 .Type(SchemaValueType.Object)
153 .Properties(parameters.Select(item => (item.paramName, item.schema)).ToArray())
154 .Required(parameters.Where(item => item.required).Select(item => item.paramName))
155 .Build();
156 }
157}