Skip to content

Commit 8a8cc8d

Browse files
committed
fix(memory): refresh tool config at execution
1 parent fa468d0 commit 8a8cc8d

6 files changed

Lines changed: 74 additions & 13 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Docs: https://docs.openclaw.ai
2020

2121
### Fixes
2222

23+
- Memory-core: re-resolve the active runtime config whenever `memory_search` or `memory_get` executes, so provider changes made by `config.patch` stop leaving stale embedding backends behind in existing tool instances. Fixes #61098. Thanks @BradGroux and @Linux2010.
2324
- Channels/setup: treat bundled channel plugins as already bundled during `channels add` and onboarding, enabling them without writing redundant `plugins.load.paths` entries or path install records. Fixes #72740. Thanks @iCodePoet.
2425
- WhatsApp: honor gateway `HTTPS_PROXY` / `HTTP_PROXY` env vars for QR-login WebSocket connections, while respecting `NO_PROXY`, so proxied networks no longer fall back to direct `mmg.whatsapp.net` connections that time out with 408. Fixes #72547; supersedes #72692. Thanks @mebusw and @SymbolStar.
2526
- Bonjour: default mDNS advertisements to the system hostname when it is DNS-safe, avoiding `openclaw.local` probing conflicts and Gateway restart loops on hosts such as `Lobster` or `ubuntu`. Fixes #72355 and #72689; supersedes #72694. Thanks @mscheuerlein-bot, @gcusms, @moyuwuhen601, @pavan987, @zml-0912, @hhq365, and @SymbolStar.

