Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,17 @@ public string? ChatThreadId
[JsonIgnore]
public IList<AITool>? Tools { get; set; }

/// <summary>
/// Gets or sets the raw representation of the chat options from an underlying implementation.
/// </summary>
/// <remarks>
/// If a <see cref="ChatOptions"/> is created to represent some underlying object from another object
/// model, this property can be used to store that original object. This can be useful for debugging or
/// for enabling a consumer to access the underlying object model if needed.
/// </remarks>
[JsonIgnore]
public object? RawRepresentation { get; set; }

/// <summary>Gets or sets any additional properties associated with the options.</summary>
public AdditionalPropertiesDictionary? AdditionalProperties { get; set; }

Expand All @@ -144,6 +155,7 @@ public virtual ChatOptions Clone()
ModelId = ModelId,
AllowMultipleToolCalls = AllowMultipleToolCalls,
ToolMode = ToolMode,
RawRepresentation = RawRepresentation,
AdditionalProperties = AdditionalProperties?.Clone(),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,109 +273,99 @@ private static ChatRole ToChatRole(global::Azure.AI.Inference.ChatRole role) =>
finishReason == CompletionsFinishReason.ToolCalls ? ChatFinishReason.ToolCalls :
new(s);

private ChatCompletionsOptions CreateAzureAIOptions(IEnumerable<ChatMessage> chatContents, ChatOptions? options) =>
new(ToAzureAIInferenceChatMessages(chatContents))
{
Model = options?.ModelId ?? _metadata.DefaultModelId ?? throw new InvalidOperationException("No model id was provided when either constructing the client or in the chat options.")
};

/// <summary>Converts an extensions options instance to an AzureAI options instance.</summary>
private ChatCompletionsOptions ToAzureAIOptions(IEnumerable<ChatMessage> chatContents, ChatOptions? options)
{
ChatCompletionsOptions result = new(ToAzureAIInferenceChatMessages(chatContents))
if (options is null)
{
Model = options?.ModelId ?? _metadata.DefaultModelId ?? throw new InvalidOperationException("No model id was provided when either constructing the client or in the chat options.")
};
return CreateAzureAIOptions(chatContents, options);
}

if (options is not null)
ChatCompletionsOptions result;
if (options.RawRepresentation is ChatCompletionsOptions azureAIOptions)
{
result.FrequencyPenalty = options.FrequencyPenalty;
result.MaxTokens = options.MaxOutputTokens;
result.NucleusSamplingFactor = options.TopP;
result.PresencePenalty = options.PresencePenalty;
result.Temperature = options.Temperature;
result.Seed = options.Seed;

if (options.StopSequences is { Count: > 0 } stopSequences)
{
foreach (string stopSequence in stopSequences)
{
result.StopSequences.Add(stopSequence);
}
}
result = azureAIOptions;
result.Messages = ToAzureAIInferenceChatMessages(chatContents).ToList();
result.Model = options.ModelId ?? _metadata.DefaultModelId ?? throw new InvalidOperationException("No model id was provided when either constructing the client or in the chat options.");
}
else
{
result = CreateAzureAIOptions(chatContents, options);
}

result.FrequencyPenalty = options.FrequencyPenalty;
result.MaxTokens = options.MaxOutputTokens;
result.NucleusSamplingFactor = options.TopP;
result.PresencePenalty = options.PresencePenalty;
result.Temperature = options.Temperature;
result.Seed = options.Seed;

// These properties are strongly typed on ChatOptions but not on ChatCompletionsOptions.
if (options.TopK is int topK)
if (options.StopSequences is { Count: > 0 } stopSequences)
{
foreach (string stopSequence in stopSequences)
{
result.AdditionalProperties["top_k"] = new BinaryData(JsonSerializer.SerializeToUtf8Bytes(topK, AIJsonUtilities.DefaultOptions.GetTypeInfo(typeof(int))));
result.StopSequences.Add(stopSequence);
}
}

