Skip to content

Commit

Permalink
Merge pull request #164 from Joy-less/replace-JsonSchema
Browse files Browse the repository at this point in the history
Remove JsonSchema, use System.Text.Json.Schema instead
  • Loading branch information
awaescher authored Jan 8, 2025
2 parents a7daa3f + 1f78ef3 commit fcba491
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 188 deletions.
4 changes: 2 additions & 2 deletions src/Chat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public IAsyncEnumerable<string> SendAsync(string message, IEnumerable<string>? i
/// <param name="message">The message to send</param>
/// <param name="tools">Tools that the model can make use of, see https://ollama.com/blog/tool-support. By using tools, response streaming is automatically turned off</param>
/// <param name="imagesAsBase64">Base64 encoded images to send to the model</param>
/// <param name="format">Currently accepts "json" or JsonSchema or null.</param>
/// <param name="format">Accepts <c>"json"</c> or an object created with <c>JsonSerializerOptions.Default.GetJsonSchemaAsNode</c></param>
/// <param name="cancellationToken">The token to cancel the operation with</param>
public IAsyncEnumerable<string> SendAsync(string message, IEnumerable<Tool>? tools, IEnumerable<string>? imagesAsBase64 = null, object? format = null, CancellationToken cancellationToken = default)
=> SendAsAsync(ChatRole.User, message, tools: tools, imagesAsBase64: imagesAsBase64, format: format, cancellationToken: cancellationToken);
Expand Down Expand Up @@ -204,7 +204,7 @@ public IAsyncEnumerable<string> SendAsAsync(ChatRole role, string message, IEnum
/// <param name="message">The message to send</param>
/// <param name="tools">Tools that the model can make use of, see https://ollama.com/blog/tool-support. By using tools, response streaming is automatically turned off</param>
/// <param name="imagesAsBase64">Base64 encoded images to send to the model</param>
/// <param name="format">Currently accepts "json" or JsonSchema or null.</param>
/// <param name="format">Accepts <c>"json"</c> or an object created with <c>JsonSerializerOptions.Default.GetJsonSchemaAsNode</c></param>
/// <param name="cancellationToken">The token to cancel the operation with</param>
public async IAsyncEnumerable<string> SendAsAsync(ChatRole role, string message, IEnumerable<Tool>? tools, IEnumerable<string>? imagesAsBase64 = null, object? format = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
Expand Down
186 changes: 0 additions & 186 deletions src/Models/JsonSchema.cs

This file was deleted.

66 changes: 66 additions & 0 deletions test/FunctionalTests/JsonSchemaTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System.Text.Json;
using System.Text.Json.Schema;
using NUnit.Framework;
using FluentAssertions;
using OllamaSharp;

namespace Tests.FunctionalTests;

public class JsonSchemaTests
{
private readonly Uri _baseUri = new("http://localhost:11434");
private readonly string _model = "llama3.2:1b";

private OllamaApiClient _client = null!;
private Chat _chat = null!;

[SetUp]
public async Task Setup()
{
_client = new OllamaApiClient(_baseUri);
_chat = new Chat(_client);

var modelExists = (await _client.ListLocalModelsAsync()).Any(m => m.Name == _model);
if (!modelExists)
await _client.PullModelAsync(_model).ToListAsync();
}

[TearDown]
public Task Teardown()
{
_client?.Dispose();
return Task.CompletedTask;
}

[Test]
public async Task GenerateSword_ShouldSucceed()
{
var responseSchema = JsonSerializerOptions.Default.GetJsonSchemaAsNode(typeof(Sword));

_client.SelectedModel = _model;

var response = await _chat
.SendAsync("""
Generate a sword with the name 'Excalibur'.
Return a valid JSON object like:
{
"Name": "",
"Damage": 0
}
""", tools: null, format: responseSchema)
.StreamToEndAsync();
response.Should().NotBeNullOrEmpty();

var responseSword = JsonSerializer.Deserialize<Sword>(response);
responseSword.Should().NotBeNull();
responseSword.Name.ToLowerInvariant().Should().Contain("excalibur");
responseSword.Damage.Should().BeOfType(typeof(int));
}

private class Sword
{
public required string Name { get; set; }
public required int Damage { get; set; }
}
}

0 comments on commit fcba491

Please sign in to comment.