Skip to content

Update Azure.AI.Inference to 1.0.0-beta.3 #5904

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion eng/packages/General.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageVersion Include="Azure.Storage.Files.DataLake" Version="12.21.0" />
<PackageVersion Include="Azure.AI.Inference" Version="1.0.0-beta.2" />
<PackageVersion Include="Azure.AI.Inference" Version="1.0.0-beta.3" />
<PackageVersion Include="ICSharpCode.Decompiler" Version="8.2.0.7535" />
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="$(MicrosoftCodeAnalysisAnalyzersVersion)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public sealed class AzureAIInferenceChatClient : IChatClient
/// <summary>The <see cref="JsonSerializerOptions"/> use for any serialization activities related to tool call arguments and results.</summary>
private JsonSerializerOptions _toolCallJsonSerializerOptions = AIJsonUtilities.DefaultOptions;

/// <summary>Gets a ChatRole.Developer value.</summary>
private static ChatRole ChatRoleDeveloper { get; } = new("developer");

/// <summary>Initializes a new instance of the <see cref="AzureAIInferenceChatClient"/> class for the specified <see cref="ChatCompletionsClient"/>.</summary>
/// <param name="chatCompletionsClient">The underlying client.</param>
/// <param name="modelId">The ID of the model to use. If null, it can be provided per request via <see cref="ChatOptions.ModelId"/>.</param>
Expand Down Expand Up @@ -273,6 +276,7 @@ private static ChatRole ToChatRole(global::Azure.AI.Inference.ChatRole role) =>
role.Equals(global::Azure.AI.Inference.ChatRole.User) ? ChatRole.User :
role.Equals(global::Azure.AI.Inference.ChatRole.Assistant) ? ChatRole.Assistant :
role.Equals(global::Azure.AI.Inference.ChatRole.Tool) ? ChatRole.Tool :
role.Equals(global::Azure.AI.Inference.ChatRole.Developer) ? ChatRoleDeveloper :
new ChatRole(role.ToString());

/// <summary>Converts an AzureAI finish reason to an Extensions finish reason.</summary>
Expand Down Expand Up @@ -365,17 +369,40 @@ private ChatCompletionsOptions ToAzureAIOptions(IList<ChatMessage> chatContents,

if (options.ResponseFormat is ChatResponseFormatText)
{
result.ResponseFormat = new ChatCompletionsResponseFormatText();
result.ResponseFormat = ChatCompletionsResponseFormat.CreateTextFormat();
}
else if (options.ResponseFormat is ChatResponseFormatJson)
else if (options.ResponseFormat is ChatResponseFormatJson json)
{
result.ResponseFormat = new ChatCompletionsResponseFormatJSON();
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();
}
}
}

return result;
}

/// <summary>Cached <see cref="BinaryData"/> for "object".</summary>
private static readonly BinaryData _objectString = BinaryData.FromString("\"object\"");

/// <summary>Cached <see cref="BinaryData"/> for "false".</summary>
private static readonly BinaryData _falseString = BinaryData.FromString("false");

