Arcana.Config (Arcana v3.0.0)

Copy Markdown View Source

Configuration management for Arcana.

Handles parsing and resolving configuration for embedders, chunkers, and other pluggable components.

Redacting Sensitive Values

Use Arcana.Config.redact/1 to wrap any config value for safe inspection:

config = Application.get_env(:arcana, :llm)
inspect(Arcana.Config.redact(config))
# => {"zai:glm-4.7", [api_key: "[REDACTED]"]}

Embedder Configuration

# Default: Local Bumblebee with bge-small-en-v1.5
config :arcana, embedder: :local

# Local with different model
config :arcana, embedder: {:local, model: "BAAI/bge-large-en-v1.5"}

# OpenAI (requires req_llm and OPENAI_API_KEY)
config :arcana, embedder: :openai
config :arcana, embedder: {:openai, model: "text-embedding-3-large"}

# Custom function
config :arcana, embedder: fn text -> {:ok, embedding} end

# Custom module implementing Arcana.Embedder behaviour
config :arcana, embedder: MyApp.CohereEmbedder
config :arcana, embedder: {MyApp.CohereEmbedder, api_key: "..."}

Chunker Configuration

# Default: text_chunker-based chunking
config :arcana, chunker: :default

# Default chunker with custom options
config :arcana, chunker: {:default, chunk_size: 512, chunk_overlap: 100}

# Custom function (receives text, opts; returns list of chunk maps)
config :arcana, chunker: fn text, _opts ->
  [%{text: text, chunk_index: 0, token_count: 10}]
end

# Custom module implementing Arcana.Chunker behaviour
config :arcana, chunker: MyApp.SemanticChunker
config :arcana, chunker: {MyApp.SemanticChunker, model: "..."}

PDF Parser Configuration

# Default: poppler's pdftotext
config :arcana, pdf_parser: :poppler

# Custom module implementing Arcana.FileParser.PDF behaviour
config :arcana, pdf_parser: MyApp.PDFParser
config :arcana, pdf_parser: {MyApp.PDFParser, some_option: "value"}

Search Defaults

Set defaults for Arcana.search/2. Per-call options override these. Any option accepted by Arcana.Search.search/2 can be set globally.

config :arcana, search: [
  limit: 10,
  threshold: 0.0,
  mode: :vector,              # :vector | :keyword | :hybrid
  vector_weight: 0.5,         # for hybrid mode
  keyword_weight: 0.5,        # for hybrid mode
  rewriter: &MyApp.rewrite/1, # query rewriter function
  hnsw_ef_search: 100,       # pgvector only, see Arcana.VectorStore.Pgvector
]

Ask Defaults

Set defaults for Arcana.ask/2. Per-call options override these. Any option accepted by Arcana.Ask.ask/2 can be set globally.

config :arcana, ask: [
  limit: 5,
  mode: :semantic,
  threshold: 0.0,
  prompt: &MyApp.custom_prompt/3
]

Reranker Configuration

Set a global reranker that will be applied automatically by Arcana.search/2 and Arcana.ask/2. Per-call :reranker options override this. Pass reranker: false per-call to disable for a single request.

# Global reranker module
config :arcana, reranker: Arcana.Reranker.CrossEncoder

# With options (e.g. over_fetch multiplier, threshold)
config :arcana, reranker: {Arcana.Reranker.CrossEncoder, over_fetch: 3}

# Custom function: fn question, chunks, opts -> {:ok, reranked} end
config :arcana, reranker: &MyApp.rerank/3

Summary

Functions

Returns the configured chunker as a {module, opts} tuple.

Returns the current Arcana configuration.

Returns the configured embedder as a {module, opts} tuple.

Returns the configured fallback parser as {module, opts}, or nil.

Returns the configured file parsers as a map of extension to {module, opts}.

Returns the value for key from opts, falling back to the global app env.

Returns the value for key from the :arcana app env.

Returns whether GraphRAG is enabled globally or for specific options.

Merges global keyword-list config under app_key with per-call opts.

Returns the configured PDF parser as a {module, opts} tuple.

Wraps a config value for safe inspection with sensitive data redacted.

Resolves the Ecto repo configured for Arcana's mix tasks.

Returns the repo from opts or the global config, raising when neither is set.

Returns the configured reranker, resolving per-call opts and global config.

Resolves chunker from options, falling back to global config.

Resolves embedder from options, falling back to global config.

Returns whether strict collection scoping is enabled.

Functions

chunker()

Returns the configured chunker as a {module, opts} tuple.

current()

Returns the current Arcana configuration.

