UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

250 lines (249 loc) 13.8 kB
import { A as resolvePositiveTimerTimeoutMs, n as MAX_TIMER_TIMEOUT_MS } from "./number-coercion-CJQ8TR--.js"; import { y as resolveStateDir } from "./paths-mvMm5bYV.js"; import { _ as uniqueStrings, l as normalizeStringEntries } from "./string-normalization-WNUDCpXX.js"; import { i as clampNumber, p as resolveUserPath, r as clampInt } from "./utils-CCC-BEJH.js"; import { i as normalizeProviderId, n as findNormalizedProviderValue } from "./provider-id-Dq06Bcx6.js"; import "./agent-scope-MrLta7Pq.js"; import { r as resolveAgentConfig } from "./agent-scope-config-CgCYpZfK.js"; import { C as getMemoryEmbeddingProvider } from "./registry-CYsBNH12.js"; import { a as isMemoryMultimodalEnabled, o as normalizeMemoryMultimodalSettings } from "./multimodal-D0Bazgv_.js"; import { t as getEmbeddingProvider } from "./embedding-provider-runtime-gzo2-uRP.js"; import path from "node:path"; import os from "node:os"; //#region src/agents/memory-search.ts /** * Resolves memory-search source, sync, and ranking configuration. */ const DEFAULT_CHUNK_TOKENS = 400; const DEFAULT_CHUNK_OVERLAP = 80; const DEFAULT_WATCH_DEBOUNCE_MS = 1500; const DEFAULT_SESSION_DELTA_BYTES = 1e5; const DEFAULT_SESSION_DELTA_MESSAGES = 50; const DEFAULT_MAX_RESULTS = 6; const DEFAULT_MIN_SCORE = .35; const DEFAULT_HYBRID_ENABLED = true; const DEFAULT_HYBRID_VECTOR_WEIGHT = .7; const DEFAULT_HYBRID_TEXT_WEIGHT = .3; const DEFAULT_HYBRID_CANDIDATE_MULTIPLIER = 4; const DEFAULT_MMR_ENABLED = false; const DEFAULT_MMR_LAMBDA = .7; const DEFAULT_TEMPORAL_DECAY_ENABLED = false; const DEFAULT_TEMPORAL_DECAY_HALF_LIFE_DAYS = 30; const DEFAULT_CACHE_ENABLED = true; const DEFAULT_SOURCES = ["memory"]; const DEFAULT_MEMORY_EMBEDDING_PROVIDER = "openai"; const DEFAULT_REMOTE_BATCH_POLL_INTERVAL_MS = 2e3; const DEFAULT_REMOTE_BATCH_TIMEOUT_MINUTES = 60; const MAX_REMOTE_BATCH_TIMEOUT_MINUTES = Math.floor(MAX_TIMER_TIMEOUT_MS / 6e4); function resolveRemoteBatchPollIntervalMs(overrideValue, defaultValue) { return resolvePositiveTimerTimeoutMs(overrideValue ?? defaultValue, DEFAULT_REMOTE_BATCH_POLL_INTERVAL_MS); } function resolveRemoteBatchTimeoutMinutes(overrideValue, defaultValue) { const value = overrideValue ?? defaultValue; return typeof value === "number" && Number.isFinite(value) && value > 0 ? clampInt(value, 1, MAX_REMOTE_BATCH_TIMEOUT_MINUTES) : DEFAULT_REMOTE_BATCH_TIMEOUT_MINUTES; } function normalizeSources(sources, sessionMemoryEnabled) { const normalized = /* @__PURE__ */ new Set(); const input = sources?.length ? sources : DEFAULT_SOURCES; for (const source of input) { if (source === "memory") normalized.add("memory"); if (source === "sessions" && sessionMemoryEnabled) normalized.add("sessions"); } if (normalized.size === 0) normalized.add("memory"); return Array.from(normalized); } function resolveStorePath(agentId, raw) { const stateDir = resolveStateDir(process.env, os.homedir); const fallback = path.join(stateDir, "memory", `${agentId}.sqlite`); if (!raw) return fallback; return resolveUserPath(raw.includes("{agentId}") ? raw.replaceAll("{agentId}", agentId) : raw); } function getConfiguredMemoryEmbeddingProvider(providerId, cfg) { const directAdapter = getMemoryEmbeddingProvider(providerId); if (directAdapter) return directAdapter; const ownerApi = findNormalizedProviderValue(cfg.models?.providers, providerId)?.api?.trim(); if (!ownerApi) return; const normalizedProvider = normalizeProviderId(providerId); const normalizedOwner = normalizeProviderId(ownerApi); if (!normalizedOwner || normalizedOwner === normalizedProvider) return; return getMemoryEmbeddingProvider(normalizedOwner); } function mergeConfig(cfg, defaults, overrides, agentId) { const enabled = overrides?.enabled ?? defaults?.enabled ?? true; const sessionMemory = overrides?.experimental?.sessionMemory ?? defaults?.experimental?.sessionMemory ?? false; const rawProvider = overrides?.provider ?? defaults?.provider; const provider = rawProvider?.trim() === "auto" ? DEFAULT_MEMORY_EMBEDDING_PROVIDER : rawProvider?.trim() || DEFAULT_MEMORY_EMBEDDING_PROVIDER; const primaryAdapter = getConfiguredMemoryEmbeddingProvider(provider, cfg); const defaultRemote = defaults?.remote; const overrideRemote = overrides?.remote; const fallback = overrides?.fallback ?? defaults?.fallback ?? "none"; const fallbackAdapter = fallback && fallback !== "none" ? getConfiguredMemoryEmbeddingProvider(fallback, cfg) : void 0; const includeRemote = Boolean(overrideRemote?.baseUrl || overrideRemote?.apiKey || overrideRemote?.headers || overrideRemote?.nonBatchConcurrency != null || defaultRemote?.baseUrl || defaultRemote?.apiKey || defaultRemote?.headers || defaultRemote?.nonBatchConcurrency != null) || primaryAdapter?.transport !== "local" || fallbackAdapter?.transport === "remote"; const batch = { enabled: overrideRemote?.batch?.enabled ?? defaultRemote?.batch?.enabled ?? false, wait: overrideRemote?.batch?.wait ?? defaultRemote?.batch?.wait ?? true, concurrency: Math.max(1, overrideRemote?.batch?.concurrency ?? defaultRemote?.batch?.concurrency ?? 2), pollIntervalMs: resolveRemoteBatchPollIntervalMs(overrideRemote?.batch?.pollIntervalMs, defaultRemote?.batch?.pollIntervalMs), timeoutMinutes: resolveRemoteBatchTimeoutMinutes(overrideRemote?.batch?.timeoutMinutes, defaultRemote?.batch?.timeoutMinutes) }; const remote = includeRemote ? { baseUrl: overrideRemote?.baseUrl ?? defaultRemote?.baseUrl, apiKey: overrideRemote?.apiKey ?? defaultRemote?.apiKey, headers: overrideRemote?.headers ?? defaultRemote?.headers, nonBatchConcurrency: overrideRemote?.nonBatchConcurrency ?? defaultRemote?.nonBatchConcurrency, batch } : void 0; const modelDefault = primaryAdapter?.defaultModel; const model = overrides?.model ?? defaults?.model ?? modelDefault ?? ""; const inputType = overrides?.inputType?.trim() || defaults?.inputType?.trim() || void 0; const queryInputType = overrides?.queryInputType?.trim() || defaults?.queryInputType?.trim() || void 0; const documentInputType = overrides?.documentInputType?.trim() || defaults?.documentInputType?.trim() || void 0; const outputDimensionality = overrides?.outputDimensionality ?? defaults?.outputDimensionality; const local = { modelPath: overrides?.local?.modelPath ?? defaults?.local?.modelPath, modelCacheDir: overrides?.local?.modelCacheDir ?? defaults?.local?.modelCacheDir, contextSize: overrides?.local?.contextSize ?? defaults?.local?.contextSize }; const sources = normalizeSources(overrides?.sources ?? defaults?.sources, sessionMemory); const extraPaths = uniqueStrings(normalizeStringEntries([...defaults?.extraPaths ?? [], ...overrides?.extraPaths ?? []])); const multimodal = normalizeMemoryMultimodalSettings({ enabled: overrides?.multimodal?.enabled ?? defaults?.multimodal?.enabled, modalities: overrides?.multimodal?.modalities ?? defaults?.multimodal?.modalities, maxFileBytes: overrides?.multimodal?.maxFileBytes ?? defaults?.multimodal?.maxFileBytes }); const vector = { enabled: overrides?.store?.vector?.enabled ?? defaults?.store?.vector?.enabled ?? true, extensionPath: overrides?.store?.vector?.extensionPath ?? defaults?.store?.vector?.extensionPath }; const fts = { tokenizer: overrides?.store?.fts?.tokenizer ?? defaults?.store?.fts?.tokenizer ?? "unicode61" }; const store = { driver: overrides?.store?.driver ?? defaults?.store?.driver ?? "sqlite", path: resolveStorePath(agentId, overrides?.store?.path ?? defaults?.store?.path), fts, vector }; const chunking = { tokens: overrides?.chunking?.tokens ?? defaults?.chunking?.tokens ?? DEFAULT_CHUNK_TOKENS, overlap: overrides?.chunking?.overlap ?? defaults?.chunking?.overlap ?? DEFAULT_CHUNK_OVERLAP }; const sync = resolveSyncConfig(defaults, overrides); const query = { maxResults: overrides?.query?.maxResults ?? defaults?.query?.maxResults ?? DEFAULT_MAX_RESULTS, minScore: overrides?.query?.minScore ?? defaults?.query?.minScore ?? DEFAULT_MIN_SCORE }; const hybrid = { enabled: overrides?.query?.hybrid?.enabled ?? defaults?.query?.hybrid?.enabled ?? DEFAULT_HYBRID_ENABLED, vectorWeight: overrides?.query?.hybrid?.vectorWeight ?? defaults?.query?.hybrid?.vectorWeight ?? DEFAULT_HYBRID_VECTOR_WEIGHT, textWeight: overrides?.query?.hybrid?.textWeight ?? defaults?.query?.hybrid?.textWeight ?? DEFAULT_HYBRID_TEXT_WEIGHT, candidateMultiplier: overrides?.query?.hybrid?.candidateMultiplier ?? defaults?.query?.hybrid?.candidateMultiplier ?? DEFAULT_HYBRID_CANDIDATE_MULTIPLIER, mmr: { enabled: overrides?.query?.hybrid?.mmr?.enabled ?? defaults?.query?.hybrid?.mmr?.enabled ?? DEFAULT_MMR_ENABLED, lambda: overrides?.query?.hybrid?.mmr?.lambda ?? defaults?.query?.hybrid?.mmr?.lambda ?? DEFAULT_MMR_LAMBDA }, temporalDecay: { enabled: overrides?.query?.hybrid?.temporalDecay?.enabled ?? defaults?.query?.hybrid?.temporalDecay?.enabled ?? DEFAULT_TEMPORAL_DECAY_ENABLED, halfLifeDays: overrides?.query?.hybrid?.temporalDecay?.halfLifeDays ?? defaults?.query?.hybrid?.temporalDecay?.halfLifeDays ?? DEFAULT_TEMPORAL_DECAY_HALF_LIFE_DAYS } }; const cache = { enabled: overrides?.cache?.enabled ?? defaults?.cache?.enabled ?? DEFAULT_CACHE_ENABLED, maxEntries: overrides?.cache?.maxEntries ?? defaults?.cache?.maxEntries }; const overlap = clampNumber(chunking.overlap, 0, Math.max(0, chunking.tokens - 1)); const minScore = clampNumber(query.minScore, 0, 1); const vectorWeight = clampNumber(hybrid.vectorWeight, 0, 1); const textWeight = clampNumber(hybrid.textWeight, 0, 1); const sum = vectorWeight + textWeight; const normalizedVectorWeight = sum > 0 ? vectorWeight / sum : DEFAULT_HYBRID_VECTOR_WEIGHT; const normalizedTextWeight = sum > 0 ? textWeight / sum : DEFAULT_HYBRID_TEXT_WEIGHT; const candidateMultiplier = clampInt(hybrid.candidateMultiplier, 1, 20); const temporalDecayHalfLifeDays = Math.max(1, Math.floor(Number.isFinite(hybrid.temporalDecay.halfLifeDays) ? hybrid.temporalDecay.halfLifeDays : DEFAULT_TEMPORAL_DECAY_HALF_LIFE_DAYS)); const deltaBytes = clampInt(sync.sessions.deltaBytes, 0, Number.MAX_SAFE_INTEGER); const deltaMessages = clampInt(sync.sessions.deltaMessages, 0, Number.MAX_SAFE_INTEGER); const postCompactionForce = sync.sessions.postCompactionForce; return { enabled, sources, extraPaths, multimodal, provider, remote, experimental: { sessionMemory }, fallback, model, inputType, queryInputType, documentInputType, outputDimensionality, local, store, chunking: { tokens: Math.max(1, chunking.tokens), overlap }, sync: { ...sync, sessions: { deltaBytes, deltaMessages, postCompactionForce } }, query: { ...query, minScore, hybrid: { enabled: hybrid.enabled, vectorWeight: normalizedVectorWeight, textWeight: normalizedTextWeight, candidateMultiplier, mmr: { enabled: hybrid.mmr.enabled, lambda: Number.isFinite(hybrid.mmr.lambda) ? Math.max(0, Math.min(1, hybrid.mmr.lambda)) : DEFAULT_MMR_LAMBDA }, temporalDecay: { enabled: hybrid.temporalDecay.enabled, halfLifeDays: temporalDecayHalfLifeDays } } }, cache: { enabled: cache.enabled, maxEntries: typeof cache.maxEntries === "number" && Number.isFinite(cache.maxEntries) ? Math.max(1, Math.floor(cache.maxEntries)) : void 0 } }; } function resolveSyncConfig(defaults, overrides) { return { onSessionStart: overrides?.sync?.onSessionStart ?? defaults?.sync?.onSessionStart ?? true, onSearch: overrides?.sync?.onSearch ?? defaults?.sync?.onSearch ?? true, watch: overrides?.sync?.watch ?? defaults?.sync?.watch ?? true, watchDebounceMs: overrides?.sync?.watchDebounceMs ?? defaults?.sync?.watchDebounceMs ?? DEFAULT_WATCH_DEBOUNCE_MS, intervalMinutes: overrides?.sync?.intervalMinutes ?? defaults?.sync?.intervalMinutes ?? 0, embeddingBatchTimeoutSeconds: overrides?.sync?.embeddingBatchTimeoutSeconds ?? defaults?.sync?.embeddingBatchTimeoutSeconds, sessions: { deltaBytes: overrides?.sync?.sessions?.deltaBytes ?? defaults?.sync?.sessions?.deltaBytes ?? DEFAULT_SESSION_DELTA_BYTES, deltaMessages: overrides?.sync?.sessions?.deltaMessages ?? defaults?.sync?.sessions?.deltaMessages ?? DEFAULT_SESSION_DELTA_MESSAGES, postCompactionForce: overrides?.sync?.sessions?.postCompactionForce ?? defaults?.sync?.sessions?.postCompactionForce ?? true } }; } function resolveMemorySearchConfig(cfg, agentId) { const defaults = cfg.agents?.defaults?.memorySearch; const overrides = resolveAgentConfig(cfg, agentId)?.memorySearch; const resolved = mergeConfig(cfg, defaults, overrides, agentId); if (!resolved.enabled) return null; const multimodalActive = isMemoryMultimodalEnabled(resolved.multimodal); const multimodalProvider = getConfiguredMemoryEmbeddingProvider(resolved.provider, cfg); if (multimodalActive && (multimodalProvider && !(multimodalProvider.supportsMultimodalEmbeddings?.({ model: resolved.model }) ?? false) || !multimodalProvider && getEmbeddingProvider(resolved.provider, cfg))) throw new Error("agents.*.memorySearch.multimodal requires a provider adapter that supports multimodal embeddings for the configured model."); if (multimodalActive && resolved.fallback !== "none") throw new Error("agents.*.memorySearch.multimodal does not support memorySearch.fallback. Set fallback to \"none\"."); return resolved; } function resolveMemorySearchSyncConfig(cfg, agentId) { const defaults = cfg.agents?.defaults?.memorySearch; const overrides = resolveAgentConfig(cfg, agentId)?.memorySearch; if (!(overrides?.enabled ?? defaults?.enabled ?? true)) return null; return resolveSyncConfig(defaults, overrides); } //#endregion export { resolveMemorySearchSyncConfig as n, resolveMemorySearchConfig as t };