/// <summary>Converts an Extensions function to an AzureAI chat tool.</summary>
private static ChatCompletionsToolDefinition ToAzureAIChatTool(AIFunction aiFunction)
{
Expand All @@ -401,6 +428,10 @@ private IEnumerable<ChatRequestMessage> ToAzureAIInferenceChatMessages(IList<Cha
{
yield return new ChatRequestSystemMessage(input.Text ?? string.Empty);
}
else if (input.Role == ChatRoleDeveloper)
{
yield return new ChatRequestDeveloperMessage(input.Text ?? string.Empty);
}
else if (input.Role == ChatRole.Tool)
{
foreach (AIContent item in input.Contents)
Expand Down Expand Up @@ -477,6 +508,32 @@ private static List<ChatMessageContentItem> GetContentParts(IList<AIContent> con
parts.Add(new ChatMessageImageContentItem(new Uri(uri)));
}

break;

case DataContent dataContent when dataContent.MediaTypeStartsWith("audio/"):
if (dataContent.Data.HasValue)
{
AudioContentFormat format;
if (dataContent.MediaTypeStartsWith("audio/mpeg"))
{
format = AudioContentFormat.Mp3;
}
else if (dataContent.MediaTypeStartsWith("audio/wav"))
{
format = AudioContentFormat.Wav;
}
else
{
break;
}

parts.Add(new ChatMessageAudioContentItem(BinaryData.FromBytes(dataContent.Data.Value), format));
}
else if (dataContent.Uri is string uri)
{
parts.Add(new ChatMessageAudioContentItem(new Uri(uri)));
}

break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

<ItemGroup>
<PackageReference Include="Azure.AI.Inference" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
<PackageReference Include="System.Memory.Data" />
<PackageReference Include="System.Text.Json" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,12 @@ public void GetService_SuccessfullyReturnsUnderlyingClient()
public async Task BasicRequestResponse_NonStreaming(bool multiContent)
{
const string Input = """
{"messages":[{"content":"hello","role":"user"}],"max_tokens":10,"temperature":0.5,"model":"gpt-4o-mini"}
{
"messages": [{"role":"user", "content":"hello"}],
"max_tokens":10,
"temperature":0.5,
"model":"gpt-4o-mini"
}
""";

const string Output = """
Expand Down Expand Up @@ -178,7 +183,12 @@ [new ChatMessage(ChatRole.User, "hello".Select(c => (AIContent)new TextContent(c
public async Task BasicRequestResponse_Streaming(bool multiContent)
{
const string Input = """
{"messages":[{"content":"hello","role":"user"}],"max_tokens":20,"temperature":0.5,"stream":true,"model":"gpt-4o-mini"}
{
"messages": [{"role":"user", "content":"hello"}],
"max_tokens":20,
"temperature":0.5,
"stream":true,
"model":"gpt-4o-mini"}
""";

const string Output = """
Expand Down Expand Up @@ -248,7 +258,7 @@ public async Task AdditionalOptions_NonStreaming()
{
const string Input = """
{
"messages":[{"content":"hello","role":"user"}],
"messages":[{"role":"user", "content":"hello"}],
"max_tokens":10,
"temperature":0.5,
"top_p":0.5,
Expand Down Expand Up @@ -305,7 +315,7 @@ public async Task ResponseFormat_Text_NonStreaming()
{
const string Input = """
{
"messages":[{"content":"hello","role":"user"}],
"messages":[{"role":"user", "content":"hello"}],
"model":"gpt-4o-mini",
"response_format":{"type":"text"}
}
Expand Down Expand Up @@ -341,7 +351,7 @@ public async Task ResponseFormat_Json_NonStreaming()
{
const string Input = """
{
"messages":[{"content":"hello","role":"user"}],
"messages":[{"role":"user", "content":"hello"}],
"model":"gpt-4o-mini",
"response_format":{"type":"json_object"}
}
Expand Down Expand Up @@ -375,14 +385,32 @@ public async Task ResponseFormat_Json_NonStreaming()
[Fact]
public async Task ResponseFormat_JsonSchema_NonStreaming()
{
// NOTE: Azure.AI.Inference doesn't yet expose JSON schema support, so it's currently
// mapped to "json_object" for the time being.

const string Input = """
{
"messages":[{"content":"hello","role":"user"}],
"messages":[{"role":"user", "content":"hello"}],
"model":"gpt-4o-mini",
"response_format":{"type":"json_object"}
"response_format":
{
"type":"json_schema",
"json_schema":
{
"name": "DescribedObject",
"schema":
{
"type":"object",
"properties":
{
"description":
{
"type":"string"
}
},
"required":["description"],
"additionalProperties":false
},
"description":"An object with a description"
}
}
}
""";

Expand Down Expand Up @@ -428,30 +456,30 @@ public async Task MultipleMessages_NonStreaming()
{
"messages": [
{
"content": "You are a really nice friend.",
"role": "system"
"role": "system",
"content": "You are a really nice friend."
},
{
"content": "hello!",
"role": "user"
"role": "user",
"content": "hello!"
},
{
"content": "hi, how are you?",
"role": "assistant"
"role": "assistant",
"content": "hi, how are you?"
},
{
"content": "i\u0027m good. how are you?",
"role": "user"
"role": "user",
"content": "i\u0027m good. how are you?"
},
{
"role": "assistant",
"content": "",
"tool_calls": [{"id":"abcd123","type":"function","function":{"name":"GetMood","arguments":"null"}}],
"role": "assistant"
"tool_calls": [{"id":"abcd123","type":"function","function":{"name":"GetMood","arguments":"null"}}]
},
{
"role": "tool",
"content": "happy",
"tool_call_id": "abcd123",
"role": "tool"
"tool_call_id": "abcd123"
}
],
"temperature": 0.25,
Expand Down Expand Up @@ -544,21 +572,21 @@ public async Task MultipleContent_NonStreaming()
"messages":
[
{
"role": "user",
"content":
[
{
"text": "Describe this picture.",
"type": "text"
"type": "text",
"text": "Describe this picture."
},
{
"type": "image_url",
"image_url":
{
"url": "http://dot.net/someimage.png"
},
"type": "image_url"
}
}
],
"role":"user"
]
}
],
"model": "gpt-4o-mini"
Expand Down Expand Up @@ -598,12 +626,12 @@ public async Task NullAssistantText_ContentEmpty_NonStreaming()
{
"messages": [
{
"content": "",
"role": "assistant"
"role": "assistant",
"content": ""
},
{
"content": "hello!",
"role": "user"
"role": "user",
"content": "hello!"
}
],
"model": "gpt-4o-mini"
Expand Down Expand Up @@ -686,8 +714,8 @@ public async Task FunctionCallContent_NonStreaming(ChatToolMode mode)
{
"messages": [
{
"content": "How old is Alice?",
"role": "user"
"role": "user",
"content": "How old is Alice?"
}
],
"model": "gpt-4o-mini",
Expand Down Expand Up @@ -797,8 +825,8 @@ public async Task FunctionCallContent_Streaming()
{
"messages": [
{
"content": "How old is Alice?",
"role": "user"
"role": "user",
"content": "How old is Alice?"
}
],
"stream": true,
Expand Down