Useful for logging, debugging, and storing with evaluation runs to track which settings produced which results.

Example

Arcana.Config.current()
# => %{
#   embedding: %{module: Arcana.Embedder.Local, model: "BAAI/bge-small-en-v1.5", dimensions: 384},
#   vector_store: :pgvector
# }

embedder()

Returns the configured embedder as a {module, opts} tuple.

fallback_parser()

Returns the configured fallback parser as {module, opts}, or nil.

Consulted for any extension without a native or registered parser:

config :arcana, fallback_parser: {MyApp.ExtractionService, []}

nil and false both mean "no fallback".

file_parsers()

Returns the configured file parsers as a map of extension to {module, opts}.

Extensions are normalized to lowercase with a leading dot, so %{"docx" => ...} and %{".DOCX" => ...} both register ".docx".

config :arcana, file_parsers: %{".docx" => {MyApp.DocxParser, []}}

Mapping an extension to false disables it: nothing parses it, not the built-in route and not the :fallback_parser. Such entries come back as nil.

config :arcana, file_parsers: %{".pdf" => false}

get(opts, key)

Returns the value for key from opts, falling back to the global app env.

Used to thread configuration like :repo and :llm from per-call opts with a fallback to config :arcana, key: value.

Examples

repo = Arcana.Config.get(opts, :repo)
llm = Arcana.Config.get(opts, :llm)

get_env(key, default \\ nil)

Returns the value for key from the :arcana app env.

All runtime configuration reads in Arcana go through this function. Test suites can install a custom reader with install_env_reader/1 to shadow keys per-process instead of mutating global state.

graph_enabled?(opts)

Returns whether GraphRAG is enabled globally or for specific options.

Checks the :graph option in the provided opts first, then falls back to the global configuration.

Examples

# Check global config
Arcana.Config.graph_enabled?([])

# Override with per-call option
Arcana.Config.graph_enabled?(graph: true)

merge_app_opts(opts, app_key)

Merges global keyword-list config under app_key with per-call opts.

Per-call opts override the global config. Used to thread namespace configs like :search, :ask, and :graph.

Examples

# Reads `config :arcana, search: [limit: 10]` and merges
opts = Arcana.Config.merge_app_opts(opts, :search)

# Reads `config :arcana, ask: [limit: 5]` and merges
opts = Arcana.Config.merge_app_opts(opts, :ask)

pdf_parser()

Returns the configured PDF parser as a {module, opts} tuple.

redact(value)

Wraps a config value for safe inspection with sensitive data redacted.

Returns a struct that implements the Inspect protocol and automatically redacts sensitive keys like :api_key, :token, :password, etc.

Example

iex> config = {"zai:glm-4.7", [api_key: "secret123"]}
iex> inspect(Arcana.Config.redact(config))
~s|{"zai:glm-4.7", [api_key: "[REDACTED]"]}|

repo!(env \\ nil)

Resolves the Ecto repo configured for Arcana's mix tasks.

Accepts either configuration shape:

# Explicit repo key
config :arcana, repo: MyApp.Repo

# Per-repo configuration (e.g. custom priv directory)
config :arcana, MyApp.Repo, priv: "priv/my_repo"

When only the per-repo shape is present and exactly one repo is configured, that repo is used (with a note printed to stderr). Raises ArgumentError when no repo can be resolved, or when several per-repo entries exist without an explicit :repo key to disambiguate.

repo: nil means "not set" and falls through to the per-repo scan. repo: false is an explicit "no repo", so it raises the same "no Ecto repo configured" error instead of quietly picking a per-repo entry.

Called without arguments, the :repo key is read through get_env/2 so process-scoped overrides installed via install_env_reader/1 are honored. Pass an explicit env keyword list to resolve against it directly.

require_repo!(opts)

Returns the repo from opts or the global config, raising when neither is set.

reranker(opts \\ [])

Returns the configured reranker, resolving per-call opts and global config.

Returns nil if no reranker is set or if explicitly disabled with reranker: false. Otherwise returns {module_or_fun, opts}.

resolve_chunker(opts)

Resolves chunker from options, falling back to global config.

resolve_embedder(opts)

Resolves embedder from options, falling back to global config.

strict_collections?(opts \\ [])

Returns whether strict collection scoping is enabled.

When strict, an unknown collection name is an error ({:error, {:unknown_collection, name}}) instead of silently widening the operation to every collection. Checks the :strict_collections option in the provided opts first (so strict_collections: false can override a global true per call), then falls back to config :arcana, strict_collections: true. Defaults to false; the default will flip to true in Arcana 3.0.