< Summary

Information
Class: Services.ApiServices.OpenRouterApi.Models.SseMetaEvent
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/OpenRouterApi/Models/OpenRouterModels.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 9
Coverable lines: 9
Total lines: 352
Line coverage: 0%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_ToolName()100%210%
get_ToolLabel()100%210%
get_Steps()100%210%
get_RowCount()100%210%
get_DbMs()100%210%
get_Sql()100%210%
get_Phase()100%210%
get_FromCache()100%210%
get_FilterSpecification()100%210%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/OpenRouterApi/Models/OpenRouterModels.cs

#LineLine coverage
 1using Newtonsoft.Json;
 2using Services.AiAssistant;
 3
 4namespace Services.ApiServices.OpenRouterApi.Models;
 5
 6// ── Request ──────────────────────────────────────────────────────────────────
 7
 8public class ChatCompletionRequest
 9{
 10    [JsonProperty("model")]       public string            Model       { get; set; } = string.Empty;
 11    [JsonProperty("messages")]    public List<ChatMessage> Messages    { get; set; } = new();
 12    [JsonProperty("max_tokens")]  public int               MaxTokens   { get; set; } = 2048;
 13    [JsonProperty("temperature")] public double            Temperature { get; set; } = 0.3;
 14    [JsonProperty("stream", NullValueHandling = NullValueHandling.Ignore)]
 15    public bool? Stream { get; set; }
 16    [JsonProperty("stream_options", NullValueHandling = NullValueHandling.Ignore)]
 17    public StreamOptions? StreamOptions { get; set; }
 18}
 19
 20public class StreamOptions
 21{
 22    [JsonProperty("include_usage")] public bool IncludeUsage { get; set; } = true;
 23}
 24
 25// ── Streaming chunk ───────────────────────────────────────────────────────────
 26
 27public class ChatCompletionChunk
 28{
 29    [JsonProperty("choices")] public List<ChunkChoice> Choices { get; set; } = new();
 30    [JsonProperty("usage")]   public UsageInfo?        Usage   { get; set; }
 31}
 32
 33public class ChunkChoice
 34{
 35    [JsonProperty("delta")]         public DeltaMessage Delta        { get; set; } = new();
 36    [JsonProperty("finish_reason")] public string?      FinishReason { get; set; }
 37}
 38
 39public class DeltaMessage
 40{
 41    [JsonProperty("content")]  public string? Content  { get; set; }
 42    [JsonProperty("role")]     public string? Role     { get; set; }
 43}
 44
 45public class ChatMessage
 46{
 47    [JsonProperty("role")]    public string Role    { get; set; } = string.Empty;
 48    [JsonProperty("content")] public string Content { get; set; } = string.Empty;
 49}
 50
 51// ── Response ─────────────────────────────────────────────────────────────────
 52
 53public class ChatCompletionResponse
 54{
 55    [JsonProperty("choices")] public List<ChatChoice> Choices { get; set; } = new();
 56    [JsonProperty("usage")]   public UsageInfo?       Usage   { get; set; }
 57}
 58
 59public class ChatChoice
 60{
 61    [JsonProperty("message")]       public ChatMessage Message      { get; set; } = new();
 62    [JsonProperty("finish_reason")] public string?     FinishReason { get; set; }
 63}
 64
 65public class UsageInfo
 66{
 67    [JsonProperty("prompt_tokens")]     public int PromptTokens     { get; set; }
 68    [JsonProperty("completion_tokens")] public int CompletionTokens { get; set; }
 69    [JsonProperty("total_tokens")]      public int TotalTokens      { get; set; }
 70}
 71
 72// ── Controller contract ───────────────────────────────────────────────────────
 73
 74public class AiChatRequest
 75{
 76    public string Message { get; set; } = string.Empty;
 77
 78    /// <summary>Последний обсуждаемый заказ (с клиента или предыдущего ответа).</summary>
 79    public AiChatConversationContext? Context { get; set; }
 80
 81    /// <summary>История диалога для LLM (последние реплики).</summary>
 82    public List<AiChatTurn>? History { get; set; }
 83
 84    /// <summary>Идентификатор модели OpenRouter (null → default из конфига).</summary>
 85    public string? Model { get; set; }
 86
 87    /// <summary>Режим работы агента: "confirm" (запрашивать подтверждение) или "auto" (выполнить сразу).</summary>
 88    public string? AgentMode { get; set; }
 89}
 90
 91public class AiChatTurn
 92{
 93    public string Role    { get; set; } = string.Empty;
 94    public string Content { get; set; } = string.Empty;
 95}
 96
 97public class AiChatPrepareResponse
 98{
 99    public List<AiProcessStepDto> Steps     { get; set; } = new();
 100    public string?                ToolLabel { get; set; }
 101    public string?                ToolName  { get; set; }
 102    /// <summary>intent | db | agents | ai</summary>
 103    public string                 Phase     { get; set; } = "intent";
 104}
 105
 106public class AiChatResponse
 107{
 108    public bool                       Success     { get; set; }
 109    public string                     Answer      { get; set; } = string.Empty;
 110    public string?                    ToolUsed    { get; set; }
 111    public string?                    ToolLabel   { get; set; }
 112    public List<OrderSummaryDto>?     Data        { get; set; }
 113    public List<AiProcessStepDto>?    Steps       { get; set; }
 114    public List<AiActionLinkDto>?     ActionLinks   { get; set; }
 115    public AiChatConversationContext? Context       { get; set; }
 116    public Dictionary<string, string>? StatusPalette { get; set; }
 117    public AiChatEnrichmentDto?     Enrichment      { get; set; }
 118    /// <summary>SQL-запрос к БД (если выполнялся).</summary>
 119    public string?                  DbQuery         { get; set; }
 120    public string?                    Error         { get; set; }
 121}
 122
 123public class AiProcessStepDto
 124{
 125    public string Key   { get; set; } = string.Empty;
 126    public string Label { get; set; } = string.Empty;
 127    public bool   Done  { get; set; }
 128    /// <summary>"pending" | "active" | "done" | "error"</summary>
 129    public string? Status  { get; set; }
 130    /// <summary>Миллисекунды выполнения агента (для done-состояния).</summary>
 131    public long?   Ms      { get; set; }
 132    /// <summary>true → рендерить как карточку агента в grid, а не строку списка.</summary>
 133    public bool    IsAgent { get; set; }
 134    /// <summary>Подстатус агента (например «Запрос WarehouseStock…»).</summary>
 135    public string? Detail    { get; set; }
 136    /// <summary>true → результат взят из IMemoryCache.</summary>
 137    public bool    FromCache { get; set; }
 138}
 139
 140public class AiActionLinkDto
 141{
 142    public string Label { get; set; } = string.Empty;
 143    public string Url   { get; set; } = string.Empty;
 144    public string Kind  { get; set; } = "orders"; // orders | order | ozon_live
 145    /// <summary>Для kind=orders — id через запятую (cookie FilterData без OpenOrders).</summary>
 146    public string? FilterIds    { get; set; }
 147    public string? FilterPreset { get; set; }
 148    /// <summary>Для kind=ozon_live — текст сообщения, отправляемого в чат по клику.</summary>
 149    public string? ChatMessage { get; set; }
 150    /// <summary>
 151    /// true → серый nav-чип (переход к разделу системы).
 152    /// false/null → синий read-чип (запрос данных).
 153    /// </summary>
 154    public bool IsNav { get; set; }
 155}
 156
 157public class OrderSummaryDto
 158{
 159    public int       Id             { get; set; }
 160    public string?   ShipmentNumber { get; set; }
 161    public string?   ProductName    { get; set; }
 162    public string?   Article        { get; set; }
 163    public string?   AppStatus      { get; set; }
 164    public string?   ClientStatus   { get; set; }
 165    public string?   Supplier       { get; set; }
 166    public string?   ShipmentWarehouseName { get; set; }
 167    public string?   OzonClientName { get; set; }
 168    public DateTime? ShippingDate   { get; set; }
 169    public decimal?  Price             { get; set; }
 170    public decimal?  MinProfit         { get; set; }
 171    public string?   ManufacturerName  { get; set; }
 172    public string?   ProductImageUrl   { get; set; }
 173    public int?      Quantity          { get; set; }
 174    public int?      TrueQuantity      { get; set; }
 175    public string?   AppStatusColor    { get; set; }
 176    public string?   ClientStatusColor { get; set; }
 177    public bool      IsArchived        { get; set; }
 178    public DateTime? ArchivedAt        { get; set; }
 179    public string?   ArchivedBy        { get; set; }
 180    public string?   ArchiveReason     { get; set; }
 181}
 182
 183// ── Write action DTOs ─────────────────────────────────────────────────────────
 184
 185/// <summary>Запрос на исполнение действия агента (редактирование заказа или транзакция).</summary>
 186public class AiExecuteActionRequest
 187{
 188    /// <summary>"edit_order" или "create_transaction".</summary>
 189    public string  Kind    { get; set; } = string.Empty;
 190    public int     OrderId { get; set; }
 191    /// <summary>Идентификатор модели OpenRouter — сохраняется в истории изменений.</summary>
 192    public string? Model   { get; set; }
 193    public AiOrderEditDto?      EditDto        { get; set; }
 194    public AiTransactionParamsDto? TransactionDto { get; set; }
 195}
 196
 197/// <summary>Поля для редактирования заказа — строго MultiplayEditV2.</summary>
 198public class AiOrderEditDto
 199{
 200    public int?     AppStatusId          { get; set; }
 201    public int?     SupplierId           { get; set; }
 202    public int?     ShipmentWarehouseId  { get; set; }
 203    public decimal? PurchasePrice        { get; set; }
 204    public int?     Quantity             { get; set; }
 205    public string?  OrderNumberToSupplier { get; set; }
 206    public string?  Comment              { get; set; }
 207    // Человекочитаемые имена для карточки подтверждения
 208    public string?  AppStatusName        { get; set; }
 209    public string?  SupplierName         { get; set; }
 210    public string?  WarehouseName        { get; set; }
 211}
 212
 213/// <summary>Параметры транзакции.</summary>
 214public class AiTransactionParamsDto
 215{
 216    public int      TransactionTypeValue    { get; set; }
 217    public string   TransactionLabel        { get; set; } = string.Empty;
 218    public string?  Comment                { get; set; }
 219    public string?  WarehouseSenderName    { get; set; }
 220    public string?  WarehouseRecipientName { get; set; }
 221    /// <summary>
 222    /// Цена закупки — если задана, обновляется на заказе до создания транзакции.
 223    /// Используется для «Заказан поставщику» / «Отгружен поставщиком».
 224    /// </summary>
 225    public decimal? PurchasePrice          { get; set; }
 226    /// <summary>Поставщик (ID) — если задан, обновляется на заказе до создания транзакции.</summary>
 227    public int?     SupplierId             { get; set; }
 228    public string?  SupplierName           { get; set; }
 229
 230    // ── 1С-параметры для ShippedBySupplier (приходная накладная) ─────────────
 231    /// <summary>Провести в 1С (приходная накладная). Только для ShippedBySupplier.</summary>
 232    public bool     ProcessIn1C  { get; set; } = true;
 233    /// <summary>GUID договора из Catalog_ДоговорыКонтрагентов 1С.</summary>
 234    public string?  ContractLink { get; set; }
 235    /// <summary>Номер входящего документа поставщика.</summary>
 236    public string?  NumberVh     { get; set; }
 237    /// <summary>Дата входящего документа.</summary>
 238    public DateTime? DateVh      { get; set; }
 239    /// <summary>Ставка НДС (null = без НДС, 20 = 20%, 22 = 22%).</summary>
 240    public int?     VatRate      { get; set; }
 241    /// <summary>Комментарий к документу 1С (авто-заполняется агентом, редактируется пользователем).</summary>
 242    public string?  OneCComment  { get; set; }
 243}
 244
 245/// <summary>Предложение действия для карточки подтверждения (в done event).</summary>
 246public class AiActionProposalDto
 247{
 248    public string Kind           { get; set; } = string.Empty;
 249    public int    OrderId        { get; set; }
 250    public string? ShipmentNumber { get; set; }
 251    public string? CurrentStatus  { get; set; }
 252    public AiOrderEditDto?      EditDto      { get; set; }
 253    public AiTransactionParamsDto? TransactionDto { get; set; }
 254    /// <summary>URL страницы для ручного выполнения действия.</summary>
 255    public string? ManualPageUrl  { get; set; }
 256    /// <summary>Поля, которых не хватает — агент должен их запросить у пользователя.</summary>
 257    public List<string>? MissingFields { get; set; }
 258    /// <summary>true если транзакция требует ручной проводки в 1С после выполнения.</summary>
 259    public bool   Requires1CManual  { get; set; }
 260    public string? OneCDocumentType { get; set; }
 261    /// <summary>true → показать форму ввода 1С-данных (ProcessIn1C, NumberVh, DateVh, ContractLink).</summary>
 262    public bool   Requires1CInput   { get; set; }
 263    /// <summary>ИНН поставщика — для загрузки списка договоров из 1С.</summary>
 264    public string? SupplierInn      { get; set; }
 265}
 266
 267/// <summary>Результат выполнения действия агента.</summary>
 268public class AiExecuteActionResponse
 269{
 270    public bool    Success          { get; set; }
 271    public string? Message          { get; set; }
 272    public string? NewStatus        { get; set; }
 273    public string? OrderPageUrl     { get; set; }
 274    public string? TransactionPageUrl { get; set; }
 275    public string? ManualPageUrl    { get; set; }
 276    /// <summary>Резюме от LLM о выполненном действии (для показа в чате).</summary>
 277    public string? AiSummary        { get; set; }
 278    /// <summary>Shipment number заказа для подсветки в резюме.</summary>
 279    public string? ShipmentNumber   { get; set; }
 280    /// <summary>Результат проводки в 1С (если выполнялась). Содержит GUID документа или сообщение об ошибке.</summary>
 281    public string? OneCResult       { get; set; }
 282    /// <summary>true — иконка truck-moving (перемещение), false — file-invoice (приходная)</summary>
 283    public bool    OneCTransferIcon { get; set; }
 284}
 285
 286// ── SSE event payloads ────────────────────────────────────────────────────────
 287
 288public class SseMetaEvent
 289{
 0290    public string?                    ToolName  { get; set; }
 0291    public string?                    ToolLabel { get; set; }
 0292    public List<AiProcessStepDto>?    Steps     { get; set; }
 0293    public int?                       RowCount  { get; set; }
 0294    public long?                      DbMs      { get; set; }
 0295    public string?                    Sql       { get; set; }
 296    /// <summary>intent | studio | db | agents | ai | done</summary>
 0297    public string?                    Phase     { get; set; }
 0298    public bool?                      FromCache { get; set; }
 299    /// <summary>Спецификация фильтра из студии запроса (orders_filter).</summary>
 0300    public string?                    FilterSpecification { get; set; }
 301}
 302
 303public class SseLogEvent
 304{
 305    public string  Line { get; set; } = string.Empty;
 306    /// <summary>check | spin | error | info | cache</summary>
 307    public string? Icon { get; set; }
 308}
 309
 310public class AiTokenUsageDto
 311{
 312    public int PromptTokens     { get; set; }
 313    public int CompletionTokens { get; set; }
 314    public int TotalTokens      { get; set; }
 315}
 316
 317public class SseDoneEvent
 318{
 319    public AiChatEnrichmentDto?       Enrichment      { get; set; }
 320    public List<AiActionLinkDto>?     ActionLinks     { get; set; }
 321    public List<OrderSummaryDto>?     Data            { get; set; }
 322    public Dictionary<string,string>? StatusPalette   { get; set; }
 323    public AiChatConversationContext? Context         { get; set; }
 324    /// <summary>Предложение write-действия (редактирование или транзакция) для карточки подтверждения.</summary>
 325    public AiActionProposalDto?       ActionProposal  { get; set; }
 326    /// <summary>Несколько предложений (batch) — используется когда в запросе несколько заказов.</summary>
 327    public List<AiActionProposalDto>? ActionProposals { get; set; }
 328    /// <summary>Статистика токенов от OpenRouter (prompt + completion).</summary>
 329    public AiTokenUsageDto?           TokenUsage      { get; set; }
 330    /// <summary>true → результат инструмента orders_filter, показывать стилизованную search-карточку.</summary>
 331    public bool                       IsSearchResult  { get; set; }
 332    /// <summary>Строка описания применённых фильтров (из AiOrderFilterCriteria.DescribeRu).</summary>
 333    public string?                    AppliedFiltersDescription { get; set; }
 334    /// <summary>Всего найдено заказов (до лимита 50).</summary>
 335    public int?                       TotalFound      { get; set; }
 336    /// <summary>Критерии поиска — передаются клиенту для кнопок "Открыть в таблице" и "Excel".</summary>
 337    public AiAssistant.AiOrderFilterCriteria? AppliedCriteria { get; set; }
 338    /// <summary>Контекстуальные follow-up запросы (генерируются параллельным LLM-вызовом).</summary>
 339    public List<string>?              SuggestedFollowUps { get; set; }
 340    /// <summary>Готовая фраза для повторного поиска при 0 результатах.</summary>
 341    public string?                    SuggestionQuery { get; set; }
 342    /// <summary>Ослабленные критерии поиска (если основной запрос дал 0).</summary>
 343    public AiAssistant.AiOrderFilterCriteria? RelaxedSuggestion { get; set; }
 344    public int?                       RelaxedCount    { get; set; }
 345    /// <summary>SQL-запрос к БД (если выполнялся).</summary>
 346    public string?                    DbQuery         { get; set; }
 347    public string?                    ToolLabel       { get; set; }
 348    /// <summary>Спецификация фильтра из студии запроса.</summary>
 349    public string?                    FilterSpecification { get; set; }
 350    /// <summary>Итоговый текст ответа (заменяет стрим LLM при детерминированном/fallback-ответе).</summary>
 351    public string?                    AnswerText      { get; set; }
 352}