Skip to content

Commit 014d788

Browse files
gunpal5Gunpal Jain
andauthored
feat: Added M.E.A.I. AIFunction Generation support (#24)
* fix: Json Schema Generation, used System.Text.Json JsonSchema generation. * fix: warning suppressions * feat: Added FunctionTool attribute, which can be used to convert individual methods to Tools. * feat: Added GoogleFunctionTool optional parameters in GenerateJsonSchemaAttribute.cs and FunctionToolAttribute.cs * Updated README.md * fix: schema generation * removed uncessary variable * feat: Added M.E.A.I AIFunction generation * Simplify description retrieval in SchemaSubsetHelper. Replaced direct dictionary access with TryGetValue to prevent potential KeyNotFound exceptions. This ensures safer and more robust handling of missing keys when fetching "mainFunction_Desc". * Refactor MeaiFunction.cs for improved readability Removed unnecessary try-catch block around async call invocation and adjusted formatting for better code clarity. Minor whitespace and indentation improvements were also made to enhance consistency and maintainability. * Refactor MeaiFunction to enhance clarity and functionality. Added detailed XML documentation for MeaiFunction class and its members, improving code readability and maintainability. Introduced support for strict mode and updated method implementations to enhance functionality. These changes provide better structure and guidance for future development. * Update GoogleFunctionTool type references in generator Replaced GenericFunctionTool with GoogleFunctionTool to align with the updated namespace and class structure. This ensures compatibility with the latest library changes and maintains consistency in functionality. --------- Co-authored-by: Gunpal Jain <[email protected]>
1 parent 14f9a0c commit 014d788

19 files changed

+705
-24
lines changed

CSharpToJsonSchema.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpToJsonSchema.Integrat
4242
EndProject
4343
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpToJsonSchema.AotTests", "src\tests\CSharpToJsonSchema.AotTests\CSharpToJsonSchema.AotTests.csproj", "{6167F915-83EB-42F9-929B-AD4719A55811}"
4444
EndProject
45+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpToJsonSchema.MeaiTests", "src\tests\CSharpToJsonSchema.MeaiTests\CSharpToJsonSchema.MeaiTests.csproj", "{DC07C90E-A58C-44B3-82D2-E2EB8F777B92}"
46+
EndProject
4547
Global
4648
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4749
Debug|Any CPU = Debug|Any CPU
@@ -76,6 +78,10 @@ Global
7678
{6167F915-83EB-42F9-929B-AD4719A55811}.Debug|Any CPU.Build.0 = Debug|Any CPU
7779
{6167F915-83EB-42F9-929B-AD4719A55811}.Release|Any CPU.ActiveCfg = Release|Any CPU
7880
{6167F915-83EB-42F9-929B-AD4719A55811}.Release|Any CPU.Build.0 = Release|Any CPU
81+
{DC07C90E-A58C-44B3-82D2-E2EB8F777B92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
82+
{DC07C90E-A58C-44B3-82D2-E2EB8F777B92}.Debug|Any CPU.Build.0 = Debug|Any CPU
83+
{DC07C90E-A58C-44B3-82D2-E2EB8F777B92}.Release|Any CPU.ActiveCfg = Release|Any CPU
84+
{DC07C90E-A58C-44B3-82D2-E2EB8F777B92}.Release|Any CPU.Build.0 = Release|Any CPU
7985
EndGlobalSection
8086
GlobalSection(SolutionProperties) = preSolution
8187
HideSolutionNode = FALSE
@@ -89,6 +95,7 @@ Global
8995
{8AFCC30C-C59D-498D-BE68-9A328B3E5599} = {AAA11B78-2764-4520-A97E-46AA7089A588}
9096
{247C813A-9072-4DF3-B403-B35E3688DB4B} = {AAA11B78-2764-4520-A97E-46AA7089A588}
9197
{6167F915-83EB-42F9-929B-AD4719A55811} = {AAA11B78-2764-4520-A97E-46AA7089A588}
98+
{DC07C90E-A58C-44B3-82D2-E2EB8F777B92} = {AAA11B78-2764-4520-A97E-46AA7089A588}
9299
EndGlobalSection
93100
GlobalSection(ExtensibilityGlobals) = postSolution
94101
SolutionGuid = {CED9A020-DBA5-4BE6-8096-75E528648EC1}

src/libs/CSharpToJsonSchema.Generators/Conversion/ToModels.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public static InterfaceData PrepareData(
1818
strict;
1919
var generateGoogleFunctionTool = attributeData.NamedArguments.FirstOrDefault(x => x.Key == "GoogleFunctionTool").Value.Value is bool googleFunctionTool &&
2020
googleFunctionTool;
21+
var meaiFunctionTool= attributeData.NamedArguments.FirstOrDefault(x => x.Key == "MeaiFunctionTool").Value.Value is bool meaift &&
22+
meaift;
2123
var methods = interfaceSymbol
2224
.GetMembers()
2325
.OfType<IMethodSymbol>()
@@ -46,6 +48,7 @@ public static InterfaceData PrepareData(
4648
Namespace: interfaceSymbol.ContainingNamespace.ToDisplayString(),
4749
Name: interfaceSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
4850
GoogleFunctionTool:generateGoogleFunctionTool,
51+
MeaiFunctionTool:meaiFunctionTool,
4952
Methods: methods);
5053
}
5154

@@ -60,6 +63,7 @@ public static InterfaceData PrepareMethodData(
6063
List<MethodData> methodList = new();
6164
List<string> namespaces = new();
6265
bool generateGoogleFunctionTools = false;
66+
bool meaiFunctionTools = false;
6367
foreach (var l in list)
6468
{
6569
var (interfaceSymbol, attributeData) = l;
@@ -70,6 +74,11 @@ public static InterfaceData PrepareMethodData(
7074
if(ggft)
7175
generateGoogleFunctionTools = true;
7276

77+
var meai = attributeData.NamedArguments.FirstOrDefault(x => x.Key == "MeaiFunctionTool").Value.Value is bool meaift &&
78+
meaift;
79+
if(meai)
80+
meaiFunctionTools = true;
81+
7382
var x = interfaceSymbol;
7483
var parameters = x.Parameters
7584
//.Where(static x => x.Type.MetadataName != "CancellationToken")
@@ -94,6 +103,7 @@ public static InterfaceData PrepareMethodData(
94103
Namespace: GetCommonRootNamespace(namespaces)??namespaceName,
95104
Name: className,
96105
GoogleFunctionTool: generateGoogleFunctionTools,
106+
MeaiFunctionTool:meaiFunctionTools,
97107
Methods: methodList.ToArray());
98108
}
99109
public static string? GetCommonRootNamespace(IEnumerable<string> namespaces)

src/libs/CSharpToJsonSchema.Generators/JsonSchemaGenerator.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ private void ProcessMethods(IncrementalGeneratorInitializationContext context)
5050
attributes
5151
.SelectAndReportExceptions(AsGoogleFunctionToolsForMethods, context, Id)
5252
.AddSource(context);
53+
attributes
54+
.SelectAndReportExceptions(AsMeaiFunctionToolsForMethods, context, Id)
55+
.AddSource(context);
5356

5457
var generator = new JsonSourceGenerator();
5558
generator.InitializeForFunctionTools(context);
@@ -73,6 +76,9 @@ private void ProcessInterfaces(IncrementalGeneratorInitializationContext context
7376
attributes
7477
.SelectAndReportExceptions(AsGoogleFunctionToolsForInterface, context, Id)
7578
.AddSource(context);
79+
attributes
80+
.SelectAndReportExceptions(AsMeaiFunctionToolsForInterface, context, Id)
81+
.AddSource(context);
7682

7783
var generator = new JsonSourceGenerator();
7884
generator.Initialize2(context);
@@ -119,14 +125,28 @@ private static FileWithName AsFunctionCalls(InterfaceData @interface)
119125
Name: $"{@interface.Name}.FunctionCalls.generated.cs",
120126
Text: Sources.GenerateFunctionCalls(@interface));
121127
}
122-
128+
123129
private static FileWithName AsGoogleFunctionToolsForMethods(InterfaceData @interface)
124130
{
125131
return new FileWithName(
126132
Name: $"{@interface.Name}.GoogleFunctionTools.generated.cs",
127133
Text: Sources.GenerateGoogleFunctionToolForMethods(@interface));
128134
}
129135

136+
private static FileWithName AsMeaiFunctionToolsForMethods(InterfaceData @interface)
137+
{
138+
return new FileWithName(
139+
Name: $"{@interface.Name}.MeaiTools.generated.cs",
140+
Text: Sources.GenerateMeaiFunctionToolForMethods(@interface));
141+
}
142+
143+
private static FileWithName AsMeaiFunctionToolsForInterface(InterfaceData @interface)
144+
{
145+
return new FileWithName(
146+
Name: $"{@interface.Name}.MeaiToolsExtensions.generated.cs",
147+
Text: Sources.GenerateMeaiFunctionToolForInterface(@interface));
148+
}
149+
130150
private static FileWithName AsGoogleFunctionToolsForInterface(InterfaceData @interface)
131151
{
132152
return new FileWithName(

src/libs/CSharpToJsonSchema.Generators/Models/InterfaceData.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ public readonly record struct InterfaceData(
44
string Namespace,
55
string Name,
66
bool GoogleFunctionTool,
7+
bool MeaiFunctionTool,
78
IReadOnlyCollection<MethodData> Methods);

src/libs/CSharpToJsonSchema.Generators/Sources.Method.Calls.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ public static string GenerateFunctionCalls(InterfaceData @interface)
1717
1818
namespace {@interface.Namespace}
1919
{{
20+
21+
22+
23+
24+
25+
26+
27+
2028
{@interface.Methods.Select(static method => $@"
2129
public class {method.Name}Args
2230
{{

src/libs/CSharpToJsonSchema.Generators/Sources.Method.GoogleFunctionTools.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ namespace {@interface.Namespace}
1818
{{
1919
public partial class {extensionsClassName}
2020
{{
21-
public static implicit operator global::GenerativeAI.Tools.GenericFunctionTool ({@interface.Namespace}.{extensionsClassName} tools)
21+
public static implicit operator global::GenerativeAI.Core.GoogleFunctionTool ({@interface.Namespace}.{extensionsClassName} tools)
2222
{{
2323
return tools.AsGoogleFunctionTool();
2424
}}
2525
26-
public global::GenerativeAI.Tools.GenericFunctionTool AsGoogleFunctionTool()
26+
public global::GenerativeAI.Core.GoogleFunctionTool AsGoogleFunctionTool()
2727
{{
2828
return new global::GenerativeAI.Tools.GenericFunctionTool(this.AsTools(), this.AsCalls());
2929
}}
@@ -42,9 +42,9 @@ public static string GenerateGoogleFunctionToolForInterface(InterfaceData @inter
4242
4343
namespace {@interface.Namespace}
4444
{{
45-
public partial class {extensionsClassName}
45+
public static partial class {extensionsClassName}
4646
{{
47-
public global::GenerativeAI.Core.IFunctionTool AsGoogleFunctionTool(this {@interface.Name} service)
47+
public static global::GenerativeAI.Core.IFunctionTool AsGoogleFunctionTool(this {@interface.Name} service)
4848
{{
4949
return new global::GenerativeAI.Tools.GenericFunctionTool(service.AsTools(), service.AsCalls());
5050
}}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using CSharpToJsonSchema.Generators.Models;
2+
3+
namespace CSharpToJsonSchema.Generators;
4+
5+
internal static partial class Sources
6+
{
7+
public static string GenerateMeaiFunctionToolForMethods(InterfaceData @interface)
8+
{
9+
if(@interface.Methods.Count == 0 || !@interface.MeaiFunctionTool)
10+
return string.Empty;
11+
var extensionsClassName = @interface.Name;
12+
13+
return @$"
14+
#nullable enable
15+
16+
namespace {@interface.Namespace}
17+
{{
18+
public partial class {extensionsClassName}
19+
{{
20+
public static implicit operator global::System.Collections.Generic.List<global::Microsoft.Extensions.AI.AITool>? ({@interface.Namespace}.{extensionsClassName} tools)
21+
{{
22+
return tools.AsMeaiTools();
23+
}}
24+
25+
public global::System.Collections.Generic.List<global::Microsoft.Extensions.AI.AITool> AsMeaiTools()
26+
{{
27+
var lst = new global::System.Collections.Generic.List<global::Microsoft.Extensions.AI.AITool>();
28+
var tools = this.AsTools();
29+
var calls = this.AsCalls();
30+
foreach (var tool in tools)
31+
{{
32+
var call = calls[tool.Name];
33+
lst.Add(new global::CSharpToJsonSchema.MeaiFunction(tool, call));
34+
}}
35+
return lst;
36+
}}
37+
}}
38+
}}";
39+
}
40+
41+
public static string GenerateMeaiFunctionToolForInterface(InterfaceData @interface)
42+
{
43+
if(!@interface.MeaiFunctionTool)
44+
return string.Empty;
45+
var extensionsClassName = @interface.Name.Substring(startIndex: 1) + "Extensions";
46+
47+
return @$"
48+
#nullable enable
49+
50+
namespace {@interface.Namespace}
51+
{{
52+
public partial class {extensionsClassName}
53+
{{
54+
public static global::System.Collections.Generic.List<global::Microsoft.Extensions.AI.AITool> AsMeaiTools(this {@interface.Name} service)
55+
{{
56+
var lst = new global::System.Collections.Generic.List<global::Microsoft.Extensions.AI.AITool>();
57+
var tools = service.AsTools();
58+
var calls = service.AsCalls();
59+
foreach (var tool in tools)
60+
{{
61+
var call = calls[tool.Name];
62+
lst.Add(new global::CSharpToJsonSchema.MeaiFunction(tool, call));
63+
}}
64+
return lst;
65+
}}
66+
}}
67+
}}";
68+
}
69+
}

src/libs/CSharpToJsonSchema/CSharpToJsonSchema.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
</PropertyGroup>
1818

1919
<ItemGroup>
20+
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="9.3.0-preview.1.25114.11" />
2021
<PackageReference Include="System.Text.Json" Version="9.0.0" />
2122
</ItemGroup>
2223

src/libs/CSharpToJsonSchema/FunctionToolAttribute.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,9 @@ public sealed class FunctionToolAttribute : Attribute
1616
/// Generate Google Function Tools extensions for Google_GenerativeAI SDK
1717
/// </summary>
1818
public bool GoogleFunctionTool { get; set; }
19+
20+
/// <summary>
21+
/// Generate Microsoft.Extension.AI compatible function tools
22+
/// </summary>
23+
public bool MeaiFunctionTool { get; set; }
1924
}

src/libs/CSharpToJsonSchema/GenerateJsonSchemaAttribute.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,9 @@ public sealed class GenerateJsonSchemaAttribute : Attribute
1717
/// Generate Google Function Tools extensions for Google_GenerativeAI SDK
1818
/// </summary>
1919
public bool GoogleFunctionTool { get; set; }
20+
21+
/// <summary>
22+
/// Generate Microsoft.Extension.AI compatible function tools
23+
/// </summary>
24+
public bool MeaiFunctionTool { get; set; }
2025
}

0 commit comments

Comments
 (0)