if (options.AdditionalProperties is { } props)
if (options.Tools is { Count: > 0 } tools)
{
foreach (AITool tool in tools)
{
foreach (var prop in props)
if (tool is AIFunction af)
{
switch (prop.Key)
{
// Propagate everything else to the ChatCompletionsOptions' AdditionalProperties.
default:
if (prop.Value is not null)
{
byte[] data = JsonSerializer.SerializeToUtf8Bytes(prop.Value, AIJsonUtilities.DefaultOptions.GetTypeInfo(typeof(object)));
result.AdditionalProperties[prop.Key] = new BinaryData(data);
}

break;
}
result.Tools.Add(ToAzureAIChatTool(af));
}
}

if (options.Tools is { Count: > 0 } tools)
switch (options.ToolMode)
{
foreach (AITool tool in tools)
{
if (tool is AIFunction af)
{
result.Tools.Add(ToAzureAIChatTool(af));
}
}

switch (options.ToolMode)
{
case NoneChatToolMode:
result.ToolChoice = ChatCompletionsToolChoice.None;
break;
case NoneChatToolMode:
result.ToolChoice = ChatCompletionsToolChoice.None;
break;

case AutoChatToolMode:
case null:
result.ToolChoice = ChatCompletionsToolChoice.Auto;
break;
case AutoChatToolMode:
case null:
result.ToolChoice = ChatCompletionsToolChoice.Auto;
break;

case RequiredChatToolMode required:
result.ToolChoice = required.RequiredFunctionName is null ?
ChatCompletionsToolChoice.Required :
new ChatCompletionsToolChoice(new FunctionDefinition(required.RequiredFunctionName));
break;
}
case RequiredChatToolMode required:
result.ToolChoice = required.RequiredFunctionName is null ?
ChatCompletionsToolChoice.Required :
new ChatCompletionsToolChoice(new FunctionDefinition(required.RequiredFunctionName));
break;
}
}

if (options.ResponseFormat is ChatResponseFormatText)
if (options.ResponseFormat is ChatResponseFormatText)
{
result.ResponseFormat = ChatCompletionsResponseFormat.CreateTextFormat();
}
else if (options.ResponseFormat is ChatResponseFormatJson json)
{
if (json.Schema is { } schema)
{
result.ResponseFormat = ChatCompletionsResponseFormat.CreateTextFormat();
var tool = JsonSerializer.Deserialize(schema, JsonContext.Default.AzureAIChatToolJson)!;
result.ResponseFormat = ChatCompletionsResponseFormat.CreateJsonFormat(
json.SchemaName ?? "json_schema",
new Dictionary<string, BinaryData>
{
["type"] = _objectString,
["properties"] = BinaryData.FromBytes(JsonSerializer.SerializeToUtf8Bytes(tool.Properties, JsonContext.Default.DictionaryStringJsonElement)),
["required"] = BinaryData.FromBytes(JsonSerializer.SerializeToUtf8Bytes(tool.Required, JsonContext.Default.ListString)),
["additionalProperties"] = _falseString,
},
json.SchemaDescription);
}
else if (options.ResponseFormat is ChatResponseFormatJson json)
else
{
if (json.Schema is { } schema)
{
var tool = JsonSerializer.Deserialize(schema, JsonContext.Default.AzureAIChatToolJson)!;
result.ResponseFormat = ChatCompletionsResponseFormat.CreateJsonFormat(
json.SchemaName ?? "json_schema",
new Dictionary<string, BinaryData>
{
["type"] = _objectString,
["properties"] = BinaryData.FromBytes(JsonSerializer.SerializeToUtf8Bytes(tool.Properties, JsonContext.Default.DictionaryStringJsonElement)),
["required"] = BinaryData.FromBytes(JsonSerializer.SerializeToUtf8Bytes(tool.Required, JsonContext.Default.ListString)),
["additionalProperties"] = _falseString,
},
json.SchemaDescription);
}
else
{
result.ResponseFormat = ChatCompletionsResponseFormat.CreateJsonFormat();
}
result.ResponseFormat = ChatCompletionsResponseFormat.CreateJsonFormat();
}
}

Expand Down
Loading
Loading