Skip to content

Commit

Permalink
improve vector stores, fix potentially not disposing httpresult
Browse files Browse the repository at this point in the history
  • Loading branch information
lofcz committed Jan 24, 2025
1 parent 1f0b21d commit d3bc768
Show file tree
Hide file tree
Showing 14 changed files with 573 additions and 129 deletions.
12 changes: 12 additions & 0 deletions LlmTornado.Demo/ChatDemo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,18 @@ public static async Task<bool> ChatFunctionGeminiStrict()

return false;
}

public static async Task AnthropicCaching()
{
await File.ReadAllTextAsync("");

Conversation chat = Program.Connect(LLmProviders.Cohere).Chat.CreateConversation(new ChatRequest
{
Model = ChatModel.Anthropic.Claude35.SonnetLatest,
});

chat.AppendMessage(new ChatMessage(ChatMessageRoles.User, [ new ChatMessagePart() ]));
}

public static async Task CohereWebSearch()
{
Expand Down
2 changes: 2 additions & 0 deletions LlmTornado.Demo/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ public enum Demos
CustomProviderOllama,
[Flaky("requires ollama")]
CustomProviderOllamaStreaming,
ChatAnthropicCaching,
Last
}

Expand Down Expand Up @@ -281,6 +282,7 @@ public static async Task<bool> SetupApi()
Demos.ChatCompletionO1Developer => ChatDemo.CompletionO1Developer,
Demos.CustomProviderOllama => CustomProviderDemo.Ollama,
Demos.CustomProviderOllamaStreaming => CustomProviderDemo.OllamaStreaming,
Demos.ChatAnthropicCaching => ChatDemo.AnthropicCaching,
_ => null
};

Expand Down
323 changes: 323 additions & 0 deletions LlmTornado.Demo/Static/Files/pride_and_prejudice.txt

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions LlmTornado.Demo/VectorStoreDemo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,7 @@ public static async Task<VectorStore> CreateVectorStore()

