logger.LogDebug("Skipping local retrieval for data source '{DataSourceName}' ({DataSourceId}) because the latest prompt does not contain text.",dataSource.Name,dataSource.Id);
"Retrieved {MergedHits} local RAG hits for data source '{DataSourceName}' ({DataSourceId}). VectorCandidates={VectorHits}, BM25Candidates={BM25Hits}, RequestedPerChannel={RequestedPerChannel}.",
"Skipping vector retrieval for data source '{DataSourceName}' ({DataSourceId}) because vector store '{VectorStoreName}' is unavailable.",
dataSource.Name,
dataSource.Id,
vectorStore.Name);
awaitthis.ReportRetrievalGapAsync(dataSource,"no-vector-store",string.Format(TB("The data source '{0}' was left out of the answer: its local index is not available."),dataSource.Name));
logger.LogWarning("Skipping vector retrieval for data source '{DataSourceName}' ({DataSourceId}) because the selected embedding provider is not available.",dataSource.Name,dataSource.Id);
awaitthis.ReportRetrievalGapAsync(dataSource,"no-embedding-provider",string.Format(TB("The data source '{0}' was left out of the answer: its embedding provider is not available. Please check it in the settings."),dataSource.Name));
logger.LogWarning("Skipping vector retrieval for data source '{DataSourceName}' ({DataSourceId}) because query embedding returned no vector.",dataSource.Name,dataSource.Id);
awaitthis.ReportRetrievalGapAsync(dataSource,"no-query-vector",string.Format(TB("The data source '{0}' was left out of the answer: its embedding provider '{1}' did not return a vector for your message."),dataSource.Name,embeddingProvider.Name));
// The embedding provider named the cause and what to do about it. That sentence is
// worth far more to the user than the fact that a search came back empty:
//
logger.LogWarning(
exception,
"Vector retrieval failed for data source '{DataSourceName}' ({DataSourceId}) because the embedding provider failed. FailureReason={FailureReason}, StatusCode={StatusCode}.",
awaitthis.ReportRetrievalGapAsync(dataSource,$"provider-{exception.FailureReason}",string.Format(TB("The data source '{0}' was left out of the answer. {1}"),dataSource.Name,exception.UserMessage));
return[];
}
catch(Exceptionexception)
{
logger.LogWarning(exception,"Vector retrieval failed for data source '{DataSourceName}' ({DataSourceId}).",dataSource.Name,dataSource.Id);
awaitthis.ReportRetrievalGapAsync(dataSource,"vector-search-failed",string.Format(TB("The data source '{0}' was left out of the answer because searching it failed."),dataSource.Name));
return[];
}
}
/// <summary>
/// Tells the user once that a data source cannot take part in answering.
/// </summary>
/// <remarks>
/// A failed search is not an error of the chat: the model still answers, only without what
/// this data source knows. Saying so once is what keeps somebody from trusting an answer
/// which was put together without half of its sources. Saying it with every prompt would be
/// worse than saying nothing, which is why every gap is reported once per session.
/// </remarks>
/// <param name="dataSource">The data source which could not be searched.</param>
/// <param name="gapKey">What kind of gap this is, so a different problem is reported again.</param>
/// <param name="userMessage">What to tell the user.</param>
"Skipping vector retrieval for data source '{DataSourceName}' ({DataSourceId}) because the latest prompt has {CharacterCount} characters and exceeds the safe tokenizer request length of {MaxCharacterCount}. ProviderTokenLimit={ProviderTokenLimit}.",
dataSource.Name,
dataSource.Id,
query.Length,
RustService.MAX_TOKEN_COUNT_REQUEST_TEXT_LENGTH,
providerTokenLimit);
awaitthis.ReportRetrievalGapAsync(dataSource,"query-too-long",string.Format(TB("The data source '{0}' was left out of the answer because your message is too long to search with."),dataSource.Name));
"Skipping vector retrieval for data source '{DataSourceName}' ({DataSourceId}) because the token count for embedding provider '{EmbeddingProviderName}' could not be determined. Reason='{Reason}'.",
dataSource.Name,
dataSource.Id,
embeddingProvider.Name,
tokenCountResponse?.Message??"No response was returned by the tokenizer service.");
awaitthis.ReportRetrievalGapAsync(dataSource,"no-token-count",string.Format(TB("The data source '{0}' was left out of the answer: the tokenizer of its embedding provider '{1}' is not available."),dataSource.Name,embeddingProvider.Name));
"Skipping vector retrieval for data source '{DataSourceName}' ({DataSourceId}) because the latest prompt has {QueryTokenCount} tokens, exceeding embedding provider '{EmbeddingProviderName}' limit of {ProviderTokenLimit} tokens.",
dataSource.Name,
dataSource.Id,
queryTokenCount,
embeddingProvider.Name,
providerTokenLimit);
awaitthis.ReportRetrievalGapAsync(dataSource,"query-over-token-limit",string.Format(TB("The data source '{0}' was left out of the answer because your message is longer than its embedding provider '{1}' accepts."),dataSource.Name,embeddingProvider.Name));
"Local RAG {SearchName} search returned {ReturnedHits} chunks for data source '{DataSourceName}' ({DataSourceId}), which exceeds the configured maximum {MaxMatches}. Truncating to the datasource limit.",