




















@@ -45,6 +45,44 @@ function collectActionValues(schema: unknown, values: Set<string>): void {
4545}
4646}
474748+async function writeSessionStore(
49+storeTemplate: string,
50+agentId: string,
51+entries: Record<string, unknown>,
52+) {
53+await fs.writeFile(
54+storeTemplate.replaceAll("{agentId}", agentId),
55+JSON.stringify(entries, null, 2),
56+"utf-8",
57+);
58+}
59+60+function createToolsForStoredSession(storeTemplate: string, sessionKey: string) {
61+return createOpenClawCodingTools({
62+ sessionKey,
63+config: {
64+session: {
65+store: storeTemplate,
66+},
67+agents: {
68+defaults: {
69+subagents: {
70+maxSpawnDepth: 2,
71+},
72+},
73+},
74+},
75+});
76+}
77+78+function expectNoSubagentControlTools(tools: ReturnType<typeof createOpenClawCodingTools>) {
79+const names = new Set(tools.map((tool) => tool.name));
80+expect(names.has("sessions_spawn")).toBe(false);
81+expect(names.has("sessions_list")).toBe(false);
82+expect(names.has("sessions_history")).toBe(false);
83+expect(names.has("subagents")).toBe(false);
84+}
85+4886describe("createOpenClawCodingTools", () => {
4987const testConfig: OpenClawConfig = {};
5088@@ -196,43 +234,16 @@ describe("createOpenClawCodingTools", () => {
196234const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-depth-policy-"));
197235try {
198236const storeTemplate = path.join(tmpDir, "sessions-{agentId}.json");
199-const storePath = storeTemplate.replaceAll("{agentId}", "main");
200-await fs.writeFile(
201-storePath,
202-JSON.stringify(
203-{
204-"agent:main:subagent:flat": {
205-sessionId: "session-flat-depth-2",
206-updatedAt: Date.now(),
207-spawnDepth: 2,
208-},
209-},
210-null,
211-2,
212-),
213-"utf-8",
214-);
215-216-const tools = createOpenClawCodingTools({
217-sessionKey: "agent:main:subagent:flat",
218-config: {
219-session: {
220-store: storeTemplate,
221-},
222-agents: {
223-defaults: {
224-subagents: {
225-maxSpawnDepth: 2,
226-},
227-},
228-},
237+await writeSessionStore(storeTemplate, "main", {
238+"agent:main:subagent:flat": {
239+sessionId: "session-flat-depth-2",
240+updatedAt: Date.now(),
241+spawnDepth: 2,
229242},
230243});
231-const names = new Set(tools.map((tool) => tool.name));
232-expect(names.has("sessions_spawn")).toBe(false);
233-expect(names.has("sessions_list")).toBe(false);
234-expect(names.has("sessions_history")).toBe(false);
235-expect(names.has("subagents")).toBe(false);
244+245+const tools = createToolsForStoredSession(storeTemplate, "agent:main:subagent:flat");
246+expectNoSubagentControlTools(tools);
236247} finally {
237248await fs.rm(tmpDir, { recursive: true, force: true });
238249}
@@ -242,112 +253,47 @@ describe("createOpenClawCodingTools", () => {
242253const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-acp-subagent-policy-"));
243254try {
244255const storeTemplate = path.join(tmpDir, "sessions-{agentId}.json");
245-const mainStorePath = storeTemplate.replaceAll("{agentId}", "main");
246-const writerStorePath = storeTemplate.replaceAll("{agentId}", "writer");
247-await fs.writeFile(
248-mainStorePath,
249-JSON.stringify(
250-{
251-"agent:main:acp:child": {
252-sessionId: "session-acp-child",
253-updatedAt: Date.now(),
254-spawnedBy: "agent:main:subagent:parent",
255-spawnDepth: 2,
256-subagentRole: "leaf",
257-subagentControlScope: "none",
258-},
259-"agent:main:acp:plain": {
260-sessionId: "session-acp-plain",
261-updatedAt: Date.now(),
262-spawnedBy: "agent:main:main",
263-},
264-"agent:main:acp:parent": {
265-sessionId: "session-acp-parent",
266-updatedAt: Date.now(),
267-spawnedBy: "agent:main:subagent:parent",
268-},
269-},
270-null,
271-2,
272-),
273-"utf-8",
274-);
275-await fs.writeFile(
276-writerStorePath,
277-JSON.stringify(
278-{
279-"agent:writer:acp:child": {
280-sessionId: "session-acp-cross-agent-child",
281-updatedAt: Date.now(),
282-spawnedBy: "agent:main:acp:parent",
283-},
284-},
285-null,
286-2,
287-),
288-"utf-8",
289-);
290-291-const persistedEnvelopeTools = createOpenClawCodingTools({
292-sessionKey: "agent:main:acp:child",
293-config: {
294-session: {
295-store: storeTemplate,
296-},
297-agents: {
298-defaults: {
299-subagents: {
300-maxSpawnDepth: 2,
301-},
302-},
303-},
256+await writeSessionStore(storeTemplate, "main", {
257+"agent:main:acp:child": {
258+sessionId: "session-acp-child",
259+updatedAt: Date.now(),
260+spawnedBy: "agent:main:subagent:parent",
261+spawnDepth: 2,
262+subagentRole: "leaf",
263+subagentControlScope: "none",
264+},
265+"agent:main:acp:plain": {
266+sessionId: "session-acp-plain",
267+updatedAt: Date.now(),
268+spawnedBy: "agent:main:main",
269+},
270+"agent:main:acp:parent": {
271+sessionId: "session-acp-parent",
272+updatedAt: Date.now(),
273+spawnedBy: "agent:main:subagent:parent",
304274},
305275});
306-const persistedEnvelopeNames = new Set(persistedEnvelopeTools.map((tool) => tool.name));
307-expect(persistedEnvelopeNames.has("sessions_spawn")).toBe(false);
308-expect(persistedEnvelopeNames.has("sessions_list")).toBe(false);
309-expect(persistedEnvelopeNames.has("sessions_history")).toBe(false);
310-expect(persistedEnvelopeNames.has("subagents")).toBe(false);
311-312-const restrictedTools = createOpenClawCodingTools({
313-sessionKey: "agent:main:acp:plain",
314-config: {
315-session: {
316-store: storeTemplate,
317-},
318-agents: {
319-defaults: {
320-subagents: {
321-maxSpawnDepth: 2,
322-},
323-},
324-},
276+await writeSessionStore(storeTemplate, "writer", {
277+"agent:writer:acp:child": {
278+sessionId: "session-acp-cross-agent-child",
279+updatedAt: Date.now(),
280+spawnedBy: "agent:main:acp:parent",
325281},
326282});
283+284+const persistedEnvelopeTools = createToolsForStoredSession(
285+storeTemplate,
286+"agent:main:acp:child",
287+);
288+expectNoSubagentControlTools(persistedEnvelopeTools);
289+290+const restrictedTools = createToolsForStoredSession(storeTemplate, "agent:main:acp:plain");
327291const restrictedNames = new Set(restrictedTools.map((tool) => tool.name));
328292expect(restrictedNames.has("sessions_spawn")).toBe(true);
329293expect(restrictedNames.has("subagents")).toBe(true);
330294331-const ancestryTools = createOpenClawCodingTools({
332-sessionKey: "agent:writer:acp:child",
333-config: {
334-session: {
335-store: storeTemplate,
336-},
337-agents: {
338-defaults: {
339-subagents: {
340-maxSpawnDepth: 2,
341-},
342-},
343-},
344-},
345-});
346-const ancestryNames = new Set(ancestryTools.map((tool) => tool.name));
347-expect(ancestryNames.has("sessions_spawn")).toBe(false);
348-expect(ancestryNames.has("sessions_list")).toBe(false);
349-expect(ancestryNames.has("sessions_history")).toBe(false);
350-expect(ancestryNames.has("subagents")).toBe(false);
295+const ancestryTools = createToolsForStoredSession(storeTemplate, "agent:writer:acp:child");
296+expectNoSubagentControlTools(ancestryTools);
351297} finally {
352298await fs.rm(tmpDir, { recursive: true, force: true });
353299}
@@ -357,59 +303,23 @@ describe("createOpenClawCodingTools", () => {
357303const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-cross-agent-subagent-"));
358304try {
359305const storeTemplate = path.join(tmpDir, "sessions-{agentId}.json");
360-const mainStorePath = storeTemplate.replaceAll("{agentId}", "main");
361-const writerStorePath = storeTemplate.replaceAll("{agentId}", "writer");
362-await fs.writeFile(
363-mainStorePath,
364-JSON.stringify(
365-{
366-"agent:main:subagent:parent": {
367-sessionId: "session-main-parent",
368-updatedAt: Date.now(),
369-spawnedBy: "agent:main:main",
370-},
371-},
372-null,
373-2,
374-),
375-"utf-8",
376-);
377-await fs.writeFile(
378-writerStorePath,
379-JSON.stringify(
380-{
381-"agent:writer:subagent:child": {
382-sessionId: "session-writer-child",
383-updatedAt: Date.now(),
384-spawnedBy: "agent:main:subagent:parent",
385-},
386-},
387-null,
388-2,
389-),
390-"utf-8",
391-);
392-393-const tools = createOpenClawCodingTools({
394-sessionKey: "agent:writer:subagent:child",
395-config: {
396-session: {
397-store: storeTemplate,
398-},
399-agents: {
400-defaults: {
401-subagents: {
402-maxSpawnDepth: 2,
403-},
404-},
405-},
306+await writeSessionStore(storeTemplate, "main", {
307+"agent:main:subagent:parent": {
308+sessionId: "session-main-parent",
309+updatedAt: Date.now(),
310+spawnedBy: "agent:main:main",
406311},
407312});
408-const names = new Set(tools.map((tool) => tool.name));
409-expect(names.has("sessions_spawn")).toBe(false);
410-expect(names.has("sessions_list")).toBe(false);
411-expect(names.has("sessions_history")).toBe(false);
412-expect(names.has("subagents")).toBe(false);
313+await writeSessionStore(storeTemplate, "writer", {
314+"agent:writer:subagent:child": {
315+sessionId: "session-writer-child",
316+updatedAt: Date.now(),
317+spawnedBy: "agent:main:subagent:parent",
318+},
319+});
320+321+const tools = createToolsForStoredSession(storeTemplate, "agent:writer:subagent:child");
322+expectNoSubagentControlTools(tools);
413323} finally {
414324await fs.rm(tmpDir, { recursive: true, force: true });
415325}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。