using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.TypeSpec.Generator.ClientModel;
using Microsoft.TypeSpec.Generator.Expressions;
using Microsoft.TypeSpec.Generator.Primitives;
using Microsoft.TypeSpec.Generator.Providers;
using Microsoft.TypeSpec.Generator.Snippets;
using Microsoft.TypeSpec.Generator.Statements;
using static OpenAILibraryPlugin.Visitors.VisitorHelpers;
namespace OpenAILibraryPlugin.Visitors;
/// <summary>
/// This visitor fixes up usage of the metadata query parameter into the proper format.
/// </summary>
public class MetadataQueryParamVisitor : ScmLibraryVisitor
{
private static readonly string[] _chatParamsToReplace = ["after", "before", "limit", "order", "model", "metadata"];
/// <summary>
/// Visits Create*Request methods to modify how metadata query parameters are handled.
/// It replaces the following statements:
/// <code>
/// List<object> list = new List<object>();
/// foreach (var @param in metadata)
/// {
/// uri.AppendQuery($"metadata[{@param.Key}]", @param.Value, true);
/// list.Add(@param.Key);
/// list.Add(@param.Value);
/// }
/// uri.AppendQueryDelimited("metadata", list, ",", null, true);
/// </code>
/// with:
/// <code>
/// foreach (var @param in metadata)
/// {
/// uri.AppendQuery($"metadata[{@param.Key}]", @param.Value, true);
/// }
/// </summary>
/// <param name="method"></param>
/// <returns></returns>
protected override MethodProvider? VisitMethod(MethodProvider method)
{
// Check if the method is one of the Create*Request methods and has a signature that takes a metadata parameter like IDictionary<string, string> metadata
if (method.Signature.Name.StartsWith("Create") && method.Signature.Name.EndsWith("Request") &&
method.Signature.Parameters.Any(p => p.Type.IsDictionary && p.Name == "metadata"))
{
ValueExpression? uri = null;
var statements = method.BodyStatements?.ToList() ?? new List<MethodBodyStatement>();
VisitExplodedMethodBodyStatements(
statements!,
statement =>
{
// Check if the statement is an assignment to a variable named "uri"
// Capture it if so
if (statement is ExpressionStatement expressionStatement &&
expressionStatement.Expression is AssignmentExpression assignmentExpression &&
assignmentExpression.Variable is DeclarationExpression declarationExpression &&
declarationExpression.Variable is VariableExpression variableExpression &&
variableExpression.Declaration.RequestedName == "uri")
{
uri = variableExpression;
}
// Try to remove the unnecessary list declaration
if (statement is ExpressionStatement expressionStatement2 &&
expressionStatement2.Expression is AssignmentExpression assignmentExpression2 &&
assignmentExpression2.Variable is DeclarationExpression declarationExpression2 &&
declarationExpression2.Variable is VariableExpression variableExpression2 &&
variableExpression2.Declaration.RequestedName == "list" &&
variableExpression2.Type.IsCollection && variableExpression2.Type.IsGenericType)
{
// Remove the list declaration
return new SingleLineCommentStatement("Plugin customization: remove unnecessary list declaration");
}
if (uri is not null &&
statement is ForEachStatement foreachStatement &&
foreachStatement.Enumerable is DictionaryExpression dictionaryExpression &&
dictionaryExpression.Original is VariableExpression variable &&
variable.Declaration.RequestedName == "metadata")
{
var formatString = new FormattableStringExpression("metadata[{0}]", [foreachStatement.ItemVariable.Property("Key")]);
var appendQueryStatement = uri.Invoke("AppendQuery", [formatString, foreachStatement.ItemVariable.Property("Value"), Snippet.True]);
foreachStatement.Body.Clear();
foreachStatement.Body.Add(new SingleLineCommentStatement("Plugin customization: Properly handle metadata query parameters"));
foreachStatement.Body.Add(appendQueryStatement.Terminate());
}
// Remove the call to AppendQueryDelimited for metadata
if (statement is ExpressionStatement expressionStatement3 &&
expressionStatement3.Expression is InvokeMethodExpression invokeMethodExpression &&
invokeMethodExpression.MethodName == "AppendQueryDelimited" &&
invokeMethodExpression.Arguments.Count == 5 &&
invokeMethodExpression.Arguments[0].ToDisplayString() == "\"metadata\"")
{
return new SingleLineCommentStatement("Plugin customization: remove unnecessary AppendQueryDelimited for metadata");
}
return statement;
});
// Rebuild the method body with the modified statements
method.Update(bodyStatements: statements);
}
return base.VisitMethod(method);
}
}openai/openai-dotnet
Publicmirrored from https://github.com/openai/openai-dotnetAvailable
codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs
109lines · modepreview