Skip to main content

Advanced Search

Memory search is the core operation in Memsolus. This page covers how to get the most relevant results using search modes, filters, pagination, and the feedback loop.


Search modes

The mode parameter controls how memories are matched to your query. Choose based on the type of information you are looking for.

ModeBest forHow it works
hybridGeneral-purpose retrieval — recommended defaultCombines semantic similarity and keyword matching, re-ranked for best results
semanticConceptual similarity, paraphrases, translated contentMatches by meaning, not exact words
keywordExact names, IDs, specific terms, codesBM25 full-text matching
import { MemsolusClient } from '@memsolus/sdk';

const client = new MemsolusClient({
apiKey: process.env.MEMSOLUS_API_KEY,
workspaceId: process.env.MEMSOLUS_WORKSPACE_ID,
});

// Hybrid — best for most queries
const hybrid = await client.memories.search({
query: 'what does the user prefer for backend development?',
userId: 'user_123',
mode: 'hybrid',
});

// Semantic — when you care about meaning, not exact words
const semantic = await client.memories.search({
query: 'server-side programming technology choices',
userId: 'user_123',
mode: 'semantic',
});

// Keyword — when you need exact term matching
const keyword = await client.memories.search({
query: 'project-alpha api-gateway',
userId: 'user_123',
mode: 'keyword',
});

Filtering results

Narrow results using filters. All filters can be combined.

Filter by user

Scope search to a specific user's memories:

const results = await client.memories.search({
query: 'programming language preferences',
userId: 'user_123',
});

Filter by categories

Return only memories tagged with specific categories:

const results = await client.memories.search({
query: 'tech preferences',
userId: 'user_123',
categories: ['tech-stack', 'preferences'],
});

Filter by priority

Return only memories at a given priority level:

const highPriority = await client.memories.search({
query: 'important constraints',
userId: 'user_123',
priority: 'HIGH',
});

Combining filters

const results = await client.memories.search({
query: 'database decisions',
userId: 'user_123',
categories: ['architecture', 'decisions'],
priority: 'HIGH',
mode: 'hybrid',
limit: 10,
});

Controlling result count

Use limit to control how many memories are returned. The maximum is determined by your plan.

// Get the single most relevant memory
const [topResult] = (await client.memories.search({
query: 'user timezone preference',
userId: 'user_123',
limit: 1,
})).data;

console.log(topResult?.content); // "The user is in São Paulo, UTC-3"
console.log(topResult?.score); // 0.96

Understanding relevance scores

Each memory in a search result has a score field between 0.0 and 1.0:

const results = await client.memories.search({
query: 'preferred database',
userId: 'user_123',
});

for (const memory of results.data) {
if (memory.score > 0.8) {
// High confidence match
} else if (memory.score > 0.5) {
// Moderate match — review before using
} else {
// Low confidence — likely tangential
}
}

Results are returned in descending score order. The first result is always the most relevant.


Paginating list results

For browsing all memories (not search-ranked), use client.memories.list with pagination:

async function getAllMemories(userId: string): Promise<Memory[]> {
const all: Memory[] = [];
let page = 1;
let hasMore = true;

while (hasMore) {
const result = await client.memories.list({
userId,
page,
pageSize: 50,
});

all.push(...result.data);
hasMore = page < result.meta.totalPages;
page++;
}

return all;
}

Feedback loop

After using a memory in a conversation, submit feedback to improve future search quality. Positive feedback boosts a memory's retrieval score; negative feedback reduces it.

const results = await client.memories.search({
query: 'user project stack',
userId: 'user_123',
limit: 3,
});

const [best] = results.data;

// Memory was accurate and helped answer the question
await client.memories.feedback({
id: best.id,
signal: 'POSITIVE',
});

// Another memory was retrieved but was outdated
await client.memories.feedback({
id: results.data[1].id,
signal: 'NEGATIVE',
comment: 'User no longer uses this framework.',
});

Over time, consistent feedback makes search more accurate for each user.


Common patterns

Load context at conversation start

At the beginning of a session, load the structured knowledge profile instead of doing a broad search:

// Preferred: load the full knowledge profile
const profile = await client.knowledge.list({
userId: 'user_123',
merged: true,
});

// Then search for specific context during the conversation
const relevant = await client.memories.search({
query: userMessage,
userId: 'user_123',
mode: 'hybrid',
limit: 5,
});

Search before storing

Before storing a new memory, search for existing ones to avoid duplicates:

const existing = await client.memories.search({
query: newFact,
userId: 'user_123',
limit: 3,
mode: 'semantic',
});

const isDuplicate = existing.data.some((m) => m.score > 0.92);

if (isDuplicate) {
// Update the existing memory instead of creating a new one
await client.memories.update({
id: existing.data[0].id,
content: newFact,
});
} else {
await client.memories.create({
content: newFact,
userId: 'user_123',
});
}

  • Memories — full reference for create, list, feedback, and other methods
  • Knowledge — structured profile built from memories, ideal for conversation start
  • Type ReferenceSearchResult, SearchMode, Memory, and related types