Skip to main content
doc0blade47/mem0documentation home
Sign in

OpenClaw Integration

Last updated Oct 11, 2026100% grounded
Relevant source files

The following files were used as context for generating this wiki page:

Overview

The OpenClaw Integration binds Mem0 memory management into the OpenClaw agent runtime, supporting both cloud-hosted Mem0 platform backends and self-hosted open-source deployments. It solves the problem of stateless agent turns by providing automated context injection and fact extraction alongside granular tool execution. Key design decisions include per-agent session namespacing to isolate state, token-budgeted and category-ranked recall engines, and robust CLI authentication helpers that persist credentials safely within local configuration files.

Sources: integrations/openclaw/openclaw.plugin.json:4-5, integrations/openclaw/index.ts:90-105, integrations/openclaw/recall.ts:1-10

Plugin Lifecycle and Hook Registration

The memoryPlugin entry point orchestrates plugin bootstrapping, configuration validation, and backend initialization within the OpenClaw execution environment. Upon registration through definePluginEntry, the register method initializes telemetry flags and reads persistent authentication state from configuration artifacts. It validates settings using mem0ConfigSchema against api.pluginConfig combined with file-based credentials, determining whether the host runs in cli-metadata registration mode or standard execution.

Sources: integrations/openclaw/index.ts:90-184

Warning

If cfg.needsSetup evaluates to true due to a missing API key, full memory capabilities are disabled, logging a warning instructing operators to run openclaw mem0 init. Even in this unauthenticated state, the plugin registers CLI commands and a waiting service so the initialization flow remains accessible. Sources: integrations/openclaw/index.ts:137-167

When fully configured, createProvider instantiates either a PlatformProvider for cloud-hosted backends or an OSSProvider for self-hosted instances. The lifecycle manager begins a new session, and a Backend instance is selected: PlatformBackend is assigned when cfg.mode === "platform", while providerToBackend wraps local providers for open-source mode.

const provider = createProvider(cfg, api);
const lifecycle = createMemoryLifecycle();
lifecycle.beginSession();
 
// Create Backend instance — PlatformBackend for platform mode, providerToBackend adapter for OSS
let backend: Backend;
if (cfg.mode === "platform") {
  backend = new PlatformBackend({
    apiKey: cfg.apiKey!,
    baseUrl: cfg.baseUrl ?? "https://api.mem0.ai",
  });
} else {
  backend = providerToBackend(provider, cfg.userId);
}
 

Sources: integrations/openclaw/index.ts:170-184, integrations/openclaw/providers.ts:530-584

Per-Agent Isolation and Scoping

Session Trigger Filtering and Subagent Detection

Multi-agent memory boundary enforcement relies on deriving structured user identifiers from session keys, ensuring distinct agent workspaces do not pollute shared storage namespaces. The isolation engine processes OpenClaw session keys to detect system automation triggers, identify ephemeral subagent runs, and extract specific agent identifiers.

System-initiated execution loops such as cron jobs, heartbeats, automation pipelines, and schedules are filtered out using isNonInteractiveTrigger to prevent automated prompts from contaminating long-term user memory stores. This function checks explicit trigger names against the SKIP_TRIGGERS set and falls back to inspecting the session key pattern for :cron: or :heartbeat: tokens.

 */
const SKIP_TRIGGERS = new Set(["cron", "heartbeat", "automation", "schedule"]);
 
/**
 * Returns true if the session trigger is non-interactive and memory
 * hooks should be skipped entirely.
 *
 * Also detects cron-style session keys (e.g. "agent:main:cron:<id>")
 * as a fallback when the trigger field is not set.
 */
export function isNonInteractiveTrigger(
  trigger: string | undefined,
  sessionKey: string | undefined,
): boolean {
  if (trigger && SKIP_TRIGGERS.has(trigger.toLowerCase())) return true;
 
  // Fallback: detect cron/heartbeat from the session key pattern
  if (sessionKey) {
    if (/:cron:/i.test(sessionKey) || /:heartbeat:/i.test(sessionKey))
      return true;
  }
 
  return false;
}

Sources: integrations/openclaw/isolation.ts:16-39

Warning

