Module: Brainchat::Retriever

Defined in:
lib/brainchat/retriever.rb,
sig/brainchat.rbs

Overview

Retrieves knowledge-brain chunks by shelling out to the hitgate rag-query CLI in its JSON output mode:

rag-query --top N --format json [--scope-repo all] [--fast] "<query>"

stdout is a pure JSON array of chunks (warnings and model-load progress go to stderr), each shaped:

{ "rank", "rrf", "cos", "bm25", "reranked", "source_type", "repo",
"language", "symbol", "path", "start_line", "end_line", "text" }

The query and every flag travel as separate argv entries through Open3.capture3 — no shell is ever involved, so a query containing metacharacters ($(...), backticks, ;) is inert data, not a command.

Defined Under Namespace

Classes: Chunk

Constant Summary collapse

DEFAULT_TOP =
5

Class Method Summary collapse

Class Method Details

.argv(bin, query, top:, scope_repo:, fast:) ⇒ Object



50
51
52
53
54
55
# File 'lib/brainchat/retriever.rb', line 50

def argv(bin, query, top:, scope_repo:, fast:)
  args = [bin, "--top", top.to_s, "--format", "json"]
  args += ["--scope-repo", scope_repo] if scope_repo
  args << "--fast" if fast
  args << query
end

.call(query, top: DEFAULT_TOP, scope_repo: nil, fast: true, bin: default_bin) ⇒ Array[Chunk]

Returns an array of Chunk, empty when the index has no matches.

Parameters:

  • query (String)
  • top: (Integer) (defaults to: DEFAULT_TOP)
  • scope_repo: (String, nil) (defaults to: nil)
  • fast: (Boolean) (defaults to: true)
  • bin: (String) (defaults to: default_bin)

Returns:



39
40
41
42
43
44
45
46
47
48
# File 'lib/brainchat/retriever.rb', line 39

def call(query, top: DEFAULT_TOP, scope_repo: nil, fast: true, bin: default_bin)
  stdout, stderr, status = Open3.capture3(*argv(bin, query, top:, scope_repo:, fast:))
  raise Error, "rag-query failed (exit #{status.exitstatus}): #{stderr.strip}" unless status.success?

  parse(stdout)
rescue Errno::ENOENT
  raise Error, "`#{bin}` was not found on PATH. Install hitgate " \
                "(https://github.com/LucasSantana-Dev/hitgate) or point " \
                "BRAINCHAT_RAG_QUERY_BIN at a rag-query executable."
end

.chunk_from(row) ⇒ Object



68
69
70
71
72
73
74
75
76
77
# File 'lib/brainchat/retriever.rb', line 68

def chunk_from(row)
  Chunk.new(rank: row["rank"],
            source_type: row["source_type"],
            repo: row["repo"],
            symbol: row["symbol"],
            path: row["path"],
            start_line: row["start_line"],
            end_line: row["end_line"],
            text: row["text"])
end

.default_binObject



79
80
81
# File 'lib/brainchat/retriever.rb', line 79

def default_bin
  ENV.fetch("BRAINCHAT_RAG_QUERY_BIN", "rag-query")
end

.parse(stdout) ⇒ Object



57
58
59
60
61
62
63
64
65
66
# File 'lib/brainchat/retriever.rb', line 57

def parse(stdout)
  rows = JSON.parse(stdout)
  unless rows.is_a?(Array) && rows.all?(Hash)
    raise Error, "rag-query returned unexpected JSON (expected an array of chunks)"
  end

  rows.map { |row| chunk_from(row) }
rescue JSON::ParserError => e
  raise Error, "rag-query did not return valid JSON: #{e.message}"
end