Skip to content

Latest commit

ย 

History

37 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Gitter License: MIT InterSystems IRIS ObjectScript

OmniEmbedding Logo

๐Ÿง  dc.omniEmbedding

The Universal Embedding Gateway for InterSystems IRIS

One EMBEDDING() call. Any provider. Same vector space.


๐ŸŒŒ Motivation

InterSystems IRIS 2026 ships a native embeddings runtime โ€” %Embedding.Interface + EMBEDDING() SQL โ€” but each embedding provider has its own quirks:

  • Ollama speaks OpenAI-compatible JSON but needs no auth
  • OpenAI uses Authorization: Bearer
  • Azure OpenAI wants api-key (not Bearer) and a deployment-scoped URL
  • Cohere returns embeddings under embeddings.float[0]
  • Gemini authenticates via ?key= on the URL itself
  • Mistral is OpenAI-shaped but adds output_dimension / output_dtype for Codestral truncation
  • Voyage AI adds input_type (query vs document), truncation and int8/binary quantization
  • Jina AI requires input as an array (even for one text) and exposes task + late_chunking for coherent long-doc chunks
  • AWS Bedrock speaks SigV4 (not Bearer) and switches payload/response shape per family (amazon.titan-embed-* vs cohere.embed-* hosted on Bedrock)
  • Google Vertex AI needs region + project in the URL and an OAuth 2.0 access token in the header โ€” the same text-embedding-* family name as OpenAI lives here too

Swapping 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.

  • โœ… Ten providers, one interface: Ollama ยท OpenAI ยท Azure OpenAI ยท Cohere ยท Gemini ยท Mistral (text + code) ยท Voyage (text + code + domain) ยท Jina (with late_chunking) ยท AWS Bedrock (SigV4, Titan + Cohere via Bedrock) ยท Google Vertex AI (text-embedding + gemini-embedding)
  • โœ… Native HTTP: %Net.HttpRequest โ€” no Python required on the hot path
  • โœ… Resilient: exponential backoff, Retry-After honored, circuit breaker per provider
  • โœ… Safe fallback: vector-space invariance is enforced before any HTTP call
  • โœ… Secure by default: apiKey is a credential name, never the raw secret
  • โœ… CI-friendly: the whole happy path runs against local Ollama, no cloud keys

๐Ÿ› ๏ธ How It Works

dc.omniEmbedding sits between IRIS's native embedding runtime and any of the ten supported external providers, applying three architectural pillars:

  1. HTTP native first โ€” the happy path uses %Net.HttpRequest end-to-end; Embedded Python is opt-in only (for accurate tiktoken token counts).
  2. Polymorphism by class hierarchy โ€” a Template Method in provider.Base fixes the sequence ValidateConfig โ†’ SetAuth โ†’ GetEmbeddingsUrl โ†’ BuildPayload โ†’ RetryWithBackoff โ†’ ParseResponse; each provider overrides only what differs.
  3. Vector-space integrity as a hard invariant โ€” a fallback with a different modelName or dimensions is fatal, never a silent downgrade.

Core Components

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

Architecture Overview


โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                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) } โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Resilience Model

  • Retry: 429 and 5xx are retried with MIN(baseDelayMs * 2^(attempt-1) + jitter, maxDelayMs) โ€” Retry-After is honored verbatim when present. 4xx (except 429) fast-fail.
  • Circuit breaker: per provider|modelName|apiBase key stored in ^omniEmbedding.Breaker. Opens after 5 consecutive failures; 60 s cooldown; half-open lets one probe through.
  • Fallback: iterates 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.

๐Ÿ“‹ Prerequisites

  • InterSystems IRIS 2026.2+ (native %Embedding.Interface and %Library.Vector are required)
  • Docker and Docker Compose (if you use the bundled dev container)
  • Optional: Ollama at http://localhost:11434 for zero-cost end-to-end integration tests
  • Optional: Embedded Python with tiktoken for exact OpenAI token counts (a conservative floor is used when unavailable)

๐Ÿ› ๏ธ Installation

1. Clone the Repository

git clone https://github.com/henryhamon/dc.omniEmbedding.git
cd dc.omniEmbedding

2. Build and Run the Dev Container

docker-compose up -d --build

The IPM module dc-omni-embedding is loaded automatically into the IRISAPP namespace.

3. Or Install as an IPM Package

zpm "install dc-omni-embedding"

4. Wire it into %Embedding.Config

Register 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)'
)

5. Use It

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}"
)

๐Ÿ’ก Configuration Reference

Every field is a top-level key on the JSON stored in %Embedding.Config.Configuration.

Common fields (all providers)

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

Provider-specific extras

  • Azure OpenAI: deployment, apiVersion (deployment is optional when apiBase is already deployment-scoped)
  • Cohere: inputType (default search_document)
  • Gemini: taskType (default RETRIEVAL_DOCUMENT)
  • Mistral: outputDimension (truncate โ€” Codestral supports up to 3072), outputDtype (float ยท int8 ยท uint8 ยท binary ยท ubinary)
  • Voyage: inputType (query ยท document), truncation (bool), outputDimension, outputDtype
  • Jina: task (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)
  • AWS Bedrock: 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 family
  • Google Vertex AI: region (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)

Example โ€” Ollama with an OpenAI fallback

{
    "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.

Example โ€” AWS Bedrock Titan v2 with a session token

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.

Example โ€” Mistral Codestral for code retrieval, truncated to 1024 dims

{
    "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.


๐Ÿ” Credentials

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).


๐Ÿ—‚๏ธ Project Structure

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

๐Ÿงช Testing

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.


๐Ÿ“Š Roadmap

โœ… v1.0 โ€” Complete

  • %Embedding.Interface bridge & runtime integration
  • Provider resolution by explicit name or model-prefix inference
  • Ten providers: Ollama, OpenAI, Azure OpenAI, Cohere, Gemini, Mistral (text + code), Voyage (text + code + domain), Jina (with late_chunking), AWS Bedrock (SigV4, Titan + Cohere-on-Bedrock), Google Vertex AI (text-embedding + gemini-embedding)
  • Retry with exponential backoff + Retry-After honoring
  • Circuit breaker (5 failures / 60 s cooldown / half-open probe)
  • Fallback with vector-space invariance (fatal on mismatch)
  • Credentials via Ens.Config.Credentials (secret never leaks)
  • Polymorphic EstimateTokenCount (tiktoken ยท Cohere ยท Gemini formulas)
  • Property-based test suite covering every correctness invariant

๐Ÿ”ฎ Future

  • Batching support (multiple inputs per request)
  • Vertex AI: automatic OAuth 2.0 access-token refresh via service-account JWT-bearer flow (currently the token is supplied externally through Ens.Config.Credentials)
  • Optional in-process embedding cache with TTL

๐ŸŽ–๏ธ Credits

dc.omniEmbedding is designed and developed with ๐Ÿ’œ by:


๐Ÿ“„ License

This project is licensed under the MIT License.

About

The Universal Embedding Gateway for InterSystems IRIS

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages