audit notes work completed, test fixes work (95% done), new sprints, new data sources setup and configuration
This commit is contained in:
235
src/Cli/StellaOps.Cli/Services/Chat/ChatClient.cs
Normal file
235
src/Cli/StellaOps.Cli/Services/Chat/ChatClient.cs
Normal file
@@ -0,0 +1,235 @@
|
||||
// Copyright (c) StellaOps. All rights reserved.
|
||||
// Licensed under the AGPL-3.0-or-later license.
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using StellaOps.Cli.Configuration;
|
||||
using StellaOps.Cli.Services.Models.Chat;
|
||||
|
||||
namespace StellaOps.Cli.Services.Chat;
|
||||
|
||||
/// <summary>
|
||||
/// HTTP client for AdvisoryAI chat operations.
|
||||
/// </summary>
|
||||
internal sealed class ChatClient : IChatClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly StellaOpsCliOptions _options;
|
||||
private readonly JsonSerializerOptions _jsonOptions;
|
||||
|
||||
public ChatClient(HttpClient httpClient, StellaOpsCliOptions options)
|
||||
{
|
||||
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
_jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web);
|
||||
}
|
||||
|
||||
public async Task<ChatQueryResponse> QueryAsync(
|
||||
ChatQueryRequest request,
|
||||
string? tenantId = null,
|
||||
string? userId = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
var url = BuildUrl("/api/v1/chat/query");
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, url);
|
||||
AddHeaders(httpRequest, tenantId, userId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
using var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
await EnsureSuccessOrThrowAsync(response, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<ChatQueryResponse>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
return result ?? throw new InvalidOperationException("Chat query returned null response.");
|
||||
}
|
||||
|
||||
public async Task<ChatDoctorResponse> GetDoctorAsync(
|
||||
string? tenantId = null,
|
||||
string? userId = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var url = BuildUrl("/api/v1/chat/doctor");
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
AddHeaders(httpRequest, tenantId, userId);
|
||||
|
||||
using var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
await EnsureSuccessOrThrowAsync(response, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<ChatDoctorResponse>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
return result ?? throw new InvalidOperationException("Chat doctor returned null response.");
|
||||
}
|
||||
|
||||
public async Task<ChatSettingsResponse> GetSettingsAsync(
|
||||
string scope = "effective",
|
||||
string? tenantId = null,
|
||||
string? userId = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var url = BuildUrl($"/api/v1/chat/settings?scope={Uri.EscapeDataString(scope)}");
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
AddHeaders(httpRequest, tenantId, userId);
|
||||
|
||||
using var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
await EnsureSuccessOrThrowAsync(response, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<ChatSettingsResponse>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
return result ?? throw new InvalidOperationException("Chat settings returned null response.");
|
||||
}
|
||||
|
||||
public async Task<ChatSettingsResponse> UpdateSettingsAsync(
|
||||
ChatSettingsUpdateRequest request,
|
||||
string scope = "user",
|
||||
string? tenantId = null,
|
||||
string? userId = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
var url = BuildUrl($"/api/v1/chat/settings?scope={Uri.EscapeDataString(scope)}");
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Put, url);
|
||||
AddHeaders(httpRequest, tenantId, userId);
|
||||
httpRequest.Content = JsonContent.Create(request, options: _jsonOptions);
|
||||
|
||||
using var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
await EnsureSuccessOrThrowAsync(response, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<ChatSettingsResponse>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
return result ?? throw new InvalidOperationException("Chat settings update returned null response.");
|
||||
}
|
||||
|
||||
public async Task ClearSettingsAsync(
|
||||
string scope = "user",
|
||||
string? tenantId = null,
|
||||
string? userId = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var url = BuildUrl($"/api/v1/chat/settings?scope={Uri.EscapeDataString(scope)}");
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Delete, url);
|
||||
AddHeaders(httpRequest, tenantId, userId);
|
||||
|
||||
using var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
await EnsureSuccessOrThrowAsync(response, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private string BuildUrl(string path)
|
||||
{
|
||||
var baseUrl = _options.BackendUrl?.TrimEnd('/') ?? "http://localhost:5000";
|
||||
return $"{baseUrl}{path}";
|
||||
}
|
||||
|
||||
private static void AddHeaders(HttpRequestMessage request, string? tenantId, string? userId)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(tenantId))
|
||||
{
|
||||
request.Headers.TryAddWithoutValidation("X-Tenant-Id", tenantId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(userId))
|
||||
{
|
||||
request.Headers.TryAddWithoutValidation("X-User-Id", userId);
|
||||
}
|
||||
|
||||
request.Headers.TryAddWithoutValidation("X-Correlation-Id", Guid.NewGuid().ToString("N"));
|
||||
}
|
||||
|
||||
private async Task EnsureSuccessOrThrowAsync(HttpResponseMessage response, CancellationToken cancellationToken)
|
||||
{
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChatErrorResponse? errorResponse = null;
|
||||
try
|
||||
{
|
||||
errorResponse = await response.Content.ReadFromJsonAsync<ChatErrorResponse>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore JSON parse errors for error response
|
||||
}
|
||||
|
||||
var statusCode = (int)response.StatusCode;
|
||||
var errorMessage = errorResponse?.Error ?? response.ReasonPhrase ?? "Unknown error";
|
||||
var errorCode = errorResponse?.Code;
|
||||
|
||||
var exception = response.StatusCode switch
|
||||
{
|
||||
HttpStatusCode.BadRequest when errorCode == "GUARDRAIL_BLOCKED" =>
|
||||
new ChatGuardrailException(errorMessage, errorResponse),
|
||||
HttpStatusCode.Forbidden when errorCode == "TOOL_DENIED" =>
|
||||
new ChatToolDeniedException(errorMessage, errorResponse),
|
||||
HttpStatusCode.TooManyRequests =>
|
||||
new ChatQuotaExceededException(errorMessage, errorResponse),
|
||||
HttpStatusCode.ServiceUnavailable =>
|
||||
new ChatServiceUnavailableException(errorMessage, errorResponse),
|
||||
_ => new ChatException($"Chat API error ({statusCode}): {errorMessage}", errorResponse)
|
||||
};
|
||||
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base exception for chat API errors.
|
||||
/// </summary>
|
||||
internal class ChatException : Exception
|
||||
{
|
||||
public ChatErrorResponse? ErrorResponse { get; }
|
||||
|
||||
public ChatException(string message, ChatErrorResponse? errorResponse = null)
|
||||
: base(message)
|
||||
{
|
||||
ErrorResponse = errorResponse;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exception thrown when a guardrail blocks the request.
|
||||
/// </summary>
|
||||
internal sealed class ChatGuardrailException : ChatException
|
||||
{
|
||||
public ChatGuardrailException(string message, ChatErrorResponse? errorResponse = null)
|
||||
: base(message, errorResponse)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exception thrown when tool access is denied.
|
||||
/// </summary>
|
||||
internal sealed class ChatToolDeniedException : ChatException
|
||||
{
|
||||
public ChatToolDeniedException(string message, ChatErrorResponse? errorResponse = null)
|
||||
: base(message, errorResponse)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exception thrown when quota is exceeded.
|
||||
/// </summary>
|
||||
internal sealed class ChatQuotaExceededException : ChatException
|
||||
{
|
||||
public ChatQuotaExceededException(string message, ChatErrorResponse? errorResponse = null)
|
||||
: base(message, errorResponse)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exception thrown when chat service is unavailable.
|
||||
/// </summary>
|
||||
internal sealed class ChatServiceUnavailableException : ChatException
|
||||
{
|
||||
public ChatServiceUnavailableException(string message, ChatErrorResponse? errorResponse = null)
|
||||
: base(message, errorResponse)
|
||||
{
|
||||
}
|
||||
}
|
||||
59
src/Cli/StellaOps.Cli/Services/Chat/IChatClient.cs
Normal file
59
src/Cli/StellaOps.Cli/Services/Chat/IChatClient.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) StellaOps. All rights reserved.
|
||||
// Licensed under the AGPL-3.0-or-later license.
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using StellaOps.Cli.Services.Models.Chat;
|
||||
|
||||
namespace StellaOps.Cli.Services.Chat;
|
||||
|
||||
/// <summary>
|
||||
/// Client interface for AdvisoryAI chat operations.
|
||||
/// </summary>
|
||||
internal interface IChatClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Send a chat query and receive a response.
|
||||
/// </summary>
|
||||
Task<ChatQueryResponse> QueryAsync(
|
||||
ChatQueryRequest request,
|
||||
string? tenantId = null,
|
||||
string? userId = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get chat doctor diagnostics (quota status, tool access, last denial).
|
||||
/// </summary>
|
||||
Task<ChatDoctorResponse> GetDoctorAsync(
|
||||
string? tenantId = null,
|
||||
string? userId = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get current chat settings.
|
||||
/// </summary>
|
||||
Task<ChatSettingsResponse> GetSettingsAsync(
|
||||
string scope = "effective",
|
||||
string? tenantId = null,
|
||||
string? userId = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Update chat settings.
|
||||
/// </summary>
|
||||
Task<ChatSettingsResponse> UpdateSettingsAsync(
|
||||
ChatSettingsUpdateRequest request,
|
||||
string scope = "user",
|
||||
string? tenantId = null,
|
||||
string? userId = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Clear chat settings overrides.
|
||||
/// </summary>
|
||||
Task ClearSettingsAsync(
|
||||
string scope = "user",
|
||||
string? tenantId = null,
|
||||
string? userId = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
429
src/Cli/StellaOps.Cli/Services/Models/Chat/ChatModels.cs
Normal file
429
src/Cli/StellaOps.Cli/Services/Models/Chat/ChatModels.cs
Normal file
@@ -0,0 +1,429 @@
|
||||
// Copyright (c) StellaOps. All rights reserved.
|
||||
// Licensed under the AGPL-3.0-or-later license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace StellaOps.Cli.Services.Models.Chat;
|
||||
|
||||
/// <summary>
|
||||
/// Output format for chat commands.
|
||||
/// </summary>
|
||||
internal enum ChatOutputFormat
|
||||
{
|
||||
Table,
|
||||
Json,
|
||||
Markdown
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chat query request sent to the AdvisoryAI chat API.
|
||||
/// </summary>
|
||||
internal sealed record ChatQueryRequest
|
||||
{
|
||||
[JsonPropertyName("query")]
|
||||
public required string Query { get; init; }
|
||||
|
||||
[JsonPropertyName("artifactDigest")]
|
||||
public string? ArtifactDigest { get; init; }
|
||||
|
||||
[JsonPropertyName("imageReference")]
|
||||
public string? ImageReference { get; init; }
|
||||
|
||||
[JsonPropertyName("environment")]
|
||||
public string? Environment { get; init; }
|
||||
|
||||
[JsonPropertyName("conversationId")]
|
||||
public string? ConversationId { get; init; }
|
||||
|
||||
[JsonPropertyName("userRoles")]
|
||||
public List<string>? UserRoles { get; init; }
|
||||
|
||||
[JsonPropertyName("noAction")]
|
||||
public bool NoAction { get; init; } = true;
|
||||
|
||||
[JsonPropertyName("includeEvidence")]
|
||||
public bool IncludeEvidence { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chat query response from the AdvisoryAI chat API.
|
||||
/// </summary>
|
||||
internal sealed record ChatQueryResponse
|
||||
{
|
||||
[JsonPropertyName("responseId")]
|
||||
public required string ResponseId { get; init; }
|
||||
|
||||
[JsonPropertyName("bundleId")]
|
||||
public string? BundleId { get; init; }
|
||||
|
||||
[JsonPropertyName("intent")]
|
||||
public required string Intent { get; init; }
|
||||
|
||||
[JsonPropertyName("generatedAt")]
|
||||
public required DateTimeOffset GeneratedAt { get; init; }
|
||||
|
||||
[JsonPropertyName("summary")]
|
||||
public required string Summary { get; init; }
|
||||
|
||||
[JsonPropertyName("impact")]
|
||||
public ChatImpactAssessment? Impact { get; init; }
|
||||
|
||||
[JsonPropertyName("reachability")]
|
||||
public ChatReachabilityAssessment? Reachability { get; init; }
|
||||
|
||||
[JsonPropertyName("mitigations")]
|
||||
public List<ChatMitigationOption> Mitigations { get; init; } = [];
|
||||
|
||||
[JsonPropertyName("evidenceLinks")]
|
||||
public List<ChatEvidenceLink> EvidenceLinks { get; init; } = [];
|
||||
|
||||
[JsonPropertyName("confidence")]
|
||||
public required ChatConfidence Confidence { get; init; }
|
||||
|
||||
[JsonPropertyName("proposedActions")]
|
||||
public List<ChatProposedAction> ProposedActions { get; init; } = [];
|
||||
|
||||
[JsonPropertyName("followUp")]
|
||||
public ChatFollowUp? FollowUp { get; init; }
|
||||
|
||||
[JsonPropertyName("diagnostics")]
|
||||
public ChatDiagnostics? Diagnostics { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatImpactAssessment
|
||||
{
|
||||
[JsonPropertyName("severity")]
|
||||
public string? Severity { get; init; }
|
||||
|
||||
[JsonPropertyName("affectedComponents")]
|
||||
public List<string> AffectedComponents { get; init; } = [];
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
public string? Description { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatReachabilityAssessment
|
||||
{
|
||||
[JsonPropertyName("reachable")]
|
||||
public bool Reachable { get; init; }
|
||||
|
||||
[JsonPropertyName("paths")]
|
||||
public List<string> Paths { get; init; } = [];
|
||||
|
||||
[JsonPropertyName("confidence")]
|
||||
public double Confidence { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatMitigationOption
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public required string Id { get; init; }
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public required string Title { get; init; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
public string? Description { get; init; }
|
||||
|
||||
[JsonPropertyName("effort")]
|
||||
public string? Effort { get; init; }
|
||||
|
||||
[JsonPropertyName("recommended")]
|
||||
public bool Recommended { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatEvidenceLink
|
||||
{
|
||||
[JsonPropertyName("type")]
|
||||
public required string Type { get; init; }
|
||||
|
||||
[JsonPropertyName("ref")]
|
||||
public required string Ref { get; init; }
|
||||
|
||||
[JsonPropertyName("label")]
|
||||
public string? Label { get; init; }
|
||||
|
||||
[JsonPropertyName("digest")]
|
||||
public string? Digest { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatConfidence
|
||||
{
|
||||
[JsonPropertyName("overall")]
|
||||
public double Overall { get; init; }
|
||||
|
||||
[JsonPropertyName("evidenceQuality")]
|
||||
public double EvidenceQuality { get; init; }
|
||||
|
||||
[JsonPropertyName("modelCertainty")]
|
||||
public double ModelCertainty { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatProposedAction
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public required string Id { get; init; }
|
||||
|
||||
[JsonPropertyName("tool")]
|
||||
public required string Tool { get; init; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
public required string Description { get; init; }
|
||||
|
||||
[JsonPropertyName("parameters")]
|
||||
public Dictionary<string, object>? Parameters { get; init; }
|
||||
|
||||
[JsonPropertyName("requiresConfirmation")]
|
||||
public bool RequiresConfirmation { get; init; }
|
||||
|
||||
[JsonPropertyName("denied")]
|
||||
public bool Denied { get; init; }
|
||||
|
||||
[JsonPropertyName("denyReason")]
|
||||
public string? DenyReason { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatFollowUp
|
||||
{
|
||||
[JsonPropertyName("suggestedQueries")]
|
||||
public List<string> SuggestedQueries { get; init; } = [];
|
||||
|
||||
[JsonPropertyName("relatedTopics")]
|
||||
public List<string> RelatedTopics { get; init; } = [];
|
||||
}
|
||||
|
||||
internal sealed record ChatDiagnostics
|
||||
{
|
||||
[JsonPropertyName("tokensUsed")]
|
||||
public int TokensUsed { get; init; }
|
||||
|
||||
[JsonPropertyName("processingTimeMs")]
|
||||
public long ProcessingTimeMs { get; init; }
|
||||
|
||||
[JsonPropertyName("evidenceSourcesQueried")]
|
||||
public int EvidenceSourcesQueried { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chat doctor response with quota and tool access status.
|
||||
/// </summary>
|
||||
internal sealed record ChatDoctorResponse
|
||||
{
|
||||
[JsonPropertyName("tenantId")]
|
||||
public required string TenantId { get; init; }
|
||||
|
||||
[JsonPropertyName("userId")]
|
||||
public required string UserId { get; init; }
|
||||
|
||||
[JsonPropertyName("quotas")]
|
||||
public required ChatQuotaStatus Quotas { get; init; }
|
||||
|
||||
[JsonPropertyName("tools")]
|
||||
public required ChatToolAccess Tools { get; init; }
|
||||
|
||||
[JsonPropertyName("lastDenied")]
|
||||
public ChatDenialInfo? LastDenied { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatQuotaStatus
|
||||
{
|
||||
[JsonPropertyName("requestsPerMinuteLimit")]
|
||||
public int RequestsPerMinuteLimit { get; init; }
|
||||
|
||||
[JsonPropertyName("requestsPerMinuteRemaining")]
|
||||
public int RequestsPerMinuteRemaining { get; init; }
|
||||
|
||||
[JsonPropertyName("requestsPerMinuteResetsAt")]
|
||||
public DateTimeOffset RequestsPerMinuteResetsAt { get; init; }
|
||||
|
||||
[JsonPropertyName("requestsPerDayLimit")]
|
||||
public int RequestsPerDayLimit { get; init; }
|
||||
|
||||
[JsonPropertyName("requestsPerDayRemaining")]
|
||||
public int RequestsPerDayRemaining { get; init; }
|
||||
|
||||
[JsonPropertyName("requestsPerDayResetsAt")]
|
||||
public DateTimeOffset RequestsPerDayResetsAt { get; init; }
|
||||
|
||||
[JsonPropertyName("tokensPerDayLimit")]
|
||||
public int TokensPerDayLimit { get; init; }
|
||||
|
||||
[JsonPropertyName("tokensPerDayRemaining")]
|
||||
public int TokensPerDayRemaining { get; init; }
|
||||
|
||||
[JsonPropertyName("tokensPerDayResetsAt")]
|
||||
public DateTimeOffset TokensPerDayResetsAt { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatToolAccess
|
||||
{
|
||||
[JsonPropertyName("allowAll")]
|
||||
public bool AllowAll { get; init; }
|
||||
|
||||
[JsonPropertyName("allowedTools")]
|
||||
public List<string> AllowedTools { get; init; } = [];
|
||||
|
||||
[JsonPropertyName("providers")]
|
||||
public ChatToolProviders? Providers { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatToolProviders
|
||||
{
|
||||
[JsonPropertyName("sbom")]
|
||||
public bool Sbom { get; init; }
|
||||
|
||||
[JsonPropertyName("vex")]
|
||||
public bool Vex { get; init; }
|
||||
|
||||
[JsonPropertyName("reachability")]
|
||||
public bool Reachability { get; init; }
|
||||
|
||||
[JsonPropertyName("policy")]
|
||||
public bool Policy { get; init; }
|
||||
|
||||
[JsonPropertyName("findings")]
|
||||
public bool Findings { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatDenialInfo
|
||||
{
|
||||
[JsonPropertyName("timestamp")]
|
||||
public DateTimeOffset Timestamp { get; init; }
|
||||
|
||||
[JsonPropertyName("reason")]
|
||||
public required string Reason { get; init; }
|
||||
|
||||
[JsonPropertyName("code")]
|
||||
public string? Code { get; init; }
|
||||
|
||||
[JsonPropertyName("query")]
|
||||
public string? Query { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chat settings response.
|
||||
/// </summary>
|
||||
internal sealed record ChatSettingsResponse
|
||||
{
|
||||
[JsonPropertyName("tenantId")]
|
||||
public required string TenantId { get; init; }
|
||||
|
||||
[JsonPropertyName("userId")]
|
||||
public string? UserId { get; init; }
|
||||
|
||||
[JsonPropertyName("scope")]
|
||||
public required string Scope { get; init; }
|
||||
|
||||
[JsonPropertyName("quotas")]
|
||||
public ChatQuotaSettings? Quotas { get; init; }
|
||||
|
||||
[JsonPropertyName("tools")]
|
||||
public ChatToolSettings? Tools { get; init; }
|
||||
|
||||
[JsonPropertyName("effective")]
|
||||
public ChatEffectiveSettings? Effective { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatQuotaSettings
|
||||
{
|
||||
[JsonPropertyName("requestsPerMinute")]
|
||||
public int? RequestsPerMinute { get; init; }
|
||||
|
||||
[JsonPropertyName("requestsPerDay")]
|
||||
public int? RequestsPerDay { get; init; }
|
||||
|
||||
[JsonPropertyName("tokensPerDay")]
|
||||
public int? TokensPerDay { get; init; }
|
||||
|
||||
[JsonPropertyName("toolCallsPerDay")]
|
||||
public int? ToolCallsPerDay { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatToolSettings
|
||||
{
|
||||
[JsonPropertyName("allowAll")]
|
||||
public bool? AllowAll { get; init; }
|
||||
|
||||
[JsonPropertyName("allowedTools")]
|
||||
public List<string>? AllowedTools { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatEffectiveSettings
|
||||
{
|
||||
[JsonPropertyName("quotas")]
|
||||
public required ChatQuotaSettings Quotas { get; init; }
|
||||
|
||||
[JsonPropertyName("tools")]
|
||||
public required ChatToolSettings Tools { get; init; }
|
||||
|
||||
[JsonPropertyName("source")]
|
||||
public required string Source { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chat settings update request.
|
||||
/// </summary>
|
||||
internal sealed record ChatSettingsUpdateRequest
|
||||
{
|
||||
[JsonPropertyName("quotas")]
|
||||
public ChatQuotaSettingsUpdate? Quotas { get; init; }
|
||||
|
||||
[JsonPropertyName("tools")]
|
||||
public ChatToolSettingsUpdate? Tools { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatQuotaSettingsUpdate
|
||||
{
|
||||
[JsonPropertyName("requestsPerMinute")]
|
||||
public int? RequestsPerMinute { get; init; }
|
||||
|
||||
[JsonPropertyName("requestsPerDay")]
|
||||
public int? RequestsPerDay { get; init; }
|
||||
|
||||
[JsonPropertyName("tokensPerDay")]
|
||||
public int? TokensPerDay { get; init; }
|
||||
|
||||
[JsonPropertyName("toolCallsPerDay")]
|
||||
public int? ToolCallsPerDay { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatToolSettingsUpdate
|
||||
{
|
||||
[JsonPropertyName("allowAll")]
|
||||
public bool? AllowAll { get; init; }
|
||||
|
||||
[JsonPropertyName("allowedTools")]
|
||||
public List<string>? AllowedTools { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Error response from chat API.
|
||||
/// </summary>
|
||||
internal sealed record ChatErrorResponse
|
||||
{
|
||||
[JsonPropertyName("error")]
|
||||
public required string Error { get; init; }
|
||||
|
||||
[JsonPropertyName("code")]
|
||||
public string? Code { get; init; }
|
||||
|
||||
[JsonPropertyName("details")]
|
||||
public Dictionary<string, object>? Details { get; init; }
|
||||
|
||||
[JsonPropertyName("doctor")]
|
||||
public ChatDoctorAction? Doctor { get; init; }
|
||||
}
|
||||
|
||||
internal sealed record ChatDoctorAction
|
||||
{
|
||||
[JsonPropertyName("endpoint")]
|
||||
public required string Endpoint { get; init; }
|
||||
|
||||
[JsonPropertyName("suggestedCommand")]
|
||||
public required string SuggestedCommand { get; init; }
|
||||
|
||||
[JsonPropertyName("reason")]
|
||||
public required string Reason { get; init; }
|
||||
}
|
||||
Reference in New Issue
Block a user