























@@ -4,14 +4,20 @@ import { afterEach, describe, expect, it, vi } from "vitest";
44import { filterMemorySearchHitsBySessionVisibility } from "./session-search-visibility.js";
55import { asOpenClawConfig } from "./tools.test-helpers.js";
667-const crossAgentStore = {
7+type TestSessionEntry = {
8+sessionId: string;
9+updatedAt: number;
10+sessionFile: string;
11+};
12+13+const crossAgentStore: Record<string, TestSessionEntry> = {
814"agent:peer:only": {
915sessionId: "w1",
1016updatedAt: 1,
1117sessionFile: "/tmp/sessions/w1.jsonl",
1218},
1319};
14-let combinedSessionStore: typeof crossAgentStore | Record<string, never> = crossAgentStore;
20+let combinedSessionStore: Record<string, TestSessionEntry> = crossAgentStore;
15211622vi.mock("openclaw/plugin-sdk/session-transcript-hit", async (importOriginal) => {
1723const actual =
@@ -100,10 +106,19 @@ describe("filterMemorySearchHitsBySessionVisibility", () => {
100106 hits,
101107});
102108expect(sessionTranscriptHit.loadCombinedSessionStoreForGateway).toHaveBeenCalledTimes(1);
103-expect(sessionTranscriptHit.loadCombinedSessionStoreForGateway).toHaveBeenCalledWith(cfg);
109+expect(sessionTranscriptHit.loadCombinedSessionStoreForGateway).toHaveBeenCalledWith(cfg, {
110+agentId: "main",
111+});
104112});
105113106-it("allows cross-agent session hits when visibility=all and agent-to-agent is enabled", async () => {
114+it("keeps same-agent session hits when visibility=all and agent-to-agent is enabled", async () => {
115+combinedSessionStore = {
116+"agent:main:only": {
117+sessionId: "w1",
118+updatedAt: 1,
119+sessionFile: "/tmp/sessions/w1.jsonl",
120+},
121+};
107122const hit: MemorySearchResult = {
108123path: "sessions/w1.jsonl",
109124source: "sessions",
@@ -127,6 +142,120 @@ describe("filterMemorySearchHitsBySessionVisibility", () => {
127142expect(filtered).toEqual([hit]);
128143});
129144145+it("keeps global-scope session hits for non-default agents", async () => {
146+combinedSessionStore = {
147+global: {
148+sessionId: "w1",
149+updatedAt: 1,
150+sessionFile: "/tmp/sessions/w1.jsonl",
151+},
152+};
153+const hit: MemorySearchResult = {
154+path: "sessions/w1.jsonl",
155+source: "sessions",
156+score: 1,
157+snippet: "x",
158+startLine: 1,
159+endLine: 2,
160+};
161+const cfg = asOpenClawConfig({
162+session: { scope: "global" },
163+tools: {
164+sessions: { visibility: "all" },
165+agentToAgent: { enabled: true, allow: ["*"] },
166+},
167+});
168+const filtered = await filterMemorySearchHitsBySessionVisibility({
169+ cfg,
170+agentId: "secondary",
171+requesterSessionKey: "agent:secondary:main",
172+sandboxed: false,
173+hits: [hit],
174+});
175+expect(filtered).toEqual([hit]);
176+});
177+178+it("does not keep cross-agent session hits outside the scoped store", async () => {
179+combinedSessionStore = {};
180+const hit: MemorySearchResult = {
181+path: "sessions/w1.jsonl",
182+source: "sessions",
183+score: 1,
184+snippet: "x",
185+startLine: 1,
186+endLine: 2,
187+};
188+const cfg = asOpenClawConfig({
189+tools: {
190+sessions: { visibility: "all" },
191+agentToAgent: { enabled: true, allow: ["*"] },
192+},
193+});
194+const filtered = await filterMemorySearchHitsBySessionVisibility({
195+ cfg,
196+requesterSessionKey: "agent:main:main",
197+sandboxed: false,
198+hits: [hit],
199+});
200+expect(filtered).toStrictEqual([]);
201+});
202+203+it("does not keep cross-agent session hits when a shared store returns out-of-scope keys", async () => {
204+combinedSessionStore = crossAgentStore;
205+const hit: MemorySearchResult = {
206+path: "sessions/w1.jsonl",
207+source: "sessions",
208+score: 1,
209+snippet: "x",
210+startLine: 1,
211+endLine: 2,
212+};
213+const cfg = asOpenClawConfig({
214+tools: {
215+sessions: { visibility: "all" },
216+agentToAgent: { enabled: true, allow: ["*"] },
217+},
218+});
219+const filtered = await filterMemorySearchHitsBySessionVisibility({
220+ cfg,
221+requesterSessionKey: "agent:main:main",
222+sandboxed: false,
223+hits: [hit],
224+});
225+expect(filtered).toStrictEqual([]);
226+});
227+228+it("does not keep owner-qualified cross-agent hits that collide with a scoped stem", async () => {
229+combinedSessionStore = {
230+"agent:main:main": {
231+sessionId: "main",
232+updatedAt: 1,
233+sessionFile: "/tmp/sessions/main.jsonl",
234+},
235+};
236+const hit: MemorySearchResult = {
237+path: "sessions/peer/main.jsonl",
238+source: "sessions",
239+score: 1,
240+snippet: "x",
241+startLine: 1,
242+endLine: 2,
243+};
244+const cfg = asOpenClawConfig({
245+tools: {
246+sessions: { visibility: "all" },
247+agentToAgent: { enabled: true, allow: ["*"] },
248+},
249+});
250+const filtered = await filterMemorySearchHitsBySessionVisibility({
251+ cfg,
252+requesterSessionKey: "agent:main:main",
253+sandboxed: false,
254+hits: [hit],
255+});
256+expect(filtered).toStrictEqual([]);
257+});
258+130259it("denies cross-agent session hits when agent-to-agent is disabled", async () => {
131260const hit: MemorySearchResult = {
132261path: "sessions/w1.jsonl",
@@ -203,4 +332,31 @@ describe("filterMemorySearchHitsBySessionVisibility", () => {
203332204333expect(filtered).toStrictEqual([]);
205334});
335+336+it("does not keep cross-agent deleted archive hits outside the scoped store when a2a is allowed", async () => {
337+combinedSessionStore = {};
338+const hit: MemorySearchResult = {
339+path: "sessions/peer/deleted-stem.jsonl.deleted.2026-02-16T22-27-33.000Z",
340+source: "sessions",
341+score: 1,
342+snippet: "x",
343+startLine: 1,
344+endLine: 2,
345+};
346+const cfg = asOpenClawConfig({
347+tools: {
348+sessions: { visibility: "all" },
349+agentToAgent: { enabled: true, allow: ["*"] },
350+},
351+});
352+353+const filtered = await filterMemorySearchHitsBySessionVisibility({
354+ cfg,
355+requesterSessionKey: "agent:main:main",
356+sandboxed: false,
357+hits: [hit],
358+});
359+360+expect(filtered).toStrictEqual([]);
361+});
206362});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。