extensions/memory-core/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getRuntimeConfigSnapshot } from "openclaw/plugin-sdk/config-runtime";
12
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
23
import { registerMemoryCli } from "./src/cli.js";
34
import { registerDreamingCommand } from "./src/dreaming-command.js";
@@ -42,7 +43,8 @@ export default definePluginEntry({
4243
api.registerTool(
4344
(ctx) =>
4445
createMemorySearchTool({
45-
config: ctx.config,
46+
config: ctx.runtimeConfig ?? ctx.config,
47+
getConfig: () => getRuntimeConfigSnapshot() ?? ctx.runtimeConfig ?? ctx.config,
4648
agentSessionKey: ctx.sessionKey,
4749
sandboxed: ctx.sandboxed,
4850
}),
@@ -52,7 +54,8 @@ export default definePluginEntry({
5254
api.registerTool(
5355
(ctx) =>
5456
createMemoryGetTool({
55-
config: ctx.config,
57+
config: ctx.runtimeConfig ?? ctx.config,
58+
getConfig: () => getRuntimeConfigSnapshot() ?? ctx.runtimeConfig ?? ctx.config,
5659
agentSessionKey: ctx.sessionKey,
5760
}),
5861
{ names: ["memory_get"] },

extensions/memory-core/src/memory-tool-manager-mock.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ const stubManager = {
5252
close: vi.fn(),
5353
};
5454

55-
const getMemorySearchManagerMock = vi.fn(async () => ({ manager: stubManager }));
55+
const getMemorySearchManagerMock = vi.fn(async (_params: { cfg?: unknown }) => ({
56+
manager: stubManager,
57+
}));
5658
const readAgentMemoryFileMock = vi.fn(
5759
async (params: MemoryReadParams) => await readFileImpl(params),
5860
);
@@ -116,6 +118,10 @@ export function getMemorySearchManagerMockCalls(): number {
116118
return getMemorySearchManagerMock.mock.calls.length;
117119
}
118120

121+
export function getMemorySearchManagerMockConfigs(): unknown[] {
122+
return getMemorySearchManagerMock.mock.calls.map(([params]) => params.cfg);
123+
}
124+
119125
export function getReadAgentMemoryFileMockCalls(): number {
120126
return readAgentMemoryFileMock.mock.calls.length;
121127
}

extensions/memory-core/src/tools.shared.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ type MemoryToolRuntime = typeof import("./tools.runtime.js");
1313
type MemorySearchManagerResult = Awaited<
1414
ReturnType<(typeof import("./memory/index.js"))["getMemorySearchManager"]>
1515
>;
16+
type MemoryToolOptions = {
17+
config?: OpenClawConfig;
18+
getConfig?: () => OpenClawConfig | undefined;
19+
agentSessionKey?: string;
20+
};
1621

1722
let memoryToolRuntimePromise: Promise<MemoryToolRuntime> | null = null;
1823

@@ -44,11 +49,8 @@ export const MemoryGetSchema = Type.Object({
4449
),
4550
});
4651

47-
export function resolveMemoryToolContext(options: {
48-
config?: OpenClawConfig;
49-
agentSessionKey?: string;
50-
}) {
51-
const cfg = options.config;
52+
export function resolveMemoryToolContext(options: MemoryToolOptions) {
53+
const cfg = options.getConfig?.() ?? options.config;
5254
if (!cfg) {
5355
return null;
5456
}
@@ -98,10 +100,7 @@ export async function getMemoryManagerContextWithPurpose(params: {
98100
}
99101

100102
export function createMemoryTool(params: {
101-
options: {
102-
config?: OpenClawConfig;
103-
agentSessionKey?: string;
104-
};
103+
options: MemoryToolOptions;
105104
label: string;
106105
name: string;
107106
description: string;
@@ -117,7 +116,10 @@ export function createMemoryTool(params: {
117116
name: params.name,
118117
description: params.description,
119118
parameters: params.parameters,
120-
execute: params.execute(ctx),
119+
execute: async (toolCallId, toolParams) => {
120+
const latestCtx = resolveMemoryToolContext(params.options) ?? ctx;
121+
return await params.execute(latestCtx)(toolCallId, toolParams);
122+
},
121123
};
122124
}
123125

extensions/memory-core/src/tools.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { beforeEach, describe, expect, it } from "vitest";
22
import {
3+
getMemorySearchManagerMockConfigs,
34
resetMemoryToolMockState,
45
setMemoryBackend,
56
setMemorySearchImpl,
67
} from "./memory-tool-manager-mock.js";
8+
import { createMemorySearchTool } from "./tools.js";
79
import {
10+
asOpenClawConfig,
811
createMemorySearchToolOrThrow,
912
expectUnavailableMemorySearchDetails,
1013
} from "./tools.test-helpers.js";
@@ -103,4 +106,48 @@ describe("memory_search unavailable payloads", () => {
103106
expect.any(Number),
104107
);
105108
});
109+
110+
it("re-resolves config when executing a previously created tool", async () => {
111+
const startupConfig = asOpenClawConfig({
112+
agents: {
113+
defaults: {
114+
memorySearch: {
115+
provider: "ollama",
116+
model: "nomic-embed-text",
117+
},
118+
},
119+
list: [{ id: "main", default: true }],
120+
},
121+
memory: {
122+
backend: "builtin",
123+
},
124+
});
125+
const patchedConfig = asOpenClawConfig({
126+
agents: {
127+
defaults: {
128+
memorySearch: {
129+
provider: "openai",
130+
model: "text-embedding-3-small",
131+
},
132+
},
133+
list: [{ id: "main", default: true }],
134+
},
135+
memory: {
136+
backend: "builtin",
137+
},
138+
});
139+
let liveConfig = startupConfig;
140+
const tool = createMemorySearchTool({
141+
config: startupConfig,
142+
getConfig: () => liveConfig,
143+
});
144+
if (!tool) {
145+
throw new Error("tool missing");
146+
}
147+
148+
liveConfig = patchedConfig;
149+
await tool.execute("patched-config", { query: "provider switch" });
150+
151+
expect(getMemorySearchManagerMockConfigs()).toEqual([patchedConfig]);
152+
});
106153
});

extensions/memory-core/src/tools.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ async function executeMemoryReadResult<T>(params: {
182182

183183
export function createMemorySearchTool(options: {
184184
config?: OpenClawConfig;
185+
getConfig?: () => OpenClawConfig | undefined;
185186
agentSessionKey?: string;
186187
sandboxed?: boolean;
187188
}) {
@@ -344,6 +345,7 @@ export function createMemorySearchTool(options: {
344345

345346
export function createMemoryGetTool(options: {
346347
config?: OpenClawConfig;
348+
getConfig?: () => OpenClawConfig | undefined;
347349
agentSessionKey?: string;
348350
}) {
349351
return createMemoryTool({

0 commit comments

Comments
 (0)