Skip to content
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

feat: Microsoft.Extensions.AI support #64

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- All modern .NET features - nullability, trimming, NativeAOT, etc.
- Support .Net Framework/.Net Standard 2.0
- Support for all Ollama API endpoints including chats, embeddings, listing models, pulling and creating new models, and more.
- Supporting [Microsoft.Extensions.AI](https://devblogs.microsoft.com/dotnet/introducing-microsoft-extensions-ai-preview/)

## Usage

Expand Down
3 changes: 2 additions & 1 deletion src/libs/Ollama/Ollama.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@

<PropertyGroup Label="Nuget">
<Description>Generated C# SDK based on Ollama OpenAPI specification.</Description>
<PackageTags>api;client;sdk;dotnet;swagger;openapi;specification;ollama;generated</PackageTags>
<PackageTags>api;client;sdk;dotnet;swagger;openapi;specification;ollama;generated;ai;abstractions;llama;ichatclient</PackageTags>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CSharpToJsonSchema" Version="3.9.1" />
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="9.0.0-preview.9.24507.7" />
<PackageReference Include="PolySharp" Version="1.14.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
90 changes: 90 additions & 0 deletions src/libs/Ollama/OllamaApiClient.IChatClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using Microsoft.Extensions.AI;

namespace Ollama;

public partial class OllamaApiClient : Microsoft.Extensions.AI.IChatClient
{
/// <inheritdoc />
public async Task<ChatCompletion> CompleteAsync(

Check warning on line 8 in src/libs/Ollama/OllamaApiClient.IChatClient.cs

View workflow job for this annotation

GitHub Actions / Test / Build, test and publish

Return type of 'OllamaApiClient.CompleteAsync(IList<ChatMessage>, ChatOptions?, CancellationToken)' is not CLS-compliant

Check warning on line 8 in src/libs/Ollama/OllamaApiClient.IChatClient.cs

View workflow job for this annotation

GitHub Actions / Test / Build, test and publish

Return type of 'OllamaApiClient.CompleteAsync(IList<ChatMessage>, ChatOptions?, CancellationToken)' is not CLS-compliant
IList<ChatMessage> chatMessages,

Check warning on line 9 in src/libs/Ollama/OllamaApiClient.IChatClient.cs

View workflow job for this annotation

GitHub Actions / Test / Build, test and publish

Argument type 'IList<ChatMessage>' is not CLS-compliant

Check warning on line 9 in src/libs/Ollama/OllamaApiClient.IChatClient.cs

View workflow job for this annotation

GitHub Actions / Test / Build, test and publish

Argument type 'IList<ChatMessage>' is not CLS-compliant
ChatOptions? options = null,

Check warning on line 10 in src/libs/Ollama/OllamaApiClient.IChatClient.cs

View workflow job for this annotation

GitHub Actions / Test / Build, test and publish

Argument type 'ChatOptions' is not CLS-compliant

Check warning on line 10 in src/libs/Ollama/OllamaApiClient.IChatClient.cs

View workflow job for this annotation

GitHub Actions / Test / Build, test and publish

Argument type 'ChatOptions' is not CLS-compliant
CancellationToken cancellationToken = default)
{
var response = await Chat.GenerateChatCompletionAsync(
model: options?.ModelId ?? "ollama",
messages: chatMessages.Select(x => new Message
{
Content = x.Text ?? string.Empty,
Role = x.Role.Value switch
{
"assistant" => MessageRole.Assistant,
"user" => MessageRole.User,
"system" => MessageRole.System,
"tool" => MessageRole.Tool,
_ => MessageRole.User,
},
Comment on lines +18 to +25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential null values in x.Role

The code uses x.Role.Value without verifying if x.Role or x.Role.Value is null. This could lead to a NullReferenceException if x.Role is null. To prevent this, consider adding a null-conditional operator or a null check.

Apply this diff to safely access x.Role.Value:

-                    Role = x.Role.Value switch
+                    Role = (x.Role?.Value) switch
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Role = x.Role.Value switch
{
"assistant" => MessageRole.Assistant,
"user" => MessageRole.User,
"system" => MessageRole.System,
"tool" => MessageRole.Tool,
_ => MessageRole.User,
},
Role = (x.Role?.Value) switch
{
"assistant" => MessageRole.Assistant,
"user" => MessageRole.User,
"system" => MessageRole.System,
"tool" => MessageRole.Tool,
_ => MessageRole.User,
},

}).ToArray(),
format: options?.ResponseFormat switch
{
ChatResponseFormatJson => ResponseFormat.Json,
_ => null,
},
options: new RequestOptions
{
Temperature = options?.Temperature,
},
stream: false,
keepAlive: default,
tools: options?.Tools?.Select(x => new Tool
{
Function = new ToolFunction
{
Name = string.Empty,
Description = string.Empty,
Parameters = x.AsJson(),
},
}).ToList(),
Comment on lines +38 to +46
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Provide meaningful Name and Description for tools

Currently, the Name and Description properties of ToolFunction are set to string.Empty. This may not provide sufficient information for tool functionality. Consider populating these properties with relevant values from x to enhance clarity and utility.

Apply this diff to assign appropriate values:

                     Function = new ToolFunction
                     {
-                        Name = string.Empty,
-                        Description = string.Empty,
+                        Name = x.Name,
+                        Description = x.Description,
                         Parameters = x.AsJson(),
                     },

Committable suggestion skipped: line range outside the PR's diff.

cancellationToken: cancellationToken).WaitAsync().ConfigureAwait(false);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Review the use of WaitAsync with ConfigureAwait(false)

Using WaitAsync() in combination with await and ConfigureAwait(false) may be unnecessary and could introduce complexity. Consider removing WaitAsync() to simplify the code unless there is a specific need for it.

Apply this diff to streamline the await statement:

-            cancellationToken: cancellationToken).WaitAsync().ConfigureAwait(false);
+            cancellationToken: cancellationToken).ConfigureAwait(false);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cancellationToken: cancellationToken).WaitAsync().ConfigureAwait(false);
cancellationToken: cancellationToken).ConfigureAwait(false);

