
























@@ -62,12 +62,23 @@ const VECTOR_TABLE = "chunks_vec";
6262const FTS_TABLE = "chunks_fts";
6363const EMBEDDING_CACHE_TABLE = "embedding_cache";
6464const MEMORY_INDEX_MANAGER_CACHE_KEY = Symbol.for("openclaw.memoryIndexManagerCache");
65+export const EMBEDDING_PROBE_CACHE_TTL_MS = 30_000;
6566const log = createSubsystemLogger("memory");
6667type MemoryIndexManagerPurpose = "default" | "status" | "cli";
67686869const { cache: INDEX_CACHE, pending: INDEX_CACHE_PENDING } =
6970resolveSingletonManagedCache<MemoryIndexManager>(MEMORY_INDEX_MANAGER_CACHE_KEY);
71+72+type EmbeddingProbeCacheEntry = {
73+result: MemoryEmbeddingProbeResult;
74+checkedAtMs: number;
75+expireAtMs: number;
76+};
77+78+const EMBEDDING_PROBE_CACHE = new Map<string, EmbeddingProbeCacheEntry>();
79+7080export async function closeAllMemoryIndexManagers(): Promise<void> {
81+EMBEDDING_PROBE_CACHE.clear();
7182await closeManagedCacheEntries({
7283cache: INDEX_CACHE,
7384pending: INDEX_CACHE_PENDING,
@@ -818,21 +829,54 @@ export class MemoryIndexManager extends MemoryManagerEmbeddingOps implements Mem
818829return this.ensureVectorReady();
819830}
820831832+private cacheProbeResult(result: MemoryEmbeddingProbeResult): MemoryEmbeddingProbeResult {
833+const checkedAtMs = Date.now();
834+EMBEDDING_PROBE_CACHE.set(this.cacheKey, {
835+ result,
836+ checkedAtMs,
837+expireAtMs: checkedAtMs + EMBEDDING_PROBE_CACHE_TTL_MS,
838+});
839+return result;
840+}
841+842+getCachedEmbeddingAvailability(): MemoryEmbeddingProbeResult | null {
843+const cached = EMBEDDING_PROBE_CACHE.get(this.cacheKey);
844+if (!cached) {
845+return null;
846+}
847+const nowMs = Date.now();
848+if (nowMs >= cached.expireAtMs) {
849+EMBEDDING_PROBE_CACHE.delete(this.cacheKey);
850+return null;
851+}
852+return {
853+ ...cached.result,
854+checked: true,
855+cached: true,
856+checkedAtMs: cached.checkedAtMs,
857+cacheExpiresAtMs: cached.expireAtMs,
858+};
859+}
860+821861async probeEmbeddingAvailability(): Promise<MemoryEmbeddingProbeResult> {
862+const cached = this.getCachedEmbeddingAvailability();
863+if (cached) {
864+return cached;
865+}
822866await this.ensureProviderInitialized();
823867// FTS-only mode: embeddings not available but search still works
824868if (!this.provider) {
825-return {
869+return this.cacheProbeResult({
826870ok: false,
827871error: this.providerUnavailableReason ?? "No embedding provider available (FTS-only mode)",
828-};
872+});
829873}
830874try {
831875await this.embedBatchWithRetry(["ping"]);
832-return { ok: true };
876+return this.cacheProbeResult({ ok: true });
833877} catch (err) {
834878const message = formatErrorMessage(err);
835-return { ok: false, error: message };
879+return this.cacheProbeResult({ ok: false, error: message });
836880}
837881}
838882此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。