


























@@ -38,15 +38,25 @@ type PendingQmdManagerCreate = {
3838promise: Promise<Maybe<MemorySearchManager>>;
3939};
404041+type QmdManagerOpenFailure = {
42+identityKey: string;
43+reason: string;
44+retryAfterMs: number;
45+};
46+4147type MemorySearchManagerCacheStore = {
4248qmdManagerCache: Map<string, CachedQmdManagerEntry>;
4349pendingQmdManagerCreates: Map<string, PendingQmdManagerCreate>;
50+qmdManagerOpenFailures: Map<string, QmdManagerOpenFailure>;
4451};
455253+const QMD_MANAGER_OPEN_FAILURE_COOLDOWN_MS = 60_000;
54+4655function createMemorySearchManagerCacheStore(): MemorySearchManagerCacheStore {
4756return {
4857qmdManagerCache: new Map<string, CachedQmdManagerEntry>(),
4958pendingQmdManagerCreates: new Map<string, PendingQmdManagerCreate>(),
59+qmdManagerOpenFailures: new Map<string, QmdManagerOpenFailure>(),
5060};
5161}
5262@@ -62,7 +72,11 @@ function getMemorySearchManagerCacheStore(): MemorySearchManagerCacheStore {
6272(resolved as Partial<MemorySearchManagerCacheStore>).qmdManagerCache instanceof Map &&
6373(resolved as Partial<MemorySearchManagerCacheStore>).pendingQmdManagerCreates instanceof Map
6474) {
65-return resolved as MemorySearchManagerCacheStore;
75+const cacheStore = resolved as Partial<MemorySearchManagerCacheStore>;
76+if (!(cacheStore.qmdManagerOpenFailures instanceof Map)) {
77+cacheStore.qmdManagerOpenFailures = new Map<string, QmdManagerOpenFailure>();
78+}
79+return cacheStore as MemorySearchManagerCacheStore;
6680}
6781const repaired = createMemorySearchManagerCacheStore();
6882(globalThis as Record<PropertyKey, unknown>)[MEMORY_SEARCH_MANAGER_CACHE_KEY] = repaired;
@@ -73,6 +87,7 @@ const log = createSubsystemLogger("memory");
7387const {
7488qmdManagerCache: QMD_MANAGER_CACHE,
7589pendingQmdManagerCreates: PENDING_QMD_MANAGER_CREATES,
90+qmdManagerOpenFailures: QMD_MANAGER_OPEN_FAILURES,
7691} = getMemorySearchManagerCacheStore();
7792let managerRuntimePromise: Promise<typeof import("../../manager-runtime.js")> | null = null;
7893let qmdManagerModulePromise: Promise<typeof import("./qmd-manager.js")> | null = null;
@@ -94,6 +109,42 @@ export type MemorySearchManagerResult = {
9410995110export type MemorySearchManagerPurpose = "default" | "status" | "cli";
96111112+function getActiveQmdManagerOpenFailure(
113+scopeKey: string,
114+identityKey: string,
115+nowMs = Date.now(),
116+): QmdManagerOpenFailure | null {
117+const failure = QMD_MANAGER_OPEN_FAILURES.get(scopeKey);
118+if (!failure) {
119+return null;
120+}
121+if (failure.identityKey !== identityKey || failure.retryAfterMs <= nowMs) {
122+QMD_MANAGER_OPEN_FAILURES.delete(scopeKey);
123+return null;
124+}
125+return failure;
126+}
127+128+function recordQmdManagerOpenFailure(
129+scopeKey: string,
130+identityKey: string,
131+reason: string,
132+nowMs = Date.now(),
133+): void {
134+QMD_MANAGER_OPEN_FAILURES.set(scopeKey, {
135+ identityKey,
136+ reason,
137+retryAfterMs: nowMs + QMD_MANAGER_OPEN_FAILURE_COOLDOWN_MS,
138+});
139+}
140+141+function clearQmdManagerOpenFailure(scopeKey: string, identityKey: string): void {
142+const failure = QMD_MANAGER_OPEN_FAILURES.get(scopeKey);
143+if (failure?.identityKey === identityKey) {
144+QMD_MANAGER_OPEN_FAILURES.delete(scopeKey);
145+}
146+}
147+97148export async function getMemorySearchManager(params: {
98149cfg: OpenClawConfig;
99150agentId: string;
@@ -111,14 +162,18 @@ export async function getMemorySearchManager(params: {
111162112163const createPrimaryQmdManager = async (
113164mode: "full" | "status" | "cli",
114-): Promise<Maybe<MemorySearchManager>> => {
165+): Promise<{ manager: Maybe<MemorySearchManager>; failureReason?: string }> => {
115166try {
116167await fs.mkdir(workspaceDir, { recursive: true });
117168} catch (err) {
169+const message = formatErrorMessage(err);
118170log.warn(
119-`qmd workspace unavailable (${workspaceDir}); falling back to builtin: ${formatErrorMessage(err)}`,
171+`qmd workspace unavailable (${workspaceDir}); falling back to builtin: ${message}`,
120172);
121-return null;
173+return {
174+manager: null,
175+failureReason: `qmd workspace unavailable (${workspaceDir}): ${message}`,
176+};
122177}
123178124179const qmdBinary = await checkQmdBinaryAvailability({
@@ -127,10 +182,14 @@ export async function getMemorySearchManager(params: {
127182cwd: workspaceDir,
128183});
129184if (!qmdBinary.available) {
185+const message = qmdBinary.error ?? "unknown error";
130186log.warn(
131-`qmd binary unavailable (${qmdResolved.command}); falling back to builtin: ${qmdBinary.error ?? "unknown error"}`,
187+`qmd binary unavailable (${qmdResolved.command}); falling back to builtin: ${message}`,
132188);
133-return null;
189+return {
190+manager: null,
191+failureReason: `qmd binary unavailable (${qmdResolved.command}): ${message}`,
192+};
134193}
135194try {
136195const { QmdMemoryManager } = await loadQmdManagerModule();
@@ -142,21 +201,23 @@ export async function getMemorySearchManager(params: {
142201 runtimeConfig,
143202});
144203if (primary) {
145-return primary;
204+clearQmdManagerOpenFailure(scopeKey, identityKey);
205+return { manager: primary };
146206}
147207} catch (err) {
148208const message = formatErrorMessage(err);
149209log.warn(`qmd memory unavailable; falling back to builtin: ${message}`);
210+return { manager: null, failureReason: `qmd memory unavailable: ${message}` };
150211}
151-return null;
212+return { manager: null, failureReason: "qmd memory unavailable: no manager returned" };
152213};
153214154215const createFullQmdManager = async (
155216expectedIdentityKey: string,
156-): Promise<Maybe<CachedQmdManagerEntry>> => {
157-const primary = await createPrimaryQmdManager("full");
217+): Promise<{ entry: Maybe<CachedQmdManagerEntry>; failureReason?: string }> => {
218+const { manager: primary, failureReason } = await createPrimaryQmdManager("full");
158219if (!primary) {
159-return null;
220+return { entry: null, failureReason };
160221}
161222let cacheEntry!: CachedQmdManagerEntry;
162223const wrapper = new FallbackMemoryManager(
@@ -178,7 +239,7 @@ export async function getMemorySearchManager(params: {
178239identityKey: expectedIdentityKey,
179240manager: wrapper,
180241};
181-return cacheEntry;
242+return { entry: cacheEntry };
182243};
183244184245while (true) {
@@ -197,10 +258,20 @@ export async function getMemorySearchManager(params: {
197258}
198259199260if (transient) {
200-const manager = await createPrimaryQmdManager(params.purpose === "cli" ? "cli" : "status");
261+const { manager } = await createPrimaryQmdManager(
262+params.purpose === "cli" ? "cli" : "status",
263+);
201264return manager ? { manager } : await getBuiltinMemorySearchManager(params);
202265}
203266267+const recentFailure = getActiveQmdManagerOpenFailure(scopeKey, identityKey);
268+if (recentFailure) {
269+log.debug?.(
270+`qmd memory unavailable; using builtin during cooldown: ${recentFailure.reason}`,
271+);
272+return await getBuiltinMemorySearchManager(params);
273+}
274+204275const pending = PENDING_QMD_MANAGER_CREATES.get(scopeKey);
205276if (pending) {
206277await pending.promise;
@@ -211,16 +282,21 @@ export async function getMemorySearchManager(params: {
211282 identityKey,
212283promise: (async () => {
213284const created = await createFullQmdManager(identityKey);
214-if (!created) {
285+if (!created.entry) {
286+recordQmdManagerOpenFailure(
287+scopeKey,
288+identityKey,
289+created.failureReason ?? "qmd memory unavailable",
290+);
215291return null;
216292}
217-QMD_MANAGER_CACHE.set(scopeKey, created);
293+QMD_MANAGER_CACHE.set(scopeKey, created.entry);
218294if (cached) {
219295await closeQmdManagerForReplacement(cached.manager).catch((err) => {
220296log.warn(`failed to retire replaced qmd memory manager: ${formatErrorMessage(err)}`);
221297});
222298}
223-return created.manager;
299+return created.entry.manager;
224300})().finally(() => {
225301const currentPending = PENDING_QMD_MANAGER_CREATES.get(scopeKey);
226302if (currentPending === pendingCreate) {
@@ -307,6 +383,7 @@ export async function closeAllMemorySearchManagers(): Promise<void> {
307383const managers = Array.from(QMD_MANAGER_CACHE.values(), (entry) => entry.manager);
308384PENDING_QMD_MANAGER_CREATES.clear();
309385QMD_MANAGER_CACHE.clear();
386+QMD_MANAGER_OPEN_FAILURES.clear();
310387for (const manager of managers) {
311388try {
312389await manager.close?.();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。