Ruby SDK
Official Ruby client for VectorAmp. Defaults to https://api.vectoramp.com; REST transport today, designed so gRPC can be added later.
Install
gem "vector_amp"
From a checkout for local development:
git clone https://github.com/vectoramp/vectoramp-ruby.git
cd vectoramp-ruby
bundle install
Configure
require "vector_amp"
# api_key defaults to ENV["VECTORAMP_API_KEY"]; base_url defaults to production.
client = VectorAmp::Client.new
# Or configure explicitly.
client = VectorAmp::Client.new(
api_key: ENV.fetch("VECTORAMP_API_KEY"),
timeout: 30
)
Auth uses the X-Api-Key header.
Quickstart
A minimal init, a one-call create, then object → method calls. Only a name is required: the SDK defaults to the managed vectoramp/VectorAmp-Embedding-4B model, infers dim (2560), metric "cosine", and always uses the SABLE index.
require "vector_amp"
client = VectorAmp::Client.new
# One-call create.
dataset = client.datasets.create(name: "product-docs")
# Object -> method style: call helpers directly on the returned dataset.
dataset.add_texts(["VectorAmp is powered by SABLE."], metadata: { source: "readme" })
results = dataset.search("What powers VectorAmp?", top_k: 5, include_documents: true)
answer = dataset.ask("What powers VectorAmp?")
puts results.inspect
puts answer["answer"]
Dataset creation intentionally does not accept index_type; all datasets are created with SABLE.
Creating datasets
# Minimal: name only.
client.datasets.create(name: "docs")
# Enable hybrid (dense + sparse) search.
client.datasets.create(name: "docs", hybrid: true)
# Use an OpenAI embedding model (dim inferred from the model).
client.datasets.create(name: "docs", embedding: VectorAmp::Embedding.openai("large"))
# Custom/unknown model: pass dim explicitly.
client.datasets.create(name: "docs", embedding: { provider: "acme", model: "acme-embed" }, dim: 1024)
Object and service styles
# Object -> method style (preferred)
page = client.datasets.list(limit: 50, offset: 0)
dataset = page["datasets"].first
dataset.search("release notes", top_k: 10)
dataset.delete
# Service style
client.datasets.search("dataset-uuid", "release notes", top_k: 10)
client.datasets.insert("dataset-uuid", vectors: [])
client.datasets.delete("dataset-uuid")
List calls return pagination envelopes such as { "datasets" => [...], "total" => n, "limit" => 50, "offset" => 0 }.
Insert, add text, and search
Vector ids may be strings or integers; integer ids stay numbers.
# Raw vectors
dataset.insert(vectors: [
{ id: 1, values: [0.1, 0.2, 0.3], metadata: { title: "Intro" } },
{ id: "doc-002", values: [0.4, 0.5, 0.6], metadata: { title: "Details" } }
])
# Embed text with the dataset model, then insert.
dataset.add_texts(["Wireless headphones"], metadata: { category: "electronics" })
search accepts a bare string (text query) or a float vector; top_k defaults to 10.
dataset.search(
"wireless headphones",
top_k: 10,
filters: { category: "electronics" },
advanced_filters: [{ field: "price", op: "lt", value: 100.0 }],
include_metadata: true,
rerank: true # expands to vectoramp / VectorAmp-Rerank-v1
)
# Hybrid search on a hybrid dataset.
dataset.search("wireless headphones", hybrid: true, sparse_query: "headphones", alpha: 0.5)
rerank: true enables the optional model reranker after initial retrieval. The separate rerank_depth_override only tunes SABLE's vector-index candidate depth and is not the model reranker.
Organization secrets and vector deletion
Store external provider credentials as organization secrets, then reference the secret from datasets. The default OpenAI BYOM reference is emb:openai:api_key.
# One-step convenience: saves/updates the OpenAI org secret, then creates
# the dataset with embedding.secret_ref = "emb:openai:api_key".
dataset = client.datasets.create(
name: "openai-docs",
openai_api_key: ENV.fetch("OPENAI_API_KEY")
)
# Or manage the secret explicitly.
client.secrets.put_openai_api_key(ENV.fetch("OPENAI_API_KEY"))
# Delete individual vector ids from search.
dataset.delete_vectors(ids: ["doc-001", 42], write_concern: "quorum")
client.datasets.delete_vectors(dataset.id, ids: ["doc-002"])
Ingestion
Typed builders cover web, s3, gcs, gdrive, jira, confluence, and file_upload.
web = client.sources.create_web(start_urls: ["https://docs.example.com"], max_depth: 1)
s3 = client.sources.create_s3(bucket: "vectoramp-docs", prefix: "public/")
gcs = client.sources.create_gcs(bucket: "vectoramp-docs-gcs", prefix: "public/")
jira = client.sources.create_jira(cloud_id: "atlassian-cloud-id", project_keys: ["ENG"])
confluence = client.sources.create_confluence(
cloud_id: "atlassian-cloud-id",
spaces: ["ENG"],
username: "bot@vectoramp.com",
api_token: ENV["CONFLUENCE_API_TOKEN"]
)
gdrive = client.sources.create_google_drive(folder_ids: ["google-drive-folder-id"])
file_source = client.sources.create_file_upload
# One-liner: ingest by source id or a typed source object that has an id.
job = dataset.ingest_source(web["id"])
Use VectorAmp::GenericSource or client.ingestion.create_source(...) when the API supports a source type before the SDK has a dedicated helper.
generic_source = VectorAmp::GenericSource.new(
source_type: "custom",
name: "custom-source",
config: { endpoint: "https://example.com/feed" }
)
client.sources.create(generic_source)
Manage and clean up sources
Validate a config, delete a source, or find and remove sources nothing is using.
# Validate without persisting.
client.sources.validate("web", { start_urls: ["https://docs.example.com"] })
# See what's using a source (active schedules + in-flight jobs).
refs = client.sources.get_references("source-uuid") # { "schedules" => [...], "schedule_count" => …, "active_job_count" => …, "in_use" => … }
# Delete. Raises 409 if in use unless force: true (force also disables its schedules).
client.sources.delete("source-uuid")
client.sources.delete("source-uuid", force: true)
# Find unused sources, or remove all of them in one call.
unused = client.sources.list_unused
result = client.sources.cleanup_unused # { "deleted" => [...], "count" => n }
Authenticated sources & connections
Authenticate a gdrive/gcs/confluence/jira source with a headless service account, or a reusable connection granted once in the browser.
# Option 1 — service account (headless, no browser).
client.sources.create_google_drive(
folder_ids: ["drive-folder-id"],
service_account_json: { type: "service_account", client_email: "ingest@proj.iam.gserviceaccount.com", private_key: "…" }
)
# Option 2 — connection (interactive once, reused server-side).
# connect creates the grant, prints/opens authorization_url, and polls until connected.
conn = client.connections.connect(provider: "google", source_type: "gdrive")
client.sources.create_google_drive(folder_ids: ["drive-folder-id"], connection_id: conn["id"])
Drive the grant flow yourself when you need to:
conn = client.connections.create(provider: "google", source_type: "gdrive") # { "id" => …, "status" => "pending", "authorization_url" => … }
puts "Open in a browser: #{conn["authorization_url"]}"
client.connections.get(conn["id"]) # poll until status == "connected"
client.connections.list(provider: "google")
client.connections.delete(conn["id"])
Minimal file upload ingestion
ingest_files uses the REST upload flow. No source name is required; the SDK creates a file_upload source with a generated name before uploading.
dataset.ingest_files(paths: ["docs/whitepaper.pdf"])
# Service style
client.ingestion.ingest_files(
dataset_id: "dataset-uuid",
paths: ["docs/whitepaper.pdf", "docs/notes.md"],
metadata: { team: "product" }
)
Dataset documents
List retained source documents and download originals when download_available is true. Pagination is cursor-based; keep passing next_cursor until it is empty.
page = client.datasets.list_documents("dataset-uuid", limit: 50, status: "ready")
page.fetch("documents").each do |document|
next unless document["download_available"]
bytes = client.datasets.download_document("dataset-uuid", document.fetch("id"))
File.binwrite(document["file_name"] || document.fetch("id"), bytes)
end
if page["next_cursor"]
next_page = client.datasets.list_documents("dataset-uuid", cursor: page["next_cursor"])
end
# Object style
docs = dataset.list_documents(limit: 25)
raw = dataset.download_document(docs.fetch("documents").first.fetch("id"))
The SDK follows download redirects and returns raw bytes. Storage buckets, object keys, and payload references are never exposed.
Ask / RAG
ask defaults top_k=5 (server-side), includes sources, and uses "all" datasets when unscoped.
answer = client.ask("What are the key features?", dataset_id: "all", top_k: 5)
puts answer["answer"]
client.ask_stream("Summarize the docs", dataset_id: "dataset-uuid") do |event|
print event["content"] if event["chunk_type"] == "text"
end
Multi-turn conversations
The Intelligence API is stateless. To ask a follow-up, send the prior turns as conversation history; you decide how many previous messages to include.
history = [
{ role: "user", content: "What are the key features?" },
{ role: "assistant", content: "Hybrid search, reranking, and managed ingestion." }
]
answer = client.intelligence.query(
"Which of those help with relevance?",
dataset_id: "all",
conversation_history: history.last(10)
)
puts answer["answer"]
Persistent Intelligence sessions
Persist multi-turn conversations server-side instead of resending history.
session = client.intelligence.create_session(title: "Onboarding", dataset_id: "dataset-uuid")
client.intelligence.append_message(session.fetch("id"), role: "user", content: "What is SABLE?")
client.intelligence.append_message(session.fetch("id"), role: "assistant", content: "A managed index type.")
messages = client.intelligence.list_messages(session.fetch("id"))
sessions = client.intelligence.list_sessions(limit: 20)
client.intelligence.get_session(session.fetch("id"))
client.intelligence.delete_session(session.fetch("id"))
answer["sources"] contains source-level citations. Inline [1] markers refer to sources[0]; preview_ref is an opaque preview token, never a raw storage key.
Error handling
Non-2xx responses raise VectorAmp::APIError with status, body, and headers.
begin
client.datasets.get("missing")
rescue VectorAmp::APIError => e
warn "VectorAmp API error #{e.status}: #{e.message}"
end
Method reference
Both access styles work everywhere: client.datasets.<m>(id, ...) and the equivalent datasetObj.<m>(...) on a returned VectorAmp::Dataset.
Datasets — client.datasets
| Method | Required | Optional (default) |
|---|---|---|
create(name:) | name | dim (inferred), embedding (vectoramp/VectorAmp-Embedding-4B), metric ("cosine"), hybrid, filters, metadata_schema, tuning, metadata |
list | — | limit (50), offset (0) |
get(id) | id | — |
delete(id) / ds.delete | id | — |
stats(id) / ds.stats | id | — |
search(id, query = nil) / ds.search(query) | id | query/query_text/search_text, top_k (10), filters, advanced_filters, hybrid, sparse_query, alpha, rerank, include_documents, include_metadata, include_embeddings, embedding_model, embedding_provider, nprobe_override, rerank_depth_override |
insert(id, vectors:) / ds.insert(vectors:) | id, vectors | — (integer ids preserved as numbers) |
embed(id) / ds.embed | id | text, texts (one required) |
add_texts(id, texts = nil) / ds.add_texts(texts) | id, texts | ids (auto-generated), metadata |
list_documents(id) / ds.list_documents | id | limit (50), cursor, status |
download_document(id, document_id) / ds.download_document(document_id) | id, document_id | — |
ds.ask(query) | query | top_k, conversation_history, include_sources |
ds.ingest_source(source) | source (id or builder) | pipeline_id |
ds.ingest_files(paths:) | paths | source_name, metadata |
Intelligence — client.intelligence (and client.ask / client.ask_stream)
| Method | Required | Optional (default) |
|---|---|---|
query(query) / ask / ask_stream | query | dataset_id ("all" when unscoped), top_k (5 server-side), conversation_history, include_sources, stream |
create_session | — | title, dataset_id, workspace_id, metadata |
list_sessions | — | limit (50) |
get_session(session_id) / delete_session(session_id) | session_id | — |
append_message(session_id, role:, content:) | session_id, role, content | metadata |
list_messages(session_id) | session_id | limit (100) |
Sources — client.sources (alias of client.ingestion)
create(source), create_web(start_urls:), create_s3(bucket:), create_gcs(bucket:), create_google_drive(folder_ids:|file_ids:, service_account_json:|connection_id:), create_jira(cloud_id:), create_confluence(cloud_id:|base_url:), create_file_upload, list_sources, get_source(id). Management: validate(source_type, config), get_references(id), delete(id, force: false), list_unused, cleanup_unused. Jobs: start_job(source_id:, dataset_id:), list_jobs, get_job(id), retry_job(id), ingest_files(dataset_id:, paths:).
Schedules — client.schedules
list, get(id), create(source_id:, dataset_id:, cron:), update(id), delete(id), trigger(id).
Connections — client.connections
list(provider: nil), create(provider:, source_type: nil) → { "id", "status" => "pending", "authorization_url" }, get(id) (poll until status == "connected"), delete(id), and the connect(provider:, source_type: nil) helper (create → open authorization_url → poll until connected).