Moss.Client (moss v1.8.0)

Copy Markdown

High-level entry point for the moss Elixir SDK.

Counterpart to MossClient in the Python SDK.

Example:

{:ok, client} = Moss.Client.new("project-id", "project-key")

# Cloud CRUD
{:ok, result} = Moss.Client.create_index(client, "my-index", docs)
{:ok, info}   = Moss.Client.get_index(client, "my-index")

# Load and query a cloud index locally
{:ok, _}       = Moss.Client.load_index(client, "faq-index")
{:ok, results} = Moss.Client.query(client, "faq-index", "cancel")

# Search several loaded indexes in one call
{:ok, _}       = Moss.Client.load_indexes(client, ["a", "b"])
{:ok, results} = Moss.Client.query_multi_index(client, ["a", "b"], "query")

# Session workflow with built-in embeddings
{:ok, session} = Moss.Client.session(client, "session-abc")
{:ok, {2, 0}}  = Moss.Session.add_docs(session, docs)
{:ok, result}  = Moss.Session.query(session, "billing issue")
{:ok, _}       = Moss.Session.push_index(session)

# Custom models still use explicit embeddings
{:ok, custom_session} = Moss.Client.session(client, "custom-session", model_id: "custom")
{:ok, {1, 0}} = Moss.Session.add_docs(custom_session, docs)
{:ok, custom_result} = Moss.Session.query(custom_session, "billing issue", embedding: my_vec)

Summary

Functions

Add documents to an existing cloud index.

Close the client's index manager: send its final usage telemetry, unload its indexes and stop its process.

Create a cloud index with initial documents.

Create an index from raw files via the server-side parse pipeline.

Delete documents by IDs from a cloud index.

Delete a cloud index.

Get documents from a cloud index.

Get metadata for a cloud index.

Get metadata for a loaded index.

Poll the status of an async job.

Check if an index is loaded.

List all cloud indexes for this project.

Load a cloud index into memory.

Bulk-load many indexes into memory. Best-effort: names that fail are reported in failed without rolling back the ones that loaded.

Create a new Moss.Client.

Query a locally loaded index.

Search several loaded indexes in one call and get the global top-k, each result tagged with its source index_name. All names must be loaded (load_index/3 or load_indexes/3) and share one embedding model.

Install the cloud's snapshot of a loaded index when it is newer. A snapshot no newer than the loaded one, with the same model, downloads nothing and returns was_updated: false.

Create or resume a local session index.

Unload an index from memory.

Bulk-unload indexes. Idempotent for names that are not loaded.

Types

t()

@type t() :: %Moss.Client{
  cache_path: String.t() | nil,
  client_id: String.t(),
  manage_ref: reference(),
  manager_pid: pid(),
  project_id: String.t(),
  project_key: String.t()
}

Functions

add_docs(client, name, docs, opts \\ [])

@spec add_docs(t(), String.t(), [Moss.DocumentInfo.t()], keyword()) ::
  {:ok, Moss.MutationResult.t()} | {:error, Moss.Error.t()}

Add documents to an existing cloud index.

Options:

  • :upsert (boolean, default nil — use server default)

close(client)

@spec close(t()) :: :ok

Close the client's index manager: send its final usage telemetry, unload its indexes and stop its process.

Waits until the telemetry is delivered or 2 seconds pass. Sessions are separate processes, so close each with Moss.Session.close/1. Cloud calls such as create_index/4 keep working afterwards; calls that need the manager exit.

create_index(client, name, docs, model_id \\ "moss-minilm")

@spec create_index(t(), String.t(), [Moss.DocumentInfo.t()], String.t()) ::
  {:ok, Moss.MutationResult.t()} | {:error, Moss.Error.t()}

Create a cloud index with initial documents.

create_index_from_files(client, name, files, model_id \\ "moss-minilm", parse_options \\ nil)

