Download src/agents/tools/agents-list-tool.test.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 7.93 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/agents/tools/agents-list-tool.test.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/agents/tools/agents-list-tool.test.ts
-
curl -L -o agents-list-tool.test.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/agents/tools/agents-list-tool.test.ts
7.93 kB
| // agents_list tests cover subagent discovery, runtime metadata, and legacy | |
| // runtime override handling. | |
| import { beforeEach, describe, expect, it, vi } from "vitest"; | |
| import type { OpenClawConfig } from "../../config/types.openclaw.js"; | |
| import { compactToolOutputHint } from "../tool-schema-hints.js"; | |
| import { createAgentsListTool } from "./agents-list-tool.js"; | |
| const loadConfigMock = vi.fn<() => OpenClawConfig>(); | |
| type AgentListDetails = { | |
| requester?: string; | |
| allowAny?: boolean; | |
| agents?: Array<{ | |
| id?: string; | |
| name?: string; | |
| configured?: boolean; | |
| model?: string; | |
| agentRuntime?: { id?: string; source?: string }; | |
| }>; | |
| }; | |
| vi.mock("../../config/config.js", async () => { | |
| const actual = | |
| await vi.importActual<typeof import("../../config/config.js")>("../../config/config.js"); | |
| return { | |
| ...actual, | |
| getRuntimeConfig: () => loadConfigMock(), | |
| }; | |
| }); | |
| describe("agents_list tool", () => { | |
| beforeEach(() => { | |
| vi.unstubAllEnvs(); | |
| loadConfigMock.mockReset(); | |
| }); | |
| it("returns model and agent runtime metadata for allowed agents", async () => { | |
| loadConfigMock.mockReturnValue({ | |
| agents: { | |
| defaults: { | |
| model: "anthropic/claude-opus-4.5", | |
| agentRuntime: { id: "openclaw" }, | |
| subagents: { allowAgents: ["codex"] }, | |
| }, | |
| list: [ | |
| { id: "main", default: true }, | |
| { | |
| id: "codex", | |
| name: "Codex", | |
| model: "openai/gpt-5.5", | |
| agentRuntime: { id: "openclaw" }, | |
| models: { | |
| "openai/gpt-5.5": { agentRuntime: { id: "codex" } }, | |
| }, | |
| }, | |
| ], | |
| }, | |
| } as unknown as OpenClawConfig); | |
| const tool = createAgentsListTool({ agentSessionKey: "agent:main:main" }); | |
| expect(tool.outputSchema).toMatchObject({ | |
| type: "object", | |
| required: ["requester", "allowAny", "agents"], | |
| }); | |
| expect(compactToolOutputHint(tool.outputSchema)).toBe( | |
| '{ agents: Array<{ configured: boolean; id: string; agentRuntime?: { id: string; source: "env" | "agent" | "defaults" | "model" | "provider" | "implicit" | "session" | "session-key" }; model?: string; name?: string }>; allowAny: boolean; requester: string }', | |
| ); | |
| const result = await tool.execute("call", {}); | |
| const details = result.details as AgentListDetails; | |
| expect(details).toStrictEqual({ | |
| requester: "main", | |
| allowAny: false, | |
| agents: [ | |
| { | |
| id: "codex", | |
| name: "Codex", | |
| configured: true, | |
| model: "openai/gpt-5.5", | |
| agentRuntime: { id: "codex", source: "model" }, | |
| }, | |
| ], | |
| }); | |
| }); | |
| it("resolves configured model aliases to the canonical model identity", async () => { | |
| // Routing aliases are transport-level names; the tool must publish the | |
| // resolved model that will actually run so spawn decisions see one identity. | |
| loadConfigMock.mockReturnValue({ | |
| agents: { | |
| defaults: { | |
| model: { | |
| primary: "clawrouter/openai/gpt-5.6", | |
| fallbacks: ["openai/gpt-5.6-luna"], | |
| }, | |
| models: { | |
| "openai/gpt-5.6-sol": { | |
| alias: "clawrouter/openai/gpt-5.6", | |
| agentRuntime: { id: "codex" }, | |
| }, | |
| }, | |
| subagents: { allowAgents: ["main"] }, | |
| }, | |
| list: [{ id: "main", default: true }], | |
| }, | |
| } as unknown as OpenClawConfig); | |
| const result = await createAgentsListTool({ agentSessionKey: "agent:main:main" }).execute( | |
| "call", | |
| {}, | |
| ); | |
| const details = result.details as AgentListDetails; | |
| expect(details).toStrictEqual({ | |
| requester: "main", | |
| allowAny: false, | |
| agents: [ | |
| { | |
| id: "main", | |
| name: undefined, | |
| configured: true, | |
| model: "openai/gpt-5.6-sol", | |
| agentRuntime: { id: "codex", source: "model" }, | |
| }, | |
| ], | |
| }); | |
| }); | |
| it("does not advertise stale allowlist-only targets as spawnable agents", async () => { | |
| // Allowlist entries are permissions, not agent definitions; stale ids should | |
| // not be presented as runnable subagents. | |
| loadConfigMock.mockReturnValue({ | |
| agents: { | |
| list: [ | |
| { | |
| id: "main", | |
| default: true, | |
| subagents: { allowAgents: ["stale"] }, | |
| }, | |
| ], | |
| }, | |
| } satisfies OpenClawConfig); | |
| const result = await createAgentsListTool({ agentSessionKey: "agent:main:main" }).execute( | |
| "call", | |
| {}, | |
| ); | |
| const details = result.details as AgentListDetails; | |
| expect(details).toStrictEqual({ | |
| requester: "main", | |
| allowAny: false, | |
| agents: [], | |
| }); | |
| }); | |
| it("returns requester as the only target when no subagent allowlist is configured", async () => { | |
| loadConfigMock.mockReturnValue({ | |
| agents: { | |
| list: [{ id: "main", default: true }, { id: "codex" }], | |
| }, | |
| } satisfies OpenClawConfig); | |
| const result = await createAgentsListTool({ agentSessionKey: "agent:main:main" }).execute( | |
| "call", | |
| {}, | |
| ); | |
| const details = result.details as AgentListDetails; | |
| expect(details).toStrictEqual({ | |
| requester: "main", | |
| allowAny: false, | |
| agents: [ | |
| { | |
| id: "main", | |
| name: undefined, | |
| configured: true, | |
| model: "openai/gpt-6-astra", | |
| agentRuntime: { id: "codex", source: "implicit" }, | |
| }, | |
| ], | |
| }); | |
| }); | |
| it("ignores legacy env-forced plugin runtime selections", async () => { | |
| // Runtime selection now comes from config/model routing, not a process-wide | |
| // legacy env override. | |
| vi.stubEnv("OPENCLAW_AGENT_RUNTIME", "codex"); | |
| loadConfigMock.mockReturnValue({ | |
| agents: { | |
| defaults: { | |
| model: "openai/gpt-5.5", | |
| }, | |
| list: [{ id: "main", default: true }], | |
| }, | |
| } satisfies OpenClawConfig); | |
| const result = await createAgentsListTool({ agentSessionKey: "agent:main:main" }).execute( | |
| "call", | |
| {}, | |
| ); | |
| const details = result.details as AgentListDetails; | |
| expect(details).toStrictEqual({ | |
| requester: "main", | |
| allowAny: false, | |
| agents: [ | |
| { | |
| id: "main", | |
| name: undefined, | |
| configured: true, | |
| model: "openai/gpt-5.5", | |
| agentRuntime: { id: "codex", source: "implicit" }, | |
| }, | |
| ], | |
| }); | |
| }); | |
| it("ignores legacy per-agent runtime overrides", async () => { | |
| loadConfigMock.mockReturnValue({ | |
| agents: { | |
| defaults: { | |
| agentRuntime: { id: "auto" }, | |
| subagents: { allowAgents: ["strict"] }, | |
| }, | |
| list: [ | |
| { id: "main", default: true }, | |
| { id: "strict", agentRuntime: { id: "codex" } }, | |
| ], | |
| }, | |
| } satisfies OpenClawConfig); | |
| const result = await createAgentsListTool({ agentSessionKey: "agent:main:main" }).execute( | |
| "call", | |
| {}, | |
| ); | |
| const details = result.details as AgentListDetails; | |
| expect(details).toStrictEqual({ | |
| requester: "main", | |
| allowAny: false, | |
| agents: [ | |
| { | |
| id: "strict", | |
| name: undefined, | |
| configured: true, | |
| model: "openai/gpt-6-astra", | |
| agentRuntime: { id: "codex", source: "implicit" }, | |
| }, | |
| ], | |
| }); | |
| }); | |
| it("uses the persisted fixed-store owner for a bare requester key", async () => { | |
| loadConfigMock.mockReturnValue({ | |
| session: { store: "/tmp/shared-sessions.sqlite", scope: "global" }, | |
| agents: { | |
| ownership: "explicit", | |
| defaults: { sessionStore: { agentId: "ops" } }, | |
| entries: { ops: {}, research: {} }, | |
| }, | |
| }); | |
| const result = await createAgentsListTool({ agentSessionKey: "global" }).execute("call", {}); | |
| expect(result.details).toMatchObject({ | |
| requester: "ops", | |
| agents: [{ id: "ops", configured: true }], | |
| }); | |
| }); | |
| }); | |