Ephemeral subagent sessions identified by isSubagentSession through the :subagent: pattern evaluate to empty namespaces during memory recall and leave orphaned data after capture because their random UUIDs change with every spawn. Sources: integrations/openclaw/isolation.ts:46-49

User Identification Resolution and Session Parsing

Session keys follow specific formats that determine how the agent extracts isolation boundaries. The extractAgentId function parses subagent UUIDs, named agent identifiers, and primary main sessions.

Session Key PatternExample FormatExtracted Agent ID Result
Main Agent Sessionagent:main:mainundefined (falls back to base user ID)
Subagent Sessionagent:main:subagent:d3b07384subagent-d3b07384
Named Agent Sessionagent:researcher:mainresearcher

Sources: integrations/openclaw/isolation.ts:53-77

The resolution hierarchy implemented in resolveUserId enforces priority rules when determining the active namespace for memory reads and writes. Explicit parameter overrides take precedence over session context, which in turn overrides base configuration settings.

Sources: integrations/openclaw/isolation.ts:98-107

Memory Tool Execution and CRUD

Tool Registration and Execution Lifecycle

The plugin exposes a comprehensive set of capabilities for managing stored memories through the OpenClaw tool registration framework. The registerAllTools function registers eight distinct tool handlers using the plugin API with optional: false settings, ensuring that memory management tools are always available during agent execution loops.

export function registerAllTools(deps: ToolDeps): void {
  const { api } = deps;
  const nonOptional = { optional: false };
 
  api.registerTool(createMemorySearchTool(deps), nonOptional);
  api.registerTool(createMemoryAddTool(deps), nonOptional);
  api.registerTool(createMemoryGetTool(deps), nonOptional);
  api.registerTool(createMemoryListTool(deps), nonOptional);
  api.registerTool(createMemoryUpdateTool(deps), nonOptional);
  api.registerTool(createMemoryDeleteTool(deps), nonOptional);
  api.registerTool(createMemoryEventListTool(deps), nonOptional);
  api.registerTool(createMemoryEventStatusTool(deps), nonOptional);
}

Sources: integrations/openclaw/tools/index.ts:29-41

Tool NameCreating FunctionDescription / Purpose
memory_searchcreateMemorySearchToolRetrieves memories relevant to a query using semantic search with rank ordering.
memory_addcreateMemoryAddToolSaves preferences, facts, decisions, rules, or technical notes to long-term memory.
memory_getcreateMemoryGetToolFetches a single memory by exact ID to inspect its full content and metadata.
memory_listcreateMemoryListToolLists all stored memories for auditing purposes without requiring a query string.
memory_updatecreateMemoryUpdateToolModifies an existing memory's text in-place while preserving its ID and update history.
memory_deletecreateMemoryDeleteToolDeletes memories via explicit ID, query search, or bulk deletion (all: true).
memory_event_listcreateMemoryEventListToolLists recent background processing events from the platform backend.
memory_event_statuscreateMemoryEventStatusToolInspects status and telemetry of specific background memory processing events.

Sources: integrations/openclaw/tools/index.ts:5-12, integrations/openclaw/tools/memory-list.ts:9-11, integrations/openclaw/tools/memory-add.ts:11-14, integrations/openclaw/tools/memory-get.ts:8-10, integrations/openclaw/tools/memory-update.ts:9-11, integrations/openclaw/tools/memory-delete.ts:9-11, integrations/openclaw/tools/memory-event-list.ts:6-9

Search, Retrieval, and Listing Handlers

The memory_search tool accepts queries, result limits, scoping filters (session, long-term, all), categories, and advanced search metadata filters. When scope is set to session, it queries specifically against the current session's run ID; when set to all, it combines long-term results with session-scoped items while deduplicating records by memory ID.

if (scope === "session") {
  if (currentSessionId) {
    results = await provider.search(query, applyFilters(buildSearchOptions(uid, limit, undefined, currentSessionId)));
  }
} else if (scope === "long-term") {
  results = await provider.search(query, applyFilters(buildSearchOptions(uid, limit)));
} else {
  const longTerm = await provider.search(query, applyFilters(buildSearchOptions(uid, limit)));
  let session: MemoryItem[] = [];
  if (currentSessionId) {
    session = await provider.search(query, applyFilters(buildSearchOptions(uid, limit, undefined, currentSessionId)));
  }
  const seen = new Set(longTerm.map((r) => r.id));
  results = [...longTerm, ...session.filter((r) => !seen.has(r.id))];
}