@spec create_index_from_files(
  t(),
  String.t(),
  [map()],
  String.t(),
  map() | nil
) :: {:ok, Moss.MutationResult.t()} | {:error, Moss.Error.t()}

Create an index from raw files via the server-side parse pipeline.

Each file in files is a map with all three keys required:

  • :path — filesystem path
  • :name — filename sent to the server
  • :content_type — MIME type

model_id defaults to "moss-minilm". Must be a built-in model. "custom" is not supported because the parse pipeline generates embeddings server-side.

At most 20 files per call.

parse_options is an optional map controlling extraction. Omitted keys use the server defaults:

  • :ocr_mode: "auto_ocr" or "full_ocr". Use "full_ocr" for scanned documents with no text layer.
  • :segmentation_method: "smart_layout_detection" or "page_by_page"
  • :use_high_resolution: boolean, slower but better on dense tables
  • :merge_tables: boolean, join tables split across a page break
  • :chunk_size: integer, target length of each chunk in characters, 200 to 2000 (default 1200)
  • :chunk_overlap: integer, characters shared by consecutive chunks, 0 to half of :chunk_size (default 200, capped at half of :chunk_size)

Supported content types: "application/pdf" and the DOCX MIME "application/vnd.openxmlformats-officedocument.wordprocessingml.document".

Example:

{:ok, result} = Moss.Client.create_index_from_files(
  client,
  "my-index",
  [
    %{
      name: "report.pdf",
      content_type: "application/pdf",
      path: "/docs/report.pdf"
    },
    %{
      name: "manual.docx",
      content_type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      path: "/docs/manual.docx"
    }
  ],
  "moss-minilm",
  %{ocr_mode: "full_ocr"}
)

delete_docs(client, name, doc_ids)

@spec delete_docs(t(), String.t(), [String.t()]) ::
  {:ok, Moss.MutationResult.t()} | {:error, Moss.Error.t()}

Delete documents by IDs from a cloud index.

delete_index(client, name)

@spec delete_index(t(), String.t()) :: {:ok, boolean()} | {:error, Moss.Error.t()}

Delete a cloud index.

get_docs(client, name, opts \\ [])

@spec get_docs(t(), String.t(), keyword()) ::
  {:ok, [Moss.DocumentInfo.t()]} | {:error, Moss.Error.t()}

Get documents from a cloud index.

Options:

  • :doc_ids (list of strings) — if provided, only fetch those docs

get_index(client, name)

@spec get_index(t(), String.t()) ::
  {:ok, Moss.IndexInfo.t()} | {:error, Moss.Error.t()}

Get metadata for a cloud index.

get_index_info(client, name)

@spec get_index_info(t(), String.t()) ::
  {:ok, Moss.IndexInfo.t()} | {:error, Moss.Error.t()}

Get metadata for a loaded index.

get_job_status(client, job_id)

@spec get_job_status(t(), String.t()) ::
  {:ok, Moss.JobStatusResponse.t()} | {:error, Moss.Error.t()}

Poll the status of an async job.

has_index(client, name)

@spec has_index(t(), String.t()) :: boolean()

Check if an index is loaded.

list_indexes(client)

@spec list_indexes(t()) :: {:ok, [Moss.IndexInfo.t()]} | {:error, Moss.Error.t()}

List all cloud indexes for this project.

load_index(client, name, opts \\ [])

@spec load_index(t(), String.t(), keyword()) ::
  {:ok, Moss.IndexInfo.t()} | {:error, Moss.Error.t()}

Load a cloud index into memory.

Options:

  • :auto_refresh (boolean, default false)
  • :polling_interval (integer seconds, default 600, minimum 1; 0 uses the default)

Returns {:ok, Moss.IndexInfo.t()} or {:error, reason}.

load_indexes(client, names, opts \\ [])

@spec load_indexes(t(), [String.t()], keyword()) :: {:ok, Moss.LoadIndexesResult.t()}

Bulk-load many indexes into memory. Best-effort: names that fail are reported in failed without rolling back the ones that loaded.

