
Initial Release

The Universal Embedding Gateway for InterSystems IRIS
One
EMBEDDING()call. Any provider. Same vector space.
InterSystems IRIS 2026 ships a native embeddings runtime โ %Embedding.Interface + EMBEDDING() SQL โ but each embedding provider has its own quirks:
Authorization: Bearerapi-key (not Bearer) and a deployment-scoped URLembeddings.float[0]?key= on the URL itselfoutput_dimension / output_dtype for Codestral truncationinput_type (query vs document), truncation and int8/binary quantizationinput as an array (even for one text) and exposes task + late_chunking for coherent long-doc chunksamazon.titan-embed-* vs cohere.embed-* hosted on Bedrock)text-embedding-* family name as OpenAI lives here tooSwapping providers usually means rewriting glue code, and mixing them in fallback flows silently mixes vector spaces โ a data-integrity disaster that only surfaces months later, when your similarity searches start returning nonsense.
dc.omniEmbedding changes that.
Plug it in once as your EmbeddingClass and every EMBEDDING('text', 'config') call โ from SQL, from ObjectScript, from Interoperability โ routes to the right provider, retries transient errors, opens a circuit breaker on failing providers, and refuses to fall back to a config whose vector space differs from the primary.
late_chunking) ยท AWS Bedrock (SigV4, Titan + Cohere via Bedrock) ยท Google Vertex AI (text-embedding + gemini-embedding)%Net.HttpRequest โ no Python required on the hot pathRetry-After honored, circuit breaker per providerapiKey is a credential name, never the raw secretdc.omniEmbedding sits between IRISโs native embedding runtime and any of the ten supported external providers, applying three architectural pillars:
%Net.HttpRequest end-to-end; Embedded Python is opt-in only (for accurate tiktoken token counts).provider.Base fixes the sequence ValidateConfig โ SetAuth โ GetEmbeddingsUrl โ BuildPayload โ RetryWithBackoff โ ParseResponse; each provider overrides only what differs.modelName or dimensions is fatal, never a silent downgrade.| Class | Role |
|---|---|
dc.omniEmbedding.Interface |
Bridge to %Embedding.Interface โ the class you register in %Embedding.Config |
dc.omniEmbedding.Engine |
Provider resolution, circuit breaker, fallback with vector-space check |
dc.omniEmbedding.provider.Base |
Abstract Template Method; retry/backoff; credential resolution |
dc.omniEmbedding.provider.OpenACompatible |
Shared payload/parse for the OpenAI-shaped family |
dc.omniEmbedding.provider.Ollama |
Local Ollama, keyless, /v1/embeddings |
dc.omniEmbedding.provider.OpenAi |
api.openai.com, Bearer auth |
dc.omniEmbedding.provider.AzureOpenAi |
Deployment-scoped URL, api-key header |
dc.omniEmbedding.provider.Cohere |
v2/embed, nested embeddings.float[0] |
dc.omniEmbedding.provider.Gemini |
Auth via ?key=, content.parts[].text payload |
dc.omniEmbedding.provider.Mistral |
api.mistral.ai/v1/embeddings, text (mistral-embed) + code (codestral-embed), optional output_dimension / output_dtype |
dc.omniEmbedding.provider.Voyage |
api.voyageai.com/v1/embeddings, text (voyage-3*) + code (voyage-code-3) + domain (voyage-finance-2, voyage-law-2, voyage-multilingual-2); input_type (query/document), truncation, output_dimension, output_dtype |
dc.omniEmbedding.provider.Jina |
api.jina.ai/v1/embeddings, jina-embeddings-v3 and jina-* variants; input wrapped as array; task, dimensions, late_chunking, embedding_type |
dc.omniEmbedding.provider.Bedrock |
bedrock-runtime.{region}.amazonaws.com/model/{modelId}/invoke; SigV4 auth via util.SigV4; families amazon.titan-embed-* (inputText/normalize, response .embedding) and cohere.embed-* on Bedrock (texts[]/input_type, response .embeddings[0]); optional sessionTokenCredential for STS/AssumeRole |
dc.omniEmbedding.util.SigV4 |
AWS Signature V4 signer, isolated + testable; key derivation matches AWSโs official test vector byte-for-byte |
dc.omniEmbedding.provider.VertexAi |
{region}-aiplatform.googleapis.com/.../models/{model}:predict; Bearer OAuth 2.0 token; payload instances[{content, task_type?, title?}] + optional parameters{outputDimensionality, autoTruncate}; response predictions[0].embeddings.values |
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ Any caller โ SQL, ObjectScript, โ โ Interoperability, Embedded Python โ โ EMBEDDING('text', 'config') โ โโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ %Embedding.Interface (IRIS runtime) โ โ Reads EmbeddingClass from %Embedding.Config, dispatches: โ โโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ dc.omniEmbedding.Interface (bridge) โ โ ParseConfig ยท validate input ยท Engine.Embed() โ โโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ dc.omniEmbedding.Engine โ โ ResolveProvider ยท CheckBreaker ยท RecordSuccess/Failure โ โ TryFallback (vector-space invariant โ fatal on mismatch) โ โโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ provider.Base.Execute() โ Template Method โ โ ValidateConfig โ SetAuth โ GetEmbeddingsUrl โ โ โ BuildPayload โ RetryWithBackoff โ ParseResponse โ โโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ %Net.HttpRequest โ { Ollama | OpenAI | Azure | Cohere | โ โ Gemini | Mistral | Voyage | Jina | โ โ Bedrock (SigV4) | VertexAI (OAuth) } โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
MIN(baseDelayMs * 2^(attempt-1) + jitter, maxDelayMs) โ Retry-After is honored verbatim when present. 4xx (except 429) fast-fail.provider|modelName|apiBase key stored in ^omniEmbedding.Breaker. Opens after 5 consecutive failures; 60 s cooldown; half-open lets one probe through.config.fallbacks in order. Each candidate is refused before any HTTP call if modelName or dimensions differ from the primary โ vectors from different spaces never mix.%Embedding.Interface and %Library.Vector are required)http://localhost:11434 for zero-cost end-to-end integration teststiktoken for exact OpenAI token counts (a conservative floor is used when unavailable)git clone https://github.com/henryhamon/dc.omniEmbedding.git
cd dc.omniEmbedding
docker-compose up -d --build
The IPM module dc-omni-embedding is loaded automatically into the IRISAPP namespace.
zpm "install dc-omni-embedding"
%Embedding.ConfigRegister dc.omniEmbedding.Interface as your EmbeddingClass, then store a JSON configuration:
INSERT INTO %Embedding.Config (Name, Configuration, EmbeddingClass, VectorLength, Description)
VALUES (
'ollama-nomic',
'{"provider":"ollama","modelName":"nomic-embed-text:latest","apiBase":"http://host.docker.internal:11434","dimensions":768}',
'dc.omniEmbedding.Interface',
768,
'Local Ollama (nomic-embed-text)'
)
From SQL:
SELECT EMBEDDING('the quick brown fox', 'ollama-nomic')
From ObjectScript:
Set vec = ##class(dc.omniEmbedding.Interface).Embedding(
"the quick brown fox",
"{""provider"":""ollama"",""modelName"":""nomic-embed-text:latest"",""dimensions"":768}"
)
Every field is a top-level key on the JSON stored in %Embedding.Config.Configuration.
| Field | Required | Description |
|---|---|---|
provider |
one of: ollama, openai, azure, cohere, gemini, mistral, voyage, jina, bedrock, vertex (aliases: vertexai) โ or infer from modelName. Bedrock and Vertex do NOT infer (their model prefixes collide with OpenAI / Cohere / Gemini) |
Explicit provider selection |
modelName |
yes | Model identifier for the target provider |
dimensions |
yes | Expected vector length โ enforced when checking fallbacks |
apiKey |
provider-dependent | Credential name (not the value) โ resolved via Ens.Config.Credentials |
apiBase |
provider-dependent | Override default endpoint (Ollama, Azure) |
sslConfig |
no | Name of a %SSL.Config for TLS |
httpTimeout |
no (default 30s) |
HTTP timeout in seconds |
retry.maxAttempts |
no (default 3) |
Max attempts including the first |
retry.baseDelayMs |
no (default 500) |
Base backoff delay |
retry.maxDelayMs |
no (default 8000) |
Backoff cap |
retry.honorRetryAfter |
no (default true) |
Use the Retry-After header when present |
fallbacks |
no | Array of %Embedding.Config names โ each must share the primaryโs vector space |
deployment, apiVersion (deployment is optional when apiBase is already deployment-scoped)inputType (default search_document)taskType (default RETRIEVAL_DOCUMENT)outputDimension (truncate โ Codestral supports up to 3072), outputDtype (float ยท int8 ยท uint8 ยท binary ยท ubinary)inputType (query ยท document), truncation (bool), outputDimension, outputDtypetask (e.g. retrieval.query ยท retrieval.passage ยท text-matching ยท classification), outputDimension (mapped to Jinaโs dimensions), lateChunking (bool โ coherent long-doc chunks), outputDtype (mapped to Jinaโs embedding_type)region (required, e.g. us-east-1), sessionTokenCredential (optional, name of a second credential holding an STS token); inputType for Cohere-on-Bedrock family (default search_document); dimensions for Titan familyregion (e.g. us-central1) + project required; apiKey names a credential whose value is a valid OAuth 2.0 access token (rotation is external โ service-account JWT auto-refresh is future work); optional taskType (RETRIEVAL_QUERY ยท RETRIEVAL_DOCUMENT ยท SEMANTIC_SIMILARITY ยท CLASSIFICATION ยท CLUSTERING ยท CODE_RETRIEVAL_QUERY), title (only meaningful with RETRIEVAL_DOCUMENT), outputDimension (mapped to outputDimensionality), autoTruncate (bool){
"provider": "ollama",
"modelName": "nomic-embed-text:latest",
"apiBase": "http://host.docker.internal:11434",
"dimensions": 768,
"fallbacks": ["ollama-backup"]
}
An OpenAI config with text-embedding-3-small (1536 dims) as a fallback would be rejected before any HTTP call โ different vector space.
Register two credentials โ the AWS access key/secret pair, and the STS session token โ then reference both by name:
Set cred = ##class(Ens.Config.Credentials).%New() Set cred.SystemName = "aws-prod" Set cred.Username = "aws" Set cred.Password = "AKIA...prod:wJalrXUtnFEMI/K7MDENG..." ; accessKeyId:secretAccessKey Do cred.%Save()
Set tok = ##class(Ens.Config.Credentials).%New() Set tok.SystemName = "aws-prod-session" Set tok.Username = "sts" Set tok.Password = "FQoDYXdz...session-token..." Do tok.%Save()
{
"provider": "bedrock",
"modelName": "amazon.titan-embed-text-v2:0",
"region": "us-east-1",
"apiKey": "aws-prod",
"sessionTokenCredential": "aws-prod-session",
"dimensions": 1024
}
Bedrock requires provider: "bedrock" explicit โ the gateway will NOT infer it from cohere.embed-* or amazon.titan-embed-* prefixes to avoid collision with the direct Cohere provider.
{
"provider": "mistral",
"modelName": "codestral-embed",
"apiKey": "mistral-prod",
"outputDimension": 1024,
"outputDtype": "float",
"dimensions": 1024
}
outputDimension tells Mistral to truncate the vector server-side (Codestral supports up to 3072); dimensions is what the gateway enforces on fallbacks and what IRIS stores.
config.apiKey is always a credential name, never the raw secret. The gateway resolves the name via Ens.Config.Credentials.%OpenId(name).Password. Register one from the IRIS terminal:
Set cred = ##class(Ens.Config.Credentials).%New()
Set cred.SystemName = "openai-prod"
Set cred.Username = "apikey"
Set cred.Password = "sk-...your-real-key..."
Do cred.%Save()
Then reference it as "apiKey": "openai-prod" in your config. Exceptions raised for a missing credential carry only the name โ never the value. See TestSecurity (Property 15).
dc.omniEmbedding/
โโโ src/dc/omniEmbedding/
โ โโโ Interface.cls # Bridge to %Embedding.Interface
โ โโโ Engine.cls # Dispatch ยท breaker ยท fallback
โ โโโ provider/
โ โโโ Base.cls # Template Method ยท retry ยท ResolveApiKey
โ โโโ OpenACompatible.cls # Shared payload/parse for OpenAI-family
โ โโโ Ollama.cls
โ โโโ OpenAi.cls
โ โโโ AzureOpenAi.cls
โ โโโ Cohere.cls
โ โโโ Gemini.cls
โ โโโ Mistral.cls # mistral-embed (text) + codestral-embed (code)
โ โโโ Voyage.cls # voyage-3, voyage-code-3, voyage-finance-2, ...
โ โโโ Jina.cls # jina-embeddings-v3, with late_chunking
โ โโโ Bedrock.cls # Titan + Cohere-via-Bedrock; overrides Execute for SigV4 ordering
โ โโโ VertexAi.cls # text-embedding-* + gemini-embedding-*, OAuth 2.0 Bearer
โโโ src/dc/omniEmbedding/util/
โ โโโ SigV4.cls # AWS Signature V4 signer (isolated, testable)
โโโ tests/dc/omniEmbedding/
โ โโโ TestOpenACompatible.cls # Payload shape, parse errors, tiktoken floor
โ โโโ TestOllama.cls # URL construction + end-to-end via Ollama
โ โโโ TestAzureUrl.cls # Property 8 โ URL composition invariants
โ โโโ TestCohere.cls # Property 10 โ nested response parse
โ โโโ TestGemini.cls # Property 10 โ auth-in-URL, no-op SetAuth
โ โโโ TestMistral.cls # URL, dispatch, output_dimension/dtype passthrough
โ โโโ TestVoyage.cls # URL, dispatch, inputType enum, all passthroughs
โ โโโ TestJina.cls # Property 17 โ input always array; late_chunking; camelCaseโwire mapping
โ โโโ TestSigV4.cls # Property 18 โ key derivation matches AWS official vector byte-for-byte
โ โโโ TestBedrock.cls # URL, families, ParseResponse per family, credential formats, Property 19 (SigV4 applied), dispatch rules
โ โโโ TestVertexAi.cls # URL, ValidateConfig, Property 20 (parameters block only when needed), dispatch regression (no prefix inference)
โ โโโ TestResilience.cls # Properties 11-14 โ backoff & breaker
โ โโโ TestFallback.cls # Properties 4-5 โ vector-space invariance
โ โโโ TestSecurity.cls # Property 15 โ credentials never leak
โ โโโ TestInterface.cls # Properties 2-3 โ validation & no empty vec
โ โโโ FakeEngine.cls # Test double for fallback tests
โโโ module.xml # IPM manifest
โโโ docker-compose.yml
โโโ README.md
Run every suite from the IRIS terminal:
Set ^UnitTestRoot = "/tmp/ut"
Do ##class(%UnitTest.Manager).RunTest(":dc.omniEmbedding.tests.TestOllama", "/nodelete/noload")
Or via IPM:
zpm "test dc-omni-embedding"
The end-to-end integration test in TestOllama auto-probes localhost:11434 then host.docker.internal:11434 and skips gracefully if Ollama is unavailable โ CI stays green without any cloud key.
%Embedding.Interface bridge & runtime integrationlate_chunking), AWS Bedrock (SigV4, Titan + Cohere-on-Bedrock), Google Vertex AI (text-embedding + gemini-embedding)Retry-After honoringEns.Config.Credentials (secret never leaks)EstimateTokenCount (tiktoken ยท Cohere ยท Gemini formulas)Ens.Config.Credentials)dc.omniEmbedding is designed and developed with ๐ by:
This project is licensed under the MIT License.