searchHybridWithContext method

Future<RagSearchResult> searchHybridWithContext(
  1. String query, {
  2. int topK = 10,
  3. int tokenBudget = 2000,
  4. ContextStrategy strategy = ContextStrategy.relevanceFirst,
  5. double vectorWeight = kDefaultVectorWeight,
  6. double bm25Weight = kDefaultBm25Weight,
  7. List<int>? sourceIds,
  8. int adjacentChunks = 0,
  9. bool singleSourceMode = false,
  10. SearchHydrationMode hydrationMode = SearchHydrationMode.full,
  11. int previewMaxBytes = 512,
})

Hybrid search with context assembly for LLM.

Similar to search but uses hybrid (vector + BM25) search.

adjacentChunks - Number of adjacent chunks to include before/after each matched chunk (default: 0). Setting this to 1 will include the chunk before and after each matched chunk, helping with long articles. singleSourceMode - If true, only include chunks from the most relevant source. hydrationMode - Controls whether returned chunks are fully hydrated, preview-only, or omitted entirely while still returning assembled context. previewMaxBytes - Maximum UTF-8 byte length per preview chunk when hydrationMode is SearchHydrationMode.preview.

Implementation

Future<RagSearchResult> searchHybridWithContext(
  String query, {
  int topK = 10,
  int tokenBudget = 2000,
  ContextStrategy strategy = ContextStrategy.relevanceFirst,
  double vectorWeight = kDefaultVectorWeight,
  double bm25Weight = kDefaultBm25Weight,
  List<int>? sourceIds,
  int adjacentChunks = 0,
  bool singleSourceMode = false,
  SearchHydrationMode hydrationMode = SearchHydrationMode.full,
  int previewMaxBytes = 512,
}) async {
  RagError? lastRetryableError;
  for (var attempt = 0; attempt < 2; attempt++) {
    try {
      return await _searchHybridWithContextViaHandle(
        query,
        topK: topK,
        tokenBudget: tokenBudget,
        strategy: strategy,
        vectorWeight: vectorWeight,
        bm25Weight: bm25Weight,
        sourceIds: sourceIds,
        adjacentChunks: adjacentChunks,
        singleSourceMode: singleSourceMode,
        hydrationMode: hydrationMode,
        previewMaxBytes: previewMaxBytes,
      );
    } on RagError catch (e) {
      final isRetryable = e.when(
        databaseError: (_) => false,
        ioError: (_) => false,
        modelLoadError: (_) => false,
        invalidInput: (_) => false,
        staleSearchHandle: (_) => true,
        concurrentMutation: (_) => true,
        internalError: (_) => false,
        unknown: (_) => false,
      );
      if (!isRetryable || attempt == 1) {
        rethrow;
      }
      lastRetryableError = e;
      debugPrint(
        '[SmartError] Retrying searchHybridWithContext after transient handle invalidation: ${e.message}',
      );
    }
  }

  throw lastRetryableError ??
      RagError.unknown('searchHybridWithContext retry loop exhausted');
}