Options:

  • :auto_refresh (boolean, default false)
  • :polling_interval (integer seconds, default 600, minimum 1; 0 uses the default)

Returns {:ok, %Moss.LoadIndexesResult{loaded: [...], failed: %{name => reason}}}.

new(project_id, project_key, opts \\ [])

@spec new(String.t(), String.t(), keyword()) :: {:ok, t()} | {:error, Moss.Error.t()}

Create a new Moss.Client.

The index API URL is resolved from the MOSS_INDEX_URL environment variable (falls back to the default cloud endpoint). No URL option is needed.

Options:

  • :cache_path (directory for the on-disk index cache used by load_index/3; <cache_path>/.moss-device-id is created when missing and adopted as the device id; sessions from this client save to <cache_path>/sessions/<project id>/ by default)

query(client, name, query_text, opts \\ [])

@spec query(t(), String.t(), String.t(), keyword()) ::
  {:ok, Moss.SearchResult.t()} | {:error, Moss.Error.t()}

Query a locally loaded index.

For built-in models, the query is embedded automatically. For indexes created with model_id: "custom", pass the query embedding via embedding: [...].

Options:

  • :top_k (integer, default 5)
  • :alpha (float, default 0.8)
  • :filter (map)
  • :embedding (list of floats, required for model_id: "custom")

Returns {:ok, Moss.SearchResult.t()} or {:error, reason}.

query_multi_index(client, names, query_text, opts \\ [])

@spec query_multi_index(t(), [String.t()], String.t(), keyword()) ::
  {:ok, Moss.SearchResult.t()} | {:error, Moss.Error.t()}

Search several loaded indexes in one call and get the global top-k, each result tagged with its source index_name. All names must be loaded (load_index/3 or load_indexes/3) and share one embedding model.

:alpha works exactly as in query/4 (default 0.8): 1.0 is embedding-only, 0.0 is keyword-only, and values in between fuse both with Reciprocal Rank Fusion. Keyword scoring runs each index's own BM25 and merges hits by score before fusion. Keyword-only queries never embed the text, so they also work on custom-model indexes without :embedding.

Options:

  • :top_k (integer, default 10; caps the merged result, not each index)
  • :alpha (float, default 0.8)
  • :filter (map, applied to every index)
  • :embedding (list of floats, required for model_id: "custom" unless alpha: 0.0)

Returns {:ok, Moss.SearchResult.t()} or {:error, reason}.

refresh_index(client, name)

@spec refresh_index(t(), String.t()) ::
  {:ok, Moss.RefreshResult.t()} | {:error, Moss.Error.t()}

Install the cloud's snapshot of a loaded index when it is newer. A snapshot no newer than the loaded one, with the same model, downloads nothing and returns was_updated: false.

session(client, index_name, opts \\ [])

@spec session(t(), String.t(), keyword()) ::
  {:ok, GenServer.server()} | {:error, Moss.Error.t()}

Create or resume a local session index.

If a cloud index with index_name already exists, it is silently loaded into the session, and the session takes its model, even when the index has no documents. If not, the session starts empty. An explicit :model_id that the existing index does not use returns {:error, %Moss.Error{code: :invalid_argument}}.

With auto_load_on_init: false the session skips that load and starts empty with :model_id, so Moss.Session.load_from_disk/3 can restore it with no index download. Moss.Session.push_index/1 before any load replaces the cloud index with the session's documents.

Options:

  • :model_id (String.t(), default "moss-minilm")
  • :auto_load_on_init (boolean, default true): load an existing cloud index into the session before returning
  • :server_name — GenServer name for the Session process

Returns {:ok, pid} on success.

unload_index(client, name)

@spec unload_index(t(), String.t()) :: {:ok, :ok} | {:error, Moss.Error.t()}

Unload an index from memory.

unload_indexes(client, names)

@spec unload_indexes(t(), [String.t()]) :: :ok

Bulk-unload indexes. Idempotent for names that are not loaded.