Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,8 @@ IOllamaApiClient ConfigureOllamaClient(IServiceProvider serviceProvider)
{
HttpClient httpClient = serviceProvider.GetRequiredService<IHttpClientFactory>().CreateClient(httpClientKey);

OllamaApiClient client = new(httpClient);
if (!string.IsNullOrWhiteSpace(settings.SelectedModel))
{
client.SelectedModel = settings.SelectedModel;
client.Config.Model = settings.SelectedModel;
}
// Pass the selected model and JsonSerializerContext to the constructor
OllamaApiClient client = new(httpClient, settings.SelectedModel ?? string.Empty, settings.JsonSerializerContext);

return client;
}
Expand Down
10 changes: 10 additions & 0 deletions src/CommunityToolkit.Aspire.OllamaSharp/OllamaSharpSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,14 @@ public sealed class OllamaSharpSettings
/// <remarks>Currently, the OllamaSharp SDK does not support tracing, but this is here for future use.</remarks>
public bool DisableTracing { get; set; }

/// <summary>
/// Gets or sets the JSON serializer context for Native AOT support.
/// </summary>
/// <remarks>
/// When using Native AOT, provide a custom <see cref="System.Text.Json.Serialization.JsonSerializerContext"/>
/// that includes all types that will be serialized. This is required for AOT compatibility.
/// See https://github.com/awaescher/OllamaSharp/blob/main/docs/native-aot-support.md for more information.
/// </remarks>
public System.Text.Json.Serialization.JsonSerializerContext? JsonSerializerContext { get; set; }

}
30 changes: 30 additions & 0 deletions src/CommunityToolkit.Aspire.OllamaSharp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,36 @@ builder.AddOllamaApiClient("ollama")

The integration automatically registers the Microsoft.Extensions.AI telemetry source (`Experimental.Microsoft.Extensions.AI`) with OpenTelemetry for distributed tracing.

#### Native AOT Support

OllamaSharp supports .NET Native AOT when you provide a custom `JsonSerializerContext`. This is especially important when working with custom types in chat messages or using libraries like Semantic Kernel with complex vector store results.

First, create a custom `JsonSerializerContext` that includes all types that will be serialized:

```csharp
using System.Text.Json.Serialization;
using OllamaSharp.Models;

[JsonSerializable(typeof(ChatRequest))]
[JsonSerializable(typeof(ChatResponseStream))]
[JsonSerializable(typeof(ChatDoneResponseStream))]
// Add your custom types here
public partial class MyCustomJsonContext : JsonSerializerContext
{
}
```

Then pass it when configuring the client:

```csharp
builder.AddOllamaApiClient("ollama", settings =>
{
settings.JsonSerializerContext = MyCustomJsonContext.Default;
});
```

For more information on Native AOT support with OllamaSharp, see the [OllamaSharp Native AOT documentation](https://github.com/awaescher/OllamaSharp/blob/main/docs/native-aot-support.md).

## Additional documentation

- https://github.com/awaescher/OllamaSharp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ public void SelectedModelIsNullByDefault() =>
[Fact]
public void ModelsIsEmptyByDefault() =>
Assert.Empty(new OllamaSharpSettings().Models);

[Fact]
public void JsonSerializerContextIsNullByDefault() =>
Assert.Null(new OllamaSharpSettings().JsonSerializerContext);
}
Original file line number Diff line number Diff line change
Expand Up @@ -247,4 +247,78 @@ public void RegisteringChatClientAndEmbeddingGeneratorResultsInMultipleOllamaApi

Assert.Equal(2, ollamaApiClients.Count());
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public void CanSetJsonSerializerContext(bool useKeyed)
{
var builder = Host.CreateEmptyApplicationBuilder(null);
builder.Configuration.AddInMemoryCollection([
new KeyValuePair<string, string?>("ConnectionStrings:Ollama", $"Endpoint={Endpoint}")
]);

// Create a test JsonSerializerContext
var testContext = TestJsonContext.Default;

if (useKeyed)
{
builder.AddKeyedOllamaApiClient("Ollama", settings =>
{
settings.JsonSerializerContext = testContext;
});
}
else
{
builder.AddOllamaApiClient("Ollama", settings =>
{
settings.JsonSerializerContext = testContext;
});
}

using var host = builder.Build();

var client = useKeyed ?
host.Services.GetRequiredKeyedService<IOllamaApiClient>("Ollama") :
host.Services.GetRequiredService<IOllamaApiClient>();

// Verify the JsonSerializerContext was set on the client's Config
// Cast to OllamaApiClient to access Config property
var concreteClient = Assert.IsType<OllamaApiClient>(client);
Assert.NotNull(concreteClient.Config.JsonSerializerContext);
Assert.Equal(testContext, concreteClient.Config.JsonSerializerContext);
}

[Fact]
public void CanSetJsonSerializerContextWithSettingsOverload()
{
var builder = Host.CreateEmptyApplicationBuilder(null);

var testContext = TestJsonContext.Default;
var settings = new OllamaSharpSettings
{
Endpoint = Endpoint,
SelectedModel = "testmodel",
JsonSerializerContext = testContext
};

builder.AddKeyedOllamaApiClient("TestService", settings);

using var host = builder.Build();
var client = host.Services.GetRequiredKeyedService<IOllamaApiClient>("TestService");

Assert.Equal(Endpoint, client.Uri);
Assert.Equal("testmodel", client.SelectedModel);

// Cast to OllamaApiClient to access Config property
var concreteClient = Assert.IsType<OllamaApiClient>(client);
Assert.NotNull(concreteClient.Config.JsonSerializerContext);
Assert.Equal(testContext, concreteClient.Config.JsonSerializerContext);
}
}

// Test JsonSerializerContext for testing purposes
[System.Text.Json.Serialization.JsonSerializable(typeof(string))]
internal partial class TestJsonContext : System.Text.Json.Serialization.JsonSerializerContext
{
}
Loading