mirror of
https://github.com/marcominerva/SqlDatabaseVectorSearch.git
synced 2026-08-04 09:48:57 +00:00
Refactor models, update usage tracking, and clean citations
- Enabled additional C# code style suggestions in .editorconfig. - Removed citation rendering and extraction from Ask.razor. - Deleted Citation, ChatResponse, and TokenUsage models and references. - Updated TokenUsageResponse to use UsageDetails from Microsoft.Extensions.AI. - Refactored Response model: removed citations, added ConversationId, and adopted new token usage structure. - Updated HybridCacheSessionStoreService with new cache key format and DeleteSessionAsync method. - Refactored VectorSearchService to remove AppSettings dependency, update method signatures, and use UsageDetails for token tracking. - Updated NuGet package references in SqlDatabaseVectorSearch.csproj.
This commit is contained in:
@@ -124,6 +124,7 @@ csharp_style_prefer_null_check_over_type_check = true:suggestion
|
|||||||
|
|
||||||
# Modifier preferences
|
# Modifier preferences
|
||||||
csharp_prefer_static_local_function = true:suggestion
|
csharp_prefer_static_local_function = true:suggestion
|
||||||
|
csharp_prefer_static_anonymous_function = true:suggestion
|
||||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
||||||
|
|
||||||
# Code-block preferences
|
# Code-block preferences
|
||||||
@@ -139,9 +140,11 @@ csharp_prefer_system_threading_lock = true:suggestion
|
|||||||
csharp_prefer_simple_default_expression = true:suggestion
|
csharp_prefer_simple_default_expression = true:suggestion
|
||||||
csharp_style_deconstructed_variable_declaration = false:suggestion
|
csharp_style_deconstructed_variable_declaration = false:suggestion
|
||||||
csharp_style_inlined_variable_declaration = true:suggestion
|
csharp_style_inlined_variable_declaration = true:suggestion
|
||||||
|
csharp_style_prefer_implicitly_typed_lambda_expression = true:suggestion
|
||||||
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
||||||
csharp_style_prefer_index_operator = true:suggestion
|
csharp_style_prefer_index_operator = true:suggestion
|
||||||
csharp_style_prefer_range_operator = true:suggestion
|
csharp_style_prefer_range_operator = true:suggestion
|
||||||
|
csharp_style_prefer_unbound_generic_type_in_nameof = true:suggestion
|
||||||
csharp_style_throw_expression = true:suggestion
|
csharp_style_throw_expression = true:suggestion
|
||||||
csharp_style_unused_value_assignment_preference = discard_variable:none
|
csharp_style_unused_value_assignment_preference = discard_variable:none
|
||||||
csharp_style_unused_value_expression_statement_preference = discard_variable:none
|
csharp_style_unused_value_expression_statement_preference = discard_variable:none
|
||||||
|
|||||||
@@ -83,23 +83,6 @@
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (message.Citations is not null && message.Citations.Count() > 0)
|
|
||||||
{
|
|
||||||
<div class="mt-3 d-flex flex-wrap">
|
|
||||||
@foreach (var citation in message.Citations)
|
|
||||||
{
|
|
||||||
<div class="border rounded p-2 me-2 mb-2 citation-box small">
|
|
||||||
<div>
|
|
||||||
<strong>@citation.FileName</strong> @if (citation.PageNumber.GetValueOrDefault() > 0)
|
|
||||||
{
|
|
||||||
<span class="ms-2">pag. @citation.PageNumber</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div class="text-secondary small mt-1">@citation.Quote</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -212,17 +195,6 @@
|
|||||||
}
|
}
|
||||||
else if (delta.StreamState == StreamState.End)
|
else if (delta.StreamState == StreamState.End)
|
||||||
{
|
{
|
||||||
// Get citations from the response.
|
|
||||||
assistantMessage.Citations = delta.Citations?.Select(c => new Citation
|
|
||||||
{
|
|
||||||
DocumentId = c.DocumentId,
|
|
||||||
ChunkId = c.ChunkId,
|
|
||||||
FileName = c.FileName,
|
|
||||||
Quote = c.Quote,
|
|
||||||
PageNumber = c.PageNumber,
|
|
||||||
IndexOnPage = c.IndexOnPage
|
|
||||||
});
|
|
||||||
|
|
||||||
assistantMessage.Status = MessageStatus.Completed;
|
assistantMessage.Status = MessageStatus.Completed;
|
||||||
assistantMessage.TokenUsage += FormatTokenUsage(delta.TokenUsage);
|
assistantMessage.TokenUsage += FormatTokenUsage(delta.TokenUsage);
|
||||||
}
|
}
|
||||||
@@ -282,26 +254,22 @@
|
|||||||
? $"<p><strong>Reformulation:</strong><br />{FormatTokenUsageDetails(tokenUsageResponse.Reformulation)}</p>"
|
? $"<p><strong>Reformulation:</strong><br />{FormatTokenUsageDetails(tokenUsageResponse.Reformulation)}</p>"
|
||||||
: string.Empty;
|
: string.Empty;
|
||||||
|
|
||||||
var embeddingTokenCount = tokenUsageResponse.EmbeddingTokenCount.HasValue
|
|
||||||
? $"<p><strong>Embedding Token Count:</strong> {tokenUsageResponse.EmbeddingTokenCount}</p>"
|
|
||||||
: string.Empty;
|
|
||||||
|
|
||||||
var question = tokenUsageResponse.Question is not null
|
var question = tokenUsageResponse.Question is not null
|
||||||
? $"<p><strong>Question:</strong><br />{FormatTokenUsageDetails(tokenUsageResponse.Question)}</p>"
|
? $"<p><strong>Question:</strong><br />{FormatTokenUsageDetails(tokenUsageResponse.Question)}</p>"
|
||||||
: string.Empty;
|
: string.Empty;
|
||||||
|
|
||||||
return $"{reformulation}{embeddingTokenCount}{question}";
|
return $"{reformulation}{question}";
|
||||||
|
|
||||||
static string FormatTokenUsageDetails(TokenUsage? tokenUsage)
|
static string FormatTokenUsageDetails(Microsoft.Extensions.AI.UsageDetails? tokenUsage)
|
||||||
{
|
{
|
||||||
if (tokenUsage is null)
|
if (tokenUsage is null)
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"Prompt tokens: {tokenUsage.PromptTokens}<br />" +
|
return $"Input tokens: {tokenUsage.InputTokenCount}<br />" +
|
||||||
$"Completion tokens: {tokenUsage.CompletionTokens}<br />" +
|
$"Output tokens: {tokenUsage.OutputTokenCount}<br />" +
|
||||||
$"Total tokens: {tokenUsage.TotalTokens}";
|
$"Total tokens: {tokenUsage.TotalTokenCount}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,23 +294,5 @@
|
|||||||
public MessageStatus Status { get; set; } = MessageStatus.New;
|
public MessageStatus Status { get; set; } = MessageStatus.New;
|
||||||
|
|
||||||
public string? TokenUsage { get; set; }
|
public string? TokenUsage { get; set; }
|
||||||
|
|
||||||
// List of citations extracted from the answer.
|
|
||||||
public IEnumerable<Citation>? Citations { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Citation
|
|
||||||
{
|
|
||||||
public Guid DocumentId { get; set; }
|
|
||||||
|
|
||||||
public Guid ChunkId { get; set; }
|
|
||||||
|
|
||||||
public string FileName { get; set; } = null!;
|
|
||||||
|
|
||||||
public string Quote { get; set; } = null!;
|
|
||||||
|
|
||||||
public int? PageNumber { get; set; }
|
|
||||||
|
|
||||||
public int IndexOnPage { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
namespace SqlDatabaseVectorSearch.Models;
|
|
||||||
|
|
||||||
public record class ChatResponse(string? Text, TokenUsage? TokenUsage = null);
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
namespace SqlDatabaseVectorSearch.Models;
|
|
||||||
|
|
||||||
public class Citation
|
|
||||||
{
|
|
||||||
public Guid DocumentId { get; set; }
|
|
||||||
|
|
||||||
public Guid ChunkId { get; set; }
|
|
||||||
|
|
||||||
public string FileName { get; set; } = null!;
|
|
||||||
|
|
||||||
public string Quote { get; set; } = null!;
|
|
||||||
|
|
||||||
public int? PageNumber { get; set; }
|
|
||||||
|
|
||||||
public int IndexOnPage { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
namespace SqlDatabaseVectorSearch.Models;
|
namespace SqlDatabaseVectorSearch.Models;
|
||||||
|
|
||||||
// Question and Answer can be null when using response streaming.
|
// Question and Answer can be null when using response streaming.
|
||||||
public record class Response(string? OriginalQuestion, string? ReformulatedQuestion, string? Answer, StreamState? StreamState = null, TokenUsageResponse? TokenUsage = null, IEnumerable<Citation>? Citations = null)
|
public record class Response(Guid ConversationId, string? OriginalQuestion, string? ReformulatedQuestion, string? Answer, StreamState? StreamState = null, TokenUsageResponse? TokenUsage = null)
|
||||||
{
|
{
|
||||||
public Response(string? token, StreamState streamState, TokenUsageResponse? tokenUsageResponse = null, IEnumerable<Citation>? citations = null)
|
public Response(Guid conversationId, string? token, StreamState streamState, TokenUsageResponse? tokenUsageResponse = null)
|
||||||
: this(null, null, token, streamState, tokenUsageResponse, citations)
|
: this(conversationId, null, null, token, streamState, tokenUsageResponse)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record class RagResponse(Guid ConversationId, string OriginalQuestion, string ReformulatedQuestion, string Answer);
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace SqlDatabaseVectorSearch.Models;
|
|
||||||
|
|
||||||
public record class TokenUsage(int PromptTokens, int CompletionTokens)
|
|
||||||
{
|
|
||||||
public int TotalTokens => PromptTokens + CompletionTokens;
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
namespace SqlDatabaseVectorSearch.Models;
|
using Microsoft.Extensions.AI;
|
||||||
|
|
||||||
public record class TokenUsageResponse(TokenUsage? Reformulation, int? EmbeddingTokenCount, TokenUsage? Question)
|
namespace SqlDatabaseVectorSearch.Models;
|
||||||
{
|
|
||||||
public TokenUsageResponse(TokenUsage? question)
|
public record class TokenUsageResponse(UsageDetails? Reformulation, UsageDetails? Question);
|
||||||
: this(null, null, question)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,23 +8,30 @@ public class HybridCacheSessionStoreService(HybridCache cache) : AgentSessionSto
|
|||||||
{
|
{
|
||||||
public override async ValueTask<AgentSession> GetSessionAsync(AIAgent agent, string conversationId, CancellationToken cancellationToken = default)
|
public override async ValueTask<AgentSession> GetSessionAsync(AIAgent agent, string conversationId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var sessionContent = await cache.GetOrCreateAsync(
|
var key = GetKey(agent, conversationId);
|
||||||
GetCacheKey(conversationId),
|
var sessionContent = await cache.GetOrCreateAsync(key, async ct =>
|
||||||
async ct =>
|
|
||||||
{
|
{
|
||||||
var session = await agent.CreateSessionAsync(ct);
|
var session = await agent.CreateSessionAsync(ct);
|
||||||
return await agent.SerializeSessionAsync(session, cancellationToken: ct);
|
return await agent.SerializeSessionAsync(session, cancellationToken: ct);
|
||||||
},
|
}, cancellationToken: cancellationToken);
|
||||||
cancellationToken: cancellationToken);
|
|
||||||
|
|
||||||
return await agent.DeserializeSessionAsync(sessionContent, cancellationToken: cancellationToken);
|
return await agent.DeserializeSessionAsync(sessionContent, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async ValueTask SaveSessionAsync(AIAgent agent, string conversationId, AgentSession session, CancellationToken cancellationToken = default)
|
public override async ValueTask SaveSessionAsync(AIAgent agent, string conversationId, AgentSession session, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
var key = GetKey(agent, conversationId);
|
||||||
var sessionContent = await agent.SerializeSessionAsync(session, cancellationToken: cancellationToken);
|
var sessionContent = await agent.SerializeSessionAsync(session, cancellationToken: cancellationToken);
|
||||||
await cache.SetAsync(GetCacheKey(conversationId), sessionContent, cancellationToken: cancellationToken);
|
|
||||||
|
await cache.SetAsync(key, sessionContent, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetCacheKey(string conversationId) => $"agent-session:{conversationId}";
|
public override async ValueTask DeleteSessionAsync(AIAgent agent, string conversationId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var key = GetKey(agent, conversationId);
|
||||||
|
await cache.RemoveAsync(key, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetKey(AIAgent agent, string conversationId)
|
||||||
|
=> $"{agent.Id}:{conversationId}";
|
||||||
}
|
}
|
||||||
@@ -15,10 +15,8 @@ using SqlDatabaseVectorSearch.Workflows;
|
|||||||
namespace SqlDatabaseVectorSearch.Services;
|
namespace SqlDatabaseVectorSearch.Services;
|
||||||
|
|
||||||
public partial class VectorSearchService([FromKeyedServices("EmbeddingWorkflow")] Workflow workflow, [FromKeyedServices("ReformulationAgent")] AIAgent reformulationAgent, [FromKeyedServices("RagAgent")] AIAgent ragAgent,
|
public partial class VectorSearchService([FromKeyedServices("EmbeddingWorkflow")] Workflow workflow, [FromKeyedServices("ReformulationAgent")] AIAgent reformulationAgent, [FromKeyedServices("RagAgent")] AIAgent ragAgent,
|
||||||
[FromKeyedServices("RagAgent")] AgentSessionStore sessionStore, IOptions<AppSettings> appSettingsOptions)
|
[FromKeyedServices("RagAgent")] AgentSessionStore sessionStore)
|
||||||
{
|
{
|
||||||
private readonly AppSettings appSettings = appSettingsOptions.Value;
|
|
||||||
|
|
||||||
public async Task<StoreEmbeddingResponse> ImportAsync(FormFileEmbeddingRequest request, CancellationToken cancellationToken = default)
|
public async Task<StoreEmbeddingResponse> ImportAsync(FormFileEmbeddingRequest request, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
await using var run = await InProcessExecution.RunAsync(workflow, request, cancellationToken: cancellationToken);
|
await using var run = await InProcessExecution.RunAsync(workflow, request, cancellationToken: cancellationToken);
|
||||||
@@ -34,8 +32,9 @@ public partial class VectorSearchService([FromKeyedServices("EmbeddingWorkflow")
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<RagResponse> AskQuestionAsync(Question question, bool reformulate = true, CancellationToken cancellationToken = default)
|
public async Task<Response> AskQuestionAsync(Question question, bool reformulate = true, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
UsageDetails? reformulationUsage = null;
|
||||||
var reformulatedQuestion = question.Text;
|
var reformulatedQuestion = question.Text;
|
||||||
var session = await sessionStore.GetSessionAsync(ragAgent, question.ConversationId.ToString(), cancellationToken);
|
var session = await sessionStore.GetSessionAsync(ragAgent, question.ConversationId.ToString(), cancellationToken);
|
||||||
|
|
||||||
@@ -44,62 +43,48 @@ public partial class VectorSearchService([FromKeyedServices("EmbeddingWorkflow")
|
|||||||
// Reformulates the question taking into account the context of the chat to perform keyword search and embeddings.
|
// Reformulates the question taking into account the context of the chat to perform keyword search and embeddings.
|
||||||
var reformulationResponse = await reformulationAgent.RunAsync(question.Text, session, cancellationToken: cancellationToken);
|
var reformulationResponse = await reformulationAgent.RunAsync(question.Text, session, cancellationToken: cancellationToken);
|
||||||
reformulatedQuestion = reformulationResponse.Text;
|
reformulatedQuestion = reformulationResponse.Text;
|
||||||
|
reformulationUsage = reformulationResponse.Usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = await ragAgent.RunAsync(reformulatedQuestion, session, cancellationToken: cancellationToken);
|
var response = await ragAgent.RunAsync(reformulatedQuestion, session, cancellationToken: cancellationToken);
|
||||||
|
|
||||||
await sessionStore.SaveSessionAsync(ragAgent, question.ConversationId.ToString(), session, cancellationToken);
|
await sessionStore.SaveSessionAsync(ragAgent, question.ConversationId.ToString(), session, cancellationToken);
|
||||||
|
|
||||||
session.TryGetInMemoryChatHistory(out var chatHistory);
|
return new(question.ConversationId, question.Text, reformulatedQuestion, response.Text, null, new TokenUsageResponse(reformulationUsage, response.Usage));
|
||||||
|
|
||||||
return new(question.ConversationId, question.Text, reformulatedQuestion, response.Text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async IAsyncEnumerable<Response> AskStreamingAsync(Question question, bool reformulate = true, [EnumeratorCancellation] CancellationToken cancellationToken = default)
|
public async IAsyncEnumerable<Response> AskStreamingAsync(Question question, bool reformulate = true, [EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
yield return null!;
|
UsageDetails? reformulationUsage = null;
|
||||||
|
var reformulatedQuestion = question.Text;
|
||||||
|
var session = await sessionStore.GetSessionAsync(ragAgent, question.ConversationId.ToString(), cancellationToken);
|
||||||
|
|
||||||
//// It the user doesn't want to reforulate the question, CreateContextAsync returns the original one.
|
if (reformulate)
|
||||||
//var (reformulatedQuestion, embeddingTokenCount, chunks) = await CreateContextAsync(question, reformulate, cancellationToken);
|
{
|
||||||
|
// Reformulates the question taking into account the context of the chat to perform keyword search and embeddings.
|
||||||
|
var reformulationResponse = await reformulationAgent.RunAsync(question.Text, session, cancellationToken: cancellationToken);
|
||||||
|
reformulatedQuestion = reformulationResponse.Text;
|
||||||
|
reformulationUsage = reformulationResponse.Usage;
|
||||||
|
}
|
||||||
|
|
||||||
//var answerStream = chatService.AskStreamingAsync(question.ConversationId, chunks, reformulatedQuestion.Text!, cancellationToken: cancellationToken);
|
// The first message contains the question and the corresponding token usage (if reformulated).
|
||||||
|
yield return new(question.ConversationId, question.Text, reformulatedQuestion, null, StreamState.Start, new(reformulationUsage, null));
|
||||||
|
|
||||||
//// The first message contains the question and the corresponding token usage (if reformulated).
|
var updates = new List<AgentResponseUpdate>();
|
||||||
//yield return new(question.Text, reformulatedQuestion.Text!, null, StreamState.Start, new(reformulatedQuestion.TokenUsage, embeddingTokenCount, null));
|
|
||||||
|
|
||||||
//TokenUsageResponse? tokenUsageResponse = null;
|
await foreach (var update in ragAgent.RunStreamingAsync(reformulatedQuestion, session, cancellationToken: cancellationToken))
|
||||||
//var fullAnswer = new StringBuilder();
|
{
|
||||||
//var citationsStarted = false;
|
updates.Add(update);
|
||||||
|
if (!string.IsNullOrEmpty(update.Text))
|
||||||
|
{
|
||||||
|
yield return new(question.ConversationId, update.Text, StreamState.Append);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//// Returns each token as a partial response.
|
await sessionStore.SaveSessionAsync(ragAgent, question.ConversationId.ToString(), session, cancellationToken);
|
||||||
//await foreach (var (token, tokenUsage) in answerStream)
|
var response = updates.ToAgentResponse();
|
||||||
//{
|
|
||||||
// if (token is not null) // token can be null when the stream ends.
|
|
||||||
// {
|
|
||||||
// fullAnswer.Append(token);
|
|
||||||
|
|
||||||
// if (token.Contains('【'))
|
yield return new(question.ConversationId, null, null, response.Text, StreamState.End, new TokenUsageResponse(null, response.Usage));
|
||||||
// {
|
|
||||||
// // Citations start when we encounter a token containing a 【 character.
|
|
||||||
// // We need to track it because we don't want to return the citations in the actual response.
|
|
||||||
// citationsStarted = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (!citationsStarted)
|
|
||||||
// {
|
|
||||||
// yield return new(token, StreamState.Append);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// // Token usage is expected in the last message, when token is null.
|
|
||||||
// tokenUsageResponse ??= tokenUsage is not null ? new(tokenUsage) : null;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//// Extract citations at the end of streaming.
|
|
||||||
//var (_, citations) = ExtractCitations(fullAnswer.ToString());
|
|
||||||
//yield return new(null, StreamState.End, tokenUsageResponse, citations);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,34 +12,34 @@
|
|||||||
<PackageReference Include="DocumentFormat.OpenXml" Version="3.5.1" />
|
<PackageReference Include="DocumentFormat.OpenXml" Version="3.5.1" />
|
||||||
<PackageReference Include="EntityFrameworkCore.Exceptions.SqlServer" Version="10.0.1" />
|
<PackageReference Include="EntityFrameworkCore.Exceptions.SqlServer" Version="10.0.1" />
|
||||||
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.1.1" />
|
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.1.1" />
|
||||||
<PackageReference Include="Microsoft.Agents.AI.Hosting" Version="1.10.0-preview.260610.1" />
|
<PackageReference Include="Microsoft.Agents.AI.Hosting" Version="1.15.0-preview.260722.1" />
|
||||||
<PackageReference Include="Microsoft.Agents.AI.OpenAI" Version="1.10.0" />
|
<PackageReference Include="Microsoft.Agents.AI.OpenAI" Version="1.15.0" />
|
||||||
<PackageReference Include="Microsoft.Agents.AI.Workflows" Version="1.10.0" />
|
<PackageReference Include="Microsoft.Agents.AI.Workflows" Version="1.15.0" />
|
||||||
<PackageReference Include="Microsoft.Agents.AI.Workflows.Generators" Version="1.10.0">
|
<PackageReference Include="Microsoft.Agents.AI.Workflows.Generators" Version="1.15.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.9" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.10" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.9">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.10">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.9" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.10" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.9">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.10">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="10.7.0" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="10.8.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="10.7.0" />
|
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="10.8.0" />
|
||||||
<PackageReference Include="Microsoft.ML.Tokenizers" Version="2.0.0" />
|
<PackageReference Include="Microsoft.ML.Tokenizers" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.ML.Tokenizers.Data.Cl100kBase" Version="2.0.0" />
|
<PackageReference Include="Microsoft.ML.Tokenizers.Data.Cl100kBase" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.ML.Tokenizers.Data.O200kBase" Version="2.0.0" />
|
<PackageReference Include="Microsoft.ML.Tokenizers.Data.O200kBase" Version="2.0.0" />
|
||||||
<PackageReference Include="MimeMapping" Version="4.0.0" />
|
<PackageReference Include="MimeMapping" Version="4.0.0" />
|
||||||
<PackageReference Include="MinimalHelpers.FluentValidation" Version="1.1.8" />
|
<PackageReference Include="MinimalHelpers.FluentValidation" Version="1.1.8" />
|
||||||
<PackageReference Include="MinimalHelpers.Routing.Analyzers" Version="1.2.2" />
|
<PackageReference Include="MinimalHelpers.Routing.Analyzers" Version="1.2.2" />
|
||||||
<PackageReference Include="PdfPig" Version="0.1.14" />
|
<PackageReference Include="PdfPig" Version="0.1.15" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.2.1" />
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.2.3" />
|
||||||
<PackageReference Include="TinyHelpers.AspNetCore" Version="4.2.12" />
|
<PackageReference Include="TinyHelpers.AspNetCore" Version="4.2.17" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user