Cogitator
Memory & RAG

Embedding Providers

Configure embedding providers for semantic search — OpenAI, Ollama, and Google — and understand how embeddings power agent memory.

How Embeddings Work

Embeddings convert text into dense numerical vectors that capture semantic meaning. Two pieces of text about the same topic will have vectors that are close together in high-dimensional space, even if they use different words.

In Cogitator, embeddings enable:

  • Semantic search over stored documents and past conversations
  • Hybrid search combining vector similarity with keyword matching
  • Knowledge graph node search by meaning rather than exact name
  • Context building that retrieves the most relevant memories for the current query

All embedding providers implement the EmbeddingService interface:

interface EmbeddingService {
  embed(text: string): Promise<number[]>;
  embedBatch(texts: string[]): Promise<number[][]>;
  readonly dimensions: number;
  readonly model: string;
}

embed('') throws, and embedBatch([]) returns [] without a request. Every provider retries timeouts, network errors and HTTP 408/429/5xx responses up to 3 times with exponential backoff (honouring Retry-After), with a 30-second timeout per attempt; other errors throw with the provider's response text.

Factory Function

Use createEmbeddingService to instantiate a provider from a config object:

import { createEmbeddingService } from '@cogitator-ai/memory';

const embeddings = createEmbeddingService({
  provider: 'openai',
  apiKey: process.env.OPENAI_API_KEY!,
  model: 'text-embedding-3-small',
});

const vector = await embeddings.embed('What is Cogitator?');
console.log(vector.length); // 1536

The same config object is what memory.embedding takes in the Cogitator config.

OpenAI

Uses the OpenAI embeddings API (or any OpenAI-compatible endpoint via baseUrl).

import { OpenAIEmbeddingService } from '@cogitator-ai/memory';

const embeddings = new OpenAIEmbeddingService({
  apiKey: process.env.OPENAI_API_KEY!,
  model: 'text-embedding-3-small',
});

const vector = await embeddings.embed('Agent memory architecture');
console.log(embeddings.dimensions); // 1536
console.log(embeddings.model); // 'text-embedding-3-small'

Batch embedding sends all texts in a single API call and returns vectors in input order:

const vectors = await embeddings.embedBatch([
  'First document about agents',
  'Second document about tools',
  'Third document about memory',
]);
// vectors.length === 3, each vector.length === 1536

Request shorter vectors from text-embedding-3-* models with dimensions. Gateway ids such as openai/text-embedding-3-small (OpenRouter) count as the same model:

const compact = new OpenAIEmbeddingService({
  apiKey: process.env.OPENAI_API_KEY!,
  model: 'text-embedding-3-large',
  dimensions: 768,
});
OptionTypeDefaultDescription
apiKeystring—OpenAI API key
modelstringtext-embedding-3-smallEmbedding model name
baseUrlstringhttps://api.openai.com/v1API base URL (for proxies and compatible APIs)
dimensionsnumbermodel defaultOutput size, see below

Dimensions by model:

ModelDimensions
text-embedding-3-small1536
text-embedding-3-large3072
text-embedding-ada-0021536

Gateway ids that contain one of these names, such as openai/text-embedding-3-large, report that model's size. Other models report 1536 unless you pass dimensions.

dimensions is sent to the API only for text-embedding-3 models, which shorten their output to it. For any other model it declares the size the model returns. Either way it is the size the service promises: when a response holds vectors of another size, embed() and embedBatch() throw instead of handing them to a store sized for dimensions.

Ollama

Run embedding models locally with zero API costs. Ollama's /api/embed endpoint supports both single and batch embedding natively.

import { OllamaEmbeddingService } from '@cogitator-ai/memory';

const embeddings = new OllamaEmbeddingService({
  model: 'nomic-embed-text',
  baseUrl: 'http://localhost:11434',
});

const vector = await embeddings.embed('Local embedding example');
console.log(embeddings.dimensions); // 768

Pull a model first:

ollama pull nomic-embed-text
OptionTypeDefaultDescription
modelstringnomic-embed-textOllama embedding model
baseUrlstringhttp://localhost:11434Ollama server URL
dimensionsnumberfrom the table belowReported vector size for models not in the table

Known models and dimensions:

ModelDimensions
nomic-embed-text768
nomic-embed-text-v2-moe768
mxbai-embed-large1024
all-minilm384
snowflake-arctic-embed1024

You can use any Ollama embedding model. For models not in this list the service reports 768 dimensions unless you set dimensions — Ollama itself always returns the model's native size, so set it to match the model.

Google

Uses the Gemini gemini-embedding-001 model via the Google AI API.

import { GoogleEmbeddingService } from '@cogitator-ai/memory';

const embeddings = new GoogleEmbeddingService({
  apiKey: process.env.GOOGLE_API_KEY!,
  model: 'gemini-embedding-001',
});

const vector = await embeddings.embed('Google embedding example');
console.log(embeddings.dimensions); // 3072

Batch embedding uses Google's batchEmbedContents endpoint, split into requests of up to 100 texts that run in parallel:

const vectors = await embeddings.embedBatch(['First passage', 'Second passage']);
OptionTypeDefaultDescription
apiKeystring—Google AI API key
modelstringgemini-embedding-001Embedding model name
dimensionsnumber3072Output size; when set, sent as outputDimensionality
baseUrlstringhttps://generativelanguage.googleapis.com/v1betaAPI base URL

Dimensions: gemini-embedding-001 produces 3072-dimensional vectors by default. Pass dimensions (for example 768 or 1536) to request smaller vectors, and make sure your vector column size matches.

Using with Memory Adapters

Embeddings are stored via EmbeddingAdapter (implemented by PostgresAdapter, QdrantAdapter, and InMemoryEmbeddingAdapter).

import { PostgresAdapter, OpenAIEmbeddingService, unwrap } from '@cogitator-ai/memory';

const embeddings = new OpenAIEmbeddingService({
  apiKey: process.env.OPENAI_API_KEY!,
});

const db = new PostgresAdapter({
  provider: 'postgres',
  connectionString: process.env.DATABASE_URL!,
});
db.setVectorDimensions(embeddings.dimensions);
unwrap(await db.connect());

const text = 'Cogitator agents can use tools to interact with external systems.';
const vector = await embeddings.embed(text);

await db.addEmbedding({
  sourceId: 'doc-1',
  sourceType: 'document',
  vector,
  content: text,
});

const queryVector = await embeddings.embed('How do agents use tools?');
const results = unwrap(
  await db.search({
    vector: queryVector,
    limit: 5,
    threshold: 0.7,
  })
);

for (const result of results) {
  console.log(`${result.content} (score: ${result.score.toFixed(3)})`);
}

Dimension Matching

The vector dimensions of your embedding model must match the adapter configuration:

  • PostgresAdapter defaults to 768. Call setVectorDimensions(n) before connect() if using a different model — the column is created with that size, and the call throws once connected. An embeddings table that already exists keeps its size.
  • QdrantAdapter requires dimensions in the constructor. The collection is auto-created with the specified size.
  • InMemoryEmbeddingAdapter handles any dimension since it uses in-process cosine similarity (vectors of different lengths score 0).
  • PostgresGraphAdapter takes vectorDimensions (default 768) for node embeddings.

When memory is configured through Cogitator (memory.adapter: 'postgres'), the table is created with the dimensions of memory.embedding (768 without one). memory.qdrant.dimensions must be set to match the embedding model; the runtime logs a warning when it does not.

The adapter indexes vectors with a pgvector HNSW index, which supports up to 2000 dimensions. With larger vectors (e.g. 3072) the adapter logs a warning and searches without the index.

Provider Comparison

ProviderDimensionsCostPrivacy
OpenAI1536 / 3072 (configurable)Pay per tokenData sent to API
OllamaModel-dependent (384–1024)FreeFully local
Google3072 (configurable)Free tier availableData sent to API

Choose Ollama for local-first deployments with zero data egress, OpenAI for widely used hosted embeddings, and Google for a generous free tier.

On this page