mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:20:43 +00:00
fix(memory): preserve active recall tool agent context
This commit is contained in:
@@ -31,6 +31,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Doctor/plugins: update configured plugin installs whose stale manifests still declare channels without `channelConfigs`, so beta upgrades repair old Discord-style package payloads during `doctor --fix`.
|
||||
- Doctor/plugins: repair configured external plugin installs whose persisted install record points at a missing package directory, so upgrades reconcile phantom npm metadata before plugin runtime validation. Thanks @vincentkoc.
|
||||
- Active Memory: keep non-empty `memory_search` results from being fast-failed as empty when debug telemetry reports zero hits.
|
||||
- Active Memory: preserve the target agent context when building embedded recall plugin tools so `memory_search` and `memory_get` stay available for explicit recall sessions. Fixes #76343. Thanks @Countermarch.
|
||||
- Plugins/externalization: repair missing configured plugin installs from npm by default, reserve ClawHub downloads for explicit `clawhubSpec` metadata, and cover agent-runtime/env-selected plugin repair. Thanks @vincentkoc.
|
||||
- Plugins/install: allow official catalog-matched npm channel plugins such as Feishu to pass the trusted install scanner path while keeping spoofed package names blocked. Thanks @vincentkoc.
|
||||
- Feishu: keep timeout env parsing separate from the HTTP client wrapper so package security scans no longer report a false env-harvesting hit during install. Thanks @vincentkoc.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
jsonResult,
|
||||
resolveMemorySearchConfig,
|
||||
resolveSessionAgentId,
|
||||
resolveSessionAgentIds,
|
||||
type MemoryPluginRuntime,
|
||||
type OpenClawConfig,
|
||||
} from "openclaw/plugin-sdk/memory-core-host-runtime-core";
|
||||
@@ -23,6 +23,7 @@ type RuntimeProviderModule = typeof import("./src/runtime-provider.js");
|
||||
type MemoryToolOptions = {
|
||||
config?: OpenClawConfig;
|
||||
getConfig?: () => OpenClawConfig | undefined;
|
||||
agentId?: string;
|
||||
agentSessionKey?: string;
|
||||
sandboxed?: boolean;
|
||||
};
|
||||
@@ -49,9 +50,10 @@ function hasMemoryToolContext(options: MemoryToolOptions): boolean {
|
||||
if (!cfg) {
|
||||
return false;
|
||||
}
|
||||
const agentId = resolveSessionAgentId({
|
||||
const { sessionAgentId: agentId } = resolveSessionAgentIds({
|
||||
sessionKey: options.agentSessionKey,
|
||||
config: cfg,
|
||||
agentId: options.agentId,
|
||||
});
|
||||
return Boolean(resolveMemorySearchConfig(cfg, agentId));
|
||||
}
|
||||
@@ -145,6 +147,7 @@ function resolveMemoryToolOptions(ctx: OpenClawPluginToolContext): MemoryToolOpt
|
||||
return {
|
||||
config: getConfig(),
|
||||
getConfig,
|
||||
agentId: ctx.agentId,
|
||||
agentSessionKey: ctx.sessionKey,
|
||||
sandboxed: ctx.sandboxed,
|
||||
};
|
||||
|
||||
@@ -52,7 +52,7 @@ const stubManager = {
|
||||
close: vi.fn(),
|
||||
};
|
||||
|
||||
const getMemorySearchManagerMock = vi.fn(async (_params: { cfg?: unknown }) => ({
|
||||
const getMemorySearchManagerMock = vi.fn(async (_params: { cfg?: unknown; agentId?: string }) => ({
|
||||
manager: stubManager,
|
||||
}));
|
||||
const readAgentMemoryFileMock = vi.fn(
|
||||
@@ -118,6 +118,10 @@ export function getMemorySearchManagerMockConfigs(): unknown[] {
|
||||
return getMemorySearchManagerMock.mock.calls.map(([params]) => params.cfg);
|
||||
}
|
||||
|
||||
export function getMemorySearchManagerMockParams(): Array<{ cfg?: unknown; agentId?: string }> {
|
||||
return getMemorySearchManagerMock.mock.calls.map(([params]) => params);
|
||||
}
|
||||
|
||||
export function getReadAgentMemoryFileMockCalls(): number {
|
||||
return readAgentMemoryFileMock.mock.calls.length;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
listMemoryCorpusSupplements,
|
||||
resolveMemorySearchConfig,
|
||||
resolveSessionAgentId,
|
||||
resolveSessionAgentIds,
|
||||
type MemoryCorpusSearchResult,
|
||||
type AnyAgentTool,
|
||||
type OpenClawConfig,
|
||||
@@ -16,6 +16,7 @@ type MemorySearchManagerResult = Awaited<
|
||||
type MemoryToolOptions = {
|
||||
config?: OpenClawConfig;
|
||||
getConfig?: () => OpenClawConfig | undefined;
|
||||
agentId?: string;
|
||||
agentSessionKey?: string;
|
||||
};
|
||||
|
||||
@@ -54,9 +55,10 @@ function resolveMemoryToolContext(options: MemoryToolOptions) {
|
||||
if (!cfg) {
|
||||
return null;
|
||||
}
|
||||
const agentId = resolveSessionAgentId({
|
||||
const { sessionAgentId: agentId } = resolveSessionAgentIds({
|
||||
sessionKey: options.agentSessionKey,
|
||||
config: cfg,
|
||||
agentId: options.agentId,
|
||||
});
|
||||
if (!resolveMemorySearchConfig(cfg, agentId)) {
|
||||
return null;
|
||||
|
||||
@@ -12,10 +12,12 @@ export function createDefaultMemoryToolConfig(): OpenClawConfig {
|
||||
|
||||
export function createMemorySearchToolOrThrow(params?: {
|
||||
config?: OpenClawConfig;
|
||||
agentId?: string;
|
||||
agentSessionKey?: string;
|
||||
}) {
|
||||
const tool = createMemorySearchTool({
|
||||
config: params?.config ?? createDefaultMemoryToolConfig(),
|
||||
...(params?.agentId ? { agentId: params.agentId } : {}),
|
||||
...(params?.agentSessionKey ? { agentSessionKey: params.agentSessionKey } : {}),
|
||||
});
|
||||
if (!tool) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
getMemorySearchManagerMockConfigs,
|
||||
getMemorySearchManagerMockParams,
|
||||
resetMemoryToolMockState,
|
||||
setMemoryBackend,
|
||||
setMemorySearchImpl,
|
||||
@@ -107,6 +108,25 @@ describe("memory_search unavailable payloads", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("uses explicit plugin context agent over synthetic active-memory session keys", async () => {
|
||||
const tool = createMemorySearchToolOrThrow({
|
||||
config: asOpenClawConfig({
|
||||
agents: {
|
||||
list: [
|
||||
{ id: "main", default: true, memorySearch: { enabled: false } },
|
||||
{ id: "recall", memorySearch: { enabled: true } },
|
||||
],
|
||||
},
|
||||
}),
|
||||
agentId: "recall",
|
||||
agentSessionKey: "explicit:user-session:active-memory:abc123",
|
||||
});
|
||||
|
||||
await tool.execute("recall", { query: "favorite food" });
|
||||
|
||||
expect(getMemorySearchManagerMockParams().at(-1)?.agentId).toBe("recall");
|
||||
});
|
||||
|
||||
it("re-resolves config when executing a previously created tool", async () => {
|
||||
const startupConfig = asOpenClawConfig({
|
||||
agents: {
|
||||
|
||||
@@ -183,6 +183,7 @@ async function executeMemoryReadResult<T>(params: {
|
||||
export function createMemorySearchTool(options: {
|
||||
config?: OpenClawConfig;
|
||||
getConfig?: () => OpenClawConfig | undefined;
|
||||
agentId?: string;
|
||||
agentSessionKey?: string;
|
||||
sandboxed?: boolean;
|
||||
}) {
|
||||
@@ -346,6 +347,7 @@ export function createMemorySearchTool(options: {
|
||||
export function createMemoryGetTool(options: {
|
||||
config?: OpenClawConfig;
|
||||
getConfig?: () => OpenClawConfig | undefined;
|
||||
agentId?: string;
|
||||
agentSessionKey?: string;
|
||||
}) {
|
||||
return createMemoryTool({
|
||||
|
||||
@@ -109,6 +109,34 @@ describe("openclaw plugin tool context", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("uses requester agent override for synthetic embedded session keys", () => {
|
||||
const recallWorkspace = path.join(process.cwd(), "tmp-recall-workspace");
|
||||
const config = {
|
||||
agents: {
|
||||
defaults: { workspace: path.join(process.cwd(), "tmp-default-workspace") },
|
||||
list: [
|
||||
{ id: "main", default: true },
|
||||
{ id: "recall", workspace: recallWorkspace },
|
||||
],
|
||||
},
|
||||
} as never;
|
||||
const result = resolveOpenClawPluginToolInputs({
|
||||
options: {
|
||||
config,
|
||||
agentSessionKey: "explicit:user-session:active-memory:abc123",
|
||||
requesterAgentIdOverride: "recall",
|
||||
},
|
||||
resolvedConfig: config,
|
||||
});
|
||||
|
||||
expect(result.context).toEqual(
|
||||
expect.objectContaining({
|
||||
agentId: "recall",
|
||||
workspaceDir: recallWorkspace,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("forwards browser session wiring", () => {
|
||||
const result = resolveOpenClawPluginToolInputs({
|
||||
options: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { normalizeDeliveryContext } from "../utils/delivery-context.js";
|
||||
import type { GatewayMessageChannel } from "../utils/message-channel.js";
|
||||
import { resolveAgentWorkspaceDir, resolveSessionAgentId } from "./agent-scope.js";
|
||||
import { resolveAgentWorkspaceDir, resolveSessionAgentIds } from "./agent-scope.js";
|
||||
import type { ToolFsPolicy } from "./tool-fs-policy.js";
|
||||
import { resolveWorkspaceRoot } from "./workspace-dir.js";
|
||||
|
||||
@@ -16,6 +16,7 @@ export type OpenClawPluginToolOptions = {
|
||||
config?: OpenClawConfig;
|
||||
fsPolicy?: ToolFsPolicy;
|
||||
requesterSenderId?: string | null;
|
||||
requesterAgentIdOverride?: string;
|
||||
senderIsOwner?: boolean;
|
||||
sessionId?: string;
|
||||
sandboxBrowserBridgeUrl?: string;
|
||||
@@ -31,9 +32,10 @@ export function resolveOpenClawPluginToolInputs(params: {
|
||||
getRuntimeConfig?: () => OpenClawConfig | undefined;
|
||||
}) {
|
||||
const { options, resolvedConfig, runtimeConfig, getRuntimeConfig } = params;
|
||||
const sessionAgentId = resolveSessionAgentId({
|
||||
const { sessionAgentId } = resolveSessionAgentIds({
|
||||
sessionKey: options?.agentSessionKey,
|
||||
config: resolvedConfig,
|
||||
agentId: options?.requesterAgentIdOverride,
|
||||
});
|
||||
const inferredWorkspaceDir =
|
||||
options?.workspaceDir || !resolvedConfig
|
||||
|
||||
@@ -8,7 +8,11 @@ export {
|
||||
type AnyAgentTool,
|
||||
} from "../agents/tools/common.js";
|
||||
export { resolveCronStyleNow } from "../agents/current-time.js";
|
||||
export { resolveDefaultAgentId, resolveSessionAgentId } from "../agents/agent-scope.js";
|
||||
export {
|
||||
resolveDefaultAgentId,
|
||||
resolveSessionAgentId,
|
||||
resolveSessionAgentIds,
|
||||
} from "../agents/agent-scope.js";
|
||||
export { resolveMemorySearchConfig } from "../agents/memory-search.js";
|
||||
export { parseNonNegativeByteSize } from "../config/byte-size.js";
|
||||
export { getRuntimeConfig, loadConfig } from "../config/config.js";
|
||||
|
||||
Reference in New Issue
Block a user