public static async Task<ListResponse<VectorStore>> ListVectorStores()
{
if (vectorStoreId is null)
{
throw new Exception("No vector store created");
}

HttpCallResult<ListResponse<VectorStore>> listResult =
await Program.Connect().VectorStores.ListVectorStoresAsync();
HttpCallResult<ListResponse<VectorStore>> listResult = await Program.Connect().VectorStores.ListVectorStoresAsync();
Console.WriteLine(listResult.Response);
return listResult.Data;
}
Expand Down Expand Up @@ -112,9 +106,9 @@ public static async Task<VectorStoreFile> CreateVectorStoreFileCustomChunkingStr
vectorStoreId, new CreateVectorStoreFileRequest
{
FileId = file.Id,
ChunkingStrategy = new StaticChunkingStrategy()
ChunkingStrategy = new StaticChunkingStrategy
{
Static = new StaticChunkingConfig()
Static = new StaticChunkingConfig
{
MaxChunkSizeTokens = 500,
ChunkOverlapTokens = 100
Expand Down Expand Up @@ -266,10 +260,7 @@ public static async Task CancelVectorStoreFileBatch()

public static async Task DeleteVectorStore()
{
if (vectorStoreId is null)
{
throw new Exception("No vector store created");
}
vectorStoreId ??= "vs_r3Xs9FQRKrz5mgsxBPKOSkqm";

// final cleanup of uploaded files
if (fileIdVectorStoreFile is not null)
Expand All @@ -282,11 +273,20 @@ public static async Task DeleteVectorStore()
await FilesDemo.DeleteFile(fileIdVectorStoreFileBatch);
}

if (fileIdVectorStoreFileCustomChunkingStrategy is not null){
if (fileIdVectorStoreFileCustomChunkingStrategy is not null)
{
await FilesDemo.DeleteFile(fileIdVectorStoreFileCustomChunkingStrategy);
}

HttpCallResult<bool> deleteResult = await Program.Connect().VectorStores.DeleteVectorStoreAsync(vectorStoreId);

if (!deleteResult.Ok)
{
Console.WriteLine(deleteResult.Code);
Console.WriteLine(deleteResult.Response);
return;
}

Console.WriteLine(deleteResult.Response);
}
}
22 changes: 11 additions & 11 deletions LlmTornado/Assistants/AssistantsEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ internal AssistantsEndpoint(TornadoApi api) : base(api)
/// <returns>
/// <see cref="ListResponse{Assistant}" />
/// </returns>
public Task<HttpCallResult<ListResponse<AssistantResponse>>> ListAssistantsAsync(ListQuery? query = null, CancellationToken? cancellationToken = default)
public Task<HttpCallResult<ListResponse<AssistantResponse>>> ListAssistantsAsync(ListQuery? query = null, CancellationToken? cancellationToken = null)
{
return HttpGetRaw<ListResponse<AssistantResponse>>(Api.GetProvider(LLmProviders.OpenAi), CapabilityEndpoints.Assistants, string.Empty /* [todo] fix GetUrl(query) */, cancellationToken);
}
Expand All @@ -40,7 +40,7 @@ public Task<HttpCallResult<ListResponse<AssistantResponse>>> ListAssistantsAsync
/// <param name="request"><see cref="CreateAssistantRequest" />.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken" />.</param>
/// <returns><see cref="AssistantResponse" />.</returns>
public Task<HttpCallResult<AssistantResponse>> CreateAssistantAsync(CreateAssistantRequest request, CancellationToken? cancellationToken = default)
public Task<HttpCallResult<AssistantResponse>> CreateAssistantAsync(CreateAssistantRequest request, CancellationToken? cancellationToken = null)
{
return HttpPostRaw<AssistantResponse>(Api.GetProvider(LLmProviders.OpenAi), CapabilityEndpoints.Assistants, string.Empty /* [todo] fix GetUrl(query) */, request, cancellationToken);
}
Expand All @@ -51,7 +51,7 @@ public Task<HttpCallResult<AssistantResponse>> CreateAssistantAsync(CreateAssist
/// <param name="assistantId">The ID of the assistant to retrieve.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken" />.</param>
/// <returns><see cref="AssistantResponse" />.</returns>
public Task<HttpCallResult<AssistantResponse>> RetrieveAssistantAsync(string assistantId, CancellationToken? cancellationToken = default)
public Task<HttpCallResult<AssistantResponse>> RetrieveAssistantAsync(string assistantId, CancellationToken? cancellationToken = null)
{
return HttpGetRaw<AssistantResponse>(Api.GetProvider(LLmProviders.OpenAi), CapabilityEndpoints.Assistants, GetUrl(Api.GetProvider(LLmProviders.OpenAi), $"/{assistantId}"), cancellationToken, true);
}
Expand All @@ -64,7 +64,7 @@ public Task<HttpCallResult<AssistantResponse>> RetrieveAssistantAsync(string ass
/// <param name="request"><see cref="CreateAssistantRequest" />.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken" />.</param>
/// <returns><see cref="AssistantResponse" />.</returns>
public Task<HttpCallResult<AssistantResponse>> ModifyAssistantAsync(string assistantId, CreateAssistantRequest request, CancellationToken? cancellationToken = default)
public Task<HttpCallResult<AssistantResponse>> ModifyAssistantAsync(string assistantId, CreateAssistantRequest request, CancellationToken? cancellationToken = null)
{
return HttpPostRaw<AssistantResponse>(Api.GetProvider(LLmProviders.OpenAi), CapabilityEndpoints.Assistants, GetUrl(Api.GetProvider(LLmProviders.OpenAi), $"/{assistantId}"), request, cancellationToken);
}
Expand All @@ -75,7 +75,7 @@ public Task<HttpCallResult<AssistantResponse>> ModifyAssistantAsync(string assis
/// <param name="assistantId">The ID of the assistant to delete.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken" />.</param>
/// <returns>True, if the assistant was deleted.</returns>
public async Task<HttpCallResult<bool>> DeleteAssistantAsync(string assistantId, CancellationToken? cancellationToken = default)
public async Task<HttpCallResult<bool>> DeleteAssistantAsync(string assistantId, CancellationToken? cancellationToken = null)
{
HttpCallResult<DeletionStatus> status = await HttpAtomic<DeletionStatus>(Api.GetProvider(LLmProviders.OpenAi), CapabilityEndpoints.Assistants, HttpMethod.Delete, GetUrl(Api.GetProvider(LLmProviders.OpenAi), $"/{assistantId}"), ct: cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
return new HttpCallResult<bool>(status.Code, status.Response, status.Data?.Deleted ?? false, status.Ok, null);
Expand All @@ -88,7 +88,7 @@ public async Task<HttpCallResult<bool>> DeleteAssistantAsync(string assistantId,
/// <param name="query"><see cref="ListQuery" />.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken" />.</param>
/// <returns><see cref="ListResponse{AssistantFile}" />.</returns>
public Task<HttpCallResult<ListResponse<AssistantFileResponse>>> ListFilesAsync(string assistantId, ListQuery? query = null, CancellationToken? cancellationToken = default)
public Task<HttpCallResult<ListResponse<AssistantFileResponse>>> ListFilesAsync(string assistantId, ListQuery? query = null, CancellationToken? cancellationToken = null)
{
return HttpGetRaw<ListResponse<AssistantFileResponse>>(Api.GetProvider(LLmProviders.OpenAi), CapabilityEndpoints.Assistants, GetUrl(Api.GetProvider(LLmProviders.OpenAi), $"/{assistantId}/files") /* [todo] fix "query" 3rd arg */, cancellationToken, true);
}
Expand All @@ -103,7 +103,7 @@ public Task<HttpCallResult<ListResponse<AssistantFileResponse>>> ListFilesAsync(
/// </param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken" />.</param>
/// <returns><see cref="AssistantFileResponse" />.</returns>
public Task<HttpCallResult<AssistantFileResponse>> AttachFileAsync(string assistantId, File file, CancellationToken? cancellationToken = default)
public Task<HttpCallResult<AssistantFileResponse>> AttachFileAsync(string assistantId, File file, CancellationToken? cancellationToken = null)
{
return HttpPostRaw<AssistantFileResponse>(Api.GetProvider(LLmProviders.OpenAi), CapabilityEndpoints.Assistants, GetUrl(Api.GetProvider(LLmProviders.OpenAi), $"/{assistantId}/files"), new { file_id = file.Id }, cancellationToken);
}
Expand All @@ -117,7 +117,7 @@ public Task<HttpCallResult<AssistantFileResponse>> AttachFileAsync(string assist
/// </param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken" />.</param>
/// <returns><see cref="AssistantFileResponse" />.</returns>
public Task<HttpCallResult<AssistantFileResponse>> AttachFileAsync(string assistantId, string fileId, CancellationToken? cancellationToken = default)
public Task<HttpCallResult<AssistantFileResponse>> AttachFileAsync(string assistantId, string fileId, CancellationToken? cancellationToken = null)
{
return HttpPostRaw<AssistantFileResponse>(Api.GetProvider(LLmProviders.OpenAi), CapabilityEndpoints.Assistants, GetUrl(Api.GetProvider(LLmProviders.OpenAi), $"/{assistantId}/files"), new { file_id = fileId }, cancellationToken);
}
Expand All @@ -129,7 +129,7 @@ public Task<HttpCallResult<AssistantFileResponse>> AttachFileAsync(string assist
/// <param name="fileId">The ID of the file we're getting.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken" />.</param>
/// <returns><see cref="AssistantFileResponse" />.</returns>
public Task<HttpCallResult<AssistantFileResponse>> RetrieveFileAsync(string assistantId, string fileId, CancellationToken? cancellationToken = default)
public Task<HttpCallResult<AssistantFileResponse>> RetrieveFileAsync(string assistantId, string fileId, CancellationToken? cancellationToken = null)
{
return HttpGetRaw<AssistantFileResponse>(Api.GetProvider(LLmProviders.OpenAi), CapabilityEndpoints.Assistants, GetUrl(Api.GetProvider(LLmProviders.OpenAi), $"/{assistantId}/files/{fileId}"), cancellationToken, true);
}
Expand All @@ -146,7 +146,7 @@ public Task<HttpCallResult<AssistantFileResponse>> RetrieveFileAsync(string assi
/// <param name="fileId">The ID of the file to delete.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken" />.</param>
/// <returns>True, if file was removed.</returns>
public async Task<HttpCallResult<bool>> RemoveFileAsync(string assistantId, string fileId, CancellationToken? cancellationToken = default)
public async Task<HttpCallResult<bool>> RemoveFileAsync(string assistantId, string fileId, CancellationToken? cancellationToken = null)
{
HttpCallResult<DeletionStatus> status = await HttpAtomic<DeletionStatus>(Api.GetProvider(LLmProviders.OpenAi), CapabilityEndpoints.Assistants, HttpMethod.Delete, GetUrl(Api.GetProvider(LLmProviders.OpenAi), $"/{assistantId}/files/{fileId}"), ct: cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
return new HttpCallResult<bool>(status.Code, status.Response, status.Data?.Deleted ?? false, status.Ok, null);
Expand All @@ -164,7 +164,7 @@ public async Task<HttpCallResult<bool>> RemoveFileAsync(string assistantId, stri
/// <param name="file">The file to delete.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken" />.</param>
/// <returns>True, if file was removed.</returns>
public async Task<HttpCallResult<bool>> RemoveFileAsync(string assistantId, File file, CancellationToken? cancellationToken = default)
public async Task<HttpCallResult<bool>> RemoveFileAsync(string assistantId, File file, CancellationToken? cancellationToken = null)
{
HttpCallResult<DeletionStatus> status = await HttpAtomic<DeletionStatus>(Api.GetProvider(LLmProviders.OpenAi), CapabilityEndpoints.Assistants, HttpMethod.Delete, GetUrl(Api.GetProvider(LLmProviders.OpenAi), $"/{assistantId}/files/{file.Id}"), ct: cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
return new HttpCallResult<bool>(status.Code, status.Response, status.Data?.Deleted ?? false, status.Ok, null);
Expand Down
2 changes: 1 addition & 1 deletion LlmTornado/Chat/FunctionCall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public FunctionCall()
/// Any arguments that need to be passed to the function. This needs to be in JSON format.
/// </summary>
[JsonProperty("arguments")]
public string Arguments { get; set; } = default!;
public string Arguments { get; set; } = null!;

/// <summary>
/// The result of the function. This is resolved by the API consumer.
Expand Down
2 changes: 1 addition & 1 deletion LlmTornado/Chat/ToolCall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class ToolCall
/// The underlying function call.
/// </summary>
[JsonProperty("function")]
public FunctionCall FunctionCall { get; set; } = default!;
public FunctionCall FunctionCall { get; set; } = null!;

/// <summary>
/// Gets the json encoded function call, this is cached to avoid serializing the function over and over.
Expand Down
14 changes: 14 additions & 0 deletions LlmTornado/Code/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace LlmTornado.Code;
Expand All @@ -24,6 +26,18 @@ public static void AddOrUpdate<TK, TV>(this ConcurrentDictionary<TK, TV> diction

public static bool ContainsLineBreaks(this ReadOnlySpan<char> text) => text.IndexOfAny('\r', '\n') >= 0;

public static async Task<byte[]> ToArrayAsync(this Stream stream)
{
if (stream is MemoryStream memorySource)
{
return memorySource.ToArray();
}

using MemoryStream memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream);
return memoryStream.ToArray();
}

public static string? GetDescription<T>(this T source)
{
if (source is null)
Expand Down
34 changes: 34 additions & 0 deletions LlmTornado/Common/HttpCallResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,40 @@ public class HttpCallRequest
public HttpContent? Content { get; set; }
}

/// <summary>
/// Failed HTTP call.
/// </summary>
public class ErrorHttpCallResult : IHttpCallResult
{
/// <summary>
/// Status code received.
/// </summary>
public HttpStatusCode Code { get; set; }

/// <summary>
/// Raw response from the endpoint.
/// </summary>
public string? Response { get; set; }

/// <summary>
/// Exception.
/// </summary>
public Exception? Exception { get; set; }

/// <summary>
/// Creates new error result.
/// </summary>
/// <param name="code"></param>
/// <param name="response"></param>
/// <param name="exception"></param>
public ErrorHttpCallResult(HttpStatusCode code, string? response, Exception? exception)
{
Code = code;
Response = response;
Exception = exception;
}
}

/// <summary>
/// REST call result.
/// </summary>
Expand Down
33 changes: 20 additions & 13 deletions LlmTornado/Common/RestDataOrException.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net;
using System.Net.Http;

namespace LlmTornado.Common;

public class RestDataOrException<T>
{
private bool exceptionIsNull => Exception is null;
private bool dataIsNull => Data is null;

[MemberNotNullWhen(true, nameof(exceptionIsNull))]
public T? Data { get; set; }

[MemberNotNullWhen(true, nameof(dataIsNull))]
public Exception? Exception { get; set; }

public IHttpCallResult? HttpResult { get; set; }
public HttpCallRequest? HttpRequest { get; set; }

public RestDataOrException(T data, IHttpCallResult? httpRequest)
{
Data = data;
Expand All @@ -19,10 +32,11 @@ public RestDataOrException(T data, HttpRequestMessage httpRequest)
ParseRawRequest(httpRequest);
}

public RestDataOrException(Exception e, HttpRequestMessage httpRequest)
public RestDataOrException(Exception e, HttpRequestMessage httpRequest, ErrorHttpCallResult? errorResponse)
{
Exception = e;
ParseRawRequest(httpRequest);
HttpResult = errorResponse;
}

public RestDataOrException(Exception e, IHttpCallResult? httpRequest)
Expand All @@ -31,6 +45,11 @@ public RestDataOrException(Exception e, IHttpCallResult? httpRequest)
HttpResult = httpRequest;
}

public RestDataOrException(Exception e)
{
Exception = e;
}

public RestDataOrException(IHttpCallResult httpRequest)
{
Exception = httpRequest.Exception;
Expand All @@ -47,16 +66,4 @@ internal void ParseRawRequest(HttpRequestMessage httpRequest)
Content = httpRequest.Content
};
}

private bool exceptionIsNull => Exception is null;
private bool dataIsNull => Data is null;

[MemberNotNullWhen(true, nameof(exceptionIsNull))]
public T? Data { get; set; }

[MemberNotNullWhen(true, nameof(dataIsNull))]
public Exception? Exception { get; set; }

public IHttpCallResult? HttpResult { get; set; }
public HttpCallRequest? HttpRequest { get; set; }
}
Loading

0 comments on commit d3bc768

Please sign in to comment.