Sources: integrations/openclaw/tools/memory-search.ts:49-63

The memory_get tool calls provider.get(memoryId) directly and formats the output with creation and update timestamps, whereas memory_list returns an itemized audit listing without semantic scoring.

try {
  const memory = await provider.get(memoryId);
  deps.captureToolEvent("memory_get", { success: true, latency_ms: Date.now() - start });
  return {
    content: [{ type: "text", text: `Memory ${memory.id}:\n${memory.memory}\n\nCreated: ${memory.created_at ?? "unknown"}\nUpdated: ${memory.updated_at ?? "unknown"}` }],
    details: { memory },
  };

Sources: integrations/openclaw/tools/memory-get.ts:18-24, integrations/openclaw/tools/memory-list.ts:33-43

Note

memory_list de-duplicates entries when scope is "all" by collecting long-term results first and filtering out any session-scoped items sharing an existing record ID. Sources: integrations/openclaw/tools/memory-list.ts:37-43

Storage, Mutation, and Deletion Safeguards

The memory_add tool supports single-fact strings or arrays of facts via the facts parameter. Before storage, incoming content passes through stripNoiseFromContent and isNoiseMessage validation filters.

const allFacts = rawFacts
  .map((f) => stripNoiseFromContent(f))
  .filter((f) => f.length > 0 && !isNoiseMessage(f));
 
if (allFacts.length === 0) {
  return { content: [{ type: "text", text: "All provided facts were filtered as noise. Nothing stored." }], details: { error: "all_noise" } };
}

Sources: integrations/openclaw/tools/memory-add.ts:38-44

Mutative tools implement strict safety guardrails. Both memory_update and memory_delete check isSubagentSession(getCurrentSessionId()) upon execution and immediately reject requests made within ephemeral subagent sessions.

if (isSubagentSession(getCurrentSessionId())) {
  return { content: [{ type: "text", text: "Memory update is not available in subagent sessions." }], details: { error: "subagent_blocked" } };
}

Sources: integrations/openclaw/tools/memory-update.ts:21-23, integrations/openclaw/tools/memory-delete.ts:29-31

Warning

Bulk memory deletion (memory_delete with all: true) requires both the all: true flag and explicit confirm: true parameters to proceed; otherwise, execution aborts and returns an error details payload. Sources: integrations/openclaw/tools/memory-delete.ts:58-61

Token-Budgeted Category-Ranked Recall Engine

Query Sanitization and Vector Retrieval

The recall engine processes raw prompt inputs by stripping untrusted sender metadata prefixes and bracketed tags via sanitizeQuery before executing search operations. It then queries the memory provider using SearchOptions configured with an over-fetched top_k value of maxMemories * 2 and a custom score threshold.

export function sanitizeQuery(raw: string): string {
  let cleaned = raw.replace(
    /Sender\s*\(untrusted metadata\):\s*```json[\s\S]*?```\s*/gi,
    "",
  );
  cleaned = cleaned.replace(/^\[.*?\]\s*/g, "");
  cleaned = cleaned.trim();
  return cleaned || raw;
}
 
// ============================================================================
// Public API
// ============================================================================
 
/**
 * Perform token-budgeted, category-ranked recall.
 */
export async function recall(
  provider: Mem0Provider,
  query: string,
  userId: string,
  config: SkillsConfig = {},
  sessionId?: string,
): Promise<RecallResult> {
  const recallConfig = config.recall ?? {};
  const tokenBudget = recallConfig.tokenBudget ?? DEFAULT_TOKEN_BUDGET;
  const maxMemories = recallConfig.maxMemories ?? DEFAULT_MAX_MEMORIES;
  const threshold = recallConfig.threshold ?? DEFAULT_THRESHOLD;
  const categoryOrder = recallConfig.categoryOrder ?? DEFAULT_CATEGORY_ORDER;
  const identityAlwaysInclude = recallConfig.identityAlwaysInclude !== false;
 
  // Build search options (v3.0.0: keyword_search, reranking, filter_memories removed)
  const searchOpts: SearchOptions = {
    user_id: userId,
    top_k: maxMemories * 2, // Over-fetch for ranking
    threshold,
    source: "OPENCLAW",
  };
 

Sources: integrations/openclaw/recall.ts:225-263

When a sessionId is present, the engine performs a secondary search against session memories using run_id filtering, and subsequently deduplicates any items already retrieved in the long-term memory set.

// Search session memories if we have a session
let sessionMemories: MemoryItem[] = [];
if (sessionId) {
  try {
    sessionMemories = await provider.search(cleanQuery, {
      ...searchOpts,
      run_id: sessionId,
      top_k: 5,
    });
  } catch {
    // Session search failure is non-critical
  }
}
 
// Deduplicate: session memories that are also in long-term
const longTermIds = new Set(longTermMemories.map((m) => m.id));
const uniqueSession = sessionMemories.filter((m) => !longTermIds.has(m.id));
 

Sources: integrations/openclaw/recall.ts:279-296

Note

sanitizeQuery removes framework noise like sender metadata blocks and timestamps, leaving conversational query rewriting explicitly to the agent layer via its skill protocol. Sources: integrations/openclaw/recall.ts:219-224

Category Ranking and Importance Defaults

Retrieved memories are categorized by inspecting item metadata categories or mem0 extraction categories, falling back to "uncategorized". Memories are sorted using a multi-tiered comparator that prioritizes category configuration order, falls back to importance scores, and resolves ties using search relevance.

function getMemoryCategory(memory: MemoryItem): string {
  // Check metadata first (skill-stored memories have explicit category)
  if (
    memory.metadata?.category &&
    typeof memory.metadata.category === "string"
  ) {
    return memory.metadata.category;
  }
  // Check categories array (mem0-extracted memories)
  if (memory.categories?.length) {
    return memory.categories[0];
  }
  return "uncategorized";
}
 
function getMemoryImportance(memory: MemoryItem): number {
  if (
    memory.metadata?.importance &&
    typeof memory.metadata.importance === "number"
  ) {
    return memory.metadata.importance;
  }
  // Default importance by category
  const cat = getMemoryCategory(memory);
  const defaults: Record<string, number> = {
    identity: 0.95,
    configuration: 0.95,
    rule: 0.9,
    preference: 0.85,
    decision: 0.8,
    technical: 0.8,
    relationship: 0.75,
    project: 0.75,
    operational: 0.6,
  };
  return defaults[cat] ?? 0.5;
}

Sources: integrations/openclaw/recall.ts:57-93

function rankMemories(
  memories: MemoryItem[],
  categoryOrder: string[],
): MemoryItem[] {
  const orderMap = new Map(categoryOrder.map((cat, i) => [cat, i]));
 
  return [...memories].sort((a, b) => {
    const catA = getMemoryCategory(a);
    const catB = getMemoryCategory(b);
    const orderA = orderMap.get(catA) ?? 999;
    const orderB = orderMap.get(catB) ?? 999;
 
    // Primary sort: category priority
    if (orderA !== orderB) return orderA - orderB;
 
    // Secondary sort: importance (higher first)
    const impA = getMemoryImportance(a);
    const impB = getMemoryImportance(b);
    if (impA !== impB) return impB - impA;
 
    // Tertiary sort: search relevance score
    return (b.score ?? 0) - (a.score ?? 0);
  });
}

Sources: integrations/openclaw/recall.ts:107-130

Category NameDefault ImportanceCategory Priority Index
identity0.950 (Highest)
configuration0.951
rule0.92
preference0.853
decision0.84
technical0.85
relationship0.756
project0.757
operational0.68

Sources: integrations/openclaw/recall.ts:25-35, integrations/openclaw/recall.ts:81-91

Token Budgeting and Formatting

The budgeting step iterates through ranked memories to select items under a configured character-derived token estimation (CHARS_PER_TOKEN = 4), respecting the maxMemories limit and token constraints.

// Rough token estimate: ~4 chars per token for English text
const CHARS_PER_TOKEN = 4;

Sources: integrations/openclaw/recall.ts:37-38

function budgetMemories(
  rankedMemories: MemoryItem[],
  tokenBudget: number,
  maxMemories: number,
  identityAlwaysInclude: boolean,
): MemoryItem[] {
  const selected: MemoryItem[] = [];
  let usedTokens = 0;
 
  for (const memory of rankedMemories) {
    if (selected.length >= maxMemories) break;
 
    const memTokens = estimateTokens(memory.memory);
    const isIdentity =
      getMemoryCategory(memory) === "identity" ||
      getMemoryCategory(memory) === "configuration";
 
    // Identity/config always included if flag is set
    if (identityAlwaysInclude && isIdentity) {
      selected.push(memory);
      usedTokens += memTokens;
      continue;
    }
 
    // Budget check for non-identity memories
    if (usedTokens + memTokens > tokenBudget) continue;
 
    selected.push(memory);
    usedTokens += memTokens;
  }
 
  return selected;
}

Sources: integrations/openclaw/recall.ts:136-168

Warning

When identityAlwaysInclude is enabled (default), items categorized under identity or configuration bypass the token budget ceiling and are unconditionally forced into the selected context set. Sources: integrations/openclaw/recall.ts:149-158, integrations/openclaw/recall.ts:254

CLI Subcommands and Authentication Helpers

Command Subsections and Configuration Persistence

The OpenClaw CLI registers subcommands under openclaw mem0 to handle memory operations and plugin management. Management tasks include platform authentication (init), connectivity checks (status), and configuration queries (config show, config get, config set, event list, event status).

* Registers all `openclaw mem0 <subcommand>` commands:
*
* Memory:
*   - add         : Add a memory from text (--user-id, --agent-id)
*   - search      : Search memories (--top-k, --scope, --agent-id, --user-id)
*   - get         : Get a specific memory by ID
*   - list        : List memories with optional filters (--user-id, --agent-id, --top-k)
*   - update      : Update a memory's text
*   - delete      : Delete a memory or all memories (--all, --confirm)
*   - import      : Import memories from a JSON file
*
* Management:
*   - init        : Authenticate with Mem0 Platform (email or API key)
*   - status      : Check API connectivity and show current config
*   - config show : Display current plugin configuration
*   - config get  : Get a single config value
*   - config set  : Update a plugin config field
*   - event list  : List recent background events
*   - event status: Get status of a specific event
*

Sources: integrations/openclaw/cli/commands.ts:4-23

Configuration settings and authentication credentials are saved in ~/.openclaw/openclaw.json under plugins.entries.openclaw-mem0.config. The filesystem operations rely on safe wrappers in fs-safe.ts to isolate file I/O from network calls and comply with security scanners.

* Plugin auth and settings are stored in ~/.openclaw/openclaw.json under
* plugins.entries.openclaw-mem0.config — the single source of truth.
*
* Uses fs-safe.ts for all filesystem operations to pass the OpenClaw
* code_safety scanner.
*/

Sources: integrations/openclaw/cli/config-file.ts:4-9

Config FieldTypeDefault ValuePurpose
apiKeystringundefinedPlatform authentication token
baseUrlstringhttps://api.mem0.aiMem0 API base URL
userIdstringundefinedDefault user identity scope
userEmailstringundefinedAuthenticated user email address
modestringundefinedOperating mode for the plugin
autoRecallbooleanundefinedAutomatically inject memories into prompts
autoCapturebooleanundefinedAutomatically extract and save memories
topKnumberundefinedDefault retrieval count for searches
anonymousTelemetryIdstringundefinedTelemetry tracking identifier
keyFingerprintstringundefinedSHA-256 prefix of the active API key

Sources: integrations/openclaw/cli/config-file.ts:28-40, integrations/openclaw/cli/config-file.ts:19

Warning

readFullConfig throws an error on JSON parse failures. This fail-closed behavior prevents writeFullConfig from overwriting a corrupted config file with an empty state. Sources: integrations/openclaw/cli/config-file.ts:50-51, integrations/openclaw/cli/config-file.ts:70-77

Credential Resolution and Execution Trace

When executing commands, configuration values and authentication states are resolved through a sequence of file checks. The execution walkthrough follows the exact verified call chain registerCliCommands → readPluginAuth → readFullConfig → exists.

  1. registerCliCommands starts command setup in integrations/openclaw/cli/commands.ts. Sources: integrations/openclaw/cli/commands.ts:398
  2. readPluginAuth is called in integrations/openclaw/cli/config-file.ts to load stored credentials. Sources: integrations/openclaw/cli/config-file.ts:126-144
  3. readFullConfig is invoked to read the persistent JSON config store. Sources: integrations/openclaw/cli/config-file.ts:52-78
  4. exists checks whether ~/.openclaw/openclaw.json exists on disk via fs-safe.ts. Sources: integrations/openclaw/fs-safe.ts:15-17

Similarly, when reading configuration text, the call trace flows from registerCliCommands → readPluginAuth → readFullConfig → readText:

  1. registerCliCommands initializes command bindings. Sources: integrations/openclaw/cli/commands.ts:398
  2. readPluginAuth calls readFullConfig. Sources: integrations/openclaw/cli/config-file.ts:126-144
  3. readFullConfig calls readText to load file data. Sources: integrations/openclaw/cli/config-file.ts:52-78
  4. readText reads the file as UTF-8 text via fs-safe.ts. Sources: integrations/openclaw/fs-safe.ts:10-12

Sources: integrations/openclaw/cli/commands.ts:398, integrations/openclaw/cli/config-file.ts:52-144, integrations/openclaw/fs-safe.ts:10-17

Tip

writeFullConfig re-reads disk content immediately before writing to deep-merge OpenClaw-managed fields (installs, slots), preventing concurrent processes from clobbering gateway state. Sources: integrations/openclaw/cli/config-file.ts:87-116

Interactive Open Source Setup Wizard

OSS Provider Configurations and Builders

The OpenClaw setup wizard defines provider definitions, config builders, and flag validation logic in integrations/openclaw/cli/oss-wizard.ts. Three distinct categories of providers are supported: LLM providers, embedder providers, and vector store providers. Each provider definition specifies default models, URLs, API key requirements, and environment variables.

Provider CategorySupported IdentifiersDefault Model / PortKey Requirements
LLMopenai, ollama, anthropicgpt-5-mini, llama3.1:8b, claude-sonnet-4-5-20250514Requires API key for OpenAI and Anthropic; ollama requires a base URL.
Embedderopenai, ollamatext-embedding-3-small, nomic-embed-textRequires API key for OpenAI; ollama defaults to http://localhost:11434.
Vector Storeqdrant, pgvectorPorts 6333 (Qdrant) and 5432 (PostgreSQL)qdrant configures onDisk: true; pgvector requires user, password, and database name.

Sources: integrations/openclaw/cli/oss-wizard.ts:25-52

Config builders process user inputs or command-line flags to assemble configuration objects. buildOssLlmConfig validates the provider ID against LLM_PROVIDERS and returns the provider name alongside a config record containing the selected model and optional API key or Ollama URL. Sources: integrations/openclaw/cli/oss-wizard.ts:78-93

export function buildOssLlmConfig(
  providerId: string,
  input: LlmConfigInput,
): { provider: string; config: Record<string, unknown> } {
  const def = LLM_PROVIDERS.find((p) => p.id === providerId);
  if (!def) throw new Error(`Unknown LLM provider: ${providerId}`);
 
  const config: Record<string, unknown> = {
    model: input.model || def.defaultModel,
  };
  if (input.apiKey) config.apiKey = input.apiKey;
  if (providerId === "ollama") {
    config.url = input.url || def.defaultUrl;
  }
  return { provider: providerId, config };
}

Sources: integrations/openclaw/cli/oss-wizard.ts:78-93

Embedding Dimension Calculation and Vector Connectivity

Embedding dimensions are resolved dynamically using KNOWN_EMBEDDER_DIMS or fall back to the provider default dimensions. The collection name is derived using collectionNameForDims, which formats the dimension count into a standard string. Sources: integrations/openclaw/cli/oss-wizard.ts:54-66

export const KNOWN_EMBEDDER_DIMS: Record<string, number> = {
  "text-embedding-3-small": 1536,
  "text-embedding-3-large": 3072,
  "text-embedding-ada-002": 1536,
  "nomic-embed-text": 768,
  "mxbai-embed-large": 1024,
  "all-minilm": 384,
  "snowflake-arctic-embed": 1024,
};
 
export function collectionNameForDims(dims: number): string {
  return `mem0_${dims}d`;
}

Sources: integrations/openclaw/cli/oss-wizard.ts:54-66

buildOssVectorConfig assigns vector store parameters, setting dimension, embeddingModelDims, and the computed collectionName when dimensions are provided. Sources: integrations/openclaw/cli/oss-wizard.ts:131-155

export function buildOssVectorConfig(
  providerId: string,
  input: VectorConfigInput,
): { provider: string; config: Record<string, unknown> } {
  const config: Record<string, unknown> = {};
 
  if (providerId === "qdrant") {
    config.url = input.url || "http://localhost:6333";
    config.onDisk = true;
    if (input.apiKey) config.apiKey = input.apiKey;
  } else if (providerId === "pgvector") {
    config.host = input.host || "localhost";
    config.port = parseInt(input.port || "5432", 10);
    if (input.user) config.user = input.user;
    if (input.password) config.password = input.password;
    config.dbname = input.dbname || "postgres";
  }
 
  if (input.dims) {
    config.dimension = input.dims;
    config.embeddingModelDims = input.dims;
    config.collectionName = collectionNameForDims(input.dims);
  }
  return { provider: providerId, config };
}

Sources: integrations/openclaw/cli/oss-wizard.ts:131-155

Connectivity verification functions test network reachability with a 3000ms timeout. checkOllamaConnectivity pings /api/tags, checkQdrantConnectivity requests /healthz, and checkPgConnectivity attempts a TCP socket connection using node:net. Sources: integrations/openclaw/cli/oss-wizard.ts:157-186

export async function checkOllamaConnectivity(url: string): Promise<{ ok: boolean; error?: string }> {
  try {
    const resp = await fetch(`${url.replace(/\/+$/, "")}/api/tags`, { signal: AbortSignal.timeout(3000) });
    if (resp.ok) return { ok: true };
    return { ok: false, error: `Ollama returned HTTP ${resp.status}` };
  } catch {
    return { ok: false, error: `Cannot reach Ollama at ${url}. Install: https://ollama.com/download` };
  }
}
 
export async function checkPgConnectivity(host: string, port: number): Promise<{ ok: boolean; error?: string }> {
  return new Promise((resolve) => {
    import("node:net").then(({ createConnection }) => {
      const sock = createConnection({ host, port, timeout: 3000 });
      sock.once("connect", () => { sock.destroy(); resolve({ ok: true }); });
      sock.once("timeout", () => { sock.destroy(); resolve({ ok: false, error: `PostgreSQL not reachable at ${host}:${port}` }); });
      sock.once("error", () => { sock.destroy(); resolve({ ok: false, error: `PostgreSQL not reachable at ${host}:${port}. Ensure PostgreSQL with pgvector extension is running.` }); });
    });
  });
}
 
export async function checkQdrantConnectivity(url: string): Promise<{ ok: boolean; error?: string }> {
  try {
    const resp = await fetch(`${url.replace(/\/+$/, "")}/healthz`, { signal: AbortSignal.timeout(3000) });
    if (resp.ok) return { ok: true };
    return { ok: false, error: `Qdrant returned HTTP ${resp.status}` };
  } catch (err) {
    return { ok: false, error: `Cannot reach Qdrant at ${url}. Start it with: docker run -d -p 6333:6333 qdrant/qdrant` };
  }
}

Sources: integrations/openclaw/cli/oss-wizard.ts:157-186

Warning

validateOssFlags enforces strict parameter dependencies: if an LLM or embedder provider requires an API key (needsApiKey), omitting --oss-llm-key or --oss-embedder-key returns an immediate validation error. Similarly, configuring pgvector without specifying --oss-vector-user causes validation to fail. Sources: integrations/openclaw/cli/oss-wizard.ts:211-238

Was this page helpful?