1 line
12 KiB
JSON
1 line
12 KiB
JSON
{"path":"NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs","purpose":"Provides a MediatR query and handler that performs a semantic search over a tenant-scoped semantic knowledge cache: it generates an embedding for the input query (with retry), runs a vector similarity DB query, maps results to DTOs, and returns them.","classification":{"role":"handler","layer":"application","confidence":0.9,"evidence":["Command pattern","Implements IRequestHandler<SearchLibrarySemanticallyQuery, Result<List<SemanticSearchResultDto>>> (line 22)","Namespace NexusReader.Application.Queries.Library and uses application services (embedding generator, DbContextFactory, mapper)"]},"className":"SearchLibrarySemanticallyQueryHandler","methods":[{"name":"SearchLibrarySemanticallyQueryHandler","line":29,"endLine":39,"signature":"(embeddingGenerator: IEmbeddingGenerator<string, Embedding<float>>, dbContextFactory: IDbContextFactory<AppDbContext>, pipelineProvider: ResiliencePipelineProvider<string>, mapper: IMapper) -> SearchLibrarySemanticallyQueryHandler","purpose":"Constructor that stores injected services and obtains a named resilience pipeline for retries.","calls":[{"targetFile":"unknown","targetMethod":"GetPipeline","callLine":37,"paramSummary":"string \"ai-retry\""}],"actions":[{"id":"field-assignment_35","kind":"mapping","label":"Assigns injected dependencies","line":35,"detail":"_embeddingGenerator, _dbContextFactory, _mapper assignments","visibility":"detail-only","confidence":0.7},{"id":"external-call_37","kind":"external-call","label":"Resilience pipeline lookup","line":37,"detail":"pipelineProvider.GetPipeline(\"ai-retry\") used to set _retryPipeline","visibility":"detail-only","confidence":0.7}]},{"name":"Handle","line":41,"endLine":62,"signature":"(request: SearchLibrarySemanticallyQuery, cancellationToken: CancellationToken) -> Task<Result<List<SemanticSearchResultDto>>>","purpose":"Executes a semantic search: validates input, obtains an embedding with retry, queries the DB for nearest cached vectors for the tenant, maps to DTOs and returns a Result.","calls":[{"targetFile":"unknown","targetMethod":"ExecuteAsync","callLine":49,"paramSummary":"Func<CancellationToken, Task<Embedding[]>> that calls _embeddingGenerator.GenerateAsync"},{"targetFile":"unknown","targetMethod":"GenerateAsync","callLine":50,"paramSummary":"string[] { request.QueryText } (cancellation token forwarded)"},{"targetFile":"unknown","targetMethod":"CreateDbContextAsync","callLine":53,"paramSummary":"cancellationToken"},{"targetFile":"unknown","targetMethod":"Map","callLine":60,"paramSummary":"List<SemanticKnowledgeCache> -> List<SemanticSearchResultDto>"}],"actions":[{"id":"handle_branch_43_0","kind":"branch","label":"Evaluates branch condition","line":43,"detail":"if (string.IsNullOrWhiteSpace(request.QueryText))","conditionSummary":"string.IsNullOrWhiteSpace(request.QueryText)","outcomeLabels":["true","false"],"visibility":"secondary-visible","confidence":0.78},{"id":"guard-clause_43","kind":"guard-clause","label":"Rejects empty query text","line":43,"detail":"Returns Result.Fail when request.QueryText is empty (line 45)","conditionSummary":"string.IsNullOrWhiteSpace(request.QueryText)","outcomeLabels":["invalid","continue"],"visibility":"detail-only","confidence":0.7},{"id":"handle_return_45_1","kind":"return","label":"Returns result","line":45,"detail":"return Result.Fail(\"Query text cannot be empty.\");","visibility":"detail-only","confidence":0.7},{"id":"retry_49","kind":"retry","label":"Generate embedding with resilience pipeline","line":49,"detail":"_retryPipeline.ExecuteAsync wraps _embeddingGenerator.GenerateAsync to obtain embedding","visibility":"detail-only","confidence":0.7},{"id":"handle_await_49_2","kind":"await","label":"Waits for async work","line":49,"detail":"var embeddingResponse = await _retryPipeline.ExecuteAsync(async ct =>","visibility":"secondary-visible","confidence":0.81},{"id":"external-call_50","kind":"external-call","label":"Embedding generation","line":50,"detail":"_embeddingGenerator.GenerateAsync called with request.QueryText","visibility":"detail-only","confidence":0.7},{"id":"handle_await_50_3","kind":"await","label":"Waits for async work","line":50,"detail":"await _embeddingGenerator.GenerateAsync(new[] { request.QueryText }, cancellationToken: ct), cancellationToken);","visibility":"secondary-visible","confidence":0.81},{"id":"handle_await_53_4","kind":"await","label":"Waits for async work","line":53,"detail":"await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);","visibility":"secondary-visible","confidence":0.81},{"id":"persistence-read_54","kind":"mapping","label":"Query SemanticKnowledgeCache for tenant and compute cosine distance","line":54,"detail":"Filters by TenantId and non-null Embedding, orders by Embedding!.CosineDistance(queryVector), takes request.Limit, then ToListAsync (lines 54-58)","visibility":"detail-only","confidence":0.7},{"id":"handle_await_54_5","kind":"await","label":"Waits for async work","line":54,"detail":"var cacheEntries = await dbContext.SemanticKnowledgeCache","visibility":"secondary-visible","confidence":0.81},{"id":"handle_repository-read_55_6","kind":"repository-read","label":"Reads repository or persistence state","line":55,"detail":".Where(c => c.TenantId == request.TenantId && c.Embedding != null)","visibility":"secondary-visible","confidence":0.86},{"id":"mapping_60","kind":"mapping","label":"Map entities to DTOs","line":60,"detail":"_mapper.Map<List<SemanticSearchResultDto>>(cacheEntries)","visibility":"detail-only","confidence":0.7},{"id":"return_61","kind":"return","label":"Return successful Result with mapped DTOs","line":61,"detail":"Result.Ok(dtos)","visibility":"detail-only","confidence":0.7},{"id":"handle_return_61_7","kind":"return","label":"Returns result","line":61,"detail":"return Result.Ok(dtos);","visibility":"detail-only","confidence":0.7}]}],"types":[{"name":"SearchLibrarySemanticallyQuery","kind":"query","line":19,"purpose":"CQRS request record carrying query text, tenant id and optional limit for semantic search.","fields":[{"name":"QueryText","type":"string","required":true,"line":19,"description":"The natural language query to embed and search with"},{"name":"TenantId","type":"string","required":true,"line":19,"description":"Tenant scope for the semantic cache"},{"name":"Limit","type":"int","required":false,"line":19,"description":"Maximum number of results to return (default 5)"}]},{"name":"SearchLibrarySemanticallyQueryHandler","kind":"model","line":22,"purpose":"MediatR handler that orchestrates embedding generation, resilient execution, DB similarity query and mapping to DTOs.","fields":[{"name":"_embeddingGenerator","type":"IEmbeddingGenerator<string, Embedding<float>>","required":true,"line":24,"description":"Generates embeddings for input text"},{"name":"_dbContextFactory","type":"IDbContextFactory<AppDbContext>","required":true,"line":25,"description":"Creates EF Core DbContext instances"},{"name":"_retryPipeline","type":"ResiliencePipeline","required":true,"line":26,"description":"Resilience pipeline used for retrying AI calls"},{"name":"_mapper","type":"IMapper","required":true,"line":27,"description":"Mapster mapper for mapping entities to DTOs"}]}],"serviceRegistrations":[],"startupActions":[],"dependencies":["NexusReader.Data.Persistence (imported at line 15)","Mapster/MapsterMapper (imported at lines 12-13)","MediatR (imported line 2)","Pgvector (imported lines 3-4)","Microsoft.Extensions.Resilience / Polly (lines 9-11)"],"patterns":["CQRS Handler","Resilience/Retry (ResiliencePipeline)","Vector similarity / semantic search","Repository/DbContext read"],"domainConcepts":["SemanticKnowledgeCache (tenant-scoped cached embeddings)","Embedding (float vector)","SemanticSearchResultDto (result DTO)"],"keyDetails":"Uses a resilience pipeline named \"ai-retry\" to wrap embedding generation, computes cosine distance using Pgvector and orders DB results by similarity, then maps entities to SemanticSearchResultDto and returns a FluentResults.Result.","orchestrationMethods":[{"name":"Handle","line":41,"confidence":0.98,"reason":"Coordinates 4 downstream calls with 4 architectural actions.","actionKinds":["branch","guard-clause","return","retry","await","external-call","mapping","repository-read"],"evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs","unknown","unknown","unknown","unknown"]},{"name":"SearchLibrarySemanticallyQueryHandler","line":29,"confidence":0.65,"reason":"Contains 1 architectural actions relevant to business execution.","actionKinds":["mapping","external-call"],"evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs","unknown"]}],"typedContracts":[{"name":"SearchLibrarySemanticallyQuery","kind":"query","line":19,"fieldCount":3,"evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs"]},{"name":"SearchLibrarySemanticallyQueryHandler","kind":"model","line":22,"fieldCount":4,"evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs"]}],"persistenceInteractions":[{"methodName":"Handle","line":55,"kind":"persistence-read","detail":".Where(c => c.TenantId == request.TenantId && c.Embedding != null)","evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs"]}],"externalInteractions":[{"methodName":"SearchLibrarySemanticallyQueryHandler","line":37,"kind":"external-call","detail":"pipelineProvider.GetPipeline(\"ai-retry\") used to set _retryPipeline","evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs"]},{"methodName":"Handle","line":50,"kind":"external-call","detail":"_embeddingGenerator.GenerateAsync called with request.QueryText","evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs"]}],"evidenceAnchors":[{"kind":"orchestration-method","label":"Handle","line":41,"summary":"Coordinates 4 downstream calls with 4 architectural actions.","confidence":0.98,"evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs","unknown","unknown","unknown","unknown"]},{"kind":"orchestration-method","label":"SearchLibrarySemanticallyQueryHandler","line":29,"summary":"Contains 1 architectural actions relevant to business execution.","confidence":0.65,"evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs","unknown"]},{"kind":"typed-contract","label":"SearchLibrarySemanticallyQuery","line":19,"summary":"query with 3 fields.","confidence":0.8,"evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs"]},{"kind":"typed-contract","label":"SearchLibrarySemanticallyQueryHandler","line":22,"summary":"model with 4 fields.","confidence":0.8,"evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs"]},{"kind":"persistence","label":"Handle","line":55,"summary":".Where(c => c.TenantId == request.TenantId && c.Embedding != null)","confidence":0.82,"evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs"]},{"kind":"external-call","label":"SearchLibrarySemanticallyQueryHandler","line":37,"summary":"pipelineProvider.GetPipeline(\"ai-retry\") used to set _retryPipeline","confidence":0.8,"evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs"]},{"kind":"external-call","label":"Handle","line":50,"summary":"_embeddingGenerator.GenerateAsync called with request.QueryText","confidence":0.8,"evidencePaths":["NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs"]}],"cacheMetadata":{"schemaVersion":2,"analysisVersion":"2026-05-23.cache-v1","contentChecksum":"5f243bc5c1548862dfcfdcaaaa77ad34869160ad64391853fd1fe00ff4b56bb2","sourceByteSize":2659,"analyzedAt":"2026-05-23T16:18:06.973Z","technology":"dotnet"}} |