Comment on lines +13 to +47
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure response is not null before accessing its properties

Currently, the code checks if response.Message is null but does not verify if response itself is null. If Chat.GenerateChatCompletionAsync returns null, accessing response.Message will result in a NullReferenceException. Consider adding a null check for response to enhance robustness.

Apply this diff to add the null check:

+        if (response == null)
+        {
+            throw new InvalidOperationException("Response was null.");
+        }
         if (response.Message == null)
         {
             throw new InvalidOperationException("Response message was null.");
         }

Committable suggestion skipped: line range outside the PR's diff.

if (response.Message == null)
{
throw new InvalidOperationException("Response message was null.");
}

return new ChatCompletion(new ChatMessage(
role: response.Message.Role switch
{
MessageRole.Assistant => ChatRole.Assistant,
MessageRole.User => ChatRole.User,
MessageRole.System => ChatRole.System,
MessageRole.Tool => ChatRole.Tool,
_ => ChatRole.User,
},
content: response.Message.Content)
{
RawRepresentation = response.Message,
})
{
RawRepresentation = response,
};
}

/// <inheritdoc />
public IAsyncEnumerable<StreamingChatCompletionUpdate> CompleteStreamingAsync(

Check warning on line 72 in src/libs/Ollama/OllamaApiClient.IChatClient.cs

View workflow job for this annotation

GitHub Actions / Test / Build, test and publish

Return type of 'OllamaApiClient.CompleteStreamingAsync(IList<ChatMessage>, ChatOptions?, CancellationToken)' is not CLS-compliant
IList<ChatMessage> chatMessages,

Check warning on line 73 in src/libs/Ollama/OllamaApiClient.IChatClient.cs

View workflow job for this annotation

GitHub Actions / Test / Build, test and publish

Argument type 'IList<ChatMessage>' is not CLS-compliant
ChatOptions? options = null,

Check warning on line 74 in src/libs/Ollama/OllamaApiClient.IChatClient.cs

View workflow job for this annotation

GitHub Actions / Test / Build, test and publish

Argument type 'ChatOptions' is not CLS-compliant
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement CompleteStreamingAsync method

The CompleteStreamingAsync method currently throws a NotImplementedException. Since this method is part of the IChatClient interface, it should be properly implemented to fulfill the contract and avoid runtime exceptions.

Would you like assistance in implementing the CompleteStreamingAsync method?

}

/// <inheritdoc />
public TService? GetService<TService>(object? key = null) where TService : class
{
return this as TService;
}

/// <inheritdoc />
public ChatClientMetadata Metadata => new(

Check warning on line 87 in src/libs/Ollama/OllamaApiClient.IChatClient.cs

View workflow job for this annotation

GitHub Actions / Test / Build, test and publish

Type of 'OllamaApiClient.Metadata' is not CLS-compliant
providerName: "Ollama",
providerUri: HttpClient.BaseAddress);
}