From 0772925ab3eb0a0d7dfe15e07bba802638399f9f Mon Sep 17 00:00:00 2001 From: Prithvi Prathapan Date: Tue, 2 Jul 2024 18:28:57 -0700 Subject: [PATCH 1/5] Update FunctionCallTemplate.tt changed the desscription assigning to handle double quotes in comments and prevent the generated code from breaking. --- .../AutoGen.SourceGenerator/Template/FunctionCallTemplate.tt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/src/AutoGen.SourceGenerator/Template/FunctionCallTemplate.tt b/dotnet/src/AutoGen.SourceGenerator/Template/FunctionCallTemplate.tt index 0d1b221c35c..ab255630a4f 100644 --- a/dotnet/src/AutoGen.SourceGenerator/Template/FunctionCallTemplate.tt +++ b/dotnet/src/AutoGen.SourceGenerator/Template/FunctionCallTemplate.tt @@ -81,7 +81,7 @@ namespace <#=NameSpace#> Name = @"<#=parameter.Name#>", <#}#> <#if (parameter.Description != null) {#> - Description = @"<#=parameter.Description#>", + Description = @"<#= parameter.Description.Replace("\"", "\"\"") #>", <#}#> <#if (parameter.Type != null) {#> ParameterType = typeof(<#=parameter.Type#>), From de863c12453dc22af14e60eb9d3d34bd187d9ead Mon Sep 17 00:00:00 2001 From: Prithvi Prathapan Date: Fri, 5 Jul 2024 02:28:08 -0700 Subject: [PATCH 2/5] Added the necessary changes Fixed handling of double quotes in descriptions within FunctionCallTemplate.tt. Standardized newline characters to ensure consistency. Updated test cases in FunctionCallTemplateEncodingTests to verify correct encoding of double quotes in descriptions. Cleaned up unnecessary using directives in FunctionCallTemplateEncodingTests. Aligned the template with the approved test output. --- .../Template/FunctionCallTemplate.cs | 479 +++++++----------- .../Template/FunctionCallTemplate.tt | 2 +- ...ests.TestFunctionCallTemplate.received.txt | 71 +++ .../FunctionCallTemplateEncodingTests.cs | 92 ++++ 4 files changed, 340 insertions(+), 304 deletions(-) create mode 100644 dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.received.txt create mode 100644 dotnet/test/AutoGen.SourceGenerator.Tests/FunctionCallTemplateEncodingTests.cs diff --git a/dotnet/src/AutoGen.SourceGenerator/Template/FunctionCallTemplate.cs b/dotnet/src/AutoGen.SourceGenerator/Template/FunctionCallTemplate.cs index 40adbdcde47..cb3574a8b1e 100644 --- a/dotnet/src/AutoGen.SourceGenerator/Template/FunctionCallTemplate.cs +++ b/dotnet/src/AutoGen.SourceGenerator/Template/FunctionCallTemplate.cs @@ -1,31 +1,30 @@ -// ------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version: 17.0.0.0 -// +// // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // -// ------------------------------------------------------------------------------ -namespace AutoGen.SourceGenerator.Template -{ +//------------------------------------------------------------------------------ + +namespace AutoGen.SourceGenerator.Template { using System.Linq; using System.Collections.Generic; using Microsoft.CodeAnalysis; using System; - /// - /// Class to produce the template output - /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")] - internal partial class FunctionCallTemplate : FunctionCallTemplateBase - { - /// - /// Create the template output - /// - public virtual string TransformText() - { - this.Write(""); + + internal partial class FunctionCallTemplate : FunctionCallTemplateBase { + + +public string NameSpace {get; set;} +public string ClassName {get; set;} +public IEnumerable FunctionContracts {get; set;} +public bool IsStatic {get; set;} = false; + + + public virtual string TransformText() { + this.GenerationEnvironment = null; this.Write(@"//---------------------- // // This code was generated by a tool. @@ -42,407 +41,281 @@ public virtual string TransformText() if (!String.IsNullOrEmpty(NameSpace)) { this.Write("namespace "); this.Write(this.ToStringHelper.ToStringWithCulture(NameSpace)); - this.Write("\r\n{\r\n"); + this.Write("\n{\n"); } this.Write(" public partial class "); this.Write(this.ToStringHelper.ToStringWithCulture(ClassName)); - this.Write("\r\n {\r\n"); + this.Write("\n {\n"); foreach (var functionContract in FunctionContracts) { - this.Write("\r\n private class "); + this.Write("\n private class "); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.GetFunctionSchemaClassName())); - this.Write("\r\n {\r\n"); + this.Write("\n {\n"); foreach (var parameter in functionContract.Parameters) { if (parameter.IsOptional) { this.Write(" [JsonPropertyName(@\""); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); - this.Write("\")]\r\n\t\t\tpublic "); + this.Write("\")]\n\t\t\tpublic "); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type)); this.Write(" "); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); this.Write(" {get; set;} = "); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.DefaultValue)); - this.Write(";\r\n"); + this.Write(";\n"); } else { this.Write(" [JsonPropertyName(@\""); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); - this.Write("\")]\r\n\t\t\tpublic "); + this.Write("\")]\n\t\t\tpublic "); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type)); this.Write(" "); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); - this.Write(" {get; set;}\r\n"); + this.Write(" {get; set;}\n"); } } - this.Write(" }\r\n\r\n public "); + this.Write(" }\n\n public "); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.ReturnType)); this.Write(" "); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.GetFunctionWrapperName())); - this.Write("(string arguments)\r\n {\r\n var schema = JsonSerializer.Deserializ" + - "e<"); + this.Write("(string arguments)\n {\n var schema = JsonSerializer.Deserialize<" + + ""); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.GetFunctionSchemaClassName())); - this.Write(">(\r\n arguments, \r\n new JsonSerializerOptions\r\n " + - " {\r\n PropertyNamingPolicy = JsonNamingPolicy.CamelC" + - "ase,\r\n });\r\n"); + this.Write(">(\n arguments, \n new JsonSerializerOptions\n " + + " {\n PropertyNamingPolicy = JsonNamingPolicy.CamelCase," + + "\n });\n"); var argumentLists = string.Join(", ", functionContract.Parameters.Select(p => $"schema.{p.Name}")); - this.Write("\r\n return "); + this.Write("\n return "); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.Name)); this.Write("("); this.Write(this.ToStringHelper.ToStringWithCulture(argumentLists)); - this.Write(");\r\n }\r\n\r\n public FunctionContract "); + this.Write(");\n }\n\n public FunctionContract "); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.GetFunctionContractName())); - this.Write("\r\n {\r\n get => new FunctionContract\r\n {\r\n"); + this.Write("\n {\n get => new FunctionContract\n {\n"); if (functionContract.Namespace != null) { this.Write(" Namespace = @\""); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.Namespace)); - this.Write("\",\r\n"); + this.Write("\",\n"); } if (functionContract.ClassName != null) { this.Write(" ClassName = @\""); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.ClassName)); - this.Write("\",\r\n"); + this.Write("\",\n"); } if (functionContract.Name != null) { this.Write(" Name = @\""); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.Name)); - this.Write("\",\r\n"); + this.Write("\",\n"); } if (functionContract.Description != null) { this.Write(" Description = @\""); - this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.Description)); - this.Write("\",\r\n"); + this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.Description.Replace("\"", "\"\""))); + this.Write("\",\n"); } if (functionContract.ReturnType != null) { this.Write(" ReturnType = typeof("); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.ReturnType)); - this.Write("),\r\n"); + this.Write("),\n"); } if (functionContract.ReturnDescription != null) { this.Write(" ReturnDescription = @\""); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.ReturnDescription)); - this.Write("\",\r\n"); + this.Write("\",\n"); } if (functionContract.Parameters != null) { this.Write(" Parameters = new global::AutoGen.Core.FunctionParameterContract[]" + - "\r\n {\r\n"); + "\n {\n"); foreach (var parameter in functionContract.Parameters) { - this.Write(" new FunctionParameterContract\r\n {\r\n"); + this.Write(" new FunctionParameterContract\n {\n"); if (parameter.Name != null) { this.Write(" Name = @\""); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); - this.Write("\",\r\n"); + this.Write("\",\n"); } if (parameter.Description != null) { this.Write(" Description = @\""); - this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Description)); - this.Write("\",\r\n"); + this.Write(this.ToStringHelper.ToStringWithCulture( parameter.Description.Replace("\"", "\"\"") )); + this.Write("\",\n"); } if (parameter.Type != null) { this.Write(" ParameterType = typeof("); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Type)); - this.Write("),\r\n"); + this.Write("),\n"); } this.Write(" IsRequired = "); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.IsOptional ? "false" : "true")); - this.Write(",\r\n"); + this.Write(",\n"); if (parameter.DefaultValue != null) { this.Write(" DefaultValue = "); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.DefaultValue)); - this.Write(",\r\n"); + this.Write(",\n"); } - this.Write(" },\r\n"); + this.Write(" },\n"); } - this.Write(" },\r\n"); + this.Write(" },\n"); } - this.Write(" };\r\n }\r\n\r\n public global::Azure.AI.OpenAI.FunctionDefin" + - "ition "); + this.Write(" };\n }\n\n public global::Azure.AI.OpenAI.FunctionDefiniti" + + "on "); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.GetFunctionDefinitionName())); - this.Write("\r\n {\r\n get => this."); + this.Write("\n {\n get => this."); this.Write(this.ToStringHelper.ToStringWithCulture(functionContract.GetFunctionContractName())); - this.Write(".ToOpenAIFunctionDefinition();\r\n }\r\n"); + this.Write(".ToOpenAIFunctionDefinition();\n }\n"); } - this.Write(" }\r\n"); + this.Write(" }\n"); if (!String.IsNullOrEmpty(NameSpace)) { - this.Write("}\r\n"); + this.Write("}\n"); } - this.Write("\r\n"); + this.Write("\n"); return this.GenerationEnvironment.ToString(); } - -public string NameSpace {get; set;} -public string ClassName {get; set;} -public IEnumerable FunctionContracts {get; set;} -public bool IsStatic {get; set;} = false; - + + public virtual void Initialize() { + } } - #region Base class - /// - /// Base class for this transformation - /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")] - internal class FunctionCallTemplateBase - { - #region Fields - private global::System.Text.StringBuilder generationEnvironmentField; - private global::System.CodeDom.Compiler.CompilerErrorCollection errorsField; - private global::System.Collections.Generic.List indentLengthsField; - private string currentIndentField = ""; - private bool endsWithNewline; - private global::System.Collections.Generic.IDictionary sessionField; - #endregion - #region Properties - /// - /// The string builder that generation-time code is using to assemble generated output - /// - public System.Text.StringBuilder GenerationEnvironment - { - get - { - if ((this.generationEnvironmentField == null)) - { - this.generationEnvironmentField = new global::System.Text.StringBuilder(); - } - return this.generationEnvironmentField; + + public class FunctionCallTemplateBase { + + private global::System.Text.StringBuilder builder; + + private global::System.Collections.Generic.IDictionary session; + + private global::System.CodeDom.Compiler.CompilerErrorCollection errors; + + private string currentIndent = string.Empty; + + private global::System.Collections.Generic.Stack indents; + + private ToStringInstanceHelper _toStringHelper = new ToStringInstanceHelper(); + + public virtual global::System.Collections.Generic.IDictionary Session { + get { + return this.session; } - set - { - this.generationEnvironmentField = value; + set { + this.session = value; } } - /// - /// The error collection for the generation process - /// - public System.CodeDom.Compiler.CompilerErrorCollection Errors - { - get - { - if ((this.errorsField == null)) - { - this.errorsField = new global::System.CodeDom.Compiler.CompilerErrorCollection(); + + public global::System.Text.StringBuilder GenerationEnvironment { + get { + if ((this.builder == null)) { + this.builder = new global::System.Text.StringBuilder(); } - return this.errorsField; + return this.builder; + } + set { + this.builder = value; } } - /// - /// A list of the lengths of each indent that was added with PushIndent - /// - private System.Collections.Generic.List indentLengths - { - get - { - if ((this.indentLengthsField == null)) - { - this.indentLengthsField = new global::System.Collections.Generic.List(); + + protected global::System.CodeDom.Compiler.CompilerErrorCollection Errors { + get { + if ((this.errors == null)) { + this.errors = new global::System.CodeDom.Compiler.CompilerErrorCollection(); } - return this.indentLengthsField; + return this.errors; } } - /// - /// Gets the current indent we use when adding lines to the output - /// - public string CurrentIndent - { - get - { - return this.currentIndentField; + + public string CurrentIndent { + get { + return this.currentIndent; } } - /// - /// Current transformation session - /// - public virtual global::System.Collections.Generic.IDictionary Session - { - get - { - return this.sessionField; - } - set - { - this.sessionField = value; + + private global::System.Collections.Generic.Stack Indents { + get { + if ((this.indents == null)) { + this.indents = new global::System.Collections.Generic.Stack(); + } + return this.indents; } } - #endregion - #region Transform-time helpers - /// - /// Write text directly into the generated output - /// - public void Write(string textToAppend) - { - if (string.IsNullOrEmpty(textToAppend)) - { - return; - } - // If we're starting off, or if the previous text ended with a newline, - // we have to append the current indent first. - if (((this.GenerationEnvironment.Length == 0) - || this.endsWithNewline)) - { - this.GenerationEnvironment.Append(this.currentIndentField); - this.endsWithNewline = false; - } - // Check if the current text ends with a newline - if (textToAppend.EndsWith(global::System.Environment.NewLine, global::System.StringComparison.CurrentCulture)) - { - this.endsWithNewline = true; - } - // This is an optimization. If the current indent is "", then we don't have to do any - // of the more complex stuff further down. - if ((this.currentIndentField.Length == 0)) - { - this.GenerationEnvironment.Append(textToAppend); - return; - } - // Everywhere there is a newline in the text, add an indent after it - textToAppend = textToAppend.Replace(global::System.Environment.NewLine, (global::System.Environment.NewLine + this.currentIndentField)); - // If the text ends with a newline, then we should strip off the indent added at the very end - // because the appropriate indent will be added when the next time Write() is called - if (this.endsWithNewline) - { - this.GenerationEnvironment.Append(textToAppend, 0, (textToAppend.Length - this.currentIndentField.Length)); - } - else - { - this.GenerationEnvironment.Append(textToAppend); + + public ToStringInstanceHelper ToStringHelper { + get { + return this._toStringHelper; } } - /// - /// Write text directly into the generated output - /// - public void WriteLine(string textToAppend) - { - this.Write(textToAppend); - this.GenerationEnvironment.AppendLine(); - this.endsWithNewline = true; + + public void Error(string message) { + this.Errors.Add(new global::System.CodeDom.Compiler.CompilerError(null, -1, -1, null, message)); } - /// - /// Write formatted text directly into the generated output - /// - public void Write(string format, params object[] args) - { - this.Write(string.Format(global::System.Globalization.CultureInfo.CurrentCulture, format, args)); + + public void Warning(string message) { + global::System.CodeDom.Compiler.CompilerError val = new global::System.CodeDom.Compiler.CompilerError(null, -1, -1, null, message); + val.IsWarning = true; + this.Errors.Add(val); } - /// - /// Write formatted text directly into the generated output - /// - public void WriteLine(string format, params object[] args) - { - this.WriteLine(string.Format(global::System.Globalization.CultureInfo.CurrentCulture, format, args)); + + public string PopIndent() { + if ((this.Indents.Count == 0)) { + return string.Empty; + } + int lastPos = (this.currentIndent.Length - this.Indents.Pop()); + string last = this.currentIndent.Substring(lastPos); + this.currentIndent = this.currentIndent.Substring(0, lastPos); + return last; } - /// - /// Raise an error - /// - public void Error(string message) - { - System.CodeDom.Compiler.CompilerError error = new global::System.CodeDom.Compiler.CompilerError(); - error.ErrorText = message; - this.Errors.Add(error); + + public void PushIndent(string indent) { + this.Indents.Push(indent.Length); + this.currentIndent = (this.currentIndent + indent); } - /// - /// Raise a warning - /// - public void Warning(string message) - { - System.CodeDom.Compiler.CompilerError error = new global::System.CodeDom.Compiler.CompilerError(); - error.ErrorText = message; - error.IsWarning = true; - this.Errors.Add(error); + + public void ClearIndent() { + this.currentIndent = string.Empty; + this.Indents.Clear(); } - /// - /// Increase the indent - /// - public void PushIndent(string indent) - { - if ((indent == null)) - { - throw new global::System.ArgumentNullException("indent"); - } - this.currentIndentField = (this.currentIndentField + indent); - this.indentLengths.Add(indent.Length); + + public void Write(string textToAppend) { + this.GenerationEnvironment.Append(textToAppend); } - /// - /// Remove the last indent that was added with PushIndent - /// - public string PopIndent() - { - string returnValue = ""; - if ((this.indentLengths.Count > 0)) - { - int indentLength = this.indentLengths[(this.indentLengths.Count - 1)]; - this.indentLengths.RemoveAt((this.indentLengths.Count - 1)); - if ((indentLength > 0)) - { - returnValue = this.currentIndentField.Substring((this.currentIndentField.Length - indentLength)); - this.currentIndentField = this.currentIndentField.Remove((this.currentIndentField.Length - indentLength)); - } - } - return returnValue; + + public void Write(string format, params object[] args) { + this.GenerationEnvironment.AppendFormat(format, args); } - /// - /// Remove any indentation - /// - public void ClearIndent() - { - this.indentLengths.Clear(); - this.currentIndentField = ""; + + public void WriteLine(string textToAppend) { + this.GenerationEnvironment.Append(this.currentIndent); + this.GenerationEnvironment.AppendLine(textToAppend); } - #endregion - #region ToString Helpers - /// - /// Utility class to produce culture-oriented representation of an object as a string. - /// - public class ToStringInstanceHelper - { - private System.IFormatProvider formatProviderField = global::System.Globalization.CultureInfo.InvariantCulture; - /// - /// Gets or sets format provider to be used by ToStringWithCulture method. - /// - public System.IFormatProvider FormatProvider - { - get - { - return this.formatProviderField ; + + public void WriteLine(string format, params object[] args) { + this.GenerationEnvironment.Append(this.currentIndent); + this.GenerationEnvironment.AppendFormat(format, args); + this.GenerationEnvironment.AppendLine(); + } + + public class ToStringInstanceHelper { + + private global::System.IFormatProvider formatProvider = global::System.Globalization.CultureInfo.InvariantCulture; + + public global::System.IFormatProvider FormatProvider { + get { + return this.formatProvider; } - set - { - if ((value != null)) - { - this.formatProviderField = value; + set { + if ((value != null)) { + this.formatProvider = value; } } } - /// - /// This is called from the compile/run appdomain to convert objects within an expression block to a string - /// - public string ToStringWithCulture(object objectToConvert) - { - if ((objectToConvert == null)) - { + + public string ToStringWithCulture(object objectToConvert) { + if ((objectToConvert == null)) { throw new global::System.ArgumentNullException("objectToConvert"); } - System.Type t = objectToConvert.GetType(); - System.Reflection.MethodInfo method = t.GetMethod("ToString", new System.Type[] { - typeof(System.IFormatProvider)}); - if ((method == null)) - { - return objectToConvert.ToString(); + global::System.Type type = objectToConvert.GetType(); + global::System.Type iConvertibleType = typeof(global::System.IConvertible); + if (iConvertibleType.IsAssignableFrom(type)) { + return ((global::System.IConvertible)(objectToConvert)).ToString(this.formatProvider); } - else - { - return ((string)(method.Invoke(objectToConvert, new object[] { - this.formatProviderField }))); + global::System.Reflection.MethodInfo methInfo = type.GetMethod("ToString", new global::System.Type[] { + iConvertibleType}); + if ((methInfo != null)) { + return ((string)(methInfo.Invoke(objectToConvert, new object[] { + this.formatProvider}))); } + return objectToConvert.ToString(); } } - private ToStringInstanceHelper toStringHelperField = new ToStringInstanceHelper(); - /// - /// Helper to produce culture-oriented representation of an object as a string - /// - public ToStringInstanceHelper ToStringHelper - { - get - { - return this.toStringHelperField; - } - } - #endregion } - #endregion } diff --git a/dotnet/src/AutoGen.SourceGenerator/Template/FunctionCallTemplate.tt b/dotnet/src/AutoGen.SourceGenerator/Template/FunctionCallTemplate.tt index ab255630a4f..c7a13ce1fe9 100644 --- a/dotnet/src/AutoGen.SourceGenerator/Template/FunctionCallTemplate.tt +++ b/dotnet/src/AutoGen.SourceGenerator/Template/FunctionCallTemplate.tt @@ -63,7 +63,7 @@ namespace <#=NameSpace#> Name = @"<#=functionContract.Name#>", <#}#> <#if (functionContract.Description != null) {#> - Description = @"<#=functionContract.Description#>", + Description = @"<#=functionContract.Description.Replace("\"", "\"\"")#>", <#}#> <#if (functionContract.ReturnType != null) {#> ReturnType = typeof(<#=functionContract.ReturnType#>), diff --git a/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.received.txt b/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.received.txt new file mode 100644 index 00000000000..a5ffa3c8248 --- /dev/null +++ b/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.received.txt @@ -0,0 +1,71 @@ +//---------------------- +// +// This code was generated by a tool. +// +//---------------------- +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using System; +using AutoGen.Core; +using AutoGen.OpenAI.Extension; + +namespace AutoGen.SourceGenerator.Tests +{ + public partial class FunctionExamples + { + + private class AddAsyncSchema + { + [JsonPropertyName(@"a")] + public System.Int32 a {get; set;} + [JsonPropertyName(@"b")] + public System.Int32 b {get; set;} + } + + public System.Threading.Tasks.Task`1[System.String] AddAsyncWrapper(string arguments) + { + var schema = JsonSerializer.Deserialize( + arguments, + new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }); + + return AddAsync(schema.a, schema.b); + } + + public FunctionContract AddAsyncFunctionContract + { + get => new FunctionContract + { + Name = @"AddAsync", + Description = @"Add two numbers.", + ReturnType = typeof(System.Threading.Tasks.Task`1[System.String]), + Parameters = new global::AutoGen.Core.FunctionParameterContract[] + { + new FunctionParameterContract + { + Name = @"a", + Description = @"The first number.", + ParameterType = typeof(System.Int32), + IsRequired = true, + }, + new FunctionParameterContract + { + Name = @"b", + Description = @"The second number.", + ParameterType = typeof(System.Int32), + IsRequired = true, + }, + }, + }; + } + + public global::Azure.AI.OpenAI.FunctionDefinition AddAsyncFunction + { + get => this.AddAsyncFunctionContract.ToOpenAIFunctionDefinition(); + } + } +} + diff --git a/dotnet/test/AutoGen.SourceGenerator.Tests/FunctionCallTemplateEncodingTests.cs b/dotnet/test/AutoGen.SourceGenerator.Tests/FunctionCallTemplateEncodingTests.cs new file mode 100644 index 00000000000..8ca6e31a8a4 --- /dev/null +++ b/dotnet/test/AutoGen.SourceGenerator.Tests/FunctionCallTemplateEncodingTests.cs @@ -0,0 +1,92 @@ +// Using directives +using System.Text.Json; // Needed for JsonSerializer +using Xunit; // Needed for Fact and Assert +using AutoGen.SourceGenerator.Template; // Needed for FunctionCallTemplate + +namespace AutoGen.SourceGenerator.Tests +{ + public class FunctionCallTemplateEncodingTests + { + private readonly JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions + { + WriteIndented = true, + }; + + [Fact] + public void FunctionDescription_Should_Encode_DoubleQuotes() + { + // Arrange + var functionContracts = new List + { + new SourceGeneratorFunctionContract + { + Name = "TestFunction", + Description = "This is a \"test\" function", + Parameters = new SourceGeneratorParameterContract[] + { + new SourceGeneratorParameterContract + { + Name = "param1", + Description = "This is a \"parameter\" description", + Type = "string", + IsOptional = false + } + }, + ReturnType = "void" + } + }; + + var template = new FunctionCallTemplate + { + NameSpace = "TestNamespace", + ClassName = "TestClass", + FunctionContracts = functionContracts + }; + + // Act + var result = template.TransformText(); + + // Assert + Assert.Contains("Description = @\"This is a \"\"test\"\" function\"", result); + Assert.Contains("Description = @\"This is a \"\"parameter\"\" description\"", result); + } + + [Fact] + public void ParameterDescription_Should_Encode_DoubleQuotes() + { + // Arrange + var functionContracts = new List + { + new SourceGeneratorFunctionContract + { + Name = "TestFunction", + Description = "This is a test function", + Parameters = new SourceGeneratorParameterContract[] + { + new SourceGeneratorParameterContract + { + Name = "param1", + Description = "This is a \"parameter\" description", + Type = "string", + IsOptional = false + } + }, + ReturnType = "void" + } + }; + + var template = new FunctionCallTemplate + { + NameSpace = "TestNamespace", + ClassName = "TestClass", + FunctionContracts = functionContracts + }; + + // Act + var result = template.TransformText(); + + // Assert + Assert.Contains("Description = @\"This is a \"\"parameter\"\" description\"", result); + } + } +} \ No newline at end of file From 786bae5b6c447da2822130791eb6328530621e12 Mon Sep 17 00:00:00 2001 From: Prithvi Prathapan Date: Fri, 5 Jul 2024 15:44:27 -0700 Subject: [PATCH 3/5] test cases passing Test cases passing like `Starting test execution, please wait... A total of 1 test files matched the specified pattern. Passed! - Failed: 0, Passed: 9, Skipped: 0, Total: 9, Duration: 66 ms - AutoGen.SourceGenerator.Tests.dll (net8.0)` --- ...ests.TestFunctionCallTemplate.approved.txt | 2 +- ...ests.TestFunctionCallTemplate.received.txt | 71 ------------------- 2 files changed, 1 insertion(+), 72 deletions(-) delete mode 100644 dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.received.txt diff --git a/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt b/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt index 0439febc52c..a5ffa3c8248 100644 --- a/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt +++ b/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt @@ -1,4 +1,4 @@ -//---------------------- +//---------------------- // // This code was generated by a tool. // diff --git a/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.received.txt b/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.received.txt deleted file mode 100644 index a5ffa3c8248..00000000000 --- a/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.received.txt +++ /dev/null @@ -1,71 +0,0 @@ -//---------------------- -// -// This code was generated by a tool. -// -//---------------------- -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Threading.Tasks; -using System; -using AutoGen.Core; -using AutoGen.OpenAI.Extension; - -namespace AutoGen.SourceGenerator.Tests -{ - public partial class FunctionExamples - { - - private class AddAsyncSchema - { - [JsonPropertyName(@"a")] - public System.Int32 a {get; set;} - [JsonPropertyName(@"b")] - public System.Int32 b {get; set;} - } - - public System.Threading.Tasks.Task`1[System.String] AddAsyncWrapper(string arguments) - { - var schema = JsonSerializer.Deserialize( - arguments, - new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - }); - - return AddAsync(schema.a, schema.b); - } - - public FunctionContract AddAsyncFunctionContract - { - get => new FunctionContract - { - Name = @"AddAsync", - Description = @"Add two numbers.", - ReturnType = typeof(System.Threading.Tasks.Task`1[System.String]), - Parameters = new global::AutoGen.Core.FunctionParameterContract[] - { - new FunctionParameterContract - { - Name = @"a", - Description = @"The first number.", - ParameterType = typeof(System.Int32), - IsRequired = true, - }, - new FunctionParameterContract - { - Name = @"b", - Description = @"The second number.", - ParameterType = typeof(System.Int32), - IsRequired = true, - }, - }, - }; - } - - public global::Azure.AI.OpenAI.FunctionDefinition AddAsyncFunction - { - get => this.AddAsyncFunctionContract.ToOpenAIFunctionDefinition(); - } - } -} - From 7a6ea9cf0d5831ba7a5c445a7f9b64da713c600d Mon Sep 17 00:00:00 2001 From: Prithvi Prathapan Date: Fri, 5 Jul 2024 16:00:39 -0700 Subject: [PATCH 4/5] Delete FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt Deleted the ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt successfully! --- ...ests.TestFunctionCallTemplate.approved.txt | 71 ------------------- 1 file changed, 71 deletions(-) delete mode 100644 dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt diff --git a/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt b/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt deleted file mode 100644 index a5ffa3c8248..00000000000 --- a/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt +++ /dev/null @@ -1,71 +0,0 @@ -//---------------------- -// -// This code was generated by a tool. -// -//---------------------- -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Threading.Tasks; -using System; -using AutoGen.Core; -using AutoGen.OpenAI.Extension; - -namespace AutoGen.SourceGenerator.Tests -{ - public partial class FunctionExamples - { - - private class AddAsyncSchema - { - [JsonPropertyName(@"a")] - public System.Int32 a {get; set;} - [JsonPropertyName(@"b")] - public System.Int32 b {get; set;} - } - - public System.Threading.Tasks.Task`1[System.String] AddAsyncWrapper(string arguments) - { - var schema = JsonSerializer.Deserialize( - arguments, - new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - }); - - return AddAsync(schema.a, schema.b); - } - - public FunctionContract AddAsyncFunctionContract - { - get => new FunctionContract - { - Name = @"AddAsync", - Description = @"Add two numbers.", - ReturnType = typeof(System.Threading.Tasks.Task`1[System.String]), - Parameters = new global::AutoGen.Core.FunctionParameterContract[] - { - new FunctionParameterContract - { - Name = @"a", - Description = @"The first number.", - ParameterType = typeof(System.Int32), - IsRequired = true, - }, - new FunctionParameterContract - { - Name = @"b", - Description = @"The second number.", - ParameterType = typeof(System.Int32), - IsRequired = true, - }, - }, - }; - } - - public global::Azure.AI.OpenAI.FunctionDefinition AddAsyncFunction - { - get => this.AddAsyncFunctionContract.ToOpenAIFunctionDefinition(); - } - } -} - From 321a605204a7f193866d495e9b1235ad2e5f7b25 Mon Sep 17 00:00:00 2001 From: Prithvi Prathapan Date: Fri, 5 Jul 2024 16:05:59 -0700 Subject: [PATCH 5/5] Revert "Delete FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt" This reverts commit 7a6ea9cf0d5831ba7a5c445a7f9b64da713c600d. --- ...ests.TestFunctionCallTemplate.approved.txt | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt diff --git a/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt b/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt new file mode 100644 index 00000000000..a5ffa3c8248 --- /dev/null +++ b/dotnet/test/AutoGen.SourceGenerator.Tests/ApprovalTests/FunctionCallTemplateTests.TestFunctionCallTemplate.approved.txt @@ -0,0 +1,71 @@ +//---------------------- +// +// This code was generated by a tool. +// +//---------------------- +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using System; +using AutoGen.Core; +using AutoGen.OpenAI.Extension; + +namespace AutoGen.SourceGenerator.Tests +{ + public partial class FunctionExamples + { + + private class AddAsyncSchema + { + [JsonPropertyName(@"a")] + public System.Int32 a {get; set;} + [JsonPropertyName(@"b")] + public System.Int32 b {get; set;} + } + + public System.Threading.Tasks.Task`1[System.String] AddAsyncWrapper(string arguments) + { + var schema = JsonSerializer.Deserialize( + arguments, + new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }); + + return AddAsync(schema.a, schema.b); + } + + public FunctionContract AddAsyncFunctionContract + { + get => new FunctionContract + { + Name = @"AddAsync", + Description = @"Add two numbers.", + ReturnType = typeof(System.Threading.Tasks.Task`1[System.String]), + Parameters = new global::AutoGen.Core.FunctionParameterContract[] + { + new FunctionParameterContract + { + Name = @"a", + Description = @"The first number.", + ParameterType = typeof(System.Int32), + IsRequired = true, + }, + new FunctionParameterContract + { + Name = @"b", + Description = @"The second number.", + ParameterType = typeof(System.Int32), + IsRequired = true, + }, + }, + }; + } + + public global::Azure.AI.OpenAI.FunctionDefinition AddAsyncFunction + { + get => this.AddAsyncFunctionContract.ToOpenAIFunctionDefinition(); + } + } +} +